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.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; 23 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; 24 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE; 25 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY; 26 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE; 27 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; 28 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; 29 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST; 30 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST; 31 import static android.net.NetworkStats.SET_DEFAULT; 32 import static android.net.NetworkStats.TAG_ALL; 33 import static android.net.NetworkStats.TAG_NONE; 34 import static android.net.NetworkStats.UID_ALL; 35 import static android.net.TrafficStats.UID_TETHERING; 36 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult; 37 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult; 38 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult; 39 import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult; 40 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult; 41 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult; 42 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult; 43 import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult; 44 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult; 45 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; 46 47 import android.annotation.NonNull; 48 import android.app.ActivityManagerNative; 49 import android.content.Context; 50 import android.net.ConnectivityManager; 51 import android.net.INetworkManagementEventObserver; 52 import android.net.InterfaceConfiguration; 53 import android.net.IpPrefix; 54 import android.net.LinkAddress; 55 import android.net.Network; 56 import android.net.NetworkPolicyManager; 57 import android.net.NetworkStats; 58 import android.net.NetworkUtils; 59 import android.net.RouteInfo; 60 import android.net.UidRange; 61 import android.net.wifi.WifiConfiguration; 62 import android.net.wifi.WifiConfiguration.KeyMgmt; 63 import android.os.BatteryStats; 64 import android.os.Binder; 65 import android.os.Handler; 66 import android.os.INetworkActivityListener; 67 import android.os.INetworkManagementService; 68 import android.os.PowerManager; 69 import android.os.Process; 70 import android.os.RemoteCallbackList; 71 import android.os.RemoteException; 72 import android.os.ServiceManager; 73 import android.os.StrictMode; 74 import android.os.SystemClock; 75 import android.os.SystemProperties; 76 import android.telephony.DataConnectionRealTimeInfo; 77 import android.telephony.PhoneStateListener; 78 import android.telephony.SubscriptionManager; 79 import android.telephony.TelephonyManager; 80 import android.util.Log; 81 import android.util.Slog; 82 import android.util.SparseBooleanArray; 83 import android.util.SparseIntArray; 84 85 import com.android.internal.annotations.GuardedBy; 86 import com.android.internal.app.IBatteryStats; 87 import com.android.internal.net.NetworkStatsFactory; 88 import com.android.internal.util.HexDump; 89 import com.android.internal.util.Preconditions; 90 import com.android.server.NativeDaemonConnector.Command; 91 import com.android.server.NativeDaemonConnector.SensitiveArg; 92 import com.android.server.net.LockdownVpnTracker; 93 import com.google.android.collect.Maps; 94 95 import java.io.BufferedReader; 96 import java.io.DataInputStream; 97 import java.io.File; 98 import java.io.FileDescriptor; 99 import java.io.FileInputStream; 100 import java.io.IOException; 101 import java.io.InputStreamReader; 102 import java.io.PrintWriter; 103 import java.net.InetAddress; 104 import java.net.InterfaceAddress; 105 import java.net.NetworkInterface; 106 import java.net.SocketException; 107 import java.util.ArrayList; 108 import java.util.Arrays; 109 import java.util.HashMap; 110 import java.util.List; 111 import java.util.Map; 112 import java.util.NoSuchElementException; 113 import java.util.StringTokenizer; 114 import java.util.concurrent.CountDownLatch; 115 116 /** 117 * @hide 118 */ 119 public class NetworkManagementService extends INetworkManagementService.Stub 120 implements Watchdog.Monitor { 121 private static final String TAG = "NetworkManagement"; 122 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 123 private static final String NETD_TAG = "NetdConnector"; 124 private static final String NETD_SOCKET_NAME = "netd"; 125 126 private static final int MAX_UID_RANGES_PER_COMMAND = 10; 127 128 /** 129 * Name representing {@link #setGlobalAlert(long)} limit when delivered to 130 * {@link INetworkManagementEventObserver#limitReached(String, String)}. 131 */ 132 public static final String LIMIT_GLOBAL_ALERT = "globalAlert"; 133 134 /** 135 * String to pass to netd to indicate that a network is only accessible 136 * to apps that have the CHANGE_NETWORK_STATE permission. 137 */ 138 public static final String PERMISSION_NETWORK = "NETWORK"; 139 140 /** 141 * String to pass to netd to indicate that a network is only 142 * accessible to system apps and those with the CONNECTIVITY_INTERNAL 143 * permission. 144 */ 145 public static final String PERMISSION_SYSTEM = "SYSTEM"; 146 147 class NetdResponseCode { 148 /* Keep in sync with system/netd/server/ResponseCode.h */ 149 public static final int InterfaceListResult = 110; 150 public static final int TetherInterfaceListResult = 111; 151 public static final int TetherDnsFwdTgtListResult = 112; 152 public static final int TtyListResult = 113; 153 public static final int TetheringStatsListResult = 114; 154 155 public static final int TetherStatusResult = 210; 156 public static final int IpFwdStatusResult = 211; 157 public static final int InterfaceGetCfgResult = 213; 158 public static final int SoftapStatusResult = 214; 159 public static final int InterfaceRxCounterResult = 216; 160 public static final int InterfaceTxCounterResult = 217; 161 public static final int QuotaCounterResult = 220; 162 public static final int TetheringStatsResult = 221; 163 public static final int DnsProxyQueryResult = 222; 164 public static final int ClatdStatusResult = 223; 165 166 public static final int InterfaceChange = 600; 167 public static final int BandwidthControl = 601; 168 public static final int InterfaceClassActivity = 613; 169 public static final int InterfaceAddressChange = 614; 170 public static final int InterfaceDnsServerInfo = 615; 171 public static final int RouteChange = 616; 172 public static final int StrictCleartext = 617; 173 } 174 175 static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1; 176 177 /** 178 * Binder context for this service 179 */ 180 private final Context mContext; 181 182 /** 183 * connector object for communicating with netd 184 */ 185 private final NativeDaemonConnector mConnector; 186 187 private final Handler mFgHandler; 188 private final Handler mDaemonHandler; 189 private final PhoneStateListener mPhoneStateListener; 190 191 private IBatteryStats mBatteryStats; 192 193 private final Thread mThread; 194 private CountDownLatch mConnectedSignal = new CountDownLatch(1); 195 196 private final RemoteCallbackList<INetworkManagementEventObserver> mObservers = 197 new RemoteCallbackList<INetworkManagementEventObserver>(); 198 199 private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory(); 200 201 private Object mQuotaLock = new Object(); 202 203 /** Set of interfaces with active quotas. */ 204 @GuardedBy("mQuotaLock") 205 private HashMap<String, Long> mActiveQuotas = Maps.newHashMap(); 206 /** Set of interfaces with active alerts. */ 207 @GuardedBy("mQuotaLock") 208 private HashMap<String, Long> mActiveAlerts = Maps.newHashMap(); 209 /** Set of UIDs with active reject rules. */ 210 @GuardedBy("mQuotaLock") 211 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray(); 212 /** Set of UIDs with cleartext penalties. */ 213 @GuardedBy("mQuotaLock") 214 private SparseIntArray mUidCleartextPolicy = new SparseIntArray(); 215 /** Set of UIDs that are to be blocked/allowed by firewall controller. */ 216 @GuardedBy("mQuotaLock") 217 private SparseIntArray mUidFirewallRules = new SparseIntArray(); 218 /** 219 * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches 220 * to application idles. 221 */ 222 @GuardedBy("mQuotaLock") 223 private SparseIntArray mUidFirewallStandbyRules = new SparseIntArray(); 224 /** 225 * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches 226 * to device idles. 227 */ 228 @GuardedBy("mQuotaLock") 229 private SparseIntArray mUidFirewallDozableRules = new SparseIntArray(); 230 /** Set of states for the child firewall chains. True if the chain is active. */ 231 @GuardedBy("mQuotaLock") 232 final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray(); 233 234 private Object mIdleTimerLock = new Object(); 235 /** Set of interfaces with active idle timers. */ 236 private static class IdleTimerParams { 237 public final int timeout; 238 public final int type; 239 public int networkCount; 240 241 IdleTimerParams(int timeout, int type) { 242 this.timeout = timeout; 243 this.type = type; 244 this.networkCount = 1; 245 } 246 } 247 private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap(); 248 249 private volatile boolean mBandwidthControlEnabled; 250 private volatile boolean mFirewallEnabled; 251 private volatile boolean mStrictEnabled; 252 253 private boolean mMobileActivityFromRadio = false; 254 private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; 255 private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; 256 257 private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners = 258 new RemoteCallbackList<INetworkActivityListener>(); 259 private boolean mNetworkActive; 260 261 /** 262 * Constructs a new NetworkManagementService instance 263 * 264 * @param context Binder context for this service 265 */ 266 private NetworkManagementService(Context context, String socket) { 267 mContext = context; 268 269 // make sure this is on the same looper as our NativeDaemonConnector for sync purposes 270 mFgHandler = new Handler(FgThread.get().getLooper()); 271 272 // Don't need this wake lock, since we now have a time stamp for when 273 // the network actually went inactive. (It might be nice to still do this, 274 // but I don't want to do it through the power manager because that pollutes the 275 // battery stats history with pointless noise.) 276 //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 277 PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG); 278 279 mConnector = new NativeDaemonConnector( 280 new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl, 281 FgThread.get().getLooper()); 282 mThread = new Thread(mConnector, NETD_TAG); 283 284 mDaemonHandler = new Handler(FgThread.get().getLooper()); 285 286 mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, 287 mDaemonHandler.getLooper()) { 288 @Override 289 public void onDataConnectionRealTimeInfoChanged( 290 DataConnectionRealTimeInfo dcRtInfo) { 291 if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo); 292 notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE, 293 dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true); 294 } 295 }; 296 TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 297 if (tm != null) { 298 tm.listen(mPhoneStateListener, 299 PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO); 300 } 301 302 // Add ourself to the Watchdog monitors. 303 Watchdog.getInstance().addMonitor(this); 304 } 305 306 static NetworkManagementService create(Context context, 307 String socket) throws InterruptedException { 308 final NetworkManagementService service = new NetworkManagementService(context, socket); 309 final CountDownLatch connectedSignal = service.mConnectedSignal; 310 if (DBG) Slog.d(TAG, "Creating NetworkManagementService"); 311 service.mThread.start(); 312 if (DBG) Slog.d(TAG, "Awaiting socket connection"); 313 connectedSignal.await(); 314 if (DBG) Slog.d(TAG, "Connected"); 315 return service; 316 } 317 318 public static NetworkManagementService create(Context context) throws InterruptedException { 319 return create(context, NETD_SOCKET_NAME); 320 } 321 322 public void systemReady() { 323 prepareNativeDaemon(); 324 if (DBG) Slog.d(TAG, "Prepared"); 325 } 326 327 private IBatteryStats getBatteryStats() { 328 synchronized (this) { 329 if (mBatteryStats != null) { 330 return mBatteryStats; 331 } 332 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 333 BatteryStats.SERVICE_NAME)); 334 return mBatteryStats; 335 } 336 } 337 338 @Override 339 public void registerObserver(INetworkManagementEventObserver observer) { 340 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 341 mObservers.register(observer); 342 } 343 344 @Override 345 public void unregisterObserver(INetworkManagementEventObserver observer) { 346 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 347 mObservers.unregister(observer); 348 } 349 350 /** 351 * Notify our observers of an interface status change 352 */ 353 private void notifyInterfaceStatusChanged(String iface, boolean up) { 354 final int length = mObservers.beginBroadcast(); 355 try { 356 for (int i = 0; i < length; i++) { 357 try { 358 mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up); 359 } catch (RemoteException e) { 360 } catch (RuntimeException e) { 361 } 362 } 363 } finally { 364 mObservers.finishBroadcast(); 365 } 366 } 367 368 /** 369 * Notify our observers of an interface link state change 370 * (typically, an Ethernet cable has been plugged-in or unplugged). 371 */ 372 private void notifyInterfaceLinkStateChanged(String iface, boolean up) { 373 final int length = mObservers.beginBroadcast(); 374 try { 375 for (int i = 0; i < length; i++) { 376 try { 377 mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up); 378 } catch (RemoteException e) { 379 } catch (RuntimeException e) { 380 } 381 } 382 } finally { 383 mObservers.finishBroadcast(); 384 } 385 } 386 387 /** 388 * Notify our observers of an interface addition. 389 */ 390 private void notifyInterfaceAdded(String iface) { 391 final int length = mObservers.beginBroadcast(); 392 try { 393 for (int i = 0; i < length; i++) { 394 try { 395 mObservers.getBroadcastItem(i).interfaceAdded(iface); 396 } catch (RemoteException e) { 397 } catch (RuntimeException e) { 398 } 399 } 400 } finally { 401 mObservers.finishBroadcast(); 402 } 403 } 404 405 /** 406 * Notify our observers of an interface removal. 407 */ 408 private void notifyInterfaceRemoved(String iface) { 409 // netd already clears out quota and alerts for removed ifaces; update 410 // our sanity-checking state. 411 mActiveAlerts.remove(iface); 412 mActiveQuotas.remove(iface); 413 414 final int length = mObservers.beginBroadcast(); 415 try { 416 for (int i = 0; i < length; i++) { 417 try { 418 mObservers.getBroadcastItem(i).interfaceRemoved(iface); 419 } catch (RemoteException e) { 420 } catch (RuntimeException e) { 421 } 422 } 423 } finally { 424 mObservers.finishBroadcast(); 425 } 426 } 427 428 /** 429 * Notify our observers of a limit reached. 430 */ 431 private void notifyLimitReached(String limitName, String iface) { 432 final int length = mObservers.beginBroadcast(); 433 try { 434 for (int i = 0; i < length; i++) { 435 try { 436 mObservers.getBroadcastItem(i).limitReached(limitName, iface); 437 } catch (RemoteException e) { 438 } catch (RuntimeException e) { 439 } 440 } 441 } finally { 442 mObservers.finishBroadcast(); 443 } 444 } 445 446 /** 447 * Notify our observers of a change in the data activity state of the interface 448 */ 449 private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos, 450 boolean fromRadio) { 451 final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type); 452 if (isMobile) { 453 if (!fromRadio) { 454 if (mMobileActivityFromRadio) { 455 // If this call is not coming from a report from the radio itself, but we 456 // have previously received reports from the radio, then we will take the 457 // power state to just be whatever the radio last reported. 458 powerState = mLastPowerStateFromRadio; 459 } 460 } else { 461 mMobileActivityFromRadio = true; 462 } 463 if (mLastPowerStateFromRadio != powerState) { 464 mLastPowerStateFromRadio = powerState; 465 try { 466 getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos); 467 } catch (RemoteException e) { 468 } 469 } 470 } 471 472 if (ConnectivityManager.isNetworkTypeWifi(type)) { 473 if (mLastPowerStateFromWifi != powerState) { 474 mLastPowerStateFromWifi = powerState; 475 try { 476 getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos); 477 } catch (RemoteException e) { 478 } 479 } 480 } 481 482 boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM 483 || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH; 484 485 if (!isMobile || fromRadio || !mMobileActivityFromRadio) { 486 // Report the change in data activity. We don't do this if this is a change 487 // on the mobile network, that is not coming from the radio itself, and we 488 // have previously seen change reports from the radio. In that case only 489 // the radio is the authority for the current state. 490 final int length = mObservers.beginBroadcast(); 491 try { 492 for (int i = 0; i < length; i++) { 493 try { 494 mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged( 495 Integer.toString(type), isActive, tsNanos); 496 } catch (RemoteException e) { 497 } catch (RuntimeException e) { 498 } 499 } 500 } finally { 501 mObservers.finishBroadcast(); 502 } 503 } 504 505 boolean report = false; 506 synchronized (mIdleTimerLock) { 507 if (mActiveIdleTimers.isEmpty()) { 508 // If there are no idle timers, we are not monitoring activity, so we 509 // are always considered active. 510 isActive = true; 511 } 512 if (mNetworkActive != isActive) { 513 mNetworkActive = isActive; 514 report = isActive; 515 } 516 } 517 if (report) { 518 reportNetworkActive(); 519 } 520 } 521 522 /** 523 * Prepare native daemon once connected, enabling modules and pushing any 524 * existing in-memory rules. 525 */ 526 private void prepareNativeDaemon() { 527 mBandwidthControlEnabled = false; 528 529 // only enable bandwidth control when support exists 530 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists(); 531 if (hasKernelSupport) { 532 Slog.d(TAG, "enabling bandwidth control"); 533 try { 534 mConnector.execute("bandwidth", "enable"); 535 mBandwidthControlEnabled = true; 536 } catch (NativeDaemonConnectorException e) { 537 Log.wtf(TAG, "problem enabling bandwidth controls", e); 538 } 539 } else { 540 Slog.d(TAG, "not enabling bandwidth control"); 541 } 542 543 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0"); 544 545 if (mBandwidthControlEnabled) { 546 try { 547 getBatteryStats().noteNetworkStatsEnabled(); 548 } catch (RemoteException e) { 549 } 550 } 551 552 try { 553 mConnector.execute("strict", "enable"); 554 mStrictEnabled = true; 555 } catch (NativeDaemonConnectorException e) { 556 Log.wtf(TAG, "Failed strict enable", e); 557 } 558 559 // push any existing quota or UID rules 560 synchronized (mQuotaLock) { 561 int size = mActiveQuotas.size(); 562 if (size > 0) { 563 Slog.d(TAG, "Pushing " + size + " active quota rules"); 564 final HashMap<String, Long> activeQuotas = mActiveQuotas; 565 mActiveQuotas = Maps.newHashMap(); 566 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) { 567 setInterfaceQuota(entry.getKey(), entry.getValue()); 568 } 569 } 570 571 size = mActiveAlerts.size(); 572 if (size > 0) { 573 Slog.d(TAG, "Pushing " + size + " active alert rules"); 574 final HashMap<String, Long> activeAlerts = mActiveAlerts; 575 mActiveAlerts = Maps.newHashMap(); 576 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) { 577 setInterfaceAlert(entry.getKey(), entry.getValue()); 578 } 579 } 580 581 size = mUidRejectOnQuota.size(); 582 if (size > 0) { 583 Slog.d(TAG, "Pushing " + size + " active UID rules"); 584 final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota; 585 mUidRejectOnQuota = new SparseBooleanArray(); 586 for (int i = 0; i < uidRejectOnQuota.size(); i++) { 587 setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i)); 588 } 589 } 590 591 size = mUidCleartextPolicy.size(); 592 if (size > 0) { 593 Slog.d(TAG, "Pushing " + size + " active UID cleartext policies"); 594 final SparseIntArray local = mUidCleartextPolicy; 595 mUidCleartextPolicy = new SparseIntArray(); 596 for (int i = 0; i < local.size(); i++) { 597 setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i)); 598 } 599 } 600 601 setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled()); 602 603 size = mUidFirewallRules.size(); 604 if (size > 0) { 605 Slog.d(TAG, "Pushing " + size + " active firewall UID rules"); 606 final SparseIntArray uidFirewallRules = mUidFirewallRules; 607 mUidFirewallRules = new SparseIntArray(); 608 for (int i = 0; i < uidFirewallRules.size(); i++) { 609 setFirewallUidRuleInternal(FIREWALL_CHAIN_NONE, uidFirewallRules.keyAt(i), 610 uidFirewallRules.valueAt(i)); 611 } 612 } 613 614 size = mUidFirewallStandbyRules.size(); 615 if (size > 0) { 616 Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules"); 617 final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules; 618 mUidFirewallStandbyRules = new SparseIntArray(); 619 for (int i = 0; i < uidFirewallRules.size(); i++) { 620 setFirewallUidRuleInternal(FIREWALL_CHAIN_STANDBY, uidFirewallRules.keyAt(i), 621 uidFirewallRules.valueAt(i)); 622 } 623 } 624 if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) { 625 setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true); 626 } 627 628 size = mUidFirewallDozableRules.size(); 629 if (size > 0) { 630 Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules"); 631 final SparseIntArray uidFirewallRules = mUidFirewallDozableRules; 632 mUidFirewallDozableRules = new SparseIntArray(); 633 for (int i = 0; i < uidFirewallRules.size(); i++) { 634 setFirewallUidRuleInternal(FIREWALL_CHAIN_DOZABLE, uidFirewallRules.keyAt(i), 635 uidFirewallRules.valueAt(i)); 636 } 637 } 638 if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) { 639 setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true); 640 } 641 } 642 } 643 644 /** 645 * Notify our observers of a new or updated interface address. 646 */ 647 private void notifyAddressUpdated(String iface, LinkAddress address) { 648 final int length = mObservers.beginBroadcast(); 649 try { 650 for (int i = 0; i < length; i++) { 651 try { 652 mObservers.getBroadcastItem(i).addressUpdated(iface, address); 653 } catch (RemoteException e) { 654 } catch (RuntimeException e) { 655 } 656 } 657 } finally { 658 mObservers.finishBroadcast(); 659 } 660 } 661 662 /** 663 * Notify our observers of a deleted interface address. 664 */ 665 private void notifyAddressRemoved(String iface, LinkAddress address) { 666 final int length = mObservers.beginBroadcast(); 667 try { 668 for (int i = 0; i < length; i++) { 669 try { 670 mObservers.getBroadcastItem(i).addressRemoved(iface, address); 671 } catch (RemoteException e) { 672 } catch (RuntimeException e) { 673 } 674 } 675 } finally { 676 mObservers.finishBroadcast(); 677 } 678 } 679 680 /** 681 * Notify our observers of DNS server information received. 682 */ 683 private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { 684 final int length = mObservers.beginBroadcast(); 685 try { 686 for (int i = 0; i < length; i++) { 687 try { 688 mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, 689 addresses); 690 } catch (RemoteException e) { 691 } catch (RuntimeException e) { 692 } 693 } 694 } finally { 695 mObservers.finishBroadcast(); 696 } 697 } 698 699 /** 700 * Notify our observers of a route change. 701 */ 702 private void notifyRouteChange(String action, RouteInfo route) { 703 final int length = mObservers.beginBroadcast(); 704 try { 705 for (int i = 0; i < length; i++) { 706 try { 707 if (action.equals("updated")) { 708 mObservers.getBroadcastItem(i).routeUpdated(route); 709 } else { 710 mObservers.getBroadcastItem(i).routeRemoved(route); 711 } 712 } catch (RemoteException e) { 713 } catch (RuntimeException e) { 714 } 715 } 716 } finally { 717 mObservers.finishBroadcast(); 718 } 719 } 720 721 // 722 // Netd Callback handling 723 // 724 725 private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks { 726 @Override 727 public void onDaemonConnected() { 728 // event is dispatched from internal NDC thread, so we prepare the 729 // daemon back on main thread. 730 if (mConnectedSignal != null) { 731 mConnectedSignal.countDown(); 732 mConnectedSignal = null; 733 } else { 734 mFgHandler.post(new Runnable() { 735 @Override 736 public void run() { 737 prepareNativeDaemon(); 738 } 739 }); 740 } 741 } 742 743 @Override 744 public boolean onCheckHoldWakeLock(int code) { 745 return code == NetdResponseCode.InterfaceClassActivity; 746 } 747 748 @Override 749 public boolean onEvent(int code, String raw, String[] cooked) { 750 String errorMessage = String.format("Invalid event from daemon (%s)", raw); 751 switch (code) { 752 case NetdResponseCode.InterfaceChange: 753 /* 754 * a network interface change occured 755 * Format: "NNN Iface added <name>" 756 * "NNN Iface removed <name>" 757 * "NNN Iface changed <name> <up/down>" 758 * "NNN Iface linkstatus <name> <up/down>" 759 */ 760 if (cooked.length < 4 || !cooked[1].equals("Iface")) { 761 throw new IllegalStateException(errorMessage); 762 } 763 if (cooked[2].equals("added")) { 764 notifyInterfaceAdded(cooked[3]); 765 return true; 766 } else if (cooked[2].equals("removed")) { 767 notifyInterfaceRemoved(cooked[3]); 768 return true; 769 } else if (cooked[2].equals("changed") && cooked.length == 5) { 770 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); 771 return true; 772 } else if (cooked[2].equals("linkstate") && cooked.length == 5) { 773 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); 774 return true; 775 } 776 throw new IllegalStateException(errorMessage); 777 // break; 778 case NetdResponseCode.BandwidthControl: 779 /* 780 * Bandwidth control needs some attention 781 * Format: "NNN limit alert <alertName> <ifaceName>" 782 */ 783 if (cooked.length < 5 || !cooked[1].equals("limit")) { 784 throw new IllegalStateException(errorMessage); 785 } 786 if (cooked[2].equals("alert")) { 787 notifyLimitReached(cooked[3], cooked[4]); 788 return true; 789 } 790 throw new IllegalStateException(errorMessage); 791 // break; 792 case NetdResponseCode.InterfaceClassActivity: 793 /* 794 * An network interface class state changed (active/idle) 795 * Format: "NNN IfaceClass <active/idle> <label>" 796 */ 797 if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) { 798 throw new IllegalStateException(errorMessage); 799 } 800 long timestampNanos = 0; 801 if (cooked.length == 5) { 802 try { 803 timestampNanos = Long.parseLong(cooked[4]); 804 } catch(NumberFormatException ne) {} 805 } else { 806 timestampNanos = SystemClock.elapsedRealtimeNanos(); 807 } 808 boolean isActive = cooked[2].equals("active"); 809 notifyInterfaceClassActivity(Integer.parseInt(cooked[3]), 810 isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH 811 : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false); 812 return true; 813 // break; 814 case NetdResponseCode.InterfaceAddressChange: 815 /* 816 * A network address change occurred 817 * Format: "NNN Address updated <addr> <iface> <flags> <scope>" 818 * "NNN Address removed <addr> <iface> <flags> <scope>" 819 */ 820 if (cooked.length < 7 || !cooked[1].equals("Address")) { 821 throw new IllegalStateException(errorMessage); 822 } 823 824 String iface = cooked[4]; 825 LinkAddress address; 826 try { 827 int flags = Integer.parseInt(cooked[5]); 828 int scope = Integer.parseInt(cooked[6]); 829 address = new LinkAddress(cooked[3], flags, scope); 830 } catch(NumberFormatException e) { // Non-numeric lifetime or scope. 831 throw new IllegalStateException(errorMessage, e); 832 } catch(IllegalArgumentException e) { // Malformed/invalid IP address. 833 throw new IllegalStateException(errorMessage, e); 834 } 835 836 if (cooked[2].equals("updated")) { 837 notifyAddressUpdated(iface, address); 838 } else { 839 notifyAddressRemoved(iface, address); 840 } 841 return true; 842 // break; 843 case NetdResponseCode.InterfaceDnsServerInfo: 844 /* 845 * Information about available DNS servers has been received. 846 * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>" 847 */ 848 long lifetime; // Actually a 32-bit unsigned integer. 849 850 if (cooked.length == 6 && 851 cooked[1].equals("DnsInfo") && 852 cooked[2].equals("servers")) { 853 try { 854 lifetime = Long.parseLong(cooked[4]); 855 } catch (NumberFormatException e) { 856 throw new IllegalStateException(errorMessage); 857 } 858 String[] servers = cooked[5].split(","); 859 notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers); 860 } 861 return true; 862 // break; 863 case NetdResponseCode.RouteChange: 864 /* 865 * A route has been updated or removed. 866 * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]" 867 */ 868 if (!cooked[1].equals("Route") || cooked.length < 6) { 869 throw new IllegalStateException(errorMessage); 870 } 871 872 String via = null; 873 String dev = null; 874 boolean valid = true; 875 for (int i = 4; (i + 1) < cooked.length && valid; i += 2) { 876 if (cooked[i].equals("dev")) { 877 if (dev == null) { 878 dev = cooked[i+1]; 879 } else { 880 valid = false; // Duplicate interface. 881 } 882 } else if (cooked[i].equals("via")) { 883 if (via == null) { 884 via = cooked[i+1]; 885 } else { 886 valid = false; // Duplicate gateway. 887 } 888 } else { 889 valid = false; // Unknown syntax. 890 } 891 } 892 if (valid) { 893 try { 894 // InetAddress.parseNumericAddress(null) inexplicably returns ::1. 895 InetAddress gateway = null; 896 if (via != null) gateway = InetAddress.parseNumericAddress(via); 897 RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev); 898 notifyRouteChange(cooked[2], route); 899 return true; 900 } catch (IllegalArgumentException e) {} 901 } 902 throw new IllegalStateException(errorMessage); 903 // break; 904 case NetdResponseCode.StrictCleartext: 905 final int uid = Integer.parseInt(cooked[1]); 906 final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]); 907 try { 908 ActivityManagerNative.getDefault().notifyCleartextNetwork(uid, firstPacket); 909 } catch (RemoteException ignored) { 910 } 911 break; 912 default: break; 913 } 914 return false; 915 } 916 } 917 918 919 // 920 // INetworkManagementService members 921 // 922 923 @Override 924 public String[] listInterfaces() { 925 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 926 try { 927 return NativeDaemonEvent.filterMessageList( 928 mConnector.executeForList("interface", "list"), InterfaceListResult); 929 } catch (NativeDaemonConnectorException e) { 930 throw e.rethrowAsParcelableException(); 931 } 932 } 933 934 @Override 935 public InterfaceConfiguration getInterfaceConfig(String iface) { 936 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 937 938 final NativeDaemonEvent event; 939 try { 940 event = mConnector.execute("interface", "getcfg", iface); 941 } catch (NativeDaemonConnectorException e) { 942 throw e.rethrowAsParcelableException(); 943 } 944 945 event.checkCode(InterfaceGetCfgResult); 946 947 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3 948 final StringTokenizer st = new StringTokenizer(event.getMessage()); 949 950 InterfaceConfiguration cfg; 951 try { 952 cfg = new InterfaceConfiguration(); 953 cfg.setHardwareAddress(st.nextToken(" ")); 954 InetAddress addr = null; 955 int prefixLength = 0; 956 try { 957 addr = NetworkUtils.numericToInetAddress(st.nextToken()); 958 } catch (IllegalArgumentException iae) { 959 Slog.e(TAG, "Failed to parse ipaddr", iae); 960 } 961 962 try { 963 prefixLength = Integer.parseInt(st.nextToken()); 964 } catch (NumberFormatException nfe) { 965 Slog.e(TAG, "Failed to parse prefixLength", nfe); 966 } 967 968 cfg.setLinkAddress(new LinkAddress(addr, prefixLength)); 969 while (st.hasMoreTokens()) { 970 cfg.setFlag(st.nextToken()); 971 } 972 } catch (NoSuchElementException nsee) { 973 throw new IllegalStateException("Invalid response from daemon: " + event); 974 } 975 return cfg; 976 } 977 978 @Override 979 public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { 980 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 981 LinkAddress linkAddr = cfg.getLinkAddress(); 982 if (linkAddr == null || linkAddr.getAddress() == null) { 983 throw new IllegalStateException("Null LinkAddress given"); 984 } 985 986 final Command cmd = new Command("interface", "setcfg", iface, 987 linkAddr.getAddress().getHostAddress(), 988 linkAddr.getPrefixLength()); 989 for (String flag : cfg.getFlags()) { 990 cmd.appendArg(flag); 991 } 992 993 try { 994 mConnector.execute(cmd); 995 } catch (NativeDaemonConnectorException e) { 996 throw e.rethrowAsParcelableException(); 997 } 998 } 999 1000 @Override 1001 public void setInterfaceDown(String iface) { 1002 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1003 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 1004 ifcg.setInterfaceDown(); 1005 setInterfaceConfig(iface, ifcg); 1006 } 1007 1008 @Override 1009 public void setInterfaceUp(String iface) { 1010 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1011 final InterfaceConfiguration ifcg = getInterfaceConfig(iface); 1012 ifcg.setInterfaceUp(); 1013 setInterfaceConfig(iface, ifcg); 1014 } 1015 1016 @Override 1017 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) { 1018 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1019 try { 1020 mConnector.execute( 1021 "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable"); 1022 } catch (NativeDaemonConnectorException e) { 1023 throw e.rethrowAsParcelableException(); 1024 } 1025 } 1026 1027 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its 1028 IPv6 addresses on interface down, but we need to do full clean up here */ 1029 @Override 1030 public void clearInterfaceAddresses(String iface) { 1031 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1032 try { 1033 mConnector.execute("interface", "clearaddrs", iface); 1034 } catch (NativeDaemonConnectorException e) { 1035 throw e.rethrowAsParcelableException(); 1036 } 1037 } 1038 1039 @Override 1040 public void enableIpv6(String iface) { 1041 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1042 try { 1043 mConnector.execute("interface", "ipv6", iface, "enable"); 1044 } catch (NativeDaemonConnectorException e) { 1045 throw e.rethrowAsParcelableException(); 1046 } 1047 } 1048 1049 @Override 1050 public void disableIpv6(String iface) { 1051 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1052 try { 1053 mConnector.execute("interface", "ipv6", iface, "disable"); 1054 } catch (NativeDaemonConnectorException e) { 1055 throw e.rethrowAsParcelableException(); 1056 } 1057 } 1058 1059 @Override 1060 public void setInterfaceIpv6NdOffload(String iface, boolean enable) { 1061 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1062 try { 1063 mConnector.execute( 1064 "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable")); 1065 } catch (NativeDaemonConnectorException e) { 1066 throw e.rethrowAsParcelableException(); 1067 } 1068 } 1069 1070 @Override 1071 public void addRoute(int netId, RouteInfo route) { 1072 modifyRoute("add", "" + netId, route); 1073 } 1074 1075 @Override 1076 public void removeRoute(int netId, RouteInfo route) { 1077 modifyRoute("remove", "" + netId, route); 1078 } 1079 1080 private void modifyRoute(String action, String netId, RouteInfo route) { 1081 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1082 1083 final Command cmd = new Command("network", "route", action, netId); 1084 1085 // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr 1086 cmd.appendArg(route.getInterface()); 1087 cmd.appendArg(route.getDestination().toString()); 1088 1089 switch (route.getType()) { 1090 case RouteInfo.RTN_UNICAST: 1091 if (route.hasGateway()) { 1092 cmd.appendArg(route.getGateway().getHostAddress()); 1093 } 1094 break; 1095 case RouteInfo.RTN_UNREACHABLE: 1096 cmd.appendArg("unreachable"); 1097 break; 1098 case RouteInfo.RTN_THROW: 1099 cmd.appendArg("throw"); 1100 break; 1101 } 1102 1103 try { 1104 mConnector.execute(cmd); 1105 } catch (NativeDaemonConnectorException e) { 1106 throw e.rethrowAsParcelableException(); 1107 } 1108 } 1109 1110 private ArrayList<String> readRouteList(String filename) { 1111 FileInputStream fstream = null; 1112 ArrayList<String> list = new ArrayList<String>(); 1113 1114 try { 1115 fstream = new FileInputStream(filename); 1116 DataInputStream in = new DataInputStream(fstream); 1117 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 1118 String s; 1119 1120 // throw away the title line 1121 1122 while (((s = br.readLine()) != null) && (s.length() != 0)) { 1123 list.add(s); 1124 } 1125 } catch (IOException ex) { 1126 // return current list, possibly empty 1127 } finally { 1128 if (fstream != null) { 1129 try { 1130 fstream.close(); 1131 } catch (IOException ex) {} 1132 } 1133 } 1134 1135 return list; 1136 } 1137 1138 @Override 1139 public RouteInfo[] getRoutes(String interfaceName) { 1140 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1141 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>(); 1142 1143 // v4 routes listed as: 1144 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT 1145 for (String s : readRouteList("/proc/net/route")) { 1146 String[] fields = s.split("\t"); 1147 1148 if (fields.length > 7) { 1149 String iface = fields[0]; 1150 1151 if (interfaceName.equals(iface)) { 1152 String dest = fields[1]; 1153 String gate = fields[2]; 1154 String flags = fields[3]; // future use? 1155 String mask = fields[7]; 1156 try { 1157 // address stored as a hex string, ex: 0014A8C0 1158 InetAddress destAddr = 1159 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16)); 1160 int prefixLength = 1161 NetworkUtils.netmaskIntToPrefixLength( 1162 (int)Long.parseLong(mask, 16)); 1163 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength); 1164 1165 // address stored as a hex string, ex 0014A8C0 1166 InetAddress gatewayAddr = 1167 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16)); 1168 1169 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr); 1170 routes.add(route); 1171 } catch (Exception e) { 1172 Log.e(TAG, "Error parsing route " + s + " : " + e); 1173 continue; 1174 } 1175 } 1176 } 1177 } 1178 1179 // v6 routes listed as: 1180 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface 1181 for (String s : readRouteList("/proc/net/ipv6_route")) { 1182 String[]fields = s.split("\\s+"); 1183 if (fields.length > 9) { 1184 String iface = fields[9].trim(); 1185 if (interfaceName.equals(iface)) { 1186 String dest = fields[0]; 1187 String prefix = fields[1]; 1188 String gate = fields[4]; 1189 1190 try { 1191 // prefix length stored as a hex string, ex 40 1192 int prefixLength = Integer.parseInt(prefix, 16); 1193 1194 // address stored as a 32 char hex string 1195 // ex fe800000000000000000000000000000 1196 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest); 1197 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength); 1198 1199 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate); 1200 1201 RouteInfo route = new RouteInfo(linkAddress, gateAddr); 1202 routes.add(route); 1203 } catch (Exception e) { 1204 Log.e(TAG, "Error parsing route " + s + " : " + e); 1205 continue; 1206 } 1207 } 1208 } 1209 } 1210 return routes.toArray(new RouteInfo[routes.size()]); 1211 } 1212 1213 @Override 1214 public void setMtu(String iface, int mtu) { 1215 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1216 1217 final NativeDaemonEvent event; 1218 try { 1219 event = mConnector.execute("interface", "setmtu", iface, mtu); 1220 } catch (NativeDaemonConnectorException e) { 1221 throw e.rethrowAsParcelableException(); 1222 } 1223 } 1224 1225 @Override 1226 public void shutdown() { 1227 // TODO: remove from aidl if nobody calls externally 1228 mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG); 1229 1230 Slog.d(TAG, "Shutting down"); 1231 } 1232 1233 @Override 1234 public boolean getIpForwardingEnabled() throws IllegalStateException{ 1235 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1236 1237 final NativeDaemonEvent event; 1238 try { 1239 event = mConnector.execute("ipfwd", "status"); 1240 } catch (NativeDaemonConnectorException e) { 1241 throw e.rethrowAsParcelableException(); 1242 } 1243 1244 // 211 Forwarding enabled 1245 event.checkCode(IpFwdStatusResult); 1246 return event.getMessage().endsWith("enabled"); 1247 } 1248 1249 @Override 1250 public void setIpForwardingEnabled(boolean enable) { 1251 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1252 try { 1253 mConnector.execute("ipfwd", enable ? "enable" : "disable", "tethering"); 1254 } catch (NativeDaemonConnectorException e) { 1255 throw e.rethrowAsParcelableException(); 1256 } 1257 } 1258 1259 @Override 1260 public void startTethering(String[] dhcpRange) { 1261 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1262 // cmd is "tether start first_start first_stop second_start second_stop ..." 1263 // an odd number of addrs will fail 1264 1265 final Command cmd = new Command("tether", "start"); 1266 for (String d : dhcpRange) { 1267 cmd.appendArg(d); 1268 } 1269 1270 try { 1271 mConnector.execute(cmd); 1272 } catch (NativeDaemonConnectorException e) { 1273 throw e.rethrowAsParcelableException(); 1274 } 1275 } 1276 1277 @Override 1278 public void stopTethering() { 1279 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1280 try { 1281 mConnector.execute("tether", "stop"); 1282 } catch (NativeDaemonConnectorException e) { 1283 throw e.rethrowAsParcelableException(); 1284 } 1285 } 1286 1287 @Override 1288 public boolean isTetheringStarted() { 1289 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1290 1291 final NativeDaemonEvent event; 1292 try { 1293 event = mConnector.execute("tether", "status"); 1294 } catch (NativeDaemonConnectorException e) { 1295 throw e.rethrowAsParcelableException(); 1296 } 1297 1298 // 210 Tethering services started 1299 event.checkCode(TetherStatusResult); 1300 return event.getMessage().endsWith("started"); 1301 } 1302 1303 @Override 1304 public void tetherInterface(String iface) { 1305 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1306 try { 1307 mConnector.execute("tether", "interface", "add", iface); 1308 } catch (NativeDaemonConnectorException e) { 1309 throw e.rethrowAsParcelableException(); 1310 } 1311 List<RouteInfo> routes = new ArrayList<RouteInfo>(); 1312 // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it 1313 // suitable to use as a route destination. 1314 routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface)); 1315 addInterfaceToLocalNetwork(iface, routes); 1316 } 1317 1318 @Override 1319 public void untetherInterface(String iface) { 1320 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1321 try { 1322 mConnector.execute("tether", "interface", "remove", iface); 1323 } catch (NativeDaemonConnectorException e) { 1324 throw e.rethrowAsParcelableException(); 1325 } 1326 removeInterfaceFromLocalNetwork(iface); 1327 } 1328 1329 @Override 1330 public String[] listTetheredInterfaces() { 1331 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1332 try { 1333 return NativeDaemonEvent.filterMessageList( 1334 mConnector.executeForList("tether", "interface", "list"), 1335 TetherInterfaceListResult); 1336 } catch (NativeDaemonConnectorException e) { 1337 throw e.rethrowAsParcelableException(); 1338 } 1339 } 1340 1341 @Override 1342 public void setDnsForwarders(Network network, String[] dns) { 1343 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1344 1345 int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET; 1346 final Command cmd = new Command("tether", "dns", "set", netId); 1347 1348 for (String s : dns) { 1349 cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress()); 1350 } 1351 1352 try { 1353 mConnector.execute(cmd); 1354 } catch (NativeDaemonConnectorException e) { 1355 throw e.rethrowAsParcelableException(); 1356 } 1357 } 1358 1359 @Override 1360 public String[] getDnsForwarders() { 1361 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1362 try { 1363 return NativeDaemonEvent.filterMessageList( 1364 mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult); 1365 } catch (NativeDaemonConnectorException e) { 1366 throw e.rethrowAsParcelableException(); 1367 } 1368 } 1369 1370 private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) { 1371 ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size()); 1372 for (InterfaceAddress ia : addresses) { 1373 if (!ia.getAddress().isLinkLocalAddress()) 1374 filtered.add(ia); 1375 } 1376 return filtered; 1377 } 1378 1379 private void modifyInterfaceForward(boolean add, String fromIface, String toIface) { 1380 final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface); 1381 try { 1382 mConnector.execute(cmd); 1383 } catch (NativeDaemonConnectorException e) { 1384 throw e.rethrowAsParcelableException(); 1385 } 1386 } 1387 1388 @Override 1389 public void startInterfaceForwarding(String fromIface, String toIface) { 1390 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1391 modifyInterfaceForward(true, fromIface, toIface); 1392 } 1393 1394 @Override 1395 public void stopInterfaceForwarding(String fromIface, String toIface) { 1396 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1397 modifyInterfaceForward(false, fromIface, toIface); 1398 } 1399 1400 private void modifyNat(String action, String internalInterface, String externalInterface) 1401 throws SocketException { 1402 final Command cmd = new Command("nat", action, internalInterface, externalInterface); 1403 1404 final NetworkInterface internalNetworkInterface = NetworkInterface.getByName( 1405 internalInterface); 1406 if (internalNetworkInterface == null) { 1407 cmd.appendArg("0"); 1408 } else { 1409 // Don't touch link-local routes, as link-local addresses aren't routable, 1410 // kernel creates link-local routes on all interfaces automatically 1411 List<InterfaceAddress> interfaceAddresses = excludeLinkLocal( 1412 internalNetworkInterface.getInterfaceAddresses()); 1413 cmd.appendArg(interfaceAddresses.size()); 1414 for (InterfaceAddress ia : interfaceAddresses) { 1415 InetAddress addr = NetworkUtils.getNetworkPart( 1416 ia.getAddress(), ia.getNetworkPrefixLength()); 1417 cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength()); 1418 } 1419 } 1420 1421 try { 1422 mConnector.execute(cmd); 1423 } catch (NativeDaemonConnectorException e) { 1424 throw e.rethrowAsParcelableException(); 1425 } 1426 } 1427 1428 @Override 1429 public void enableNat(String internalInterface, String externalInterface) { 1430 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1431 try { 1432 modifyNat("enable", internalInterface, externalInterface); 1433 } catch (SocketException e) { 1434 throw new IllegalStateException(e); 1435 } 1436 } 1437 1438 @Override 1439 public void disableNat(String internalInterface, String externalInterface) { 1440 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1441 try { 1442 modifyNat("disable", internalInterface, externalInterface); 1443 } catch (SocketException e) { 1444 throw new IllegalStateException(e); 1445 } 1446 } 1447 1448 @Override 1449 public String[] listTtys() { 1450 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1451 try { 1452 return NativeDaemonEvent.filterMessageList( 1453 mConnector.executeForList("list_ttys"), TtyListResult); 1454 } catch (NativeDaemonConnectorException e) { 1455 throw e.rethrowAsParcelableException(); 1456 } 1457 } 1458 1459 @Override 1460 public void attachPppd( 1461 String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) { 1462 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1463 try { 1464 mConnector.execute("pppd", "attach", tty, 1465 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(), 1466 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(), 1467 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(), 1468 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()); 1469 } catch (NativeDaemonConnectorException e) { 1470 throw e.rethrowAsParcelableException(); 1471 } 1472 } 1473 1474 @Override 1475 public void detachPppd(String tty) { 1476 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1477 try { 1478 mConnector.execute("pppd", "detach", tty); 1479 } catch (NativeDaemonConnectorException e) { 1480 throw e.rethrowAsParcelableException(); 1481 } 1482 } 1483 1484 @Override 1485 public void startAccessPoint( 1486 WifiConfiguration wifiConfig, String wlanIface) { 1487 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1488 try { 1489 if (wifiConfig == null) { 1490 mConnector.execute("softap", "set", wlanIface); 1491 } else { 1492 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID, 1493 "broadcast", Integer.toString(wifiConfig.apChannel), 1494 getSecurityType(wifiConfig), 1495 new SensitiveArg(wifiConfig.preSharedKey)); 1496 } 1497 mConnector.execute("softap", "startap"); 1498 } catch (NativeDaemonConnectorException e) { 1499 throw e.rethrowAsParcelableException(); 1500 } 1501 } 1502 1503 private static String getSecurityType(WifiConfiguration wifiConfig) { 1504 switch (wifiConfig.getAuthType()) { 1505 case KeyMgmt.WPA_PSK: 1506 return "wpa-psk"; 1507 case KeyMgmt.WPA2_PSK: 1508 return "wpa2-psk"; 1509 default: 1510 return "open"; 1511 } 1512 } 1513 1514 /* @param mode can be "AP", "STA" or "P2P" */ 1515 @Override 1516 public void wifiFirmwareReload(String wlanIface, String mode) { 1517 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1518 try { 1519 mConnector.execute("softap", "fwreload", wlanIface, mode); 1520 } catch (NativeDaemonConnectorException e) { 1521 throw e.rethrowAsParcelableException(); 1522 } 1523 } 1524 1525 @Override 1526 public void stopAccessPoint(String wlanIface) { 1527 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1528 try { 1529 mConnector.execute("softap", "stopap"); 1530 wifiFirmwareReload(wlanIface, "STA"); 1531 } catch (NativeDaemonConnectorException e) { 1532 throw e.rethrowAsParcelableException(); 1533 } 1534 } 1535 1536 @Override 1537 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) { 1538 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1539 try { 1540 if (wifiConfig == null) { 1541 mConnector.execute("softap", "set", wlanIface); 1542 } else { 1543 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID, 1544 "broadcast", "6", getSecurityType(wifiConfig), 1545 new SensitiveArg(wifiConfig.preSharedKey)); 1546 } 1547 } catch (NativeDaemonConnectorException e) { 1548 throw e.rethrowAsParcelableException(); 1549 } 1550 } 1551 1552 @Override 1553 public void addIdleTimer(String iface, int timeout, final int type) { 1554 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1555 1556 if (DBG) Slog.d(TAG, "Adding idletimer"); 1557 1558 synchronized (mIdleTimerLock) { 1559 IdleTimerParams params = mActiveIdleTimers.get(iface); 1560 if (params != null) { 1561 // the interface already has idletimer, update network count 1562 params.networkCount++; 1563 return; 1564 } 1565 1566 try { 1567 mConnector.execute("idletimer", "add", iface, Integer.toString(timeout), 1568 Integer.toString(type)); 1569 } catch (NativeDaemonConnectorException e) { 1570 throw e.rethrowAsParcelableException(); 1571 } 1572 mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type)); 1573 1574 // Networks start up. 1575 if (ConnectivityManager.isNetworkTypeMobile(type)) { 1576 mNetworkActive = false; 1577 } 1578 mDaemonHandler.post(new Runnable() { 1579 @Override public void run() { 1580 notifyInterfaceClassActivity(type, 1581 DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 1582 SystemClock.elapsedRealtimeNanos(), false); 1583 } 1584 }); 1585 } 1586 } 1587 1588 @Override 1589 public void removeIdleTimer(String iface) { 1590 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1591 1592 if (DBG) Slog.d(TAG, "Removing idletimer"); 1593 1594 synchronized (mIdleTimerLock) { 1595 final IdleTimerParams params = mActiveIdleTimers.get(iface); 1596 if (params == null || --(params.networkCount) > 0) { 1597 return; 1598 } 1599 1600 try { 1601 mConnector.execute("idletimer", "remove", iface, 1602 Integer.toString(params.timeout), Integer.toString(params.type)); 1603 } catch (NativeDaemonConnectorException e) { 1604 throw e.rethrowAsParcelableException(); 1605 } 1606 mActiveIdleTimers.remove(iface); 1607 mDaemonHandler.post(new Runnable() { 1608 @Override public void run() { 1609 notifyInterfaceClassActivity(params.type, 1610 DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, 1611 SystemClock.elapsedRealtimeNanos(), false); 1612 } 1613 }); 1614 } 1615 } 1616 1617 @Override 1618 public NetworkStats getNetworkStatsSummaryDev() { 1619 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1620 try { 1621 return mStatsFactory.readNetworkStatsSummaryDev(); 1622 } catch (IOException e) { 1623 throw new IllegalStateException(e); 1624 } 1625 } 1626 1627 @Override 1628 public NetworkStats getNetworkStatsSummaryXt() { 1629 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1630 try { 1631 return mStatsFactory.readNetworkStatsSummaryXt(); 1632 } catch (IOException e) { 1633 throw new IllegalStateException(e); 1634 } 1635 } 1636 1637 @Override 1638 public NetworkStats getNetworkStatsDetail() { 1639 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1640 try { 1641 return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); 1642 } catch (IOException e) { 1643 throw new IllegalStateException(e); 1644 } 1645 } 1646 1647 @Override 1648 public void setInterfaceQuota(String iface, long quotaBytes) { 1649 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1650 1651 // silently discard when control disabled 1652 // TODO: eventually migrate to be always enabled 1653 if (!mBandwidthControlEnabled) return; 1654 1655 synchronized (mQuotaLock) { 1656 if (mActiveQuotas.containsKey(iface)) { 1657 throw new IllegalStateException("iface " + iface + " already has quota"); 1658 } 1659 1660 try { 1661 // TODO: support quota shared across interfaces 1662 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes); 1663 mActiveQuotas.put(iface, quotaBytes); 1664 } catch (NativeDaemonConnectorException e) { 1665 throw e.rethrowAsParcelableException(); 1666 } 1667 } 1668 } 1669 1670 @Override 1671 public void removeInterfaceQuota(String iface) { 1672 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1673 1674 // silently discard when control disabled 1675 // TODO: eventually migrate to be always enabled 1676 if (!mBandwidthControlEnabled) return; 1677 1678 synchronized (mQuotaLock) { 1679 if (!mActiveQuotas.containsKey(iface)) { 1680 // TODO: eventually consider throwing 1681 return; 1682 } 1683 1684 mActiveQuotas.remove(iface); 1685 mActiveAlerts.remove(iface); 1686 1687 try { 1688 // TODO: support quota shared across interfaces 1689 mConnector.execute("bandwidth", "removeiquota", iface); 1690 } catch (NativeDaemonConnectorException e) { 1691 throw e.rethrowAsParcelableException(); 1692 } 1693 } 1694 } 1695 1696 @Override 1697 public void setInterfaceAlert(String iface, long alertBytes) { 1698 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1699 1700 // silently discard when control disabled 1701 // TODO: eventually migrate to be always enabled 1702 if (!mBandwidthControlEnabled) return; 1703 1704 // quick sanity check 1705 if (!mActiveQuotas.containsKey(iface)) { 1706 throw new IllegalStateException("setting alert requires existing quota on iface"); 1707 } 1708 1709 synchronized (mQuotaLock) { 1710 if (mActiveAlerts.containsKey(iface)) { 1711 throw new IllegalStateException("iface " + iface + " already has alert"); 1712 } 1713 1714 try { 1715 // TODO: support alert shared across interfaces 1716 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes); 1717 mActiveAlerts.put(iface, alertBytes); 1718 } catch (NativeDaemonConnectorException e) { 1719 throw e.rethrowAsParcelableException(); 1720 } 1721 } 1722 } 1723 1724 @Override 1725 public void removeInterfaceAlert(String iface) { 1726 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1727 1728 // silently discard when control disabled 1729 // TODO: eventually migrate to be always enabled 1730 if (!mBandwidthControlEnabled) return; 1731 1732 synchronized (mQuotaLock) { 1733 if (!mActiveAlerts.containsKey(iface)) { 1734 // TODO: eventually consider throwing 1735 return; 1736 } 1737 1738 try { 1739 // TODO: support alert shared across interfaces 1740 mConnector.execute("bandwidth", "removeinterfacealert", iface); 1741 mActiveAlerts.remove(iface); 1742 } catch (NativeDaemonConnectorException e) { 1743 throw e.rethrowAsParcelableException(); 1744 } 1745 } 1746 } 1747 1748 @Override 1749 public void setGlobalAlert(long alertBytes) { 1750 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1751 1752 // silently discard when control disabled 1753 // TODO: eventually migrate to be always enabled 1754 if (!mBandwidthControlEnabled) return; 1755 1756 try { 1757 mConnector.execute("bandwidth", "setglobalalert", alertBytes); 1758 } catch (NativeDaemonConnectorException e) { 1759 throw e.rethrowAsParcelableException(); 1760 } 1761 } 1762 1763 @Override 1764 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { 1765 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1766 1767 // silently discard when control disabled 1768 // TODO: eventually migrate to be always enabled 1769 if (!mBandwidthControlEnabled) return; 1770 1771 synchronized (mQuotaLock) { 1772 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false); 1773 if (oldRejectOnQuota == rejectOnQuotaInterfaces) { 1774 // TODO: eventually consider throwing 1775 return; 1776 } 1777 1778 try { 1779 mConnector.execute("bandwidth", 1780 rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid); 1781 if (rejectOnQuotaInterfaces) { 1782 mUidRejectOnQuota.put(uid, true); 1783 } else { 1784 mUidRejectOnQuota.delete(uid); 1785 } 1786 } catch (NativeDaemonConnectorException e) { 1787 throw e.rethrowAsParcelableException(); 1788 } 1789 } 1790 } 1791 1792 @Override 1793 public void setUidCleartextNetworkPolicy(int uid, int policy) { 1794 if (Binder.getCallingUid() != uid) { 1795 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1796 } 1797 1798 synchronized (mQuotaLock) { 1799 final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT); 1800 if (oldPolicy == policy) { 1801 return; 1802 } 1803 1804 if (!mStrictEnabled) { 1805 // Module isn't enabled yet; stash the requested policy away to 1806 // apply later once the daemon is connected. 1807 mUidCleartextPolicy.put(uid, policy); 1808 return; 1809 } 1810 1811 final String policyString; 1812 switch (policy) { 1813 case StrictMode.NETWORK_POLICY_ACCEPT: 1814 policyString = "accept"; 1815 break; 1816 case StrictMode.NETWORK_POLICY_LOG: 1817 policyString = "log"; 1818 break; 1819 case StrictMode.NETWORK_POLICY_REJECT: 1820 policyString = "reject"; 1821 break; 1822 default: 1823 throw new IllegalArgumentException("Unknown policy " + policy); 1824 } 1825 1826 try { 1827 mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString); 1828 mUidCleartextPolicy.put(uid, policy); 1829 } catch (NativeDaemonConnectorException e) { 1830 throw e.rethrowAsParcelableException(); 1831 } 1832 } 1833 } 1834 1835 @Override 1836 public boolean isBandwidthControlEnabled() { 1837 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1838 return mBandwidthControlEnabled; 1839 } 1840 1841 @Override 1842 public NetworkStats getNetworkStatsUidDetail(int uid) { 1843 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1844 try { 1845 return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null); 1846 } catch (IOException e) { 1847 throw new IllegalStateException(e); 1848 } 1849 } 1850 1851 @Override 1852 public NetworkStats getNetworkStatsTethering() { 1853 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1854 1855 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); 1856 try { 1857 final NativeDaemonEvent[] events = mConnector.executeForList( 1858 "bandwidth", "gettetherstats"); 1859 for (NativeDaemonEvent event : events) { 1860 if (event.getCode() != TetheringStatsListResult) continue; 1861 1862 // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets 1863 final StringTokenizer tok = new StringTokenizer(event.getMessage()); 1864 try { 1865 final String ifaceIn = tok.nextToken(); 1866 final String ifaceOut = tok.nextToken(); 1867 1868 final NetworkStats.Entry entry = new NetworkStats.Entry(); 1869 entry.iface = ifaceOut; 1870 entry.uid = UID_TETHERING; 1871 entry.set = SET_DEFAULT; 1872 entry.tag = TAG_NONE; 1873 entry.rxBytes = Long.parseLong(tok.nextToken()); 1874 entry.rxPackets = Long.parseLong(tok.nextToken()); 1875 entry.txBytes = Long.parseLong(tok.nextToken()); 1876 entry.txPackets = Long.parseLong(tok.nextToken()); 1877 stats.combineValues(entry); 1878 } catch (NoSuchElementException e) { 1879 throw new IllegalStateException("problem parsing tethering stats: " + event); 1880 } catch (NumberFormatException e) { 1881 throw new IllegalStateException("problem parsing tethering stats: " + event); 1882 } 1883 } 1884 } catch (NativeDaemonConnectorException e) { 1885 throw e.rethrowAsParcelableException(); 1886 } 1887 return stats; 1888 } 1889 1890 @Override 1891 public void setDnsServersForNetwork(int netId, String[] servers, String domains) { 1892 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1893 1894 Command cmd; 1895 if (servers.length > 0) { 1896 cmd = new Command("resolver", "setnetdns", netId, 1897 (domains == null ? "" : domains)); 1898 for (String s : servers) { 1899 InetAddress a = NetworkUtils.numericToInetAddress(s); 1900 if (a.isAnyLocalAddress() == false) { 1901 cmd.appendArg(a.getHostAddress()); 1902 } 1903 } 1904 } else { 1905 cmd = new Command("resolver", "clearnetdns", netId); 1906 } 1907 1908 try { 1909 mConnector.execute(cmd); 1910 } catch (NativeDaemonConnectorException e) { 1911 throw e.rethrowAsParcelableException(); 1912 } 1913 } 1914 1915 @Override 1916 public void addVpnUidRanges(int netId, UidRange[] ranges) { 1917 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1918 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND]; 1919 argv[0] = "users"; 1920 argv[1] = "add"; 1921 argv[2] = netId; 1922 int argc = 3; 1923 // Avoid overly long commands by limiting number of UID ranges per command. 1924 for (int i = 0; i < ranges.length; i++) { 1925 argv[argc++] = ranges[i].toString(); 1926 if (i == (ranges.length - 1) || argc == argv.length) { 1927 try { 1928 mConnector.execute("network", Arrays.copyOf(argv, argc)); 1929 } catch (NativeDaemonConnectorException e) { 1930 throw e.rethrowAsParcelableException(); 1931 } 1932 argc = 3; 1933 } 1934 } 1935 } 1936 1937 @Override 1938 public void removeVpnUidRanges(int netId, UidRange[] ranges) { 1939 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1940 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND]; 1941 argv[0] = "users"; 1942 argv[1] = "remove"; 1943 argv[2] = netId; 1944 int argc = 3; 1945 // Avoid overly long commands by limiting number of UID ranges per command. 1946 for (int i = 0; i < ranges.length; i++) { 1947 argv[argc++] = ranges[i].toString(); 1948 if (i == (ranges.length - 1) || argc == argv.length) { 1949 try { 1950 mConnector.execute("network", Arrays.copyOf(argv, argc)); 1951 } catch (NativeDaemonConnectorException e) { 1952 throw e.rethrowAsParcelableException(); 1953 } 1954 argc = 3; 1955 } 1956 } 1957 } 1958 1959 @Override 1960 public void flushNetworkDnsCache(int netId) { 1961 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1962 try { 1963 mConnector.execute("resolver", "flushnet", netId); 1964 } catch (NativeDaemonConnectorException e) { 1965 throw e.rethrowAsParcelableException(); 1966 } 1967 } 1968 1969 @Override 1970 public void setFirewallEnabled(boolean enabled) { 1971 enforceSystemUid(); 1972 try { 1973 mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist"); 1974 mFirewallEnabled = enabled; 1975 } catch (NativeDaemonConnectorException e) { 1976 throw e.rethrowAsParcelableException(); 1977 } 1978 } 1979 1980 @Override 1981 public boolean isFirewallEnabled() { 1982 enforceSystemUid(); 1983 return mFirewallEnabled; 1984 } 1985 1986 @Override 1987 public void setFirewallInterfaceRule(String iface, boolean allow) { 1988 enforceSystemUid(); 1989 Preconditions.checkState(mFirewallEnabled); 1990 final String rule = allow ? "allow" : "deny"; 1991 try { 1992 mConnector.execute("firewall", "set_interface_rule", iface, rule); 1993 } catch (NativeDaemonConnectorException e) { 1994 throw e.rethrowAsParcelableException(); 1995 } 1996 } 1997 1998 @Override 1999 public void setFirewallEgressSourceRule(String addr, boolean allow) { 2000 enforceSystemUid(); 2001 Preconditions.checkState(mFirewallEnabled); 2002 final String rule = allow ? "allow" : "deny"; 2003 try { 2004 mConnector.execute("firewall", "set_egress_source_rule", addr, rule); 2005 } catch (NativeDaemonConnectorException e) { 2006 throw e.rethrowAsParcelableException(); 2007 } 2008 } 2009 2010 @Override 2011 public void setFirewallEgressDestRule(String addr, int port, boolean allow) { 2012 enforceSystemUid(); 2013 Preconditions.checkState(mFirewallEnabled); 2014 final String rule = allow ? "allow" : "deny"; 2015 try { 2016 mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule); 2017 } catch (NativeDaemonConnectorException e) { 2018 throw e.rethrowAsParcelableException(); 2019 } 2020 } 2021 2022 @Override 2023 public void setFirewallChainEnabled(int chain, boolean enable) { 2024 enforceSystemUid(); 2025 synchronized (mQuotaLock) { 2026 if (mFirewallChainStates.indexOfKey(chain) >= 0 && 2027 mFirewallChainStates.get(chain) == enable) { 2028 // All is the same, nothing to do. 2029 return; 2030 } 2031 mFirewallChainStates.put(chain, enable); 2032 2033 final String operation = enable ? "enable_chain" : "disable_chain"; 2034 try { 2035 String chainName; 2036 switch(chain) { 2037 case FIREWALL_CHAIN_STANDBY: 2038 chainName = FIREWALL_CHAIN_NAME_STANDBY; 2039 break; 2040 case FIREWALL_CHAIN_DOZABLE: 2041 chainName = FIREWALL_CHAIN_NAME_DOZABLE; 2042 break; 2043 default: 2044 throw new IllegalArgumentException("Bad child chain: " + chain); 2045 } 2046 mConnector.execute("firewall", operation, chainName); 2047 } catch (NativeDaemonConnectorException e) { 2048 throw e.rethrowAsParcelableException(); 2049 } 2050 } 2051 } 2052 2053 private int getFirewallType(int chain) { 2054 switch (chain) { 2055 case FIREWALL_CHAIN_STANDBY: 2056 return FIREWALL_TYPE_BLACKLIST; 2057 case FIREWALL_CHAIN_DOZABLE: 2058 return FIREWALL_TYPE_WHITELIST; 2059 default: 2060 return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST; 2061 } 2062 } 2063 2064 @Override 2065 public void setFirewallUidRules(int chain, int[] uids, int[] rules) { 2066 enforceSystemUid(); 2067 synchronized (mQuotaLock) { 2068 SparseIntArray uidFirewallRules = getUidFirewallRules(chain); 2069 SparseIntArray newRules = new SparseIntArray(); 2070 // apply new set of rules 2071 for (int index = uids.length - 1; index >= 0; --index) { 2072 int uid = uids[index]; 2073 int rule = rules[index]; 2074 setFirewallUidRule(chain, uid, rule); 2075 newRules.put(uid, rule); 2076 } 2077 // collect the rules to remove. 2078 SparseIntArray rulesToRemove = new SparseIntArray(); 2079 for (int index = uidFirewallRules.size() - 1; index >= 0; --index) { 2080 int uid = uidFirewallRules.keyAt(index); 2081 if (newRules.indexOfKey(uid) < 0) { 2082 rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT); 2083 } 2084 } 2085 // remove dead rules 2086 for (int index = rulesToRemove.size() - 1; index >= 0; --index) { 2087 int uid = rulesToRemove.keyAt(index); 2088 setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT); 2089 } 2090 } 2091 } 2092 2093 @Override 2094 public void setFirewallUidRule(int chain, int uid, int rule) { 2095 enforceSystemUid(); 2096 setFirewallUidRuleInternal(chain, uid, rule); 2097 } 2098 2099 private void setFirewallUidRuleInternal(int chain, int uid, int rule) { 2100 synchronized (mQuotaLock) { 2101 SparseIntArray uidFirewallRules = getUidFirewallRules(chain); 2102 2103 final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT); 2104 if (DBG) { 2105 Slog.d(TAG, "oldRule = " + oldUidFirewallRule 2106 + ", newRule=" + rule + " for uid=" + uid); 2107 } 2108 if (oldUidFirewallRule == rule) { 2109 if (DBG) Slog.d(TAG, "!!!!! Skipping change"); 2110 // TODO: eventually consider throwing 2111 return; 2112 } 2113 2114 try { 2115 String ruleName = getFirewallRuleName(chain, rule); 2116 String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule); 2117 2118 if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) { 2119 uidFirewallRules.delete(uid); 2120 } else { 2121 uidFirewallRules.put(uid, rule); 2122 } 2123 2124 if (!ruleName.equals(oldRuleName)) { 2125 mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid, 2126 ruleName); 2127 } 2128 } catch (NativeDaemonConnectorException e) { 2129 throw e.rethrowAsParcelableException(); 2130 } 2131 } 2132 } 2133 2134 private @NonNull String getFirewallRuleName(int chain, int rule) { 2135 String ruleName; 2136 if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) { 2137 if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) { 2138 ruleName = "allow"; 2139 } else { 2140 ruleName = "deny"; 2141 } 2142 } else { // Blacklist mode 2143 if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) { 2144 ruleName = "deny"; 2145 } else { 2146 ruleName = "allow"; 2147 } 2148 } 2149 return ruleName; 2150 } 2151 2152 private @NonNull SparseIntArray getUidFirewallRules(int chain) { 2153 switch (chain) { 2154 case FIREWALL_CHAIN_STANDBY: 2155 return mUidFirewallStandbyRules; 2156 case FIREWALL_CHAIN_DOZABLE: 2157 return mUidFirewallDozableRules; 2158 case FIREWALL_CHAIN_NONE: 2159 return mUidFirewallRules; 2160 default: 2161 throw new IllegalArgumentException("Unknown chain:" + chain); 2162 } 2163 } 2164 2165 public @NonNull String getFirewallChainName(int chain) { 2166 switch (chain) { 2167 case FIREWALL_CHAIN_STANDBY: 2168 return FIREWALL_CHAIN_NAME_STANDBY; 2169 case FIREWALL_CHAIN_DOZABLE: 2170 return FIREWALL_CHAIN_NAME_DOZABLE; 2171 case FIREWALL_CHAIN_NONE: 2172 return FIREWALL_CHAIN_NAME_NONE; 2173 default: 2174 throw new IllegalArgumentException("Unknown chain:" + chain); 2175 } 2176 } 2177 2178 private static void enforceSystemUid() { 2179 final int uid = Binder.getCallingUid(); 2180 if (uid != Process.SYSTEM_UID) { 2181 throw new SecurityException("Only available to AID_SYSTEM"); 2182 } 2183 } 2184 2185 @Override 2186 public void startClatd(String interfaceName) throws IllegalStateException { 2187 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2188 2189 try { 2190 mConnector.execute("clatd", "start", interfaceName); 2191 } catch (NativeDaemonConnectorException e) { 2192 throw e.rethrowAsParcelableException(); 2193 } 2194 } 2195 2196 @Override 2197 public void stopClatd(String interfaceName) throws IllegalStateException { 2198 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2199 2200 try { 2201 mConnector.execute("clatd", "stop", interfaceName); 2202 } catch (NativeDaemonConnectorException e) { 2203 throw e.rethrowAsParcelableException(); 2204 } 2205 } 2206 2207 @Override 2208 public boolean isClatdStarted(String interfaceName) { 2209 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2210 2211 final NativeDaemonEvent event; 2212 try { 2213 event = mConnector.execute("clatd", "status", interfaceName); 2214 } catch (NativeDaemonConnectorException e) { 2215 throw e.rethrowAsParcelableException(); 2216 } 2217 2218 event.checkCode(ClatdStatusResult); 2219 return event.getMessage().endsWith("started"); 2220 } 2221 2222 @Override 2223 public void registerNetworkActivityListener(INetworkActivityListener listener) { 2224 mNetworkActivityListeners.register(listener); 2225 } 2226 2227 @Override 2228 public void unregisterNetworkActivityListener(INetworkActivityListener listener) { 2229 mNetworkActivityListeners.unregister(listener); 2230 } 2231 2232 @Override 2233 public boolean isNetworkActive() { 2234 synchronized (mNetworkActivityListeners) { 2235 return mNetworkActive || mActiveIdleTimers.isEmpty(); 2236 } 2237 } 2238 2239 private void reportNetworkActive() { 2240 final int length = mNetworkActivityListeners.beginBroadcast(); 2241 try { 2242 for (int i = 0; i < length; i++) { 2243 try { 2244 mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive(); 2245 } catch (RemoteException e) { 2246 } catch (RuntimeException e) { 2247 } 2248 } 2249 } finally { 2250 mNetworkActivityListeners.finishBroadcast(); 2251 } 2252 } 2253 2254 /** {@inheritDoc} */ 2255 @Override 2256 public void monitor() { 2257 if (mConnector != null) { 2258 mConnector.monitor(); 2259 } 2260 } 2261 2262 @Override 2263 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2264 mContext.enforceCallingOrSelfPermission(DUMP, TAG); 2265 2266 pw.println("NetworkManagementService NativeDaemonConnector Log:"); 2267 mConnector.dump(fd, pw, args); 2268 pw.println(); 2269 2270 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled); 2271 pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio); 2272 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio); 2273 pw.print("mNetworkActive="); pw.println(mNetworkActive); 2274 2275 synchronized (mQuotaLock) { 2276 pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString()); 2277 pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString()); 2278 } 2279 2280 synchronized (mUidRejectOnQuota) { 2281 pw.print("UID reject on quota ifaces: ["); 2282 final int size = mUidRejectOnQuota.size(); 2283 for (int i = 0; i < size; i++) { 2284 pw.print(mUidRejectOnQuota.keyAt(i)); 2285 if (i < size - 1) pw.print(","); 2286 } 2287 pw.println("]"); 2288 } 2289 2290 synchronized (mUidFirewallRules) { 2291 pw.print("UID firewall rule: ["); 2292 final int size = mUidFirewallRules.size(); 2293 for (int i = 0; i < size; i++) { 2294 pw.print(mUidFirewallRules.keyAt(i)); 2295 pw.print(":"); 2296 pw.print(mUidFirewallRules.valueAt(i)); 2297 if (i < size - 1) pw.print(","); 2298 } 2299 pw.println("]"); 2300 } 2301 2302 pw.println("UID firewall standby chain enabled: " + 2303 mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)); 2304 synchronized (mUidFirewallStandbyRules) { 2305 pw.print("UID firewall standby rule: ["); 2306 final int size = mUidFirewallStandbyRules.size(); 2307 for (int i = 0; i < size; i++) { 2308 pw.print(mUidFirewallStandbyRules.keyAt(i)); 2309 pw.print(":"); 2310 pw.print(mUidFirewallStandbyRules.valueAt(i)); 2311 if (i < size - 1) pw.print(","); 2312 } 2313 pw.println("]"); 2314 } 2315 2316 pw.println("UID firewall dozable chain enabled: " + 2317 mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)); 2318 synchronized (mUidFirewallDozableRules) { 2319 pw.print("UID firewall dozable rule: ["); 2320 final int size = mUidFirewallDozableRules.size(); 2321 for (int i = 0; i < size; i++) { 2322 pw.print(mUidFirewallDozableRules.keyAt(i)); 2323 pw.print(":"); 2324 pw.print(mUidFirewallDozableRules.valueAt(i)); 2325 if (i < size - 1) pw.print(","); 2326 } 2327 pw.println("]"); 2328 } 2329 2330 synchronized (mIdleTimerLock) { 2331 pw.println("Idle timers:"); 2332 for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) { 2333 pw.print(" "); pw.print(ent.getKey()); pw.println(":"); 2334 IdleTimerParams params = ent.getValue(); 2335 pw.print(" timeout="); pw.print(params.timeout); 2336 pw.print(" type="); pw.print(params.type); 2337 pw.print(" networkCount="); pw.println(params.networkCount); 2338 } 2339 } 2340 2341 pw.print("Firewall enabled: "); pw.println(mFirewallEnabled); 2342 } 2343 2344 @Override 2345 public void createPhysicalNetwork(int netId, String permission) { 2346 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2347 2348 try { 2349 if (permission != null) { 2350 mConnector.execute("network", "create", netId, permission); 2351 } else { 2352 mConnector.execute("network", "create", netId); 2353 } 2354 } catch (NativeDaemonConnectorException e) { 2355 throw e.rethrowAsParcelableException(); 2356 } 2357 } 2358 2359 @Override 2360 public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) { 2361 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2362 2363 try { 2364 mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0", 2365 secure ? "1" : "0"); 2366 } catch (NativeDaemonConnectorException e) { 2367 throw e.rethrowAsParcelableException(); 2368 } 2369 } 2370 2371 @Override 2372 public void removeNetwork(int netId) { 2373 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2374 2375 try { 2376 mConnector.execute("network", "destroy", netId); 2377 } catch (NativeDaemonConnectorException e) { 2378 throw e.rethrowAsParcelableException(); 2379 } 2380 } 2381 2382 @Override 2383 public void addInterfaceToNetwork(String iface, int netId) { 2384 modifyInterfaceInNetwork("add", "" + netId, iface); 2385 } 2386 2387 @Override 2388 public void removeInterfaceFromNetwork(String iface, int netId) { 2389 modifyInterfaceInNetwork("remove", "" + netId, iface); 2390 } 2391 2392 private void modifyInterfaceInNetwork(String action, String netId, String iface) { 2393 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2394 try { 2395 mConnector.execute("network", "interface", action, netId, iface); 2396 } catch (NativeDaemonConnectorException e) { 2397 throw e.rethrowAsParcelableException(); 2398 } 2399 } 2400 2401 @Override 2402 public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) { 2403 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2404 2405 final Command cmd = new Command("network", "route", "legacy", uid, "add", netId); 2406 2407 // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr 2408 final LinkAddress la = routeInfo.getDestinationLinkAddress(); 2409 cmd.appendArg(routeInfo.getInterface()); 2410 cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength()); 2411 if (routeInfo.hasGateway()) { 2412 cmd.appendArg(routeInfo.getGateway().getHostAddress()); 2413 } 2414 2415 try { 2416 mConnector.execute(cmd); 2417 } catch (NativeDaemonConnectorException e) { 2418 throw e.rethrowAsParcelableException(); 2419 } 2420 } 2421 2422 @Override 2423 public void setDefaultNetId(int netId) { 2424 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2425 2426 try { 2427 mConnector.execute("network", "default", "set", netId); 2428 } catch (NativeDaemonConnectorException e) { 2429 throw e.rethrowAsParcelableException(); 2430 } 2431 } 2432 2433 @Override 2434 public void clearDefaultNetId() { 2435 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2436 2437 try { 2438 mConnector.execute("network", "default", "clear"); 2439 } catch (NativeDaemonConnectorException e) { 2440 throw e.rethrowAsParcelableException(); 2441 } 2442 } 2443 2444 @Override 2445 public void setNetworkPermission(int netId, String permission) { 2446 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2447 2448 try { 2449 if (permission != null) { 2450 mConnector.execute("network", "permission", "network", "set", permission, netId); 2451 } else { 2452 mConnector.execute("network", "permission", "network", "clear", netId); 2453 } 2454 } catch (NativeDaemonConnectorException e) { 2455 throw e.rethrowAsParcelableException(); 2456 } 2457 } 2458 2459 2460 @Override 2461 public void setPermission(String permission, int[] uids) { 2462 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2463 2464 Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND]; 2465 argv[0] = "permission"; 2466 argv[1] = "user"; 2467 argv[2] = "set"; 2468 argv[3] = permission; 2469 int argc = 4; 2470 // Avoid overly long commands by limiting number of UIDs per command. 2471 for (int i = 0; i < uids.length; ++i) { 2472 argv[argc++] = uids[i]; 2473 if (i == uids.length - 1 || argc == argv.length) { 2474 try { 2475 mConnector.execute("network", Arrays.copyOf(argv, argc)); 2476 } catch (NativeDaemonConnectorException e) { 2477 throw e.rethrowAsParcelableException(); 2478 } 2479 argc = 4; 2480 } 2481 } 2482 } 2483 2484 @Override 2485 public void clearPermission(int[] uids) { 2486 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2487 2488 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND]; 2489 argv[0] = "permission"; 2490 argv[1] = "user"; 2491 argv[2] = "clear"; 2492 int argc = 3; 2493 // Avoid overly long commands by limiting number of UIDs per command. 2494 for (int i = 0; i < uids.length; ++i) { 2495 argv[argc++] = uids[i]; 2496 if (i == uids.length - 1 || argc == argv.length) { 2497 try { 2498 mConnector.execute("network", Arrays.copyOf(argv, argc)); 2499 } catch (NativeDaemonConnectorException e) { 2500 throw e.rethrowAsParcelableException(); 2501 } 2502 argc = 3; 2503 } 2504 } 2505 } 2506 2507 @Override 2508 public void allowProtect(int uid) { 2509 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2510 2511 try { 2512 mConnector.execute("network", "protect", "allow", uid); 2513 } catch (NativeDaemonConnectorException e) { 2514 throw e.rethrowAsParcelableException(); 2515 } 2516 } 2517 2518 @Override 2519 public void denyProtect(int uid) { 2520 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 2521 2522 try { 2523 mConnector.execute("network", "protect", "deny", uid); 2524 } catch (NativeDaemonConnectorException e) { 2525 throw e.rethrowAsParcelableException(); 2526 } 2527 } 2528 2529 @Override 2530 public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { 2531 modifyInterfaceInNetwork("add", "local", iface); 2532 2533 for (RouteInfo route : routes) { 2534 if (!route.isDefaultRoute()) { 2535 modifyRoute("add", "local", route); 2536 } 2537 } 2538 } 2539 2540 @Override 2541 public void removeInterfaceFromLocalNetwork(String iface) { 2542 modifyInterfaceInNetwork("remove", "local", iface); 2543 } 2544 } 2545