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