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