2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server;
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_POWERSAVE;
26 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
27 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
28 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
29 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
30 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
31 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
32 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST;
33 import static android.net.NetworkStats.SET_DEFAULT;
34 import static android.net.NetworkStats.TAG_ALL;
35 import static android.net.NetworkStats.TAG_NONE;
36 import static android.net.NetworkStats.UID_ALL;
37 import static android.net.TrafficStats.UID_TETHERING;
38 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
39 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
40 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
41 import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
42 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
43 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
44 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
45 import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
46 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
47 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
48 import android.annotation.NonNull;
49 import android.app.ActivityManagerNative;
50 import android.content.ContentResolver;
51 import android.content.Context;
52 import android.net.ConnectivityManager;
53 import android.net.INetd;
54 import android.net.INetworkManagementEventObserver;
55 import android.net.InterfaceConfiguration;
56 import android.net.IpPrefix;
57 import android.net.LinkAddress;
58 import android.net.Network;
59 import android.net.NetworkPolicyManager;
60 import android.net.NetworkStats;
61 import android.net.NetworkUtils;
62 import android.net.RouteInfo;
63 import android.net.UidRange;
64 import android.net.wifi.WifiConfiguration;
65 import android.net.wifi.WifiConfiguration.KeyMgmt;
66 import android.os.BatteryStats;
67 import android.os.Binder;
68 import android.os.Handler;
69 import android.os.INetworkActivityListener;
70 import android.os.INetworkManagementService;
71 import android.os.PowerManager;
72 import android.os.Process;
73 import android.os.RemoteCallbackList;
74 import android.os.RemoteException;
75 import android.os.ServiceManager;
76 import android.os.ServiceSpecificException;
77 import android.os.StrictMode;
78 import android.os.SystemClock;
79 import android.os.SystemProperties;
80 import android.provider.Settings;
81 import android.telephony.DataConnectionRealTimeInfo;
82 import android.telephony.PhoneStateListener;
83 import android.telephony.SubscriptionManager;
84 import android.telephony.TelephonyManager;
85 import android.util.Log;
86 import android.util.Slog;
87 import android.util.SparseBooleanArray;
88 import android.util.SparseIntArray;
90 import com.android.internal.annotations.GuardedBy;
91 import com.android.internal.app.IBatteryStats;
92 import com.android.internal.net.NetworkStatsFactory;
93 import com.android.internal.util.HexDump;
94 import com.android.internal.util.Preconditions;
95 import com.android.server.NativeDaemonConnector.Command;
96 import com.android.server.NativeDaemonConnector.SensitiveArg;
97 import com.android.server.net.LockdownVpnTracker;
98 import com.google.android.collect.Maps;
100 import java.io.BufferedReader;
101 import java.io.DataInputStream;
103 import java.io.FileDescriptor;
104 import java.io.FileInputStream;
105 import java.io.IOException;
106 import java.io.InputStreamReader;
107 import java.io.PrintWriter;
108 import java.net.InetAddress;
109 import java.net.InterfaceAddress;
110 import java.net.NetworkInterface;
111 import java.net.SocketException;
112 import java.util.ArrayList;
113 import java.util.Arrays;
114 import java.util.HashMap;
115 import java.util.List;
116 import java.util.Map;
117 import java.util.NoSuchElementException;
118 import java.util.StringTokenizer;
119 import java.util.concurrent.CountDownLatch;
124 public class NetworkManagementService extends INetworkManagementService.Stub
125 implements Watchdog.Monitor {
126 private static final String TAG = "NetworkManagement";
127 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
128 private static final String NETD_TAG = "NetdConnector";
129 private static final String NETD_SERVICE_NAME = "netd";
131 private static final int MAX_UID_RANGES_PER_COMMAND = 10;
134 * Name representing {@link #setGlobalAlert(long)} limit when delivered to
135 * {@link INetworkManagementEventObserver#limitReached(String, String)}.
137 public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
140 * String to pass to netd to indicate that a network is only accessible
141 * to apps that have the CHANGE_NETWORK_STATE permission.
143 public static final String PERMISSION_NETWORK = "NETWORK";
146 * String to pass to netd to indicate that a network is only
147 * accessible to system apps and those with the CONNECTIVITY_INTERNAL
150 public static final String PERMISSION_SYSTEM = "SYSTEM";
152 class NetdResponseCode {
153 /* Keep in sync with system/netd/server/ResponseCode.h */
154 public static final int InterfaceListResult = 110;
155 public static final int TetherInterfaceListResult = 111;
156 public static final int TetherDnsFwdTgtListResult = 112;
157 public static final int TtyListResult = 113;
158 public static final int TetheringStatsListResult = 114;
160 public static final int TetherStatusResult = 210;
161 public static final int IpFwdStatusResult = 211;
162 public static final int InterfaceGetCfgResult = 213;
163 public static final int SoftapStatusResult = 214;
164 public static final int InterfaceRxCounterResult = 216;
165 public static final int InterfaceTxCounterResult = 217;
166 public static final int QuotaCounterResult = 220;
167 public static final int TetheringStatsResult = 221;
168 public static final int DnsProxyQueryResult = 222;
169 public static final int ClatdStatusResult = 223;
171 public static final int InterfaceChange = 600;
172 public static final int BandwidthControl = 601;
173 public static final int InterfaceClassActivity = 613;
174 public static final int InterfaceAddressChange = 614;
175 public static final int InterfaceDnsServerInfo = 615;
176 public static final int RouteChange = 616;
177 public static final int StrictCleartext = 617;
180 /* Defaults for resolver parameters. */
181 public static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
182 public static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
183 public static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
184 public static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
187 * String indicating a softap command.
189 static final String SOFT_AP_COMMAND = "softap";
192 * String passed back to netd connector indicating softap command success.
194 static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
196 static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
199 * Binder context for this service
201 private final Context mContext;
204 * connector object for communicating with netd
206 private final NativeDaemonConnector mConnector;
208 private final Handler mFgHandler;
209 private final Handler mDaemonHandler;
211 private INetd mNetdService;
213 private IBatteryStats mBatteryStats;
215 private final Thread mThread;
216 private CountDownLatch mConnectedSignal = new CountDownLatch(1);
218 private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
219 new RemoteCallbackList<INetworkManagementEventObserver>();
221 private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
223 private Object mQuotaLock = new Object();
225 /** Set of interfaces with active quotas. */
226 @GuardedBy("mQuotaLock")
227 private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
228 /** Set of interfaces with active alerts. */
229 @GuardedBy("mQuotaLock")
230 private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
231 /** Set of UIDs blacklisted on metered networks. */
232 @GuardedBy("mQuotaLock")
233 private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray();
234 /** Set of UIDs whitelisted on metered networks. */
235 @GuardedBy("mQuotaLock")
236 private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
237 /** Set of UIDs with cleartext penalties. */
238 @GuardedBy("mQuotaLock")
239 private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
240 /** Set of UIDs that are to be blocked/allowed by firewall controller. */
241 @GuardedBy("mQuotaLock")
242 private SparseIntArray mUidFirewallRules = new SparseIntArray();
244 * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
245 * to application idles.
247 @GuardedBy("mQuotaLock")
248 private SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
250 * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
253 @GuardedBy("mQuotaLock")
254 private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
256 * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
257 * to device on power-save mode.
259 @GuardedBy("mQuotaLock")
260 private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
261 /** Set of states for the child firewall chains. True if the chain is active. */
262 @GuardedBy("mQuotaLock")
263 final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
265 @GuardedBy("mQuotaLock")
266 private boolean mDataSaverMode;
268 private Object mIdleTimerLock = new Object();
269 /** Set of interfaces with active idle timers. */
270 private static class IdleTimerParams {
271 public final int timeout;
272 public final int type;
273 public int networkCount;
275 IdleTimerParams(int timeout, int type) {
276 this.timeout = timeout;
278 this.networkCount = 1;
281 private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
283 private volatile boolean mBandwidthControlEnabled;
284 private volatile boolean mFirewallEnabled;
285 private volatile boolean mStrictEnabled;
287 private boolean mMobileActivityFromRadio = false;
288 private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
289 private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
291 private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
292 new RemoteCallbackList<INetworkActivityListener>();
293 private boolean mNetworkActive;
296 * Constructs a new NetworkManagementService instance
298 * @param context Binder context for this service
300 private NetworkManagementService(Context context, String socket) {
303 // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
304 mFgHandler = new Handler(FgThread.get().getLooper());
306 // Don't need this wake lock, since we now have a time stamp for when
307 // the network actually went inactive. (It might be nice to still do this,
308 // but I don't want to do it through the power manager because that pollutes the
309 // battery stats history with pointless noise.)
310 //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
311 PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
313 mConnector = new NativeDaemonConnector(
314 new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
315 FgThread.get().getLooper());
316 mThread = new Thread(mConnector, NETD_TAG);
318 mDaemonHandler = new Handler(FgThread.get().getLooper());
320 // Add ourself to the Watchdog monitors.
321 Watchdog.getInstance().addMonitor(this);
324 static NetworkManagementService create(Context context, String socket)
325 throws InterruptedException {
326 final NetworkManagementService service = new NetworkManagementService(context, socket);
327 final CountDownLatch connectedSignal = service.mConnectedSignal;
328 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
329 service.mThread.start();
330 if (DBG) Slog.d(TAG, "Awaiting socket connection");
331 connectedSignal.await();
332 if (DBG) Slog.d(TAG, "Connected");
333 service.connectNativeNetdService();
337 public static NetworkManagementService create(Context context) throws InterruptedException {
338 return create(context, NETD_SERVICE_NAME);
341 public void systemReady() {
343 final long start = System.currentTimeMillis();
344 prepareNativeDaemon();
345 final long delta = System.currentTimeMillis() - start;
346 Slog.d(TAG, "Prepared in " + delta + "ms");
349 prepareNativeDaemon();
353 private IBatteryStats getBatteryStats() {
354 synchronized (this) {
355 if (mBatteryStats != null) {
356 return mBatteryStats;
358 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
359 BatteryStats.SERVICE_NAME));
360 return mBatteryStats;
365 public void registerObserver(INetworkManagementEventObserver observer) {
366 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
367 mObservers.register(observer);
371 public void unregisterObserver(INetworkManagementEventObserver observer) {
372 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
373 mObservers.unregister(observer);
377 * Notify our observers of an interface status change
379 private void notifyInterfaceStatusChanged(String iface, boolean up) {
380 final int length = mObservers.beginBroadcast();
382 for (int i = 0; i < length; i++) {
384 mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
385 } catch (RemoteException | RuntimeException e) {
389 mObservers.finishBroadcast();
394 * Notify our observers of an interface link state change
395 * (typically, an Ethernet cable has been plugged-in or unplugged).
397 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
398 final int length = mObservers.beginBroadcast();
400 for (int i = 0; i < length; i++) {
402 mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
403 } catch (RemoteException | RuntimeException e) {
407 mObservers.finishBroadcast();
412 * Notify our observers of an interface addition.
414 private void notifyInterfaceAdded(String iface) {
415 final int length = mObservers.beginBroadcast();
417 for (int i = 0; i < length; i++) {
419 mObservers.getBroadcastItem(i).interfaceAdded(iface);
420 } catch (RemoteException | RuntimeException e) {
424 mObservers.finishBroadcast();
429 * Notify our observers of an interface removal.
431 private void notifyInterfaceRemoved(String iface) {
432 // netd already clears out quota and alerts for removed ifaces; update
433 // our sanity-checking state.
434 mActiveAlerts.remove(iface);
435 mActiveQuotas.remove(iface);
437 final int length = mObservers.beginBroadcast();
439 for (int i = 0; i < length; i++) {
441 mObservers.getBroadcastItem(i).interfaceRemoved(iface);
442 } catch (RemoteException | RuntimeException e) {
446 mObservers.finishBroadcast();
451 * Notify our observers of a limit reached.
453 private void notifyLimitReached(String limitName, String iface) {
454 final int length = mObservers.beginBroadcast();
456 for (int i = 0; i < length; i++) {
458 mObservers.getBroadcastItem(i).limitReached(limitName, iface);
459 } catch (RemoteException | RuntimeException e) {
463 mObservers.finishBroadcast();
468 * Notify our observers of a change in the data activity state of the interface
470 private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
471 int uid, boolean fromRadio) {
472 final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
475 if (mMobileActivityFromRadio) {
476 // If this call is not coming from a report from the radio itself, but we
477 // have previously received reports from the radio, then we will take the
478 // power state to just be whatever the radio last reported.
479 powerState = mLastPowerStateFromRadio;
482 mMobileActivityFromRadio = true;
484 if (mLastPowerStateFromRadio != powerState) {
485 mLastPowerStateFromRadio = powerState;
487 getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
488 } catch (RemoteException e) {
493 if (ConnectivityManager.isNetworkTypeWifi(type)) {
494 if (mLastPowerStateFromWifi != powerState) {
495 mLastPowerStateFromWifi = powerState;
497 getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos);
498 } catch (RemoteException e) {
503 boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
504 || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
506 if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
507 // Report the change in data activity. We don't do this if this is a change
508 // on the mobile network, that is not coming from the radio itself, and we
509 // have previously seen change reports from the radio. In that case only
510 // the radio is the authority for the current state.
511 final int length = mObservers.beginBroadcast();
513 for (int i = 0; i < length; i++) {
515 mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
516 Integer.toString(type), isActive, tsNanos);
517 } catch (RemoteException | RuntimeException e) {
521 mObservers.finishBroadcast();
525 boolean report = false;
526 synchronized (mIdleTimerLock) {
527 if (mActiveIdleTimers.isEmpty()) {
528 // If there are no idle timers, we are not monitoring activity, so we
529 // are always considered active.
532 if (mNetworkActive != isActive) {
533 mNetworkActive = isActive;
538 reportNetworkActive();
542 // Sync the state of the given chain with the native daemon.
543 private void syncFirewallChainLocked(int chain, SparseIntArray uidFirewallRules, String name) {
544 int size = uidFirewallRules.size();
546 // Make a copy of the current rules, and then clear them. This is because
547 // setFirewallUidRuleInternal only pushes down rules to the native daemon if they are
548 // different from the current rules stored in the mUidFirewall*Rules array for the
549 // specified chain. If we don't clear the rules, setFirewallUidRuleInternal will do
551 final SparseIntArray rules = uidFirewallRules.clone();
552 uidFirewallRules.clear();
554 // Now push the rules. setFirewallUidRuleInternal will push each of these down to the
555 // native daemon, and also add them to the mUidFirewall*Rules array for the specified
557 if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall " + name + "UID rules");
558 for (int i = 0; i < rules.size(); i++) {
559 setFirewallUidRuleLocked(chain, rules.keyAt(i), rules.valueAt(i));
564 private void connectNativeNetdService() {
565 boolean nativeServiceAvailable = false;
567 mNetdService = INetd.Stub.asInterface(ServiceManager.getService(NETD_SERVICE_NAME));
568 nativeServiceAvailable = mNetdService.isAlive();
569 } catch (RemoteException e) {}
570 if (!nativeServiceAvailable) {
571 Slog.wtf(TAG, "Can't connect to NativeNetdService " + NETD_SERVICE_NAME);
576 * Prepare native daemon once connected, enabling modules and pushing any
577 * existing in-memory rules.
579 private void prepareNativeDaemon() {
581 mBandwidthControlEnabled = false;
583 // only enable bandwidth control when support exists
584 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
585 if (hasKernelSupport) {
586 Slog.d(TAG, "enabling bandwidth control");
588 mConnector.execute("bandwidth", "enable");
589 mBandwidthControlEnabled = true;
590 } catch (NativeDaemonConnectorException e) {
591 Log.wtf(TAG, "problem enabling bandwidth controls", e);
594 Slog.i(TAG, "not enabling bandwidth control");
597 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
599 if (mBandwidthControlEnabled) {
601 getBatteryStats().noteNetworkStatsEnabled();
602 } catch (RemoteException e) {
607 mConnector.execute("strict", "enable");
608 mStrictEnabled = true;
609 } catch (NativeDaemonConnectorException e) {
610 Log.wtf(TAG, "Failed strict enable", e);
613 // push any existing quota or UID rules
614 synchronized (mQuotaLock) {
616 setDataSaverModeEnabled(mDataSaverMode);
618 int size = mActiveQuotas.size();
620 if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules");
621 final HashMap<String, Long> activeQuotas = mActiveQuotas;
622 mActiveQuotas = Maps.newHashMap();
623 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
624 setInterfaceQuota(entry.getKey(), entry.getValue());
628 size = mActiveAlerts.size();
630 if (DBG) Slog.d(TAG, "Pushing " + size + " active alert rules");
631 final HashMap<String, Long> activeAlerts = mActiveAlerts;
632 mActiveAlerts = Maps.newHashMap();
633 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
634 setInterfaceAlert(entry.getKey(), entry.getValue());
638 size = mUidRejectOnMetered.size();
640 if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered whitelist rules");
641 final SparseBooleanArray uidRejectOnQuota = mUidRejectOnMetered;
642 mUidRejectOnMetered = new SparseBooleanArray();
643 for (int i = 0; i < uidRejectOnQuota.size(); i++) {
644 setUidMeteredNetworkBlacklist(uidRejectOnQuota.keyAt(i),
645 uidRejectOnQuota.valueAt(i));
649 size = mUidAllowOnMetered.size();
651 if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered blacklist rules");
652 final SparseBooleanArray uidAcceptOnQuota = mUidAllowOnMetered;
653 mUidAllowOnMetered = new SparseBooleanArray();
654 for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
655 setUidMeteredNetworkWhitelist(uidAcceptOnQuota.keyAt(i),
656 uidAcceptOnQuota.valueAt(i));
660 size = mUidCleartextPolicy.size();
662 if (DBG) Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
663 final SparseIntArray local = mUidCleartextPolicy;
664 mUidCleartextPolicy = new SparseIntArray();
665 for (int i = 0; i < local.size(); i++) {
666 setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i));
670 setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
672 syncFirewallChainLocked(FIREWALL_CHAIN_NONE, mUidFirewallRules, "");
673 syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, mUidFirewallStandbyRules, "standby ");
674 syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mUidFirewallDozableRules, "dozable ");
675 syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, mUidFirewallPowerSaveRules,
678 if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) {
679 setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
681 if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
682 setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
684 if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)) {
685 setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE, true);
691 * Notify our observers of a new or updated interface address.
693 private void notifyAddressUpdated(String iface, LinkAddress address) {
694 final int length = mObservers.beginBroadcast();
696 for (int i = 0; i < length; i++) {
698 mObservers.getBroadcastItem(i).addressUpdated(iface, address);
699 } catch (RemoteException | RuntimeException e) {
703 mObservers.finishBroadcast();
708 * Notify our observers of a deleted interface address.
710 private void notifyAddressRemoved(String iface, LinkAddress address) {
711 final int length = mObservers.beginBroadcast();
713 for (int i = 0; i < length; i++) {
715 mObservers.getBroadcastItem(i).addressRemoved(iface, address);
716 } catch (RemoteException | RuntimeException e) {
720 mObservers.finishBroadcast();
725 * Notify our observers of DNS server information received.
727 private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
728 final int length = mObservers.beginBroadcast();
730 for (int i = 0; i < length; i++) {
732 mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
734 } catch (RemoteException | RuntimeException e) {
738 mObservers.finishBroadcast();
743 * Notify our observers of a route change.
745 private void notifyRouteChange(String action, RouteInfo route) {
746 final int length = mObservers.beginBroadcast();
748 for (int i = 0; i < length; i++) {
750 if (action.equals("updated")) {
751 mObservers.getBroadcastItem(i).routeUpdated(route);
753 mObservers.getBroadcastItem(i).routeRemoved(route);
755 } catch (RemoteException | RuntimeException e) {
759 mObservers.finishBroadcast();
764 // Netd Callback handling
767 private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
769 public void onDaemonConnected() {
770 Slog.i(TAG, "onDaemonConnected()");
771 // event is dispatched from internal NDC thread, so we prepare the
772 // daemon back on main thread.
773 if (mConnectedSignal != null) {
774 // The system is booting and we're connecting to netd for the first time.
775 mConnectedSignal.countDown();
776 mConnectedSignal = null;
778 // We're reconnecting to netd after the socket connection
779 // was interrupted (e.g., if it crashed).
780 mFgHandler.post(new Runnable() {
783 connectNativeNetdService();
784 prepareNativeDaemon();
791 public boolean onCheckHoldWakeLock(int code) {
792 return code == NetdResponseCode.InterfaceClassActivity;
796 public boolean onEvent(int code, String raw, String[] cooked) {
797 String errorMessage = String.format("Invalid event from daemon (%s)", raw);
799 case NetdResponseCode.InterfaceChange:
801 * a network interface change occured
802 * Format: "NNN Iface added <name>"
803 * "NNN Iface removed <name>"
804 * "NNN Iface changed <name> <up/down>"
805 * "NNN Iface linkstatus <name> <up/down>"
807 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
808 throw new IllegalStateException(errorMessage);
810 if (cooked[2].equals("added")) {
811 notifyInterfaceAdded(cooked[3]);
813 } else if (cooked[2].equals("removed")) {
814 notifyInterfaceRemoved(cooked[3]);
816 } else if (cooked[2].equals("changed") && cooked.length == 5) {
817 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
819 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
820 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
823 throw new IllegalStateException(errorMessage);
825 case NetdResponseCode.BandwidthControl:
827 * Bandwidth control needs some attention
828 * Format: "NNN limit alert <alertName> <ifaceName>"
830 if (cooked.length < 5 || !cooked[1].equals("limit")) {
831 throw new IllegalStateException(errorMessage);
833 if (cooked[2].equals("alert")) {
834 notifyLimitReached(cooked[3], cooked[4]);
837 throw new IllegalStateException(errorMessage);
839 case NetdResponseCode.InterfaceClassActivity:
841 * An network interface class state changed (active/idle)
842 * Format: "NNN IfaceClass <active/idle> <label>"
844 if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
845 throw new IllegalStateException(errorMessage);
847 long timestampNanos = 0;
849 if (cooked.length >= 5) {
851 timestampNanos = Long.parseLong(cooked[4]);
852 if (cooked.length == 6) {
853 processUid = Integer.parseInt(cooked[5]);
855 } catch(NumberFormatException ne) {}
857 timestampNanos = SystemClock.elapsedRealtimeNanos();
859 boolean isActive = cooked[2].equals("active");
860 notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
861 isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
862 : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
863 timestampNanos, processUid, false);
866 case NetdResponseCode.InterfaceAddressChange:
868 * A network address change occurred
869 * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
870 * "NNN Address removed <addr> <iface> <flags> <scope>"
872 if (cooked.length < 7 || !cooked[1].equals("Address")) {
873 throw new IllegalStateException(errorMessage);
876 String iface = cooked[4];
879 int flags = Integer.parseInt(cooked[5]);
880 int scope = Integer.parseInt(cooked[6]);
881 address = new LinkAddress(cooked[3], flags, scope);
882 } catch(NumberFormatException e) { // Non-numeric lifetime or scope.
883 throw new IllegalStateException(errorMessage, e);
884 } catch(IllegalArgumentException e) { // Malformed/invalid IP address.
885 throw new IllegalStateException(errorMessage, e);
888 if (cooked[2].equals("updated")) {
889 notifyAddressUpdated(iface, address);
891 notifyAddressRemoved(iface, address);
895 case NetdResponseCode.InterfaceDnsServerInfo:
897 * Information about available DNS servers has been received.
898 * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
900 long lifetime; // Actually a 32-bit unsigned integer.
902 if (cooked.length == 6 &&
903 cooked[1].equals("DnsInfo") &&
904 cooked[2].equals("servers")) {
906 lifetime = Long.parseLong(cooked[4]);
907 } catch (NumberFormatException e) {
908 throw new IllegalStateException(errorMessage);
910 String[] servers = cooked[5].split(",");
911 notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
915 case NetdResponseCode.RouteChange:
917 * A route has been updated or removed.
918 * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
920 if (!cooked[1].equals("Route") || cooked.length < 6) {
921 throw new IllegalStateException(errorMessage);
926 boolean valid = true;
927 for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
928 if (cooked[i].equals("dev")) {
932 valid = false; // Duplicate interface.
934 } else if (cooked[i].equals("via")) {
938 valid = false; // Duplicate gateway.
941 valid = false; // Unknown syntax.
946 // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
947 InetAddress gateway = null;
948 if (via != null) gateway = InetAddress.parseNumericAddress(via);
949 RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
950 notifyRouteChange(cooked[2], route);
952 } catch (IllegalArgumentException e) {}
954 throw new IllegalStateException(errorMessage);
956 case NetdResponseCode.StrictCleartext:
957 final int uid = Integer.parseInt(cooked[1]);
958 final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]);
960 ActivityManagerNative.getDefault().notifyCleartextNetwork(uid, firstPacket);
961 } catch (RemoteException ignored) {
972 // INetworkManagementService members
976 public String[] listInterfaces() {
977 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
979 return NativeDaemonEvent.filterMessageList(
980 mConnector.executeForList("interface", "list"), InterfaceListResult);
981 } catch (NativeDaemonConnectorException e) {
982 throw e.rethrowAsParcelableException();
987 public InterfaceConfiguration getInterfaceConfig(String iface) {
988 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
990 final NativeDaemonEvent event;
992 event = mConnector.execute("interface", "getcfg", iface);
993 } catch (NativeDaemonConnectorException e) {
994 throw e.rethrowAsParcelableException();
997 event.checkCode(InterfaceGetCfgResult);
999 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
1000 final StringTokenizer st = new StringTokenizer(event.getMessage());
1002 InterfaceConfiguration cfg;
1004 cfg = new InterfaceConfiguration();
1005 cfg.setHardwareAddress(st.nextToken(" "));
1006 InetAddress addr = null;
1007 int prefixLength = 0;
1009 addr = NetworkUtils.numericToInetAddress(st.nextToken());
1010 } catch (IllegalArgumentException iae) {
1011 Slog.e(TAG, "Failed to parse ipaddr", iae);
1015 prefixLength = Integer.parseInt(st.nextToken());
1016 } catch (NumberFormatException nfe) {
1017 Slog.e(TAG, "Failed to parse prefixLength", nfe);
1020 cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
1021 while (st.hasMoreTokens()) {
1022 cfg.setFlag(st.nextToken());
1024 } catch (NoSuchElementException nsee) {
1025 throw new IllegalStateException("Invalid response from daemon: " + event);
1031 public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
1032 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1033 LinkAddress linkAddr = cfg.getLinkAddress();
1034 if (linkAddr == null || linkAddr.getAddress() == null) {
1035 throw new IllegalStateException("Null LinkAddress given");
1038 final Command cmd = new Command("interface", "setcfg", iface,
1039 linkAddr.getAddress().getHostAddress(),
1040 linkAddr.getPrefixLength());
1041 for (String flag : cfg.getFlags()) {
1042 cmd.appendArg(flag);
1046 mConnector.execute(cmd);
1047 } catch (NativeDaemonConnectorException e) {
1048 throw e.rethrowAsParcelableException();
1053 public void setInterfaceDown(String iface) {
1054 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1055 final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
1056 ifcg.setInterfaceDown();
1057 setInterfaceConfig(iface, ifcg);
1061 public void setInterfaceUp(String iface) {
1062 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1063 final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
1064 ifcg.setInterfaceUp();
1065 setInterfaceConfig(iface, ifcg);
1069 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
1070 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1073 "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
1074 } catch (NativeDaemonConnectorException e) {
1075 throw e.rethrowAsParcelableException();
1079 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
1080 IPv6 addresses on interface down, but we need to do full clean up here */
1082 public void clearInterfaceAddresses(String iface) {
1083 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1085 mConnector.execute("interface", "clearaddrs", iface);
1086 } catch (NativeDaemonConnectorException e) {
1087 throw e.rethrowAsParcelableException();
1092 public void enableIpv6(String iface) {
1093 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1095 mConnector.execute("interface", "ipv6", iface, "enable");
1096 } catch (NativeDaemonConnectorException e) {
1097 throw e.rethrowAsParcelableException();
1102 public void disableIpv6(String iface) {
1103 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1105 mConnector.execute("interface", "ipv6", iface, "disable");
1106 } catch (NativeDaemonConnectorException e) {
1107 throw e.rethrowAsParcelableException();
1112 public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
1113 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1116 "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
1117 } catch (NativeDaemonConnectorException e) {
1118 throw e.rethrowAsParcelableException();
1123 public void addRoute(int netId, RouteInfo route) {
1124 modifyRoute("add", "" + netId, route);
1128 public void removeRoute(int netId, RouteInfo route) {
1129 modifyRoute("remove", "" + netId, route);
1132 private void modifyRoute(String action, String netId, RouteInfo route) {
1133 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1135 final Command cmd = new Command("network", "route", action, netId);
1137 // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
1138 cmd.appendArg(route.getInterface());
1139 cmd.appendArg(route.getDestination().toString());
1141 switch (route.getType()) {
1142 case RouteInfo.RTN_UNICAST:
1143 if (route.hasGateway()) {
1144 cmd.appendArg(route.getGateway().getHostAddress());
1147 case RouteInfo.RTN_UNREACHABLE:
1148 cmd.appendArg("unreachable");
1150 case RouteInfo.RTN_THROW:
1151 cmd.appendArg("throw");
1156 mConnector.execute(cmd);
1157 } catch (NativeDaemonConnectorException e) {
1158 throw e.rethrowAsParcelableException();
1162 private ArrayList<String> readRouteList(String filename) {
1163 FileInputStream fstream = null;
1164 ArrayList<String> list = new ArrayList<String>();
1167 fstream = new FileInputStream(filename);
1168 DataInputStream in = new DataInputStream(fstream);
1169 BufferedReader br = new BufferedReader(new InputStreamReader(in));
1172 // throw away the title line
1174 while (((s = br.readLine()) != null) && (s.length() != 0)) {
1177 } catch (IOException ex) {
1178 // return current list, possibly empty
1180 if (fstream != null) {
1183 } catch (IOException ex) {}
1191 public void setMtu(String iface, int mtu) {
1192 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1194 final NativeDaemonEvent event;
1196 event = mConnector.execute("interface", "setmtu", iface, mtu);
1197 } catch (NativeDaemonConnectorException e) {
1198 throw e.rethrowAsParcelableException();
1203 public void shutdown() {
1204 // TODO: remove from aidl if nobody calls externally
1205 mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
1207 Slog.i(TAG, "Shutting down");
1211 public boolean getIpForwardingEnabled() throws IllegalStateException{
1212 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1214 final NativeDaemonEvent event;
1216 event = mConnector.execute("ipfwd", "status");
1217 } catch (NativeDaemonConnectorException e) {
1218 throw e.rethrowAsParcelableException();
1221 // 211 Forwarding enabled
1222 event.checkCode(IpFwdStatusResult);
1223 return event.getMessage().endsWith("enabled");
1227 public void setIpForwardingEnabled(boolean enable) {
1228 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1230 mConnector.execute("ipfwd", enable ? "enable" : "disable", "tethering");
1231 } catch (NativeDaemonConnectorException e) {
1232 throw e.rethrowAsParcelableException();
1237 public void startTethering(String[] dhcpRange) {
1238 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1239 // cmd is "tether start first_start first_stop second_start second_stop ..."
1240 // an odd number of addrs will fail
1242 final Command cmd = new Command("tether", "start");
1243 for (String d : dhcpRange) {
1248 mConnector.execute(cmd);
1249 } catch (NativeDaemonConnectorException e) {
1250 throw e.rethrowAsParcelableException();
1255 public void stopTethering() {
1256 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1258 mConnector.execute("tether", "stop");
1259 } catch (NativeDaemonConnectorException e) {
1260 throw e.rethrowAsParcelableException();
1265 public boolean isTetheringStarted() {
1266 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1268 final NativeDaemonEvent event;
1270 event = mConnector.execute("tether", "status");
1271 } catch (NativeDaemonConnectorException e) {
1272 throw e.rethrowAsParcelableException();
1275 // 210 Tethering services started
1276 event.checkCode(TetherStatusResult);
1277 return event.getMessage().endsWith("started");
1281 public void tetherInterface(String iface) {
1282 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1284 mConnector.execute("tether", "interface", "add", iface);
1285 } catch (NativeDaemonConnectorException e) {
1286 throw e.rethrowAsParcelableException();
1288 List<RouteInfo> routes = new ArrayList<RouteInfo>();
1289 // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
1290 // suitable to use as a route destination.
1291 routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
1292 addInterfaceToLocalNetwork(iface, routes);
1296 public void untetherInterface(String iface) {
1297 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1299 mConnector.execute("tether", "interface", "remove", iface);
1300 } catch (NativeDaemonConnectorException e) {
1301 throw e.rethrowAsParcelableException();
1303 removeInterfaceFromLocalNetwork(iface);
1307 public String[] listTetheredInterfaces() {
1308 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1310 return NativeDaemonEvent.filterMessageList(
1311 mConnector.executeForList("tether", "interface", "list"),
1312 TetherInterfaceListResult);
1313 } catch (NativeDaemonConnectorException e) {
1314 throw e.rethrowAsParcelableException();
1319 public void setDnsForwarders(Network network, String[] dns) {
1320 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1322 int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
1323 final Command cmd = new Command("tether", "dns", "set", netId);
1325 for (String s : dns) {
1326 cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1330 mConnector.execute(cmd);
1331 } catch (NativeDaemonConnectorException e) {
1332 throw e.rethrowAsParcelableException();
1337 public String[] getDnsForwarders() {
1338 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1340 return NativeDaemonEvent.filterMessageList(
1341 mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1342 } catch (NativeDaemonConnectorException e) {
1343 throw e.rethrowAsParcelableException();
1347 private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
1348 ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
1349 for (InterfaceAddress ia : addresses) {
1350 if (!ia.getAddress().isLinkLocalAddress())
1356 private void modifyInterfaceForward(boolean add, String fromIface, String toIface) {
1357 final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface);
1359 mConnector.execute(cmd);
1360 } catch (NativeDaemonConnectorException e) {
1361 throw e.rethrowAsParcelableException();
1366 public void startInterfaceForwarding(String fromIface, String toIface) {
1367 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1368 modifyInterfaceForward(true, fromIface, toIface);
1372 public void stopInterfaceForwarding(String fromIface, String toIface) {
1373 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1374 modifyInterfaceForward(false, fromIface, toIface);
1377 private void modifyNat(String action, String internalInterface, String externalInterface)
1378 throws SocketException {
1379 final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1381 final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1383 if (internalNetworkInterface == null) {
1386 // Don't touch link-local routes, as link-local addresses aren't routable,
1387 // kernel creates link-local routes on all interfaces automatically
1388 List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
1389 internalNetworkInterface.getInterfaceAddresses());
1390 cmd.appendArg(interfaceAddresses.size());
1391 for (InterfaceAddress ia : interfaceAddresses) {
1392 InetAddress addr = NetworkUtils.getNetworkPart(
1393 ia.getAddress(), ia.getNetworkPrefixLength());
1394 cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
1399 mConnector.execute(cmd);
1400 } catch (NativeDaemonConnectorException e) {
1401 throw e.rethrowAsParcelableException();
1406 public void enableNat(String internalInterface, String externalInterface) {
1407 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1409 modifyNat("enable", internalInterface, externalInterface);
1410 } catch (SocketException e) {
1411 throw new IllegalStateException(e);
1416 public void disableNat(String internalInterface, String externalInterface) {
1417 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1419 modifyNat("disable", internalInterface, externalInterface);
1420 } catch (SocketException e) {
1421 throw new IllegalStateException(e);
1426 public String[] listTtys() {
1427 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1429 return NativeDaemonEvent.filterMessageList(
1430 mConnector.executeForList("list_ttys"), TtyListResult);
1431 } catch (NativeDaemonConnectorException e) {
1432 throw e.rethrowAsParcelableException();
1437 public void attachPppd(
1438 String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1439 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1441 mConnector.execute("pppd", "attach", tty,
1442 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
1443 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
1444 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
1445 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
1446 } catch (NativeDaemonConnectorException e) {
1447 throw e.rethrowAsParcelableException();
1452 public void detachPppd(String tty) {
1453 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1455 mConnector.execute("pppd", "detach", tty);
1456 } catch (NativeDaemonConnectorException e) {
1457 throw e.rethrowAsParcelableException();
1462 * Private method used to call execute for a command given the provided arguments.
1464 * This function checks the returned NativeDaemonEvent for the provided expected response code
1465 * and message. If either of these is not correct, an error is logged.
1467 * @param String command The command to execute.
1468 * @param Object[] args If needed, arguments for the command to execute.
1469 * @param int expectedResponseCode The code expected to be returned in the corresponding event.
1470 * @param String expectedResponseMessage The message expected in the returned event.
1471 * @param String logMsg The message to log as an error (TAG will be applied).
1473 private void executeOrLogWithMessage(String command, Object[] args,
1474 int expectedResponseCode, String expectedResponseMessage, String logMsg)
1475 throws NativeDaemonConnectorException {
1476 NativeDaemonEvent event = mConnector.execute(command, args);
1477 if (event.getCode() != expectedResponseCode
1478 || !event.getMessage().equals(expectedResponseMessage)) {
1479 Log.e(TAG, logMsg + ": event = " + event);
1484 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1485 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1487 String logMsg = "startAccessPoint Error setting up softap";
1489 if (wifiConfig == null) {
1490 args = new Object[] {"set", wlanIface};
1492 args = new Object[] {"set", wlanIface, wifiConfig.SSID,
1493 "broadcast", Integer.toString(wifiConfig.apChannel),
1494 getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
1496 executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1497 SOFT_AP_COMMAND_SUCCESS, logMsg);
1499 logMsg = "startAccessPoint Error starting softap";
1500 args = new Object[] {"startap"};
1501 executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1502 SOFT_AP_COMMAND_SUCCESS, logMsg);
1503 } catch (NativeDaemonConnectorException e) {
1504 throw e.rethrowAsParcelableException();
1508 private static String getSecurityType(WifiConfiguration wifiConfig) {
1509 switch (wifiConfig.getAuthType()) {
1510 case KeyMgmt.WPA_PSK:
1512 case KeyMgmt.WPA2_PSK:
1519 /* @param mode can be "AP", "STA" or "P2P" */
1521 public void wifiFirmwareReload(String wlanIface, String mode) {
1522 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1523 Object[] args = {"fwreload", wlanIface, mode};
1524 String logMsg = "wifiFirmwareReload Error reloading "
1525 + wlanIface + " fw in " + mode + " mode";
1527 executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1528 SOFT_AP_COMMAND_SUCCESS, logMsg);
1529 } catch (NativeDaemonConnectorException e) {
1530 throw e.rethrowAsParcelableException();
1533 // Ensure that before we return from this command, any asynchronous
1534 // notifications generated before the command completed have been
1535 // processed by all NetworkManagementEventObservers.
1536 mConnector.waitForCallbacks();
1540 public void stopAccessPoint(String wlanIface) {
1541 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1542 Object[] args = {"stopap"};
1543 String logMsg = "stopAccessPoint Error stopping softap";
1546 executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1547 SOFT_AP_COMMAND_SUCCESS, logMsg);
1548 wifiFirmwareReload(wlanIface, "STA");
1549 } catch (NativeDaemonConnectorException e) {
1550 throw e.rethrowAsParcelableException();
1555 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1556 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1558 String logMsg = "startAccessPoint Error setting up softap";
1560 if (wifiConfig == null) {
1561 args = new Object[] {"set", wlanIface};
1563 // TODO: understand why this is set to "6" instead of
1564 // Integer.toString(wifiConfig.apChannel) as in startAccessPoint
1565 // TODO: should startAccessPoint call this instead of repeating code?
1566 args = new Object[] {"set", wlanIface, wifiConfig.SSID,
1568 getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
1570 executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1571 SOFT_AP_COMMAND_SUCCESS, logMsg);
1572 } catch (NativeDaemonConnectorException e) {
1573 throw e.rethrowAsParcelableException();
1578 public void addIdleTimer(String iface, int timeout, final int type) {
1579 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1581 if (DBG) Slog.d(TAG, "Adding idletimer");
1583 synchronized (mIdleTimerLock) {
1584 IdleTimerParams params = mActiveIdleTimers.get(iface);
1585 if (params != null) {
1586 // the interface already has idletimer, update network count
1587 params.networkCount++;
1592 mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1593 Integer.toString(type));
1594 } catch (NativeDaemonConnectorException e) {
1595 throw e.rethrowAsParcelableException();
1597 mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1599 // Networks start up.
1600 if (ConnectivityManager.isNetworkTypeMobile(type)) {
1601 mNetworkActive = false;
1603 mDaemonHandler.post(new Runnable() {
1604 @Override public void run() {
1605 notifyInterfaceClassActivity(type,
1606 DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
1607 SystemClock.elapsedRealtimeNanos(), -1, false);
1614 public void removeIdleTimer(String iface) {
1615 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1617 if (DBG) Slog.d(TAG, "Removing idletimer");
1619 synchronized (mIdleTimerLock) {
1620 final IdleTimerParams params = mActiveIdleTimers.get(iface);
1621 if (params == null || --(params.networkCount) > 0) {
1626 mConnector.execute("idletimer", "remove", iface,
1627 Integer.toString(params.timeout), Integer.toString(params.type));
1628 } catch (NativeDaemonConnectorException e) {
1629 throw e.rethrowAsParcelableException();
1631 mActiveIdleTimers.remove(iface);
1632 mDaemonHandler.post(new Runnable() {
1633 @Override public void run() {
1634 notifyInterfaceClassActivity(params.type,
1635 DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
1636 SystemClock.elapsedRealtimeNanos(), -1, false);
1643 public NetworkStats getNetworkStatsSummaryDev() {
1644 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1646 return mStatsFactory.readNetworkStatsSummaryDev();
1647 } catch (IOException e) {
1648 throw new IllegalStateException(e);
1653 public NetworkStats getNetworkStatsSummaryXt() {
1654 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1656 return mStatsFactory.readNetworkStatsSummaryXt();
1657 } catch (IOException e) {
1658 throw new IllegalStateException(e);
1663 public NetworkStats getNetworkStatsDetail() {
1664 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1666 return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1667 } catch (IOException e) {
1668 throw new IllegalStateException(e);
1673 public void setInterfaceQuota(String iface, long quotaBytes) {
1674 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1676 // silently discard when control disabled
1677 // TODO: eventually migrate to be always enabled
1678 if (!mBandwidthControlEnabled) return;
1680 synchronized (mQuotaLock) {
1681 if (mActiveQuotas.containsKey(iface)) {
1682 throw new IllegalStateException("iface " + iface + " already has quota");
1686 // TODO: support quota shared across interfaces
1687 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1688 mActiveQuotas.put(iface, quotaBytes);
1689 } catch (NativeDaemonConnectorException e) {
1690 throw e.rethrowAsParcelableException();
1696 public void removeInterfaceQuota(String iface) {
1697 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1699 // silently discard when control disabled
1700 // TODO: eventually migrate to be always enabled
1701 if (!mBandwidthControlEnabled) return;
1703 synchronized (mQuotaLock) {
1704 if (!mActiveQuotas.containsKey(iface)) {
1705 // TODO: eventually consider throwing
1709 mActiveQuotas.remove(iface);
1710 mActiveAlerts.remove(iface);
1713 // TODO: support quota shared across interfaces
1714 mConnector.execute("bandwidth", "removeiquota", iface);
1715 } catch (NativeDaemonConnectorException e) {
1716 throw e.rethrowAsParcelableException();
1722 public void setInterfaceAlert(String iface, long alertBytes) {
1723 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1725 // silently discard when control disabled
1726 // TODO: eventually migrate to be always enabled
1727 if (!mBandwidthControlEnabled) return;
1729 // quick sanity check
1730 if (!mActiveQuotas.containsKey(iface)) {
1731 throw new IllegalStateException("setting alert requires existing quota on iface");
1734 synchronized (mQuotaLock) {
1735 if (mActiveAlerts.containsKey(iface)) {
1736 throw new IllegalStateException("iface " + iface + " already has alert");
1740 // TODO: support alert shared across interfaces
1741 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1742 mActiveAlerts.put(iface, alertBytes);
1743 } catch (NativeDaemonConnectorException e) {
1744 throw e.rethrowAsParcelableException();
1750 public void removeInterfaceAlert(String iface) {
1751 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1753 // silently discard when control disabled
1754 // TODO: eventually migrate to be always enabled
1755 if (!mBandwidthControlEnabled) return;
1757 synchronized (mQuotaLock) {
1758 if (!mActiveAlerts.containsKey(iface)) {
1759 // TODO: eventually consider throwing
1764 // TODO: support alert shared across interfaces
1765 mConnector.execute("bandwidth", "removeinterfacealert", iface);
1766 mActiveAlerts.remove(iface);
1767 } catch (NativeDaemonConnectorException e) {
1768 throw e.rethrowAsParcelableException();
1774 public void setGlobalAlert(long alertBytes) {
1775 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1777 // silently discard when control disabled
1778 // TODO: eventually migrate to be always enabled
1779 if (!mBandwidthControlEnabled) return;
1782 mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1783 } catch (NativeDaemonConnectorException e) {
1784 throw e.rethrowAsParcelableException();
1788 private void setUidOnMeteredNetworkList(SparseBooleanArray quotaList, int uid,
1789 boolean blacklist, boolean enable) {
1790 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1792 // silently discard when control disabled
1793 // TODO: eventually migrate to be always enabled
1794 if (!mBandwidthControlEnabled) return;
1796 final String chain = blacklist ? "naughtyapps" : "niceapps";
1797 final String suffix = enable ? "add" : "remove";
1799 synchronized (mQuotaLock) {
1800 final boolean oldEnable = quotaList.get(uid, false);
1801 if (oldEnable == enable) {
1802 // TODO: eventually consider throwing
1807 mConnector.execute("bandwidth", suffix + chain, uid);
1809 quotaList.put(uid, true);
1811 quotaList.delete(uid);
1813 } catch (NativeDaemonConnectorException e) {
1814 throw e.rethrowAsParcelableException();
1820 public void setUidMeteredNetworkBlacklist(int uid, boolean enable) {
1821 setUidOnMeteredNetworkList(mUidRejectOnMetered, uid, true, enable);
1825 public void setUidMeteredNetworkWhitelist(int uid, boolean enable) {
1826 setUidOnMeteredNetworkList(mUidAllowOnMetered, uid, false, enable);
1830 public boolean setDataSaverModeEnabled(boolean enable) {
1831 if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
1832 synchronized (mQuotaLock) {
1833 if (mDataSaverMode == enable) {
1834 Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
1838 final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
1840 mDataSaverMode = enable;
1842 Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed");
1845 } catch (RemoteException e) {
1846 Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
1853 public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
1854 throws ServiceSpecificException {
1856 mNetdService.networkRejectNonSecureVpn(add, uidRanges);
1857 } catch (ServiceSpecificException e) {
1858 Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
1859 + ": netd command failed", e);
1861 } catch (RemoteException e) {
1862 Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
1863 + ": netd command failed", e);
1864 throw e.rethrowAsRuntimeException();
1869 public void setUidCleartextNetworkPolicy(int uid, int policy) {
1870 if (Binder.getCallingUid() != uid) {
1871 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1874 synchronized (mQuotaLock) {
1875 final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT);
1876 if (oldPolicy == policy) {
1880 if (!mStrictEnabled) {
1881 // Module isn't enabled yet; stash the requested policy away to
1882 // apply later once the daemon is connected.
1883 mUidCleartextPolicy.put(uid, policy);
1887 final String policyString;
1889 case StrictMode.NETWORK_POLICY_ACCEPT:
1890 policyString = "accept";
1892 case StrictMode.NETWORK_POLICY_LOG:
1893 policyString = "log";
1895 case StrictMode.NETWORK_POLICY_REJECT:
1896 policyString = "reject";
1899 throw new IllegalArgumentException("Unknown policy " + policy);
1903 mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString);
1904 mUidCleartextPolicy.put(uid, policy);
1905 } catch (NativeDaemonConnectorException e) {
1906 throw e.rethrowAsParcelableException();
1912 public boolean isBandwidthControlEnabled() {
1913 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1914 return mBandwidthControlEnabled;
1918 public NetworkStats getNetworkStatsUidDetail(int uid) {
1919 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1921 return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1922 } catch (IOException e) {
1923 throw new IllegalStateException(e);
1928 public NetworkStats getNetworkStatsTethering() {
1929 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1931 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1933 final NativeDaemonEvent[] events = mConnector.executeForList(
1934 "bandwidth", "gettetherstats");
1935 for (NativeDaemonEvent event : events) {
1936 if (event.getCode() != TetheringStatsListResult) continue;
1938 // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1939 final StringTokenizer tok = new StringTokenizer(event.getMessage());
1941 final String ifaceIn = tok.nextToken();
1942 final String ifaceOut = tok.nextToken();
1944 final NetworkStats.Entry entry = new NetworkStats.Entry();
1945 entry.iface = ifaceOut;
1946 entry.uid = UID_TETHERING;
1947 entry.set = SET_DEFAULT;
1948 entry.tag = TAG_NONE;
1949 entry.rxBytes = Long.parseLong(tok.nextToken());
1950 entry.rxPackets = Long.parseLong(tok.nextToken());
1951 entry.txBytes = Long.parseLong(tok.nextToken());
1952 entry.txPackets = Long.parseLong(tok.nextToken());
1953 stats.combineValues(entry);
1954 } catch (NoSuchElementException e) {
1955 throw new IllegalStateException("problem parsing tethering stats: " + event);
1956 } catch (NumberFormatException e) {
1957 throw new IllegalStateException("problem parsing tethering stats: " + event);
1960 } catch (NativeDaemonConnectorException e) {
1961 throw e.rethrowAsParcelableException();
1967 public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
1968 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1970 ContentResolver resolver = mContext.getContentResolver();
1972 int sampleValidity = Settings.Global.getInt(resolver,
1973 Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
1974 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
1975 if (sampleValidity < 0 || sampleValidity > 65535) {
1976 Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" +
1977 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
1978 sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
1981 int successThreshold = Settings.Global.getInt(resolver,
1982 Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
1983 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
1984 if (successThreshold < 0 || successThreshold > 100) {
1985 Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" +
1986 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
1987 successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
1990 int minSamples = Settings.Global.getInt(resolver,
1991 Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
1992 int maxSamples = Settings.Global.getInt(resolver,
1993 Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
1994 if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
1995 Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
1996 "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
1997 DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
1998 minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
1999 maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
2002 final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
2003 final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
2005 mNetdService.setResolverConfiguration(netId, servers, domainStrs, params);
2006 } catch (RemoteException e) {
2007 throw new RuntimeException(e);
2012 public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
2013 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2016 if (servers.length > 0) {
2017 cmd = new Command("resolver", "setnetdns", netId,
2018 (domains == null ? "" : domains));
2019 for (String s : servers) {
2020 InetAddress a = NetworkUtils.numericToInetAddress(s);
2021 if (a.isAnyLocalAddress() == false) {
2022 cmd.appendArg(a.getHostAddress());
2026 cmd = new Command("resolver", "clearnetdns", netId);
2030 mConnector.execute(cmd);
2031 } catch (NativeDaemonConnectorException e) {
2032 throw e.rethrowAsParcelableException();
2037 public void addVpnUidRanges(int netId, UidRange[] ranges) {
2038 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2039 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2044 // Avoid overly long commands by limiting number of UID ranges per command.
2045 for (int i = 0; i < ranges.length; i++) {
2046 argv[argc++] = ranges[i].toString();
2047 if (i == (ranges.length - 1) || argc == argv.length) {
2049 mConnector.execute("network", Arrays.copyOf(argv, argc));
2050 } catch (NativeDaemonConnectorException e) {
2051 throw e.rethrowAsParcelableException();
2059 public void removeVpnUidRanges(int netId, UidRange[] ranges) {
2060 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2061 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2066 // Avoid overly long commands by limiting number of UID ranges per command.
2067 for (int i = 0; i < ranges.length; i++) {
2068 argv[argc++] = ranges[i].toString();
2069 if (i == (ranges.length - 1) || argc == argv.length) {
2071 mConnector.execute("network", Arrays.copyOf(argv, argc));
2072 } catch (NativeDaemonConnectorException e) {
2073 throw e.rethrowAsParcelableException();
2081 public void setFirewallEnabled(boolean enabled) {
2084 mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist");
2085 mFirewallEnabled = enabled;
2086 } catch (NativeDaemonConnectorException e) {
2087 throw e.rethrowAsParcelableException();
2092 public boolean isFirewallEnabled() {
2094 return mFirewallEnabled;
2098 public void setFirewallInterfaceRule(String iface, boolean allow) {
2100 Preconditions.checkState(mFirewallEnabled);
2101 final String rule = allow ? "allow" : "deny";
2103 mConnector.execute("firewall", "set_interface_rule", iface, rule);
2104 } catch (NativeDaemonConnectorException e) {
2105 throw e.rethrowAsParcelableException();
2110 public void setFirewallEgressSourceRule(String addr, boolean allow) {
2112 Preconditions.checkState(mFirewallEnabled);
2113 final String rule = allow ? "allow" : "deny";
2115 mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
2116 } catch (NativeDaemonConnectorException e) {
2117 throw e.rethrowAsParcelableException();
2122 public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
2124 Preconditions.checkState(mFirewallEnabled);
2125 final String rule = allow ? "allow" : "deny";
2127 mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
2128 } catch (NativeDaemonConnectorException e) {
2129 throw e.rethrowAsParcelableException();
2133 private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
2134 // UID ranges to close sockets on.
2136 // UID ranges whose sockets we won't touch.
2139 final SparseIntArray rules = getUidFirewallRules(chain);
2142 if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
2143 // Close all sockets on all non-system UIDs...
2144 ranges = new UidRange[] {
2145 // TODO: is there a better way of finding all existing users? If so, we could
2146 // specify their ranges here.
2147 new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
2149 // ... except for the UIDs that have allow rules.
2150 exemptUids = new int[rules.size()];
2151 for (int i = 0; i < exemptUids.length; i++) {
2152 if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
2153 exemptUids[numUids] = rules.keyAt(i);
2157 // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length.
2158 // But the code does not guarantee this in any way, and at least in one case - if we add
2159 // a UID rule to the firewall, and then disable the firewall - the chains can contain
2160 // the wrong type of rule. In this case, don't close connections that we shouldn't.
2162 // TODO: tighten up this code by ensuring we never set the wrong type of rule, and
2163 // fix setFirewallEnabled to grab mQuotaLock and clear rules.
2164 if (numUids != exemptUids.length) {
2165 exemptUids = Arrays.copyOf(exemptUids, numUids);
2168 // Close sockets for every UID that has a deny rule...
2169 ranges = new UidRange[rules.size()];
2170 for (int i = 0; i < ranges.length; i++) {
2171 if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
2172 int uid = rules.keyAt(i);
2173 ranges[numUids] = new UidRange(uid, uid);
2177 // As above; usually numUids == ranges.length, but not always.
2178 if (numUids != ranges.length) {
2179 ranges = Arrays.copyOf(ranges, numUids);
2181 // ... with no exceptions.
2182 exemptUids = new int[0];
2186 mNetdService.socketDestroy(ranges, exemptUids);
2187 } catch(RemoteException | ServiceSpecificException e) {
2188 Slog.e(TAG, "Error closing sockets after enabling chain " + chainName + ": " + e);
2193 public void setFirewallChainEnabled(int chain, boolean enable) {
2195 synchronized (mQuotaLock) {
2196 if (mFirewallChainStates.get(chain) == enable) {
2197 // All is the same, nothing to do. This relies on the fact that netd has child
2198 // chains default detached.
2201 mFirewallChainStates.put(chain, enable);
2203 final String operation = enable ? "enable_chain" : "disable_chain";
2204 final String chainName;
2206 case FIREWALL_CHAIN_STANDBY:
2207 chainName = FIREWALL_CHAIN_NAME_STANDBY;
2209 case FIREWALL_CHAIN_DOZABLE:
2210 chainName = FIREWALL_CHAIN_NAME_DOZABLE;
2212 case FIREWALL_CHAIN_POWERSAVE:
2213 chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
2216 throw new IllegalArgumentException("Bad child chain: " + chain);
2220 mConnector.execute("firewall", operation, chainName);
2221 } catch (NativeDaemonConnectorException e) {
2222 throw e.rethrowAsParcelableException();
2225 // Close any sockets that were opened by the affected UIDs. This has to be done after
2226 // disabling network connectivity, in case they react to the socket close by reopening
2227 // the connection and race with the iptables commands that enable the firewall. All
2228 // whitelist and blacklist chains allow RSTs through.
2230 if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
2231 closeSocketsForFirewallChainLocked(chain, chainName);
2236 private int getFirewallType(int chain) {
2238 case FIREWALL_CHAIN_STANDBY:
2239 return FIREWALL_TYPE_BLACKLIST;
2240 case FIREWALL_CHAIN_DOZABLE:
2241 return FIREWALL_TYPE_WHITELIST;
2242 case FIREWALL_CHAIN_POWERSAVE:
2243 return FIREWALL_TYPE_WHITELIST;
2245 return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
2250 public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
2252 synchronized (mQuotaLock) {
2253 SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
2254 SparseIntArray newRules = new SparseIntArray();
2255 // apply new set of rules
2256 for (int index = uids.length - 1; index >= 0; --index) {
2257 int uid = uids[index];
2258 int rule = rules[index];
2259 updateFirewallUidRuleLocked(chain, uid, rule);
2260 newRules.put(uid, rule);
2262 // collect the rules to remove.
2263 SparseIntArray rulesToRemove = new SparseIntArray();
2264 for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
2265 int uid = uidFirewallRules.keyAt(index);
2266 if (newRules.indexOfKey(uid) < 0) {
2267 rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
2270 // remove dead rules
2271 for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
2272 int uid = rulesToRemove.keyAt(index);
2273 updateFirewallUidRuleLocked(chain, uid, FIREWALL_RULE_DEFAULT);
2277 case FIREWALL_CHAIN_DOZABLE:
2278 mNetdService.firewallReplaceUidChain("fw_dozable", true, uids);
2280 case FIREWALL_CHAIN_STANDBY:
2281 mNetdService.firewallReplaceUidChain("fw_standby", false, uids);
2283 case FIREWALL_CHAIN_POWERSAVE:
2284 mNetdService.firewallReplaceUidChain("fw_powersave", true, uids);
2286 case FIREWALL_CHAIN_NONE:
2288 Slog.d(TAG, "setFirewallUidRules() called on invalid chain: " + chain);
2290 } catch (RemoteException e) {
2291 Slog.w(TAG, "Error flushing firewall chain " + chain, e);
2297 public void setFirewallUidRule(int chain, int uid, int rule) {
2299 synchronized (mQuotaLock) {
2300 setFirewallUidRuleLocked(chain, uid, rule);
2304 private void setFirewallUidRuleLocked(int chain, int uid, int rule) {
2305 if (updateFirewallUidRuleLocked(chain, uid, rule)) {
2307 mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
2308 getFirewallRuleName(chain, rule));
2309 } catch (NativeDaemonConnectorException e) {
2310 throw e.rethrowAsParcelableException();
2315 // TODO: now that netd supports batching, NMS should not keep these data structures anymore...
2316 private boolean updateFirewallUidRuleLocked(int chain, int uid, int rule) {
2317 SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
2319 final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
2321 Slog.d(TAG, "oldRule = " + oldUidFirewallRule
2322 + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
2324 if (oldUidFirewallRule == rule) {
2325 if (DBG) Slog.d(TAG, "!!!!! Skipping change");
2326 // TODO: eventually consider throwing
2330 String ruleName = getFirewallRuleName(chain, rule);
2331 String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
2333 if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
2334 uidFirewallRules.delete(uid);
2336 uidFirewallRules.put(uid, rule);
2338 return !ruleName.equals(oldRuleName);
2341 private @NonNull String getFirewallRuleName(int chain, int rule) {
2343 if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
2344 if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
2349 } else { // Blacklist mode
2350 if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
2359 private @NonNull SparseIntArray getUidFirewallRules(int chain) {
2361 case FIREWALL_CHAIN_STANDBY:
2362 return mUidFirewallStandbyRules;
2363 case FIREWALL_CHAIN_DOZABLE:
2364 return mUidFirewallDozableRules;
2365 case FIREWALL_CHAIN_POWERSAVE:
2366 return mUidFirewallPowerSaveRules;
2367 case FIREWALL_CHAIN_NONE:
2368 return mUidFirewallRules;
2370 throw new IllegalArgumentException("Unknown chain:" + chain);
2374 public @NonNull String getFirewallChainName(int chain) {
2376 case FIREWALL_CHAIN_STANDBY:
2377 return FIREWALL_CHAIN_NAME_STANDBY;
2378 case FIREWALL_CHAIN_DOZABLE:
2379 return FIREWALL_CHAIN_NAME_DOZABLE;
2380 case FIREWALL_CHAIN_POWERSAVE:
2381 return FIREWALL_CHAIN_NAME_POWERSAVE;
2382 case FIREWALL_CHAIN_NONE:
2383 return FIREWALL_CHAIN_NAME_NONE;
2385 throw new IllegalArgumentException("Unknown chain:" + chain);
2389 private static void enforceSystemUid() {
2390 final int uid = Binder.getCallingUid();
2391 if (uid != Process.SYSTEM_UID) {
2392 throw new SecurityException("Only available to AID_SYSTEM");
2397 public void startClatd(String interfaceName) throws IllegalStateException {
2398 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2401 mConnector.execute("clatd", "start", interfaceName);
2402 } catch (NativeDaemonConnectorException e) {
2403 throw e.rethrowAsParcelableException();
2408 public void stopClatd(String interfaceName) throws IllegalStateException {
2409 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2412 mConnector.execute("clatd", "stop", interfaceName);
2413 } catch (NativeDaemonConnectorException e) {
2414 throw e.rethrowAsParcelableException();
2419 public boolean isClatdStarted(String interfaceName) {
2420 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2422 final NativeDaemonEvent event;
2424 event = mConnector.execute("clatd", "status", interfaceName);
2425 } catch (NativeDaemonConnectorException e) {
2426 throw e.rethrowAsParcelableException();
2429 event.checkCode(ClatdStatusResult);
2430 return event.getMessage().endsWith("started");
2434 public void registerNetworkActivityListener(INetworkActivityListener listener) {
2435 mNetworkActivityListeners.register(listener);
2439 public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
2440 mNetworkActivityListeners.unregister(listener);
2444 public boolean isNetworkActive() {
2445 synchronized (mNetworkActivityListeners) {
2446 return mNetworkActive || mActiveIdleTimers.isEmpty();
2450 private void reportNetworkActive() {
2451 final int length = mNetworkActivityListeners.beginBroadcast();
2453 for (int i = 0; i < length; i++) {
2455 mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
2456 } catch (RemoteException | RuntimeException e) {
2460 mNetworkActivityListeners.finishBroadcast();
2464 /** {@inheritDoc} */
2466 public void monitor() {
2467 if (mConnector != null) {
2468 mConnector.monitor();
2473 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2474 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
2476 pw.println("NetworkManagementService NativeDaemonConnector Log:");
2477 mConnector.dump(fd, pw, args);
2480 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
2481 pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
2482 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
2483 pw.print("mNetworkActive="); pw.println(mNetworkActive);
2485 synchronized (mQuotaLock) {
2486 pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
2487 pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
2488 pw.print("Data saver mode: "); pw.println(mDataSaverMode);
2489 dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered);
2490 dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered);
2493 synchronized (mUidFirewallRules) {
2494 dumpUidFirewallRule(pw, "", mUidFirewallRules);
2497 pw.print("UID firewall standby chain enabled: "); pw.println(
2498 mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
2499 synchronized (mUidFirewallStandbyRules) {
2500 dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
2503 pw.print("UID firewall dozable chain enabled: "); pw.println(
2504 mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
2505 synchronized (mUidFirewallDozableRules) {
2506 dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
2509 pw.println("UID firewall powersave chain enabled: " +
2510 mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
2511 synchronized (mUidFirewallPowerSaveRules) {
2512 dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
2515 synchronized (mIdleTimerLock) {
2516 pw.println("Idle timers:");
2517 for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
2518 pw.print(" "); pw.print(ent.getKey()); pw.println(":");
2519 IdleTimerParams params = ent.getValue();
2520 pw.print(" timeout="); pw.print(params.timeout);
2521 pw.print(" type="); pw.print(params.type);
2522 pw.print(" networkCount="); pw.println(params.networkCount);
2526 pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
2527 pw.print("Netd service status: " );
2528 if (mNetdService == null) {
2529 pw.println("disconnected");
2532 final boolean alive = mNetdService.isAlive();
2533 pw.println(alive ? "alive": "dead");
2534 } catch (RemoteException e) {
2535 pw.println("unreachable");
2540 private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) {
2541 pw.print("UID bandwith control ");
2543 pw.print(" rule: [");
2544 final int size = list.size();
2545 for (int i = 0; i < size; i++) {
2546 pw.print(list.keyAt(i));
2547 if (i < size - 1) pw.print(",");
2552 private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
2553 pw.print("UID firewall ");
2555 pw.print(" rule: [");
2556 final int size = rules.size();
2557 for (int i = 0; i < size; i++) {
2558 pw.print(rules.keyAt(i));
2560 pw.print(rules.valueAt(i));
2561 if (i < size - 1) pw.print(",");
2567 public void createPhysicalNetwork(int netId, String permission) {
2568 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2571 if (permission != null) {
2572 mConnector.execute("network", "create", netId, permission);
2574 mConnector.execute("network", "create", netId);
2576 } catch (NativeDaemonConnectorException e) {
2577 throw e.rethrowAsParcelableException();
2582 public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
2583 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2586 mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
2587 secure ? "1" : "0");
2588 } catch (NativeDaemonConnectorException e) {
2589 throw e.rethrowAsParcelableException();
2594 public void removeNetwork(int netId) {
2595 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2598 mConnector.execute("network", "destroy", netId);
2599 } catch (NativeDaemonConnectorException e) {
2600 throw e.rethrowAsParcelableException();
2605 public void addInterfaceToNetwork(String iface, int netId) {
2606 modifyInterfaceInNetwork("add", "" + netId, iface);
2610 public void removeInterfaceFromNetwork(String iface, int netId) {
2611 modifyInterfaceInNetwork("remove", "" + netId, iface);
2614 private void modifyInterfaceInNetwork(String action, String netId, String iface) {
2615 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2617 mConnector.execute("network", "interface", action, netId, iface);
2618 } catch (NativeDaemonConnectorException e) {
2619 throw e.rethrowAsParcelableException();
2624 public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
2625 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2627 final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
2629 // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
2630 final LinkAddress la = routeInfo.getDestinationLinkAddress();
2631 cmd.appendArg(routeInfo.getInterface());
2632 cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
2633 if (routeInfo.hasGateway()) {
2634 cmd.appendArg(routeInfo.getGateway().getHostAddress());
2638 mConnector.execute(cmd);
2639 } catch (NativeDaemonConnectorException e) {
2640 throw e.rethrowAsParcelableException();
2645 public void setDefaultNetId(int netId) {
2646 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2649 mConnector.execute("network", "default", "set", netId);
2650 } catch (NativeDaemonConnectorException e) {
2651 throw e.rethrowAsParcelableException();
2656 public void clearDefaultNetId() {
2657 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2660 mConnector.execute("network", "default", "clear");
2661 } catch (NativeDaemonConnectorException e) {
2662 throw e.rethrowAsParcelableException();
2667 public void setNetworkPermission(int netId, String permission) {
2668 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2671 if (permission != null) {
2672 mConnector.execute("network", "permission", "network", "set", permission, netId);
2674 mConnector.execute("network", "permission", "network", "clear", netId);
2676 } catch (NativeDaemonConnectorException e) {
2677 throw e.rethrowAsParcelableException();
2683 public void setPermission(String permission, int[] uids) {
2684 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2686 Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
2687 argv[0] = "permission";
2690 argv[3] = permission;
2692 // Avoid overly long commands by limiting number of UIDs per command.
2693 for (int i = 0; i < uids.length; ++i) {
2694 argv[argc++] = uids[i];
2695 if (i == uids.length - 1 || argc == argv.length) {
2697 mConnector.execute("network", Arrays.copyOf(argv, argc));
2698 } catch (NativeDaemonConnectorException e) {
2699 throw e.rethrowAsParcelableException();
2707 public void clearPermission(int[] uids) {
2708 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2710 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2711 argv[0] = "permission";
2715 // Avoid overly long commands by limiting number of UIDs per command.
2716 for (int i = 0; i < uids.length; ++i) {
2717 argv[argc++] = uids[i];
2718 if (i == uids.length - 1 || argc == argv.length) {
2720 mConnector.execute("network", Arrays.copyOf(argv, argc));
2721 } catch (NativeDaemonConnectorException e) {
2722 throw e.rethrowAsParcelableException();
2730 public void allowProtect(int uid) {
2731 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2734 mConnector.execute("network", "protect", "allow", uid);
2735 } catch (NativeDaemonConnectorException e) {
2736 throw e.rethrowAsParcelableException();
2741 public void denyProtect(int uid) {
2742 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2745 mConnector.execute("network", "protect", "deny", uid);
2746 } catch (NativeDaemonConnectorException e) {
2747 throw e.rethrowAsParcelableException();
2752 public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
2753 modifyInterfaceInNetwork("add", "local", iface);
2755 for (RouteInfo route : routes) {
2756 if (!route.isDefaultRoute()) {
2757 modifyRoute("add", "local", route);
2763 public void removeInterfaceFromLocalNetwork(String iface) {
2764 modifyInterfaceInNetwork("remove", "local", iface);