NetworkManagementService.java revision e8914c36276710de50b347c1e6aecfa45d6a56cd
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import static android.Manifest.permission.CONNECTIVITY_INTERNAL; 20import static android.Manifest.permission.DUMP; 21import static android.Manifest.permission.SHUTDOWN; 22import static android.net.NetworkStats.SET_DEFAULT; 23import static android.net.NetworkStats.TAG_NONE; 24import static android.net.NetworkStats.UID_ALL; 25import static android.net.TrafficStats.UID_TETHERING; 26import static android.provider.Settings.Secure.NETSTATS_ENABLED; 27import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult; 28import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult; 29import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceRxThrottleResult; 30import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceTxThrottleResult; 31import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult; 32import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult; 33import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult; 34import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult; 35import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsResult; 36import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult; 37import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; 38 39import android.content.Context; 40import android.net.INetworkManagementEventObserver; 41import android.net.InterfaceConfiguration; 42import android.net.LinkAddress; 43import android.net.NetworkStats; 44import android.net.NetworkUtils; 45import android.net.RouteInfo; 46import android.net.wifi.WifiConfiguration; 47import android.net.wifi.WifiConfiguration.KeyMgmt; 48import android.os.INetworkManagementService; 49import android.os.RemoteCallbackList; 50import android.os.RemoteException; 51import android.os.SystemClock; 52import android.os.SystemProperties; 53import android.provider.Settings; 54import android.util.Log; 55import android.util.Slog; 56import android.util.SparseBooleanArray; 57 58import com.android.internal.net.NetworkStatsFactory; 59import com.android.server.NativeDaemonConnector.Command; 60import com.google.android.collect.Sets; 61 62import java.io.BufferedReader; 63import java.io.DataInputStream; 64import java.io.File; 65import java.io.FileDescriptor; 66import java.io.FileInputStream; 67import java.io.IOException; 68import java.io.InputStreamReader; 69import java.io.PrintWriter; 70import java.net.Inet4Address; 71import java.net.InetAddress; 72import java.net.InterfaceAddress; 73import java.net.NetworkInterface; 74import java.net.SocketException; 75import java.util.ArrayList; 76import java.util.Collection; 77import java.util.HashSet; 78import java.util.NoSuchElementException; 79import java.util.StringTokenizer; 80import java.util.concurrent.CountDownLatch; 81 82/** 83 * @hide 84 */ 85public class NetworkManagementService extends INetworkManagementService.Stub 86 implements Watchdog.Monitor { 87 private static final String TAG = "NetworkManagementService"; 88 private static final boolean DBG = false; 89 private static final String NETD_TAG = "NetdConnector"; 90 91 private static final String ADD = "add"; 92 private static final String REMOVE = "remove"; 93 94 private static final String DEFAULT = "default"; 95 private static final String SECONDARY = "secondary"; 96 97 /** 98 * Name representing {@link #setGlobalAlert(long)} limit when delivered to 99 * {@link INetworkManagementEventObserver#limitReached(String, String)}. 100 */ 101 public static final String LIMIT_GLOBAL_ALERT = "globalAlert"; 102 103 class NetdResponseCode { 104 /* Keep in sync with system/netd/ResponseCode.h */ 105 public static final int InterfaceListResult = 110; 106 public static final int TetherInterfaceListResult = 111; 107 public static final int TetherDnsFwdTgtListResult = 112; 108 public static final int TtyListResult = 113; 109 110 public static final int TetherStatusResult = 210; 111 public static final int IpFwdStatusResult = 211; 112 public static final int InterfaceGetCfgResult = 213; 113 public static final int SoftapStatusResult = 214; 114 public static final int InterfaceRxCounterResult = 216; 115 public static final int InterfaceTxCounterResult = 217; 116 public static final int InterfaceRxThrottleResult = 218; 117 public static final int InterfaceTxThrottleResult = 219; 118 public static final int QuotaCounterResult = 220; 119 public static final int TetheringStatsResult = 221; 120 public static final int DnsProxyQueryResult = 222; 121 122 public static final int InterfaceChange = 600; 123 public static final int BandwidthControl = 601; 124 } 125 126 /** 127 * Binder context for this service 128 */ 129 private Context mContext; 130 131 /** 132 * connector object for communicating with netd 133 */ 134 private NativeDaemonConnector mConnector; 135 136 private Thread mThread; 137 private final CountDownLatch mConnectedSignal = new CountDownLatch(1); 138 139 private final RemoteCallbackList<INetworkManagementEventObserver> mObservers = 140 new RemoteCallbackList<INetworkManagementEventObserver>(); 141 142 private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory(); 143 144 private Object mQuotaLock = new Object(); 145 /** Set of interfaces with active quotas. */ 146 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet(); 147 /** Set of interfaces with active alerts. */ 148 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet(); 149 /** Set of UIDs with active reject rules. */ 150 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray(); 151 152 private volatile boolean mBandwidthControlEnabled; 153 154 /** 155 * Constructs a new NetworkManagementService instance 156 * 157 * @param context Binder context for this service 158 */ 159 private NetworkManagementService(Context context) { 160 mContext = context; 161 162 if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 163 return; 164 } 165 166 mConnector = new NativeDaemonConnector( 167 new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 50); 168 mThread = new Thread(mConnector, NETD_TAG); 169 170 // Add ourself to the Watchdog monitors. 171 Watchdog.getInstance().addMonitor(this); 172 } 173 174 public static NetworkManagementService create(Context context) throws InterruptedException { 175 NetworkManagementService service = new NetworkManagementService(context); 176 if (DBG) Slog.d(TAG, "Creating NetworkManagementService"); 177 service.mThread.start(); 178 if (DBG) Slog.d(TAG, "Awaiting socket connection"); 179 service.mConnectedSignal.await(); 180 if (DBG) Slog.d(TAG, "Connected"); 181 return service; 182 } 183 184 public void systemReady() { 185 // only enable bandwidth control when support exists, and requested by 186 // system setting. 187 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists(); 188 final boolean shouldEnable = 189 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0; 190 191 if (hasKernelSupport && shouldEnable) { 192 Slog.d(TAG, "enabling bandwidth control"); 193 try { 194 mConnector.execute("bandwidth", "enable"); 195 mBandwidthControlEnabled = true; 196 } catch (NativeDaemonConnectorException e) { 197 Log.wtf(TAG, "problem enabling bandwidth controls", e); 198 } 199 } else { 200 Slog.d(TAG, "not enabling bandwidth control"); 201 } 202 203 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0"); 204 } 205 206 @Override 207 public void registerObserver(INetworkManagementEventObserver observer) { 208 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 209 mObservers.register(observer); 210 } 211 212 @Override 213 public void unregisterObserver(INetworkManagementEventObserver observer) { 214 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 215 mObservers.unregister(observer); 216 } 217 218 /** 219 * Notify our observers of an interface status change 220 */ 221 private void notifyInterfaceStatusChanged(String iface, boolean up) { 222 final int length = mObservers.beginBroadcast(); 223 for (int i = 0; i < length; i++) { 224 try { 225 mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up); 226 } catch (RemoteException e) { 227 } 228 } 229 mObservers.finishBroadcast(); 230 } 231 232 /** 233 * Notify our observers of an interface link state change 234 * (typically, an Ethernet cable has been plugged-in or unplugged). 235 */ 236 private void notifyInterfaceLinkStateChanged(String iface, boolean up) { 237 final int length = mObservers.beginBroadcast(); 238 for (int i = 0; i < length; i++) { 239 try { 240 mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up); 241 } catch (RemoteException e) { 242 } 243 } 244 mObservers.finishBroadcast(); 245 } 246 247 /** 248 * Notify our observers of an interface addition. 249 */ 250 private void notifyInterfaceAdded(String iface) { 251 final int length = mObservers.beginBroadcast(); 252 for (int i = 0; i < length; i++) { 253 try { 254 mObservers.getBroadcastItem(i).interfaceAdded(iface); 255 } catch (RemoteException e) { 256 } 257 } 258 mObservers.finishBroadcast(); 259 } 260 261 /** 262 * Notify our observers of an interface removal. 263 */ 264 private void notifyInterfaceRemoved(String iface) { 265 // netd already clears out quota and alerts for removed ifaces; update 266 // our sanity-checking state. 267 mActiveAlertIfaces.remove(iface); 268 mActiveQuotaIfaces.remove(iface); 269 270 final int length = mObservers.beginBroadcast(); 271 for (int i = 0; i < length; i++) { 272 try { 273 mObservers.getBroadcastItem(i).interfaceRemoved(iface); 274 } catch (RemoteException e) { 275 } 276 } 277 mObservers.finishBroadcast(); 278 } 279 280 /** 281 * Notify our observers of a limit reached. 282 */ 283 private void notifyLimitReached(String limitName, String iface) { 284 final int length = mObservers.beginBroadcast(); 285 for (int i = 0; i < length; i++) { 286 try { 287 mObservers.getBroadcastItem(i).limitReached(limitName, iface); 288 } catch (RemoteException e) { 289 } 290 } 291 mObservers.finishBroadcast(); 292 } 293 294 /** 295 * Let us know the daemon is connected 296 */ 297 protected void onDaemonConnected() { 298 mConnectedSignal.countDown(); 299 } 300 301 302 // 303 // Netd Callback handling 304 // 305 306 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks { 307 /** {@inheritDoc} */ 308 public void onDaemonConnected() { 309 NetworkManagementService.this.onDaemonConnected(); 310 } 311 312 /** {@inheritDoc} */ 313 public boolean onEvent(int code, String raw, String[] cooked) { 314 switch (code) { 315 case NetdResponseCode.InterfaceChange: 316 /* 317 * a network interface change occured 318 * Format: "NNN Iface added <name>" 319 * "NNN Iface removed <name>" 320 * "NNN Iface changed <name> <up/down>" 321 * "NNN Iface linkstatus <name> <up/down>" 322 */ 323 if (cooked.length < 4 || !cooked[1].equals("Iface")) { 324 throw new IllegalStateException( 325 String.format("Invalid event from daemon (%s)", raw)); 326 } 327 if (cooked[2].equals("added")) { 328 notifyInterfaceAdded(cooked[3]); 329 return true; 330 } else if (cooked[2].equals("removed")) { 331 notifyInterfaceRemoved(cooked[3]); 332 return true; 333 } else if (cooked[2].equals("changed") && cooked.length == 5) { 334 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); 335 return true; 336 } else if (cooked[2].equals("linkstate") && cooked.length == 5) { 337 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); 338 return true; 339 } 340 throw new IllegalStateException( 341 String.format("Invalid event from daemon (%s)", raw)); 342 // break; 343 case NetdResponseCode.BandwidthControl: 344 /* 345 * Bandwidth control needs some attention 346 * Format: "NNN limit alert <alertName> <ifaceName>" 347 */ 348 if (cooked.length < 5 || !cooked[1].equals("limit")) { 349 throw new IllegalStateException( 350 String.format("Invalid event from daemon (%s)", raw)); 351 } 352 if (cooked[2].equals("alert")) { 353 notifyLimitReached(cooked[3], cooked[4]); 354 return true; 355 } 356 throw new IllegalStateException( 357 String.format("Invalid event from daemon (%s)", raw)); 358 // break; 359 default: break; 360 } 361 return false; 362 } 363 } 364 365 366 // 367 // INetworkManagementService members 368 // 369 370 @Override 371 public String[] listInterfaces() { 372 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 373 try { 374 return NativeDaemonEvent.filterMessageList( 375 mConnector.executeForList("interface", "list"), InterfaceListResult); 376 } catch (NativeDaemonConnectorException e) { 377 throw e.rethrowAsParcelableException(); 378 } 379 } 380 381 @Override 382 public InterfaceConfiguration getInterfaceConfig(String iface) { 383 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 384 385 final NativeDaemonEvent event; 386 try { 387 event = mConnector.execute("interface", "getcfg", iface); 388 } catch (NativeDaemonConnectorException e) { 389 throw e.rethrowAsParcelableException(); 390 } 391 392 event.checkCode(InterfaceGetCfgResult); 393 394 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3 395 final StringTokenizer st = new StringTokenizer(event.getMessage()); 396 397 InterfaceConfiguration cfg; 398 try { 399 cfg = new InterfaceConfiguration(); 400 cfg.setHardwareAddress(st.nextToken(" ")); 401 InetAddress addr = null; 402 int prefixLength = 0; 403 try { 404 addr = NetworkUtils.numericToInetAddress(st.nextToken()); 405 } catch (IllegalArgumentException iae) { 406 Slog.e(TAG, "Failed to parse ipaddr", iae); 407 } 408 409 try { 410 prefixLength = Integer.parseInt(st.nextToken()); 411 } catch (NumberFormatException nfe) { 412 Slog.e(TAG, "Failed to parse prefixLength", nfe); 413 } 414 415 cfg.setLinkAddress(new LinkAddress(addr, prefixLength)); 416 while (st.hasMoreTokens()) { 417 cfg.setFlag(st.nextToken()); 418 } 419 } catch (NoSuchElementException nsee) { 420 throw new IllegalStateException("Invalid response from daemon: " + event); 421 } 422 return cfg; 423 } 424 425 @Override 426 public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { 427 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 428 LinkAddress linkAddr = cfg.getLinkAddress(); 429 if (linkAddr == null || linkAddr.getAddress() == null) { 430 throw new IllegalStateException("Null LinkAddress given"); 431 } 432 433 final Command cmd = new Command("interface", "setcfg", iface, 434 linkAddr.getAddress().getHostAddress(), 435 linkAddr.getNetworkPrefixLength()); 436 for (String flag : cfg.getFlags()) { 437 cmd.appendArg(flag); 438 } 439 440 try { 441 mConnector.execute(cmd); 442 } catch (NativeDaemonConnectorException e) { 443 throw e.rethrowAsParcelableException(); 444 } 445 } 446 447 @Override 448 public void setInterfaceDown(String iface) { 449 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 450 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 451 ifcg.setInterfaceDown(); 452 setInterfaceConfig(iface, ifcg); 453 } 454 455 @Override 456 public void setInterfaceUp(String iface) { 457 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 458 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 459 ifcg.setInterfaceUp(); 460 setInterfaceConfig(iface, ifcg); 461 } 462 463 @Override 464 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) { 465 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 466 try { 467 mConnector.execute( 468 "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable"); 469 } catch (NativeDaemonConnectorException e) { 470 throw e.rethrowAsParcelableException(); 471 } 472 } 473 474 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its 475 IPv6 addresses on interface down, but we need to do full clean up here */ 476 @Override 477 public void clearInterfaceAddresses(String iface) { 478 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 479 try { 480 mConnector.execute("interface", "clearaddrs", iface); 481 } catch (NativeDaemonConnectorException e) { 482 throw e.rethrowAsParcelableException(); 483 } 484 } 485 486 @Override 487 public void enableIpv6(String iface) { 488 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 489 try { 490 mConnector.execute("interface", "ipv6", iface, "enable"); 491 } catch (NativeDaemonConnectorException e) { 492 throw e.rethrowAsParcelableException(); 493 } 494 } 495 496 @Override 497 public void disableIpv6(String iface) { 498 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 499 try { 500 mConnector.execute("interface", "ipv6", iface, "disable"); 501 } catch (NativeDaemonConnectorException e) { 502 throw e.rethrowAsParcelableException(); 503 } 504 } 505 506 @Override 507 public void addRoute(String interfaceName, RouteInfo route) { 508 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 509 modifyRoute(interfaceName, ADD, route, DEFAULT); 510 } 511 512 @Override 513 public void removeRoute(String interfaceName, RouteInfo route) { 514 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 515 modifyRoute(interfaceName, REMOVE, route, DEFAULT); 516 } 517 518 @Override 519 public void addSecondaryRoute(String interfaceName, RouteInfo route) { 520 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 521 modifyRoute(interfaceName, ADD, route, SECONDARY); 522 } 523 524 @Override 525 public void removeSecondaryRoute(String interfaceName, RouteInfo route) { 526 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 527 modifyRoute(interfaceName, REMOVE, route, SECONDARY); 528 } 529 530 private void modifyRoute(String interfaceName, String action, RouteInfo route, String type) { 531 final Command cmd = new Command("interface", "route", action, interfaceName, type); 532 533 // create triplet: dest-ip-addr prefixlength gateway-ip-addr 534 final LinkAddress la = route.getDestination(); 535 cmd.appendArg(la.getAddress().getHostAddress()); 536 cmd.appendArg(la.getNetworkPrefixLength()); 537 538 if (route.getGateway() == null) { 539 if (la.getAddress() instanceof Inet4Address) { 540 cmd.appendArg("0.0.0.0"); 541 } else { 542 cmd.appendArg("::0"); 543 } 544 } else { 545 cmd.appendArg(route.getGateway().getHostAddress()); 546 } 547 548 try { 549 mConnector.execute(cmd); 550 } catch (NativeDaemonConnectorException e) { 551 throw e.rethrowAsParcelableException(); 552 } 553 } 554 555 private ArrayList<String> readRouteList(String filename) { 556 FileInputStream fstream = null; 557 ArrayList<String> list = new ArrayList<String>(); 558 559 try { 560 fstream = new FileInputStream(filename); 561 DataInputStream in = new DataInputStream(fstream); 562 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 563 String s; 564 565 // throw away the title line 566 567 while (((s = br.readLine()) != null) && (s.length() != 0)) { 568 list.add(s); 569 } 570 } catch (IOException ex) { 571 // return current list, possibly empty 572 } finally { 573 if (fstream != null) { 574 try { 575 fstream.close(); 576 } catch (IOException ex) {} 577 } 578 } 579 580 return list; 581 } 582 583 @Override 584 public RouteInfo[] getRoutes(String interfaceName) { 585 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 586 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>(); 587 588 // v4 routes listed as: 589 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT 590 for (String s : readRouteList("/proc/net/route")) { 591 String[] fields = s.split("\t"); 592 593 if (fields.length > 7) { 594 String iface = fields[0]; 595 596 if (interfaceName.equals(iface)) { 597 String dest = fields[1]; 598 String gate = fields[2]; 599 String flags = fields[3]; // future use? 600 String mask = fields[7]; 601 try { 602 // address stored as a hex string, ex: 0014A8C0 603 InetAddress destAddr = 604 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16)); 605 int prefixLength = 606 NetworkUtils.netmaskIntToPrefixLength( 607 (int)Long.parseLong(mask, 16)); 608 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength); 609 610 // address stored as a hex string, ex 0014A8C0 611 InetAddress gatewayAddr = 612 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16)); 613 614 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr); 615 routes.add(route); 616 } catch (Exception e) { 617 Log.e(TAG, "Error parsing route " + s + " : " + e); 618 continue; 619 } 620 } 621 } 622 } 623 624 // v6 routes listed as: 625 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface 626 for (String s : readRouteList("/proc/net/ipv6_route")) { 627 String[]fields = s.split("\\s+"); 628 if (fields.length > 9) { 629 String iface = fields[9].trim(); 630 if (interfaceName.equals(iface)) { 631 String dest = fields[0]; 632 String prefix = fields[1]; 633 String gate = fields[4]; 634 635 try { 636 // prefix length stored as a hex string, ex 40 637 int prefixLength = Integer.parseInt(prefix, 16); 638 639 // address stored as a 32 char hex string 640 // ex fe800000000000000000000000000000 641 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest); 642 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength); 643 644 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate); 645 646 RouteInfo route = new RouteInfo(linkAddress, gateAddr); 647 routes.add(route); 648 } catch (Exception e) { 649 Log.e(TAG, "Error parsing route " + s + " : " + e); 650 continue; 651 } 652 } 653 } 654 } 655 return routes.toArray(new RouteInfo[routes.size()]); 656 } 657 658 @Override 659 public void shutdown() { 660 // TODO: remove from aidl if nobody calls externally 661 mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG); 662 663 Slog.d(TAG, "Shutting down"); 664 } 665 666 @Override 667 public boolean getIpForwardingEnabled() throws IllegalStateException{ 668 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 669 670 final NativeDaemonEvent event; 671 try { 672 event = mConnector.execute("ipfwd", "status"); 673 } catch (NativeDaemonConnectorException e) { 674 throw e.rethrowAsParcelableException(); 675 } 676 677 // 211 Forwarding enabled 678 event.checkCode(IpFwdStatusResult); 679 return event.getMessage().endsWith("enabled"); 680 } 681 682 @Override 683 public void setIpForwardingEnabled(boolean enable) { 684 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 685 try { 686 mConnector.execute("ipfwd", enable ? "enable" : "disable"); 687 } catch (NativeDaemonConnectorException e) { 688 throw e.rethrowAsParcelableException(); 689 } 690 } 691 692 @Override 693 public void startTethering(String[] dhcpRange) { 694 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 695 // cmd is "tether start first_start first_stop second_start second_stop ..." 696 // an odd number of addrs will fail 697 698 final Command cmd = new Command("tether", "start"); 699 for (String d : dhcpRange) { 700 cmd.appendArg(d); 701 } 702 703 try { 704 mConnector.execute(cmd); 705 } catch (NativeDaemonConnectorException e) { 706 throw e.rethrowAsParcelableException(); 707 } 708 } 709 710 @Override 711 public void stopTethering() { 712 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 713 try { 714 mConnector.execute("tether", "stop"); 715 } catch (NativeDaemonConnectorException e) { 716 throw e.rethrowAsParcelableException(); 717 } 718 } 719 720 @Override 721 public boolean isTetheringStarted() { 722 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 723 724 final NativeDaemonEvent event; 725 try { 726 event = mConnector.execute("tether", "status"); 727 } catch (NativeDaemonConnectorException e) { 728 throw e.rethrowAsParcelableException(); 729 } 730 731 // 210 Tethering services started 732 event.checkCode(TetherStatusResult); 733 return event.getMessage().endsWith("started"); 734 } 735 736 @Override 737 public void tetherInterface(String iface) { 738 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 739 try { 740 mConnector.execute("tether", "interface", "add", iface); 741 } catch (NativeDaemonConnectorException e) { 742 throw e.rethrowAsParcelableException(); 743 } 744 } 745 746 @Override 747 public void untetherInterface(String iface) { 748 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 749 try { 750 mConnector.execute("tether", "interface", "remove", iface); 751 } catch (NativeDaemonConnectorException e) { 752 throw e.rethrowAsParcelableException(); 753 } 754 } 755 756 @Override 757 public String[] listTetheredInterfaces() { 758 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 759 try { 760 return NativeDaemonEvent.filterMessageList( 761 mConnector.executeForList("tether", "interface", "list"), 762 TetherInterfaceListResult); 763 } catch (NativeDaemonConnectorException e) { 764 throw e.rethrowAsParcelableException(); 765 } 766 } 767 768 @Override 769 public void setDnsForwarders(String[] dns) { 770 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 771 772 final Command cmd = new Command("tether", "dns", "set"); 773 for (String s : dns) { 774 cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress()); 775 } 776 777 try { 778 mConnector.execute(cmd); 779 } catch (NativeDaemonConnectorException e) { 780 throw e.rethrowAsParcelableException(); 781 } 782 } 783 784 @Override 785 public String[] getDnsForwarders() { 786 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 787 try { 788 return NativeDaemonEvent.filterMessageList( 789 mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult); 790 } catch (NativeDaemonConnectorException e) { 791 throw e.rethrowAsParcelableException(); 792 } 793 } 794 795 private void modifyNat(String action, String internalInterface, String externalInterface) 796 throws SocketException { 797 final Command cmd = new Command("nat", action, internalInterface, externalInterface); 798 799 final NetworkInterface internalNetworkInterface = NetworkInterface.getByName( 800 internalInterface); 801 if (internalNetworkInterface == null) { 802 cmd.appendArg("0"); 803 } else { 804 Collection<InterfaceAddress> interfaceAddresses = internalNetworkInterface 805 .getInterfaceAddresses(); 806 cmd.appendArg(interfaceAddresses.size()); 807 for (InterfaceAddress ia : interfaceAddresses) { 808 InetAddress addr = NetworkUtils.getNetworkPart( 809 ia.getAddress(), ia.getNetworkPrefixLength()); 810 cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength()); 811 } 812 } 813 814 try { 815 mConnector.execute(cmd); 816 } catch (NativeDaemonConnectorException e) { 817 throw e.rethrowAsParcelableException(); 818 } 819 } 820 821 @Override 822 public void enableNat(String internalInterface, String externalInterface) { 823 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 824 try { 825 modifyNat("enable", internalInterface, externalInterface); 826 } catch (SocketException e) { 827 throw new IllegalStateException(e); 828 } 829 } 830 831 @Override 832 public void disableNat(String internalInterface, String externalInterface) { 833 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 834 try { 835 modifyNat("disable", internalInterface, externalInterface); 836 } catch (SocketException e) { 837 throw new IllegalStateException(e); 838 } 839 } 840 841 @Override 842 public String[] listTtys() { 843 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 844 try { 845 return NativeDaemonEvent.filterMessageList( 846 mConnector.executeForList("list_ttys"), TtyListResult); 847 } catch (NativeDaemonConnectorException e) { 848 throw e.rethrowAsParcelableException(); 849 } 850 } 851 852 @Override 853 public void attachPppd( 854 String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) { 855 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 856 try { 857 mConnector.execute("pppd", "attach", tty, 858 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(), 859 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(), 860 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(), 861 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()); 862 } catch (NativeDaemonConnectorException e) { 863 throw e.rethrowAsParcelableException(); 864 } 865 } 866 867 @Override 868 public void detachPppd(String tty) { 869 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 870 try { 871 mConnector.execute("pppd", "detach", tty); 872 } catch (NativeDaemonConnectorException e) { 873 throw e.rethrowAsParcelableException(); 874 } 875 } 876 877 @Override 878 public void startAccessPoint( 879 WifiConfiguration wifiConfig, String wlanIface, String softapIface) { 880 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 881 try { 882 wifiFirmwareReload(wlanIface, "AP"); 883 if (wifiConfig == null) { 884 mConnector.execute("softap", "set", wlanIface, softapIface); 885 } else { 886 mConnector.execute("softap", "set", wlanIface, softapIface, wifiConfig.SSID, 887 getSecurityType(wifiConfig), wifiConfig.preSharedKey); 888 } 889 mConnector.execute("softap", "startap"); 890 } catch (NativeDaemonConnectorException e) { 891 throw e.rethrowAsParcelableException(); 892 } 893 } 894 895 private static String getSecurityType(WifiConfiguration wifiConfig) { 896 switch (wifiConfig.getAuthType()) { 897 case KeyMgmt.WPA_PSK: 898 return "wpa-psk"; 899 case KeyMgmt.WPA2_PSK: 900 return "wpa2-psk"; 901 default: 902 return "open"; 903 } 904 } 905 906 /* @param mode can be "AP", "STA" or "P2P" */ 907 @Override 908 public void wifiFirmwareReload(String wlanIface, String mode) { 909 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 910 try { 911 mConnector.execute("softap", "fwreload", wlanIface, mode); 912 } catch (NativeDaemonConnectorException e) { 913 throw e.rethrowAsParcelableException(); 914 } 915 } 916 917 @Override 918 public void stopAccessPoint(String wlanIface) { 919 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 920 try { 921 mConnector.execute("softap", "stopap"); 922 mConnector.execute("softap", "stop", wlanIface); 923 wifiFirmwareReload(wlanIface, "STA"); 924 } catch (NativeDaemonConnectorException e) { 925 throw e.rethrowAsParcelableException(); 926 } 927 } 928 929 @Override 930 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface) { 931 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 932 try { 933 if (wifiConfig == null) { 934 mConnector.execute("softap", "set", wlanIface, softapIface); 935 } else { 936 mConnector.execute("softap", "set", wlanIface, softapIface, wifiConfig.SSID, 937 getSecurityType(wifiConfig), wifiConfig.preSharedKey); 938 } 939 } catch (NativeDaemonConnectorException e) { 940 throw e.rethrowAsParcelableException(); 941 } 942 } 943 944 @Override 945 public NetworkStats getNetworkStatsSummaryDev() { 946 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 947 return mStatsFactory.readNetworkStatsSummaryDev(); 948 } 949 950 @Override 951 public NetworkStats getNetworkStatsSummaryXt() { 952 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 953 return mStatsFactory.readNetworkStatsSummaryXt(); 954 } 955 956 @Override 957 public NetworkStats getNetworkStatsDetail() { 958 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 959 return mStatsFactory.readNetworkStatsDetail(UID_ALL); 960 } 961 962 @Override 963 public void setInterfaceQuota(String iface, long quotaBytes) { 964 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 965 966 // silently discard when control disabled 967 // TODO: eventually migrate to be always enabled 968 if (!mBandwidthControlEnabled) return; 969 970 synchronized (mQuotaLock) { 971 if (mActiveQuotaIfaces.contains(iface)) { 972 throw new IllegalStateException("iface " + iface + " already has quota"); 973 } 974 975 try { 976 // TODO: support quota shared across interfaces 977 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes); 978 mActiveQuotaIfaces.add(iface); 979 } catch (NativeDaemonConnectorException e) { 980 throw e.rethrowAsParcelableException(); 981 } 982 } 983 } 984 985 @Override 986 public void removeInterfaceQuota(String iface) { 987 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 988 989 // silently discard when control disabled 990 // TODO: eventually migrate to be always enabled 991 if (!mBandwidthControlEnabled) return; 992 993 synchronized (mQuotaLock) { 994 if (!mActiveQuotaIfaces.contains(iface)) { 995 // TODO: eventually consider throwing 996 return; 997 } 998 999 mActiveQuotaIfaces.remove(iface); 1000 mActiveAlertIfaces.remove(iface); 1001 1002 try { 1003 // TODO: support quota shared across interfaces 1004 mConnector.execute("bandwidth", "removeiquota", iface); 1005 } catch (NativeDaemonConnectorException e) { 1006 throw e.rethrowAsParcelableException(); 1007 } 1008 } 1009 } 1010 1011 @Override 1012 public void setInterfaceAlert(String iface, long alertBytes) { 1013 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1014 1015 // silently discard when control disabled 1016 // TODO: eventually migrate to be always enabled 1017 if (!mBandwidthControlEnabled) return; 1018 1019 // quick sanity check 1020 if (!mActiveQuotaIfaces.contains(iface)) { 1021 throw new IllegalStateException("setting alert requires existing quota on iface"); 1022 } 1023 1024 synchronized (mQuotaLock) { 1025 if (mActiveAlertIfaces.contains(iface)) { 1026 throw new IllegalStateException("iface " + iface + " already has alert"); 1027 } 1028 1029 try { 1030 // TODO: support alert shared across interfaces 1031 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes); 1032 mActiveAlertIfaces.add(iface); 1033 } catch (NativeDaemonConnectorException e) { 1034 throw e.rethrowAsParcelableException(); 1035 } 1036 } 1037 } 1038 1039 @Override 1040 public void removeInterfaceAlert(String iface) { 1041 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1042 1043 // silently discard when control disabled 1044 // TODO: eventually migrate to be always enabled 1045 if (!mBandwidthControlEnabled) return; 1046 1047 synchronized (mQuotaLock) { 1048 if (!mActiveAlertIfaces.contains(iface)) { 1049 // TODO: eventually consider throwing 1050 return; 1051 } 1052 1053 try { 1054 // TODO: support alert shared across interfaces 1055 mConnector.execute("bandwidth", "removeinterfacealert", iface); 1056 mActiveAlertIfaces.remove(iface); 1057 } catch (NativeDaemonConnectorException e) { 1058 throw e.rethrowAsParcelableException(); 1059 } 1060 } 1061 } 1062 1063 @Override 1064 public void setGlobalAlert(long alertBytes) { 1065 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1066 1067 // silently discard when control disabled 1068 // TODO: eventually migrate to be always enabled 1069 if (!mBandwidthControlEnabled) return; 1070 1071 try { 1072 mConnector.execute("bandwidth", "setglobalalert", alertBytes); 1073 } catch (NativeDaemonConnectorException e) { 1074 throw e.rethrowAsParcelableException(); 1075 } 1076 } 1077 1078 @Override 1079 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { 1080 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1081 1082 // silently discard when control disabled 1083 // TODO: eventually migrate to be always enabled 1084 if (!mBandwidthControlEnabled) return; 1085 1086 synchronized (mUidRejectOnQuota) { 1087 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false); 1088 if (oldRejectOnQuota == rejectOnQuotaInterfaces) { 1089 // TODO: eventually consider throwing 1090 return; 1091 } 1092 1093 try { 1094 mConnector.execute("bandwidth", 1095 rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid); 1096 if (rejectOnQuotaInterfaces) { 1097 mUidRejectOnQuota.put(uid, true); 1098 } else { 1099 mUidRejectOnQuota.delete(uid); 1100 } 1101 } catch (NativeDaemonConnectorException e) { 1102 throw e.rethrowAsParcelableException(); 1103 } 1104 } 1105 } 1106 1107 @Override 1108 public boolean isBandwidthControlEnabled() { 1109 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1110 return mBandwidthControlEnabled; 1111 } 1112 1113 @Override 1114 public NetworkStats getNetworkStatsUidDetail(int uid) { 1115 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1116 return mStatsFactory.readNetworkStatsDetail(uid); 1117 } 1118 1119 @Override 1120 public NetworkStats getNetworkStatsTethering(String[] ifacePairs) { 1121 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1122 1123 if (ifacePairs.length % 2 != 0) { 1124 throw new IllegalArgumentException( 1125 "unexpected ifacePairs; length=" + ifacePairs.length); 1126 } 1127 1128 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); 1129 for (int i = 0; i < ifacePairs.length; i += 2) { 1130 final String ifaceIn = ifacePairs[i]; 1131 final String ifaceOut = ifacePairs[i + 1]; 1132 if (ifaceIn != null && ifaceOut != null) { 1133 stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut)); 1134 } 1135 } 1136 return stats; 1137 } 1138 1139 private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) { 1140 final NativeDaemonEvent event; 1141 try { 1142 event = mConnector.execute("bandwidth", "gettetherstats", ifaceIn, ifaceOut); 1143 } catch (NativeDaemonConnectorException e) { 1144 throw e.rethrowAsParcelableException(); 1145 } 1146 1147 event.checkCode(TetheringStatsResult); 1148 1149 // 221 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets 1150 final StringTokenizer tok = new StringTokenizer(event.getMessage()); 1151 tok.nextToken(); 1152 tok.nextToken(); 1153 1154 try { 1155 final NetworkStats.Entry entry = new NetworkStats.Entry(); 1156 entry.iface = ifaceIn; 1157 entry.uid = UID_TETHERING; 1158 entry.set = SET_DEFAULT; 1159 entry.tag = TAG_NONE; 1160 entry.rxBytes = Long.parseLong(tok.nextToken()); 1161 entry.rxPackets = Long.parseLong(tok.nextToken()); 1162 entry.txBytes = Long.parseLong(tok.nextToken()); 1163 entry.txPackets = Long.parseLong(tok.nextToken()); 1164 return entry; 1165 } catch (NumberFormatException e) { 1166 throw new IllegalStateException( 1167 "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e); 1168 } 1169 } 1170 1171 @Override 1172 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) { 1173 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1174 try { 1175 mConnector.execute("interface", "setthrottle", iface, rxKbps, txKbps); 1176 } catch (NativeDaemonConnectorException e) { 1177 throw e.rethrowAsParcelableException(); 1178 } 1179 } 1180 1181 private int getInterfaceThrottle(String iface, boolean rx) { 1182 final NativeDaemonEvent event; 1183 try { 1184 event = mConnector.execute("interface", "getthrottle", iface, rx ? "rx" : "tx"); 1185 } catch (NativeDaemonConnectorException e) { 1186 throw e.rethrowAsParcelableException(); 1187 } 1188 1189 if (rx) { 1190 event.checkCode(InterfaceRxThrottleResult); 1191 } else { 1192 event.checkCode(InterfaceTxThrottleResult); 1193 } 1194 1195 try { 1196 return Integer.parseInt(event.getMessage()); 1197 } catch (NumberFormatException e) { 1198 throw new IllegalStateException("unexpected response:" + event); 1199 } 1200 } 1201 1202 @Override 1203 public int getInterfaceRxThrottle(String iface) { 1204 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1205 return getInterfaceThrottle(iface, true); 1206 } 1207 1208 @Override 1209 public int getInterfaceTxThrottle(String iface) { 1210 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1211 return getInterfaceThrottle(iface, false); 1212 } 1213 1214 @Override 1215 public void setDefaultInterfaceForDns(String iface) { 1216 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1217 try { 1218 mConnector.execute("resolver", "setdefaultif", iface); 1219 } catch (NativeDaemonConnectorException e) { 1220 throw e.rethrowAsParcelableException(); 1221 } 1222 } 1223 1224 @Override 1225 public void setDnsServersForInterface(String iface, String[] servers) { 1226 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1227 1228 final Command cmd = new Command("resolver", "setifdns", iface); 1229 for (String s : servers) { 1230 InetAddress a = NetworkUtils.numericToInetAddress(s); 1231 if (a.isAnyLocalAddress() == false) { 1232 cmd.appendArg(a.getHostAddress()); 1233 } 1234 } 1235 1236 try { 1237 mConnector.execute(cmd); 1238 } catch (NativeDaemonConnectorException e) { 1239 throw e.rethrowAsParcelableException(); 1240 } 1241 } 1242 1243 @Override 1244 public void flushDefaultDnsCache() { 1245 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1246 try { 1247 mConnector.execute("resolver", "flushdefaultif"); 1248 } catch (NativeDaemonConnectorException e) { 1249 throw e.rethrowAsParcelableException(); 1250 } 1251 } 1252 1253 @Override 1254 public void flushInterfaceDnsCache(String iface) { 1255 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1256 try { 1257 mConnector.execute("resolver", "flushif", iface); 1258 } catch (NativeDaemonConnectorException e) { 1259 throw e.rethrowAsParcelableException(); 1260 } 1261 } 1262 1263 /** {@inheritDoc} */ 1264 public void monitor() { 1265 if (mConnector != null) { 1266 mConnector.monitor(); 1267 } 1268 } 1269 1270 @Override 1271 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1272 mContext.enforceCallingOrSelfPermission(DUMP, TAG); 1273 1274 pw.println("NetworkManagementService NativeDaemonConnector Log:"); 1275 mConnector.dump(fd, pw, args); 1276 pw.println(); 1277 1278 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled); 1279 1280 synchronized (mQuotaLock) { 1281 pw.print("Active quota ifaces: "); pw.println(mActiveQuotaIfaces.toString()); 1282 pw.print("Active alert ifaces: "); pw.println(mActiveAlertIfaces.toString()); 1283 } 1284 1285 synchronized (mUidRejectOnQuota) { 1286 pw.print("UID reject on quota ifaces: ["); 1287 final int size = mUidRejectOnQuota.size(); 1288 for (int i = 0; i < size; i++) { 1289 pw.print(mUidRejectOnQuota.keyAt(i)); 1290 if (i < size - 1) pw.print(","); 1291 } 1292 pw.println("]"); 1293 } 1294 } 1295} 1296