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