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