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