NetworkManagementService.java revision 3df273e45864ba595b4d870fa3f6c81a770078e2
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); 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 mConnector.execute("softap", "start", wlanIface); 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 getNetworkStatsSummary() { 946 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 947 return mStatsFactory.readNetworkStatsSummary(); 948 } 949 950 @Override 951 public NetworkStats getNetworkStatsDetail() { 952 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 953 return mStatsFactory.readNetworkStatsDetail(UID_ALL); 954 } 955 956 @Override 957 public void setInterfaceQuota(String iface, long quotaBytes) { 958 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 959 960 // silently discard when control disabled 961 // TODO: eventually migrate to be always enabled 962 if (!mBandwidthControlEnabled) return; 963 964 synchronized (mQuotaLock) { 965 if (mActiveQuotaIfaces.contains(iface)) { 966 throw new IllegalStateException("iface " + iface + " already has quota"); 967 } 968 969 try { 970 // TODO: support quota shared across interfaces 971 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes); 972 mActiveQuotaIfaces.add(iface); 973 } catch (NativeDaemonConnectorException e) { 974 throw e.rethrowAsParcelableException(); 975 } 976 } 977 } 978 979 @Override 980 public void removeInterfaceQuota(String iface) { 981 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 982 983 // silently discard when control disabled 984 // TODO: eventually migrate to be always enabled 985 if (!mBandwidthControlEnabled) return; 986 987 synchronized (mQuotaLock) { 988 if (!mActiveQuotaIfaces.contains(iface)) { 989 // TODO: eventually consider throwing 990 return; 991 } 992 993 mActiveQuotaIfaces.remove(iface); 994 mActiveAlertIfaces.remove(iface); 995 996 try { 997 // TODO: support quota shared across interfaces 998 mConnector.execute("bandwidth", "removeiquota", iface); 999 } catch (NativeDaemonConnectorException e) { 1000 throw e.rethrowAsParcelableException(); 1001 } 1002 } 1003 } 1004 1005 @Override 1006 public void setInterfaceAlert(String iface, long alertBytes) { 1007 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1008 1009 // silently discard when control disabled 1010 // TODO: eventually migrate to be always enabled 1011 if (!mBandwidthControlEnabled) return; 1012 1013 // quick sanity check 1014 if (!mActiveQuotaIfaces.contains(iface)) { 1015 throw new IllegalStateException("setting alert requires existing quota on iface"); 1016 } 1017 1018 synchronized (mQuotaLock) { 1019 if (mActiveAlertIfaces.contains(iface)) { 1020 throw new IllegalStateException("iface " + iface + " already has alert"); 1021 } 1022 1023 try { 1024 // TODO: support alert shared across interfaces 1025 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes); 1026 mActiveAlertIfaces.add(iface); 1027 } catch (NativeDaemonConnectorException e) { 1028 throw e.rethrowAsParcelableException(); 1029 } 1030 } 1031 } 1032 1033 @Override 1034 public void removeInterfaceAlert(String iface) { 1035 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1036 1037 // silently discard when control disabled 1038 // TODO: eventually migrate to be always enabled 1039 if (!mBandwidthControlEnabled) return; 1040 1041 synchronized (mQuotaLock) { 1042 if (!mActiveAlertIfaces.contains(iface)) { 1043 // TODO: eventually consider throwing 1044 return; 1045 } 1046 1047 try { 1048 // TODO: support alert shared across interfaces 1049 mConnector.execute("bandwidth", "removeinterfacealert", iface); 1050 mActiveAlertIfaces.remove(iface); 1051 } catch (NativeDaemonConnectorException e) { 1052 throw e.rethrowAsParcelableException(); 1053 } 1054 } 1055 } 1056 1057 @Override 1058 public void setGlobalAlert(long alertBytes) { 1059 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1060 1061 // silently discard when control disabled 1062 // TODO: eventually migrate to be always enabled 1063 if (!mBandwidthControlEnabled) return; 1064 1065 try { 1066 mConnector.execute("bandwidth", "setglobalalert", alertBytes); 1067 } catch (NativeDaemonConnectorException e) { 1068 throw e.rethrowAsParcelableException(); 1069 } 1070 } 1071 1072 @Override 1073 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { 1074 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1075 1076 // silently discard when control disabled 1077 // TODO: eventually migrate to be always enabled 1078 if (!mBandwidthControlEnabled) return; 1079 1080 synchronized (mUidRejectOnQuota) { 1081 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false); 1082 if (oldRejectOnQuota == rejectOnQuotaInterfaces) { 1083 // TODO: eventually consider throwing 1084 return; 1085 } 1086 1087 try { 1088 mConnector.execute("bandwidth", 1089 rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid); 1090 if (rejectOnQuotaInterfaces) { 1091 mUidRejectOnQuota.put(uid, true); 1092 } else { 1093 mUidRejectOnQuota.delete(uid); 1094 } 1095 } catch (NativeDaemonConnectorException e) { 1096 throw e.rethrowAsParcelableException(); 1097 } 1098 } 1099 } 1100 1101 @Override 1102 public boolean isBandwidthControlEnabled() { 1103 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1104 return mBandwidthControlEnabled; 1105 } 1106 1107 @Override 1108 public NetworkStats getNetworkStatsUidDetail(int uid) { 1109 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1110 return mStatsFactory.readNetworkStatsDetail(uid); 1111 } 1112 1113 @Override 1114 public NetworkStats getNetworkStatsTethering(String[] ifacePairs) { 1115 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1116 1117 if (ifacePairs.length % 2 != 0) { 1118 throw new IllegalArgumentException( 1119 "unexpected ifacePairs; length=" + ifacePairs.length); 1120 } 1121 1122 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); 1123 for (int i = 0; i < ifacePairs.length; i += 2) { 1124 final String ifaceIn = ifacePairs[i]; 1125 final String ifaceOut = ifacePairs[i + 1]; 1126 if (ifaceIn != null && ifaceOut != null) { 1127 stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut)); 1128 } 1129 } 1130 return stats; 1131 } 1132 1133 private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) { 1134 final NativeDaemonEvent event; 1135 try { 1136 event = mConnector.execute("bandwidth", "gettetherstats", ifaceIn, ifaceOut); 1137 } catch (NativeDaemonConnectorException e) { 1138 throw e.rethrowAsParcelableException(); 1139 } 1140 1141 event.checkCode(TetheringStatsResult); 1142 1143 // 221 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets 1144 final StringTokenizer tok = new StringTokenizer(event.getMessage()); 1145 tok.nextToken(); 1146 tok.nextToken(); 1147 1148 try { 1149 final NetworkStats.Entry entry = new NetworkStats.Entry(); 1150 entry.iface = ifaceIn; 1151 entry.uid = UID_TETHERING; 1152 entry.set = SET_DEFAULT; 1153 entry.tag = TAG_NONE; 1154 entry.rxBytes = Long.parseLong(tok.nextToken()); 1155 entry.rxPackets = Long.parseLong(tok.nextToken()); 1156 entry.txBytes = Long.parseLong(tok.nextToken()); 1157 entry.txPackets = Long.parseLong(tok.nextToken()); 1158 return entry; 1159 } catch (NumberFormatException e) { 1160 throw new IllegalStateException( 1161 "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e); 1162 } 1163 } 1164 1165 @Override 1166 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) { 1167 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1168 try { 1169 mConnector.execute("interface", "setthrottle", iface, rxKbps, txKbps); 1170 } catch (NativeDaemonConnectorException e) { 1171 throw e.rethrowAsParcelableException(); 1172 } 1173 } 1174 1175 private int getInterfaceThrottle(String iface, boolean rx) { 1176 final NativeDaemonEvent event; 1177 try { 1178 event = mConnector.execute("interface", "getthrottle", iface, rx ? "rx" : "tx"); 1179 } catch (NativeDaemonConnectorException e) { 1180 throw e.rethrowAsParcelableException(); 1181 } 1182 1183 if (rx) { 1184 event.checkCode(InterfaceRxThrottleResult); 1185 } else { 1186 event.checkCode(InterfaceTxThrottleResult); 1187 } 1188 1189 try { 1190 return Integer.parseInt(event.getMessage()); 1191 } catch (NumberFormatException e) { 1192 throw new IllegalStateException("unexpected response:" + event); 1193 } 1194 } 1195 1196 @Override 1197 public int getInterfaceRxThrottle(String iface) { 1198 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1199 return getInterfaceThrottle(iface, true); 1200 } 1201 1202 @Override 1203 public int getInterfaceTxThrottle(String iface) { 1204 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1205 return getInterfaceThrottle(iface, false); 1206 } 1207 1208 @Override 1209 public void setDefaultInterfaceForDns(String iface) { 1210 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1211 try { 1212 mConnector.execute("resolver", "setdefaultif", iface); 1213 } catch (NativeDaemonConnectorException e) { 1214 throw e.rethrowAsParcelableException(); 1215 } 1216 } 1217 1218 @Override 1219 public void setDnsServersForInterface(String iface, String[] servers) { 1220 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1221 1222 final Command cmd = new Command("resolver", "setifdns", iface); 1223 for (String s : servers) { 1224 InetAddress a = NetworkUtils.numericToInetAddress(s); 1225 if (a.isAnyLocalAddress() == false) { 1226 cmd.appendArg(a.getHostAddress()); 1227 } 1228 } 1229 1230 try { 1231 mConnector.execute(cmd); 1232 } catch (NativeDaemonConnectorException e) { 1233 throw e.rethrowAsParcelableException(); 1234 } 1235 } 1236 1237 @Override 1238 public void flushDefaultDnsCache() { 1239 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1240 try { 1241 mConnector.execute("resolver", "flushdefaultif"); 1242 } catch (NativeDaemonConnectorException e) { 1243 throw e.rethrowAsParcelableException(); 1244 } 1245 } 1246 1247 @Override 1248 public void flushInterfaceDnsCache(String iface) { 1249 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1250 try { 1251 mConnector.execute("resolver", "flushif", iface); 1252 } catch (NativeDaemonConnectorException e) { 1253 throw e.rethrowAsParcelableException(); 1254 } 1255 } 1256 1257 /** {@inheritDoc} */ 1258 public void monitor() { 1259 if (mConnector != null) { 1260 mConnector.monitor(); 1261 } 1262 } 1263 1264 @Override 1265 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1266 mContext.enforceCallingOrSelfPermission(DUMP, TAG); 1267 1268 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled); 1269 1270 synchronized (mQuotaLock) { 1271 pw.print("Active quota ifaces: "); pw.println(mActiveQuotaIfaces.toString()); 1272 pw.print("Active alert ifaces: "); pw.println(mActiveAlertIfaces.toString()); 1273 } 1274 1275 synchronized (mUidRejectOnQuota) { 1276 pw.print("UID reject on quota ifaces: ["); 1277 final int size = mUidRejectOnQuota.size(); 1278 for (int i = 0; i < size; i++) { 1279 pw.print(mUidRejectOnQuota.keyAt(i)); 1280 if (i < size - 1) pw.print(","); 1281 } 1282 pw.println("]"); 1283 } 1284 } 1285} 1286