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