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