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