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