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