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.net;
18 
19 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
20 import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
21 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
22 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
23 import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_ALLOW;
24 import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
25 import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
26 import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
27 import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
28 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
29 import static android.net.INetd.FIREWALL_ALLOWLIST;
30 import static android.net.INetd.FIREWALL_CHAIN_NONE;
31 import static android.net.INetd.FIREWALL_DENYLIST;
32 import static android.net.INetd.FIREWALL_RULE_ALLOW;
33 import static android.net.INetd.FIREWALL_RULE_DENY;
34 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_BACKGROUND;
35 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
36 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY;
37 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_ALLOW;
38 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN;
39 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_METERED_DENY_USER;
40 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
41 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
42 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
43 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
44 
45 import android.annotation.NonNull;
46 import android.app.ActivityManager;
47 import android.content.Context;
48 import android.net.ConnectivityManager;
49 import android.net.INetd;
50 import android.net.INetdUnsolicitedEventListener;
51 import android.net.INetworkManagementEventObserver;
52 import android.net.InetAddresses;
53 import android.net.InterfaceConfiguration;
54 import android.net.InterfaceConfigurationParcel;
55 import android.net.IpPrefix;
56 import android.net.LinkAddress;
57 import android.net.NetworkPolicyManager;
58 import android.net.RouteInfo;
59 import android.net.util.NetdService;
60 import android.os.BatteryStats;
61 import android.os.Binder;
62 import android.os.Handler;
63 import android.os.IBinder;
64 import android.os.INetworkManagementService;
65 import android.os.PermissionEnforcer;
66 import android.os.Process;
67 import android.os.RemoteCallbackList;
68 import android.os.RemoteException;
69 import android.os.ServiceManager;
70 import android.os.ServiceSpecificException;
71 import android.os.StrictMode;
72 import android.os.SystemClock;
73 import android.os.Trace;
74 import android.text.TextUtils;
75 import android.util.Log;
76 import android.util.Slog;
77 import android.util.SparseBooleanArray;
78 import android.util.SparseIntArray;
79 
80 import com.android.internal.annotations.GuardedBy;
81 import com.android.internal.app.IBatteryStats;
82 import com.android.internal.util.DumpUtils;
83 import com.android.internal.util.HexDump;
84 import com.android.modules.utils.build.SdkLevel;
85 import com.android.net.module.util.NetdUtils;
86 import com.android.net.module.util.PermissionUtils;
87 import com.android.server.FgThread;
88 import com.android.server.LocalServices;
89 
90 import com.google.android.collect.Maps;
91 
92 import java.io.FileDescriptor;
93 import java.io.PrintWriter;
94 import java.net.InetAddress;
95 import java.util.ArrayList;
96 import java.util.HashMap;
97 import java.util.Map;
98 
99 /**
100  * @hide
101  */
102 public class NetworkManagementService extends INetworkManagementService.Stub {
103 
104     /**
105      * Helper class that encapsulates NetworkManagementService dependencies and makes them
106      * easier to mock in unit tests.
107      */
108     static class Dependencies {
getService(String name)109         public IBinder getService(String name) {
110             return ServiceManager.getService(name);
111         }
registerLocalService(NetworkManagementInternal nmi)112         public void registerLocalService(NetworkManagementInternal nmi) {
113             LocalServices.addService(NetworkManagementInternal.class, nmi);
114         }
getNetd()115         public INetd getNetd() {
116             return NetdService.get();
117         }
118 
getCallingUid()119         public int getCallingUid() {
120             return Binder.getCallingUid();
121         }
122     }
123 
124     private static final String TAG = "NetworkManagement";
125     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
126 
127     /**
128      * Binder context for this service
129      */
130     private final Context mContext;
131 
132     private final Handler mDaemonHandler;
133 
134     private final Dependencies mDeps;
135 
136     private INetd mNetdService;
137 
138     private final NetdUnsolicitedEventListener mNetdUnsolicitedEventListener;
139 
140     private IBatteryStats mBatteryStats;
141 
142     private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
143             new RemoteCallbackList<>();
144 
145     /**
146      * If both locks need to be held, then they should be obtained in the order:
147      * first {@link #mQuotaLock} and then {@link #mRulesLock}.
148      */
149     private final Object mQuotaLock = new Object();
150     private final Object mRulesLock = new Object();
151 
152     private final boolean mUseMeteredFirewallChains;
153 
154     /** Set of interfaces with active quotas. */
155     @GuardedBy("mQuotaLock")
156     private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
157     /** Set of interfaces with active alerts. */
158     @GuardedBy("mQuotaLock")
159     private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
160     /** Set of UIDs denied on metered networks. */
161     // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
162     @GuardedBy("mRulesLock")
163     private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray();
164     /** Set of UIDs allowed on metered networks. */
165     // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
166     @GuardedBy("mRulesLock")
167     private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
168     /** Set of UIDs with cleartext penalties. */
169     @GuardedBy("mQuotaLock")
170     private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
171     /** Set of UIDs that are to be blocked/allowed by firewall controller. */
172     @GuardedBy("mRulesLock")
173     private final SparseIntArray mUidFirewallRules = new SparseIntArray();
174     /**
175      * Set of UIDs that are to be blocked/allowed by firewall controller.  This set of Ids matches
176      * to application idles.
177      */
178     @GuardedBy("mRulesLock")
179     private final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
180     /**
181      * Set of UIDs that are to be blocked/allowed by firewall controller.  This set of Ids matches
182      * to device idles.
183      */
184     @GuardedBy("mRulesLock")
185     private final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
186     /**
187      * Set of UIDs that are to be blocked/allowed by firewall controller.  This set of Ids matches
188      * to device on power-save mode.
189      */
190     @GuardedBy("mRulesLock")
191     private final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
192     /**
193      * Contains the per-UID firewall rules that are used when Restricted Networking Mode is enabled.
194      */
195     @GuardedBy("mRulesLock")
196     private final SparseIntArray mUidFirewallRestrictedRules = new SparseIntArray();
197     /**
198      * Contains the per-UID firewall rules that are used when Low Power Standby is enabled.
199      */
200     @GuardedBy("mRulesLock")
201     private final SparseIntArray mUidFirewallLowPowerStandbyRules = new SparseIntArray();
202 
203     /**
204      * Contains the per-UID firewall rules that are used when Background chain is enabled.
205      */
206     @GuardedBy("mRulesLock")
207     private final SparseIntArray mUidFirewallBackgroundRules = new SparseIntArray();
208 
209     /**
210      * Contains the per-UID firewall rules that are used to allowlist the app from metered-network
211      * restrictions when data saver is enabled.
212      */
213     @GuardedBy("mRulesLock")
214     private final SparseIntArray mUidMeteredFirewallAllowRules = new SparseIntArray();
215 
216     /**
217      * Contains the per-UID firewall rules that are used to deny app access to metered networks
218      * due to user action.
219      */
220     @GuardedBy("mRulesLock")
221     private final SparseIntArray mUidMeteredFirewallDenyUserRules = new SparseIntArray();
222 
223     /**
224      * Contains the per-UID firewall rules that are used to deny app access to metered networks
225      * due to admin action.
226      */
227     @GuardedBy("mRulesLock")
228     private final SparseIntArray mUidMeteredFirewallDenyAdminRules = new SparseIntArray();
229 
230     /** Set of states for the child firewall chains. True if the chain is active. */
231     @GuardedBy("mRulesLock")
232     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
233 
234     // TODO: b/336693007 - Remove once NPMS has completely migrated to metered firewall chains.
235     @GuardedBy("mQuotaLock")
236     private volatile boolean mDataSaverMode;
237 
238     private volatile boolean mFirewallEnabled;
239     private volatile boolean mStrictEnabled;
240 
241     /**
242      * Constructs a new NetworkManagementService instance
243      *
244      * @param context  Binder context for this service
245      */
NetworkManagementService( Context context, Dependencies deps)246     private NetworkManagementService(
247             Context context, Dependencies deps) {
248         super(PermissionEnforcer.fromContext(context));
249         mContext = context;
250         mDeps = deps;
251 
252         mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
253 
254         if (mUseMeteredFirewallChains) {
255             // These firewalls are always on and currently ConnectivityService does not allow
256             // changing their enabled state.
257             mFirewallChainStates.put(FIREWALL_CHAIN_METERED_DENY_USER, true);
258             mFirewallChainStates.put(FIREWALL_CHAIN_METERED_DENY_ADMIN, true);
259         }
260 
261         mDaemonHandler = new Handler(FgThread.get().getLooper());
262 
263         mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
264 
265         mDeps.registerLocalService(new LocalService());
266     }
267 
create(Context context, Dependencies deps)268     static NetworkManagementService create(Context context, Dependencies deps)
269             throws InterruptedException {
270         final NetworkManagementService service =
271                 new NetworkManagementService(context, deps);
272         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
273         if (DBG) Slog.d(TAG, "Connecting native netd service");
274         service.connectNativeNetdService();
275         if (DBG) Slog.d(TAG, "Connected");
276         return service;
277     }
278 
create(Context context)279     public static NetworkManagementService create(Context context) throws InterruptedException {
280         return create(context, new Dependencies());
281     }
282 
systemReady()283     public void systemReady() {
284         if (DBG) {
285             final long start = System.currentTimeMillis();
286             prepareNativeDaemon();
287             final long delta = System.currentTimeMillis() - start;
288             Slog.d(TAG, "Prepared in " + delta + "ms");
289             return;
290         } else {
291             prepareNativeDaemon();
292         }
293     }
294 
getBatteryStats()295     private IBatteryStats getBatteryStats() {
296         synchronized (this) {
297             if (mBatteryStats != null) {
298                 return mBatteryStats;
299             }
300             mBatteryStats =
301                     IBatteryStats.Stub.asInterface(mDeps.getService(BatteryStats.SERVICE_NAME));
302             return mBatteryStats;
303         }
304     }
305 
306     @Override
registerObserver(INetworkManagementEventObserver observer)307     public void registerObserver(INetworkManagementEventObserver observer) {
308         PermissionUtils.enforceNetworkStackPermission(mContext);
309         mObservers.register(observer);
310     }
311 
312     @Override
unregisterObserver(INetworkManagementEventObserver observer)313     public void unregisterObserver(INetworkManagementEventObserver observer) {
314         PermissionUtils.enforceNetworkStackPermission(mContext);
315         mObservers.unregister(observer);
316     }
317 
318     @FunctionalInterface
319     private interface NetworkManagementEventCallback {
sendCallback(INetworkManagementEventObserver o)320         void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
321     }
322 
invokeForAllObservers(NetworkManagementEventCallback eventCallback)323     private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
324         final int length = mObservers.beginBroadcast();
325         try {
326             for (int i = 0; i < length; i++) {
327                 try {
328                     eventCallback.sendCallback(mObservers.getBroadcastItem(i));
329                 } catch (RemoteException | RuntimeException e) {
330                 }
331             }
332         } finally {
333             mObservers.finishBroadcast();
334         }
335     }
336 
337     /**
338      * Notify our observers of an interface status change
339      */
notifyInterfaceStatusChanged(String iface, boolean up)340     private void notifyInterfaceStatusChanged(String iface, boolean up) {
341         invokeForAllObservers(o -> o.interfaceStatusChanged(iface, up));
342     }
343 
344     /**
345      * Notify our observers of an interface link state change
346      * (typically, an Ethernet cable has been plugged-in or unplugged).
347      */
notifyInterfaceLinkStateChanged(String iface, boolean up)348     private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
349         invokeForAllObservers(o -> o.interfaceLinkStateChanged(iface, up));
350     }
351 
352     /**
353      * Notify our observers of an interface addition.
354      */
notifyInterfaceAdded(String iface)355     private void notifyInterfaceAdded(String iface) {
356         invokeForAllObservers(o -> o.interfaceAdded(iface));
357     }
358 
359     /**
360      * Notify our observers of an interface removal.
361      */
notifyInterfaceRemoved(String iface)362     private void notifyInterfaceRemoved(String iface) {
363         // netd already clears out quota and alerts for removed ifaces; update
364         // our validity-checking state.
365         mActiveAlerts.remove(iface);
366         mActiveQuotas.remove(iface);
367         invokeForAllObservers(o -> o.interfaceRemoved(iface));
368     }
369 
370     /**
371      * Notify our observers of a limit reached.
372      */
notifyLimitReached(String limitName, String iface)373     private void notifyLimitReached(String limitName, String iface) {
374         invokeForAllObservers(o -> o.limitReached(limitName, iface));
375     }
376 
377     /**
378      * Notify our observers of a change in the data activity state of the interface
379      */
notifyInterfaceClassActivity(int label, boolean isActive, long tsNanos, int uid)380     private void notifyInterfaceClassActivity(int label, boolean isActive, long tsNanos,
381             int uid) {
382         invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
383                 label, isActive, tsNanos, uid));
384     }
385 
386     // Sync the state of the given chain with the native daemon.
syncFirewallChainLocked(int chain, String name)387     private void syncFirewallChainLocked(int chain, String name) {
388         SparseIntArray rules;
389         synchronized (mRulesLock) {
390             final SparseIntArray uidFirewallRules = getUidFirewallRulesLR(chain);
391             // Make a copy of the current rules, and then clear them. This is because
392             // setFirewallUidRuleInternal only pushes down rules to the native daemon if they
393             // are different from the current rules stored in the mUidFirewall*Rules array for
394             // the specified chain. If we don't clear the rules, setFirewallUidRuleInternal
395             // will do nothing.
396             rules = uidFirewallRules.clone();
397             uidFirewallRules.clear();
398         }
399         if (rules.size() > 0) {
400             // Now push the rules. setFirewallUidRuleInternal will push each of these down to the
401             // native daemon, and also add them to the mUidFirewall*Rules array for the specified
402             // chain.
403             if (DBG) Slog.d(TAG, "Pushing " + rules.size() + " active firewall "
404                     + name + "UID rules");
405             for (int i = 0; i < rules.size(); i++) {
406                 setFirewallUidRuleLocked(chain, rules.keyAt(i), rules.valueAt(i));
407             }
408         }
409     }
410 
connectNativeNetdService()411     private void connectNativeNetdService() {
412         mNetdService = mDeps.getNetd();
413         try {
414             mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
415             if (DBG) Slog.d(TAG, "Register unsolicited event listener");
416         } catch (RemoteException | ServiceSpecificException e) {
417             Slog.e(TAG, "Failed to set Netd unsolicited event listener " + e);
418         }
419     }
420 
421     /**
422      * Prepare native daemon once connected, enabling modules and pushing any
423      * existing in-memory rules.
424      */
prepareNativeDaemon()425     private void prepareNativeDaemon() {
426 
427         // push any existing quota or UID rules
428         synchronized (mQuotaLock) {
429 
430             mStrictEnabled = true;
431 
432             setDataSaverModeEnabled(mDataSaverMode);
433 
434             int size = mActiveQuotas.size();
435             if (size > 0) {
436                 if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules");
437                 final HashMap<String, Long> activeQuotas = mActiveQuotas;
438                 mActiveQuotas = Maps.newHashMap();
439                 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
440                     setInterfaceQuota(entry.getKey(), entry.getValue());
441                 }
442             }
443 
444             size = mActiveAlerts.size();
445             if (size > 0) {
446                 if (DBG) Slog.d(TAG, "Pushing " + size + " active alert rules");
447                 final HashMap<String, Long> activeAlerts = mActiveAlerts;
448                 mActiveAlerts = Maps.newHashMap();
449                 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
450                     setInterfaceAlert(entry.getKey(), entry.getValue());
451                 }
452             }
453 
454             if (!mUseMeteredFirewallChains) {
455                 SparseBooleanArray uidRejectOnQuota = null;
456                 SparseBooleanArray uidAcceptOnQuota = null;
457                 synchronized (mRulesLock) {
458                     size = mUidRejectOnMetered.size();
459                     if (size > 0) {
460                         if (DBG) {
461                             Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules");
462                         }
463                         uidRejectOnQuota = mUidRejectOnMetered;
464                         mUidRejectOnMetered = new SparseBooleanArray();
465                     }
466 
467                     size = mUidAllowOnMetered.size();
468                     if (size > 0) {
469                         if (DBG) {
470                             Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules");
471                         }
472                         uidAcceptOnQuota = mUidAllowOnMetered;
473                         mUidAllowOnMetered = new SparseBooleanArray();
474                     }
475                 }
476                 if (uidRejectOnQuota != null) {
477                     for (int i = 0; i < uidRejectOnQuota.size(); i++) {
478                         setUidOnMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i),
479                                 uidRejectOnQuota.valueAt(i));
480                     }
481                 }
482                 if (uidAcceptOnQuota != null) {
483                     for (int i = 0; i < uidAcceptOnQuota.size(); i++) {
484                         setUidOnMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i),
485                                 uidAcceptOnQuota.valueAt(i));
486                     }
487                 }
488             }
489 
490             size = mUidCleartextPolicy.size();
491             if (size > 0) {
492                 if (DBG) Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
493                 final SparseIntArray local = mUidCleartextPolicy;
494                 mUidCleartextPolicy = new SparseIntArray();
495                 for (int i = 0; i < local.size(); i++) {
496                     setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i));
497                 }
498             }
499 
500             setFirewallEnabled(mFirewallEnabled);
501 
502             syncFirewallChainLocked(FIREWALL_CHAIN_NONE, "");
503             syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, "standby ");
504             syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, "dozable ");
505             syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, "powersave ");
506             syncFirewallChainLocked(FIREWALL_CHAIN_RESTRICTED, "restricted ");
507             syncFirewallChainLocked(FIREWALL_CHAIN_LOW_POWER_STANDBY, "low power standby ");
508             syncFirewallChainLocked(FIREWALL_CHAIN_BACKGROUND, FIREWALL_CHAIN_NAME_BACKGROUND);
509             if (mUseMeteredFirewallChains) {
510                 syncFirewallChainLocked(FIREWALL_CHAIN_METERED_ALLOW,
511                         FIREWALL_CHAIN_NAME_METERED_ALLOW);
512                 syncFirewallChainLocked(FIREWALL_CHAIN_METERED_DENY_USER,
513                         FIREWALL_CHAIN_NAME_METERED_DENY_USER);
514                 syncFirewallChainLocked(FIREWALL_CHAIN_METERED_DENY_ADMIN,
515                         FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN);
516             }
517 
518             final int[] chainsToEnable = {
519                     FIREWALL_CHAIN_STANDBY,
520                     FIREWALL_CHAIN_DOZABLE,
521                     FIREWALL_CHAIN_POWERSAVE,
522                     FIREWALL_CHAIN_RESTRICTED,
523                     FIREWALL_CHAIN_LOW_POWER_STANDBY,
524                     FIREWALL_CHAIN_BACKGROUND,
525             };
526 
527             for (int chain : chainsToEnable) {
528                 if (getFirewallChainState(chain)) {
529                     setFirewallChainEnabled(chain, true);
530                 }
531             }
532         }
533 
534         try {
535             getBatteryStats().noteNetworkStatsEnabled();
536         } catch (RemoteException e) {
537         }
538 
539     }
540 
541     /**
542      * Notify our observers of a new or updated interface address.
543      */
notifyAddressUpdated(String iface, LinkAddress address)544     private void notifyAddressUpdated(String iface, LinkAddress address) {
545         invokeForAllObservers(o -> o.addressUpdated(iface, address));
546     }
547 
548     /**
549      * Notify our observers of a deleted interface address.
550      */
notifyAddressRemoved(String iface, LinkAddress address)551     private void notifyAddressRemoved(String iface, LinkAddress address) {
552         invokeForAllObservers(o -> o.addressRemoved(iface, address));
553     }
554 
555     /**
556      * Notify our observers of DNS server information received.
557      */
notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses)558     private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
559         invokeForAllObservers(o -> o.interfaceDnsServerInfo(iface, lifetime, addresses));
560     }
561 
562     /**
563      * Notify our observers of a route change.
564      */
notifyRouteChange(boolean updated, RouteInfo route)565     private void notifyRouteChange(boolean updated, RouteInfo route) {
566         if (updated) {
567             invokeForAllObservers(o -> o.routeUpdated(route));
568         } else {
569             invokeForAllObservers(o -> o.routeRemoved(route));
570         }
571     }
572 
573     private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
574         @Override
onInterfaceClassActivityChanged(boolean isActive, int label, long timestamp, int uid)575         public void onInterfaceClassActivityChanged(boolean isActive,
576                 int label, long timestamp, int uid) throws RemoteException {
577             final long timestampNanos;
578             if (timestamp <= 0) {
579                 timestampNanos = SystemClock.elapsedRealtimeNanos();
580             } else {
581                 timestampNanos = timestamp;
582             }
583             mDaemonHandler.post(() ->
584                     notifyInterfaceClassActivity(label, isActive, timestampNanos, uid));
585         }
586 
587         @Override
onQuotaLimitReached(String alertName, String ifName)588         public void onQuotaLimitReached(String alertName, String ifName)
589                 throws RemoteException {
590             mDaemonHandler.post(() -> notifyLimitReached(alertName, ifName));
591         }
592 
593         @Override
onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers)594         public void onInterfaceDnsServerInfo(String ifName,
595                 long lifetime, String[] servers) throws RemoteException {
596             mDaemonHandler.post(() -> notifyInterfaceDnsServerInfo(ifName, lifetime, servers));
597         }
598 
599         @Override
onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope)600         public void onInterfaceAddressUpdated(String addr,
601                 String ifName, int flags, int scope) throws RemoteException {
602             final LinkAddress address = new LinkAddress(addr, flags, scope);
603             mDaemonHandler.post(() -> notifyAddressUpdated(ifName, address));
604         }
605 
606         @Override
onInterfaceAddressRemoved(String addr, String ifName, int flags, int scope)607         public void onInterfaceAddressRemoved(String addr,
608                 String ifName, int flags, int scope) throws RemoteException {
609             final LinkAddress address = new LinkAddress(addr, flags, scope);
610             mDaemonHandler.post(() -> notifyAddressRemoved(ifName, address));
611         }
612 
613         @Override
onInterfaceAdded(String ifName)614         public void onInterfaceAdded(String ifName) throws RemoteException {
615             mDaemonHandler.post(() -> notifyInterfaceAdded(ifName));
616         }
617 
618         @Override
onInterfaceRemoved(String ifName)619         public void onInterfaceRemoved(String ifName) throws RemoteException {
620             mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName));
621         }
622 
623         @Override
onInterfaceChanged(String ifName, boolean up)624         public void onInterfaceChanged(String ifName, boolean up)
625                 throws RemoteException {
626             mDaemonHandler.post(() -> notifyInterfaceStatusChanged(ifName, up));
627         }
628 
629         @Override
onInterfaceLinkStateChanged(String ifName, boolean up)630         public void onInterfaceLinkStateChanged(String ifName, boolean up)
631                 throws RemoteException {
632             mDaemonHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up));
633         }
634 
635         @Override
onRouteChanged(boolean updated, String route, String gateway, String ifName)636         public void onRouteChanged(boolean updated,
637                 String route, String gateway, String ifName) throws RemoteException {
638             final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
639                     ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
640                     ifName, RouteInfo.RTN_UNICAST);
641             mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute));
642         }
643 
644         @Override
onStrictCleartextDetected(int uid, String hex)645         public void onStrictCleartextDetected(int uid, String hex) throws RemoteException {
646             // Don't need to post to mDaemonHandler because the only thing
647             // that notifyCleartextNetwork does is post to a handler
648             ActivityManager.getService().notifyCleartextNetwork(uid,
649                     HexDump.hexStringToByteArray(hex));
650         }
651 
652         @Override
getInterfaceVersion()653         public int getInterfaceVersion() {
654             return INetdUnsolicitedEventListener.VERSION;
655         }
656 
657         @Override
getInterfaceHash()658         public String getInterfaceHash() {
659             return INetdUnsolicitedEventListener.HASH;
660         }
661     }
662 
663     //
664     // INetworkManagementService members
665     //
666     @Override
listInterfaces()667     public String[] listInterfaces() {
668         // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
669         //  APIs.
670         PermissionUtils.enforceNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
671         try {
672             return mNetdService.interfaceGetList();
673         } catch (RemoteException | ServiceSpecificException e) {
674             throw new IllegalStateException(e);
675         }
676     }
677 
678     /**
679      * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
680      */
toStableParcel(InterfaceConfiguration cfg, String iface)681     private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg,
682             String iface) {
683         InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
684         cfgParcel.ifName = iface;
685         String hwAddr = cfg.getHardwareAddress();
686         if (!TextUtils.isEmpty(hwAddr)) {
687             cfgParcel.hwAddr = hwAddr;
688         } else {
689             cfgParcel.hwAddr = "";
690         }
691         cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress();
692         cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength();
693         ArrayList<String> flags = new ArrayList<>();
694         for (String flag : cfg.getFlags()) {
695             flags.add(flag);
696         }
697         cfgParcel.flags = flags.toArray(new String[0]);
698 
699         return cfgParcel;
700     }
701 
702     /**
703      * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
704      */
fromStableParcel(InterfaceConfigurationParcel p)705     public static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) {
706         InterfaceConfiguration cfg = new InterfaceConfiguration();
707         cfg.setHardwareAddress(p.hwAddr);
708 
709         final InetAddress addr = InetAddresses.parseNumericAddress(p.ipv4Addr);
710         cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
711         for (String flag : p.flags) {
712             cfg.setFlag(flag);
713         }
714 
715         return cfg;
716     }
717 
718     @Override
getInterfaceConfig(String iface)719     public InterfaceConfiguration getInterfaceConfig(String iface) {
720         // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
721         //  APIs.
722         PermissionUtils.enforceNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
723         final InterfaceConfigurationParcel result;
724         try {
725             result = mNetdService.interfaceGetCfg(iface);
726         } catch (RemoteException | ServiceSpecificException e) {
727             throw new IllegalStateException(e);
728         }
729 
730         try {
731             final InterfaceConfiguration cfg = fromStableParcel(result);
732             return cfg;
733         } catch (IllegalArgumentException iae) {
734             throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae);
735         }
736     }
737 
738     @Override
setInterfaceConfig(String iface, InterfaceConfiguration cfg)739     public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
740         // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
741         //  APIs.
742         PermissionUtils.enforceNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
743         LinkAddress linkAddr = cfg.getLinkAddress();
744         if (linkAddr == null || linkAddr.getAddress() == null) {
745             throw new IllegalStateException("Null LinkAddress given");
746         }
747 
748         final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface);
749 
750         try {
751             mNetdService.interfaceSetCfg(cfgParcel);
752         } catch (RemoteException | ServiceSpecificException e) {
753             throw new IllegalStateException(e);
754         }
755     }
756 
757     @Override
setInterfaceDown(String iface)758     public void setInterfaceDown(String iface) {
759         PermissionUtils.enforceNetworkStackPermission(mContext);
760         final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
761         ifcg.setInterfaceDown();
762         setInterfaceConfig(iface, ifcg);
763     }
764 
765     @Override
setInterfaceUp(String iface)766     public void setInterfaceUp(String iface) {
767         PermissionUtils.enforceNetworkStackPermission(mContext);
768         final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
769         ifcg.setInterfaceUp();
770         setInterfaceConfig(iface, ifcg);
771     }
772 
773     @Override
setInterfaceIpv6PrivacyExtensions(String iface, boolean enable)774     public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
775         PermissionUtils.enforceNetworkStackPermission(mContext);
776         try {
777             mNetdService.interfaceSetIPv6PrivacyExtensions(iface, enable);
778         } catch (RemoteException | ServiceSpecificException e) {
779             throw new IllegalStateException(e);
780         }
781     }
782 
783     /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
784        IPv6 addresses on interface down, but we need to do full clean up here */
785     @Override
clearInterfaceAddresses(String iface)786     public void clearInterfaceAddresses(String iface) {
787         PermissionUtils.enforceNetworkStackPermission(mContext);
788         try {
789             mNetdService.interfaceClearAddrs(iface);
790         } catch (RemoteException | ServiceSpecificException e) {
791             throw new IllegalStateException(e);
792         }
793     }
794 
795     @Override
enableIpv6(String iface)796     public void enableIpv6(String iface) {
797         PermissionUtils.enforceNetworkStackPermission(mContext);
798         try {
799             mNetdService.interfaceSetEnableIPv6(iface, true);
800         } catch (RemoteException | ServiceSpecificException e) {
801             throw new IllegalStateException(e);
802         }
803     }
804 
805     @Override
setIPv6AddrGenMode(String iface, int mode)806     public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException {
807         PermissionUtils.enforceNetworkStackPermission(mContext);
808         try {
809             mNetdService.setIPv6AddrGenMode(iface, mode);
810         } catch (RemoteException e) {
811             throw e.rethrowAsRuntimeException();
812         }
813     }
814 
815     @Override
disableIpv6(String iface)816     public void disableIpv6(String iface) {
817         PermissionUtils.enforceNetworkStackPermission(mContext);
818         try {
819             mNetdService.interfaceSetEnableIPv6(iface, false);
820         } catch (RemoteException | ServiceSpecificException e) {
821             throw new IllegalStateException(e);
822         }
823     }
824 
825     @android.annotation.EnforcePermission(android.Manifest.permission.SHUTDOWN)
826     @Override
shutdown()827     public void shutdown() {
828         // TODO: remove from aidl if nobody calls externally
829 
830         super.shutdown_enforcePermission();
831 
832         Slog.i(TAG, "Shutting down");
833     }
834 
835     @Override
getIpForwardingEnabled()836     public boolean getIpForwardingEnabled() throws IllegalStateException{
837         PermissionUtils.enforceNetworkStackPermission(mContext);
838         if (SdkLevel.isAtLeastV()) {
839             throw new UnsupportedOperationException(
840                     "NMS#getIpForwardingEnabled not supported in V+");
841         }
842         try {
843             return mNetdService.ipfwdEnabled();
844         } catch (RemoteException | ServiceSpecificException e) {
845             throw new IllegalStateException(e);
846         }
847     }
848 
849     @Override
setIpForwardingEnabled(boolean enable)850     public void setIpForwardingEnabled(boolean enable) {
851         PermissionUtils.enforceNetworkStackPermission(mContext);
852         if (SdkLevel.isAtLeastV()) {
853             throw new UnsupportedOperationException(
854                     "NMS#setIpForwardingEnabled not supported in V+");
855         }        try {
856             if (enable) {
857                 mNetdService.ipfwdEnableForwarding("tethering");
858             } else {
859                 mNetdService.ipfwdDisableForwarding("tethering");
860             }
861         } catch (RemoteException | ServiceSpecificException e) {
862             throw new IllegalStateException(e);
863         }
864     }
865 
866     @Override
startTethering(String[] dhcpRange)867     public void startTethering(String[] dhcpRange) {
868         PermissionUtils.enforceNetworkStackPermission(mContext);
869         if (SdkLevel.isAtLeastV()) {
870             throw new UnsupportedOperationException("NMS#startTethering not supported in V+");
871         }
872         try {
873             NetdUtils.tetherStart(mNetdService, true /* usingLegacyDnsProxy */, dhcpRange);
874         } catch (RemoteException | ServiceSpecificException e) {
875             throw new IllegalStateException(e);
876         }
877     }
878 
879     @Override
stopTethering()880     public void stopTethering() {
881         PermissionUtils.enforceNetworkStackPermission(mContext);
882         if (SdkLevel.isAtLeastV()) {
883             throw new UnsupportedOperationException("NMS#stopTethering not supported in V+");
884         }
885         try {
886             mNetdService.tetherStop();
887         } catch (RemoteException | ServiceSpecificException e) {
888             throw new IllegalStateException(e);
889         }
890     }
891 
892     @Override
isTetheringStarted()893     public boolean isTetheringStarted() {
894         PermissionUtils.enforceNetworkStackPermission(mContext);
895         if (SdkLevel.isAtLeastV()) {
896             throw new UnsupportedOperationException("NMS#isTetheringStarted not supported in V+");
897         }
898         try {
899             return mNetdService.tetherIsEnabled();
900         } catch (RemoteException | ServiceSpecificException e) {
901             throw new IllegalStateException(e);
902         }
903     }
904 
905     @Override
tetherInterface(String iface)906     public void tetherInterface(String iface) {
907         PermissionUtils.enforceNetworkStackPermission(mContext);
908         if (SdkLevel.isAtLeastV()) {
909             throw new UnsupportedOperationException("NMS#tetherInterface not supported in V+");
910         }
911         try {
912             final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress();
913             final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength());
914             NetdUtils.tetherInterface(mNetdService, iface, dest);
915         } catch (RemoteException | ServiceSpecificException e) {
916             throw new IllegalStateException(e);
917         }
918     }
919 
920     @Override
untetherInterface(String iface)921     public void untetherInterface(String iface) {
922         PermissionUtils.enforceNetworkStackPermission(mContext);
923         if (SdkLevel.isAtLeastV()) {
924             throw new UnsupportedOperationException("NMS#untetherInterface not supported in V+");
925         }
926         try {
927             NetdUtils.untetherInterface(mNetdService, iface);
928         } catch (RemoteException | ServiceSpecificException e) {
929             throw new IllegalStateException(e);
930         }
931     }
932 
933     @Override
listTetheredInterfaces()934     public String[] listTetheredInterfaces() {
935         PermissionUtils.enforceNetworkStackPermission(mContext);
936         if (SdkLevel.isAtLeastV()) {
937             throw new UnsupportedOperationException(
938                     "NMS#listTetheredInterfaces not supported in V+");
939         }
940         try {
941             return mNetdService.tetherInterfaceList();
942         } catch (RemoteException | ServiceSpecificException e) {
943             throw new IllegalStateException(e);
944         }
945     }
946 
947     @Override
enableNat(String internalInterface, String externalInterface)948     public void enableNat(String internalInterface, String externalInterface) {
949         PermissionUtils.enforceNetworkStackPermission(mContext);
950         if (SdkLevel.isAtLeastV()) {
951             throw new UnsupportedOperationException("NMS#enableNat not supported in V+");
952         }
953         try {
954             mNetdService.tetherAddForward(internalInterface, externalInterface);
955         } catch (RemoteException | ServiceSpecificException e) {
956             throw new IllegalStateException(e);
957         }
958     }
959 
960     @Override
disableNat(String internalInterface, String externalInterface)961     public void disableNat(String internalInterface, String externalInterface) {
962         PermissionUtils.enforceNetworkStackPermission(mContext);
963         if (SdkLevel.isAtLeastV()) {
964             throw new UnsupportedOperationException("NMS#disableNat not supported in V+");
965         }
966         try {
967             mNetdService.tetherRemoveForward(internalInterface, externalInterface);
968         } catch (RemoteException | ServiceSpecificException e) {
969             throw new IllegalStateException(e);
970         }
971     }
972 
973     @Override
setInterfaceQuota(String iface, long quotaBytes)974     public void setInterfaceQuota(String iface, long quotaBytes) {
975         PermissionUtils.enforceNetworkStackPermission(mContext);
976 
977         synchronized (mQuotaLock) {
978             if (mActiveQuotas.containsKey(iface)) {
979                 throw new IllegalStateException("iface " + iface + " already has quota");
980             }
981 
982             try {
983                 // TODO: support quota shared across interfaces
984                 mNetdService.bandwidthSetInterfaceQuota(iface, quotaBytes);
985 
986                 mActiveQuotas.put(iface, quotaBytes);
987             } catch (RemoteException | ServiceSpecificException e) {
988                 throw new IllegalStateException(e);
989             }
990         }
991     }
992 
993     @Override
removeInterfaceQuota(String iface)994     public void removeInterfaceQuota(String iface) {
995         PermissionUtils.enforceNetworkStackPermission(mContext);
996 
997         synchronized (mQuotaLock) {
998             if (!mActiveQuotas.containsKey(iface)) {
999                 // TODO: eventually consider throwing
1000                 return;
1001             }
1002 
1003             mActiveQuotas.remove(iface);
1004             mActiveAlerts.remove(iface);
1005 
1006             try {
1007                 // TODO: support quota shared across interfaces
1008                 mNetdService.bandwidthRemoveInterfaceQuota(iface);
1009             } catch (RemoteException | ServiceSpecificException e) {
1010                 throw new IllegalStateException(e);
1011             }
1012         }
1013     }
1014 
1015     @Override
setInterfaceAlert(String iface, long alertBytes)1016     public void setInterfaceAlert(String iface, long alertBytes) {
1017         PermissionUtils.enforceNetworkStackPermission(mContext);
1018 
1019         // quick validity check
1020         if (!mActiveQuotas.containsKey(iface)) {
1021             throw new IllegalStateException("setting alert requires existing quota on iface");
1022         }
1023 
1024         synchronized (mQuotaLock) {
1025             if (mActiveAlerts.containsKey(iface)) {
1026                 throw new IllegalStateException("iface " + iface + " already has alert");
1027             }
1028 
1029             try {
1030                 // TODO: support alert shared across interfaces
1031                 mNetdService.bandwidthSetInterfaceAlert(iface, alertBytes);
1032                 mActiveAlerts.put(iface, alertBytes);
1033             } catch (RemoteException | ServiceSpecificException e) {
1034                 throw new IllegalStateException(e);
1035             }
1036         }
1037     }
1038 
1039     @Override
removeInterfaceAlert(String iface)1040     public void removeInterfaceAlert(String iface) {
1041         PermissionUtils.enforceNetworkStackPermission(mContext);
1042 
1043         synchronized (mQuotaLock) {
1044             if (!mActiveAlerts.containsKey(iface)) {
1045                 // TODO: eventually consider throwing
1046                 return;
1047             }
1048 
1049             try {
1050                 // TODO: support alert shared across interfaces
1051                 mNetdService.bandwidthRemoveInterfaceAlert(iface);
1052                 mActiveAlerts.remove(iface);
1053             } catch (RemoteException | ServiceSpecificException e) {
1054                 throw new IllegalStateException(e);
1055             }
1056         }
1057     }
1058 
setUidOnMeteredNetworkList(int uid, boolean allowlist, boolean enable)1059     private void setUidOnMeteredNetworkList(int uid, boolean allowlist, boolean enable) {
1060         PermissionUtils.enforceNetworkStackPermission(mContext);
1061 
1062         synchronized (mQuotaLock) {
1063             boolean oldEnable;
1064             SparseBooleanArray quotaList;
1065             synchronized (mRulesLock) {
1066                 quotaList = allowlist ?  mUidAllowOnMetered : mUidRejectOnMetered;
1067                 oldEnable = quotaList.get(uid, false);
1068             }
1069             if (oldEnable == enable) {
1070                 // TODO: eventually consider throwing
1071                 return;
1072             }
1073 
1074             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
1075             final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1076             try {
1077                 if (allowlist) {
1078                     if (enable) {
1079                         cm.addUidToMeteredNetworkAllowList(uid);
1080                     } else {
1081                         cm.removeUidFromMeteredNetworkAllowList(uid);
1082                     }
1083                 } else {
1084                     if (enable) {
1085                         cm.addUidToMeteredNetworkDenyList(uid);
1086                     } else {
1087                         cm.removeUidFromMeteredNetworkDenyList(uid);
1088                     }
1089                 }
1090                 synchronized (mRulesLock) {
1091                     if (enable) {
1092                         quotaList.put(uid, true);
1093                     } else {
1094                         quotaList.delete(uid);
1095                     }
1096                 }
1097             } catch (RuntimeException e) {
1098                 throw new IllegalStateException(e);
1099             } finally {
1100                 Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
1101             }
1102         }
1103     }
1104 
1105     @Override
setUidOnMeteredNetworkDenylist(int uid, boolean enable)1106     public void setUidOnMeteredNetworkDenylist(int uid, boolean enable) {
1107         setUidOnMeteredNetworkList(uid, false, enable);
1108     }
1109 
1110     @Override
setUidOnMeteredNetworkAllowlist(int uid, boolean enable)1111     public void setUidOnMeteredNetworkAllowlist(int uid, boolean enable) {
1112         setUidOnMeteredNetworkList(uid, true, enable);
1113     }
1114 
1115     @android.annotation.EnforcePermission(android.Manifest.permission.NETWORK_SETTINGS)
1116     @Override
setDataSaverModeEnabled(boolean enable)1117     public boolean setDataSaverModeEnabled(boolean enable) {
1118 
1119         super.setDataSaverModeEnabled_enforcePermission();
1120 
1121         if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
1122         synchronized (mQuotaLock) {
1123             if (mDataSaverMode == enable) {
1124                 Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
1125                 return true;
1126             }
1127             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDataSaverModeEnabled");
1128             try {
1129                 if (SdkLevel.isAtLeastV()) {
1130                     // setDataSaverEnabled throws if it fails to set data saver.
1131                     mContext.getSystemService(ConnectivityManager.class)
1132                             .setDataSaverEnabled(enable);
1133                     mDataSaverMode = enable;
1134                     if (mUseMeteredFirewallChains) {
1135                         // Copy mDataSaverMode state to FIREWALL_CHAIN_METERED_ALLOW
1136                         // until ConnectivityService allows manipulation of the data saver mode via
1137                         // FIREWALL_CHAIN_METERED_ALLOW.
1138                         synchronized (mRulesLock) {
1139                             mFirewallChainStates.put(FIREWALL_CHAIN_METERED_ALLOW, enable);
1140                         }
1141                     }
1142                     return true;
1143                 } else {
1144                     final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
1145                     if (changed) {
1146                         mDataSaverMode = enable;
1147                     } else {
1148                         Log.e(TAG, "setDataSaverMode(" + enable + "): failed to set iptables");
1149                     }
1150                     return changed;
1151                 }
1152             } catch (RemoteException | IllegalStateException e) {
1153                 Log.e(TAG, "setDataSaverMode(" + enable + "): failed with exception", e);
1154                 return false;
1155             } finally {
1156                 Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
1157             }
1158         }
1159     }
1160 
applyUidCleartextNetworkPolicy(int uid, int policy)1161     private void applyUidCleartextNetworkPolicy(int uid, int policy) {
1162         final int policyValue;
1163         switch (policy) {
1164             case StrictMode.NETWORK_POLICY_ACCEPT:
1165                 policyValue = INetd.PENALTY_POLICY_ACCEPT;
1166                 break;
1167             case StrictMode.NETWORK_POLICY_LOG:
1168                 policyValue = INetd.PENALTY_POLICY_LOG;
1169                 break;
1170             case StrictMode.NETWORK_POLICY_REJECT:
1171                 policyValue = INetd.PENALTY_POLICY_REJECT;
1172                 break;
1173             default:
1174                 throw new IllegalArgumentException("Unknown policy " + policy);
1175         }
1176 
1177         try {
1178             mNetdService.strictUidCleartextPenalty(uid, policyValue);
1179             mUidCleartextPolicy.put(uid, policy);
1180         } catch (RemoteException | ServiceSpecificException e) {
1181             throw new IllegalStateException(e);
1182         }
1183     }
1184 
1185     @Override
setUidCleartextNetworkPolicy(int uid, int policy)1186     public void setUidCleartextNetworkPolicy(int uid, int policy) {
1187         if (mDeps.getCallingUid() != uid) {
1188             PermissionUtils.enforceNetworkStackPermission(mContext);
1189         }
1190 
1191         synchronized (mQuotaLock) {
1192             final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT);
1193             if (oldPolicy == policy) {
1194                 // This also ensures we won't needlessly apply an ACCEPT policy if we've just
1195                 // enabled strict and the underlying iptables rules are empty.
1196                 return;
1197             }
1198 
1199             // TODO: remove this code after removing prepareNativeDaemon()
1200             if (!mStrictEnabled) {
1201                 // Module isn't enabled yet; stash the requested policy away to
1202                 // apply later once the daemon is connected.
1203                 mUidCleartextPolicy.put(uid, policy);
1204                 return;
1205             }
1206 
1207             // netd does not keep state on strict mode policies, and cannot replace a non-accept
1208             // policy without deleting it first. Rather than add state to netd, just always send
1209             // it an accept policy when switching between two non-accept policies.
1210             // TODO: consider keeping state in netd so we can simplify this code.
1211             if (oldPolicy != StrictMode.NETWORK_POLICY_ACCEPT &&
1212                     policy != StrictMode.NETWORK_POLICY_ACCEPT) {
1213                 applyUidCleartextNetworkPolicy(uid, StrictMode.NETWORK_POLICY_ACCEPT);
1214             }
1215 
1216             applyUidCleartextNetworkPolicy(uid, policy);
1217         }
1218     }
1219 
1220     @Override
isBandwidthControlEnabled()1221     public boolean isBandwidthControlEnabled() {
1222         return true;
1223     }
1224 
1225     @Override
setFirewallEnabled(boolean enabled)1226     public void setFirewallEnabled(boolean enabled) {
1227         enforceSystemUid();
1228         try {
1229             mNetdService.firewallSetFirewallType(
1230                     enabled ? INetd.FIREWALL_ALLOWLIST : INetd.FIREWALL_DENYLIST);
1231             mFirewallEnabled = enabled;
1232         } catch (RemoteException | ServiceSpecificException e) {
1233             throw new IllegalStateException(e);
1234         }
1235     }
1236 
1237     @Override
isFirewallEnabled()1238     public boolean isFirewallEnabled() {
1239         enforceSystemUid();
1240         return mFirewallEnabled;
1241     }
1242 
1243     @Override
setFirewallChainEnabled(int chain, boolean enable)1244     public void setFirewallChainEnabled(int chain, boolean enable) {
1245         enforceSystemUid();
1246         synchronized (mQuotaLock) {
1247             synchronized (mRulesLock) {
1248                 if (getFirewallChainState(chain) == enable) {
1249                     // All is the same, nothing to do.  This relies on the fact that netd has child
1250                     // chains default detached.
1251                     return;
1252                 }
1253                 setFirewallChainState(chain, enable);
1254             }
1255 
1256             if (!isValidFirewallChainForSetEnabled(chain)) {
1257                 throw new IllegalArgumentException("Invalid chain for setFirewallChainEnabled: "
1258                         + NetworkPolicyLogger.getFirewallChainName(chain));
1259             }
1260 
1261             final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1262             try {
1263                 cm.setFirewallChainEnabled(chain, enable);
1264             } catch (RuntimeException e) {
1265                 throw new IllegalStateException(e);
1266             }
1267         }
1268     }
1269 
isValidFirewallChainForSetEnabled(int chain)1270     private boolean isValidFirewallChainForSetEnabled(int chain) {
1271         return switch (chain) {
1272             case FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE,
1273                     FIREWALL_CHAIN_RESTRICTED, FIREWALL_CHAIN_LOW_POWER_STANDBY,
1274                     FIREWALL_CHAIN_BACKGROUND -> true;
1275             // METERED_* firewall chains are not yet supported by
1276             // ConnectivityService#setFirewallChainEnabled.
1277             default -> false;
1278         };
1279     }
1280 
getFirewallType(int chain)1281     private int getFirewallType(int chain) {
1282         switch (chain) {
1283             case FIREWALL_CHAIN_STANDBY:
1284             case FIREWALL_CHAIN_METERED_DENY_ADMIN:
1285             case FIREWALL_CHAIN_METERED_DENY_USER:
1286                 return FIREWALL_DENYLIST;
1287             case FIREWALL_CHAIN_DOZABLE:
1288             case FIREWALL_CHAIN_POWERSAVE:
1289             case FIREWALL_CHAIN_RESTRICTED:
1290             case FIREWALL_CHAIN_LOW_POWER_STANDBY:
1291             case FIREWALL_CHAIN_BACKGROUND:
1292             case FIREWALL_CHAIN_METERED_ALLOW:
1293                 return FIREWALL_ALLOWLIST;
1294             default:
1295                 return isFirewallEnabled() ? FIREWALL_ALLOWLIST : FIREWALL_DENYLIST;
1296         }
1297     }
1298 
1299     @Override
setFirewallUidRules(int chain, int[] uids, int[] rules)1300     public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
1301         enforceSystemUid();
1302         synchronized (mQuotaLock) {
1303             synchronized (mRulesLock) {
1304                 SparseIntArray uidFirewallRules = getUidFirewallRulesLR(chain);
1305                 SparseIntArray newRules = new SparseIntArray();
1306                 // apply new set of rules
1307                 for (int index = uids.length - 1; index >= 0; --index) {
1308                     int uid = uids[index];
1309                     int rule = rules[index];
1310                     updateFirewallUidRuleLocked(chain, uid, rule);
1311                     newRules.put(uid, rule);
1312                 }
1313                 // collect the rules to remove.
1314                 SparseIntArray rulesToRemove = new SparseIntArray();
1315                 for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
1316                     int uid = uidFirewallRules.keyAt(index);
1317                     if (newRules.indexOfKey(uid) < 0) {
1318                         rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
1319                     }
1320                 }
1321                 // remove dead rules
1322                 for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
1323                     int uid = rulesToRemove.keyAt(index);
1324                     updateFirewallUidRuleLocked(chain, uid, FIREWALL_RULE_DEFAULT);
1325                 }
1326             }
1327             final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1328             try {
1329                 cm.replaceFirewallChain(chain, uids);
1330             } catch (RuntimeException e) {
1331                 Slog.w(TAG, "Error flushing firewall chain " + chain, e);
1332             }
1333         }
1334     }
1335 
1336     @Override
setFirewallUidRule(int chain, int uid, int rule)1337     public void setFirewallUidRule(int chain, int uid, int rule) {
1338         enforceSystemUid();
1339         synchronized (mQuotaLock) {
1340             setFirewallUidRuleLocked(chain, uid, rule);
1341         }
1342     }
1343 
setFirewallUidRuleLocked(int chain, int uid, int rule)1344     private void setFirewallUidRuleLocked(int chain, int uid, int rule) {
1345         if (updateFirewallUidRuleLocked(chain, uid, rule)) {
1346             final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1347             try {
1348                 cm.setUidFirewallRule(chain, uid, rule);
1349             } catch (RuntimeException e) {
1350                 throw new IllegalStateException(e);
1351             }
1352         }
1353     }
1354 
1355     // TODO: now that netd supports batching, NMS should not keep these data structures anymore...
updateFirewallUidRuleLocked(int chain, int uid, int rule)1356     private boolean updateFirewallUidRuleLocked(int chain, int uid, int rule) {
1357         synchronized (mRulesLock) {
1358             SparseIntArray uidFirewallRules = getUidFirewallRulesLR(chain);
1359 
1360             final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
1361             if (DBG) {
1362                 Slog.d(TAG, "oldRule = " + oldUidFirewallRule
1363                         + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
1364             }
1365             if (oldUidFirewallRule == rule) {
1366                 if (DBG) Slog.d(TAG, "!!!!! Skipping change");
1367                 // TODO: eventually consider throwing
1368                 return false;
1369             }
1370 
1371             String ruleName = getFirewallRuleName(chain, rule);
1372             String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
1373 
1374             if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
1375                 uidFirewallRules.delete(uid);
1376             } else {
1377                 uidFirewallRules.put(uid, rule);
1378             }
1379             return !ruleName.equals(oldRuleName);
1380         }
1381     }
1382 
getFirewallRuleName(int chain, int rule)1383     private @NonNull String getFirewallRuleName(int chain, int rule) {
1384         String ruleName;
1385         if (getFirewallType(chain) == FIREWALL_ALLOWLIST) {
1386             if (rule == FIREWALL_RULE_ALLOW) {
1387                 ruleName = "allow";
1388             } else {
1389                 ruleName = "deny";
1390             }
1391         } else { // Deny mode
1392             if (rule == FIREWALL_RULE_DENY) {
1393                 ruleName = "deny";
1394             } else {
1395                 ruleName = "allow";
1396             }
1397         }
1398         return ruleName;
1399     }
1400 
1401     @GuardedBy("mRulesLock")
getUidFirewallRulesLR(int chain)1402     private @NonNull SparseIntArray getUidFirewallRulesLR(int chain) {
1403         switch (chain) {
1404             case FIREWALL_CHAIN_STANDBY:
1405                 return mUidFirewallStandbyRules;
1406             case FIREWALL_CHAIN_DOZABLE:
1407                 return mUidFirewallDozableRules;
1408             case FIREWALL_CHAIN_POWERSAVE:
1409                 return mUidFirewallPowerSaveRules;
1410             case FIREWALL_CHAIN_RESTRICTED:
1411                 return mUidFirewallRestrictedRules;
1412             case FIREWALL_CHAIN_LOW_POWER_STANDBY:
1413                 return mUidFirewallLowPowerStandbyRules;
1414             case FIREWALL_CHAIN_BACKGROUND:
1415                 return mUidFirewallBackgroundRules;
1416             case FIREWALL_CHAIN_METERED_ALLOW:
1417                 return mUidMeteredFirewallAllowRules;
1418             case FIREWALL_CHAIN_METERED_DENY_USER:
1419                 return mUidMeteredFirewallDenyUserRules;
1420             case FIREWALL_CHAIN_METERED_DENY_ADMIN:
1421                 return mUidMeteredFirewallDenyAdminRules;
1422             case FIREWALL_CHAIN_NONE:
1423                 return mUidFirewallRules;
1424             default:
1425                 throw new IllegalArgumentException("Unknown chain:" + chain);
1426         }
1427     }
1428 
enforceSystemUid()1429     private void enforceSystemUid() {
1430         final int uid = mDeps.getCallingUid();
1431         if (uid != Process.SYSTEM_UID) {
1432             throw new SecurityException("Only available to AID_SYSTEM");
1433         }
1434     }
1435 
1436     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1437     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1438         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1439 
1440         pw.println("Flags:");
1441         pw.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": " + mUseMeteredFirewallChains);
1442         pw.println();
1443 
1444         synchronized (mQuotaLock) {
1445             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1446             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
1447             pw.print("Data saver mode: "); pw.println(mDataSaverMode);
1448             synchronized (mRulesLock) {
1449                 dumpUidRuleOnQuotaLocked(pw, "denied UIDs", mUidRejectOnMetered);
1450                 dumpUidRuleOnQuotaLocked(pw, "allowed UIDs", mUidAllowOnMetered);
1451             }
1452         }
1453 
1454         synchronized (mRulesLock) {
1455             dumpUidFirewallRule(pw, "", mUidFirewallRules);
1456 
1457             pw.print("UID firewall standby chain enabled: ");
1458             pw.println(getFirewallChainState(FIREWALL_CHAIN_STANDBY));
1459             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
1460 
1461             pw.print("UID firewall dozable chain enabled: ");
1462             pw.println(getFirewallChainState(FIREWALL_CHAIN_DOZABLE));
1463             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
1464 
1465             pw.print("UID firewall powersave chain enabled: ");
1466             pw.println(getFirewallChainState(FIREWALL_CHAIN_POWERSAVE));
1467             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
1468 
1469             pw.print("UID firewall restricted mode chain enabled: ");
1470             pw.println(getFirewallChainState(FIREWALL_CHAIN_RESTRICTED));
1471             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_RESTRICTED,
1472                     mUidFirewallRestrictedRules);
1473 
1474             pw.print("UID firewall low power standby chain enabled: ");
1475             pw.println(getFirewallChainState(FIREWALL_CHAIN_LOW_POWER_STANDBY));
1476             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_LOW_POWER_STANDBY,
1477                     mUidFirewallLowPowerStandbyRules);
1478 
1479             pw.print("UID firewall background chain enabled: ");
1480             pw.println(getFirewallChainState(FIREWALL_CHAIN_BACKGROUND));
1481             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_BACKGROUND, mUidFirewallBackgroundRules);
1482 
1483             pw.print("UID firewall metered allow chain enabled (Data saver mode): ");
1484             // getFirewallChainState should maintain a duplicated state from mDataSaverMode when
1485             // mUseMeteredFirewallChains is enabled.
1486             pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_ALLOW));
1487             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_ALLOW,
1488                     mUidMeteredFirewallAllowRules);
1489 
1490             pw.print("UID firewall metered deny_user chain enabled (always-on): ");
1491             // This always-on state should be reflected by getFirewallChainState when
1492             // mUseMeteredFirewallChains is enabled.
1493             pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_USER));
1494             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_DENY_USER,
1495                     mUidMeteredFirewallDenyUserRules);
1496 
1497             pw.print("UID firewall metered deny_admin chain enabled (always-on): ");
1498             // This always-on state should be reflected by getFirewallChainState when
1499             // mUseMeteredFirewallChains is enabled.
1500             pw.println(getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_ADMIN));
1501             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_METERED_DENY_ADMIN,
1502                     mUidMeteredFirewallDenyAdminRules);
1503         }
1504 
1505         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
1506         pw.print("Netd service status: " );
1507         if (mNetdService == null) {
1508             pw.println("disconnected");
1509         } else {
1510             try {
1511                 final boolean alive = mNetdService.isAlive();
1512                 pw.println(alive ? "alive": "dead");
1513             } catch (RemoteException e) {
1514                 pw.println("unreachable");
1515             }
1516         }
1517     }
1518 
dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list)1519     private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) {
1520         pw.print("UID bandwith control ");
1521         pw.print(name);
1522         pw.print(": [");
1523         final int size = list.size();
1524         for (int i = 0; i < size; i++) {
1525             pw.print(list.keyAt(i));
1526             if (i < size - 1) pw.print(",");
1527         }
1528         pw.println("]");
1529     }
1530 
dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules)1531     private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
1532         pw.print("UID firewall ");
1533         pw.print(name);
1534         pw.print(" rule: [");
1535         final int size = rules.size();
1536         for (int i = 0; i < size; i++) {
1537             pw.print(rules.keyAt(i));
1538             pw.print(":");
1539             pw.print(rules.valueAt(i));
1540             if (i < size - 1) pw.print(",");
1541         }
1542         pw.println("]");
1543     }
1544 
1545     @Override
allowProtect(int uid)1546     public void allowProtect(int uid) {
1547         PermissionUtils.enforceNetworkStackPermission(mContext);
1548 
1549         try {
1550             mNetdService.networkSetProtectAllow(uid);
1551         } catch (RemoteException | ServiceSpecificException e) {
1552             throw new IllegalStateException(e);
1553         }
1554     }
1555 
1556     @Override
denyProtect(int uid)1557     public void denyProtect(int uid) {
1558         PermissionUtils.enforceNetworkStackPermission(mContext);
1559 
1560         try {
1561             mNetdService.networkSetProtectDeny(uid);
1562         } catch (RemoteException | ServiceSpecificException e) {
1563             throw new IllegalStateException(e);
1564         }
1565     }
1566 
1567     @android.annotation.EnforcePermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
1568     @Override
isNetworkRestricted(int uid)1569     public boolean isNetworkRestricted(int uid) {
1570         super.isNetworkRestricted_enforcePermission();
1571 
1572         return isNetworkRestrictedInternal(uid);
1573     }
1574 
isNetworkRestrictedInternal(int uid)1575     private boolean isNetworkRestrictedInternal(int uid) {
1576         synchronized (mRulesLock) {
1577             if (getFirewallChainState(FIREWALL_CHAIN_STANDBY)
1578                     && mUidFirewallStandbyRules.get(uid) == FIREWALL_RULE_DENY) {
1579                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of app standby mode");
1580                 return true;
1581             }
1582             if (getFirewallChainState(FIREWALL_CHAIN_DOZABLE)
1583                     && mUidFirewallDozableRules.get(uid) != FIREWALL_RULE_ALLOW) {
1584                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of device idle mode");
1585                 return true;
1586             }
1587             if (getFirewallChainState(FIREWALL_CHAIN_POWERSAVE)
1588                     && mUidFirewallPowerSaveRules.get(uid) != FIREWALL_RULE_ALLOW) {
1589                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
1590                 return true;
1591             }
1592             if (getFirewallChainState(FIREWALL_CHAIN_RESTRICTED)
1593                     && mUidFirewallRestrictedRules.get(uid) != FIREWALL_RULE_ALLOW) {
1594                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of restricted mode");
1595                 return true;
1596             }
1597             if (getFirewallChainState(FIREWALL_CHAIN_LOW_POWER_STANDBY)
1598                     && mUidFirewallLowPowerStandbyRules.get(uid) != FIREWALL_RULE_ALLOW) {
1599                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of low power standby");
1600                 return true;
1601             }
1602             if (getFirewallChainState(FIREWALL_CHAIN_BACKGROUND)
1603                     && mUidFirewallBackgroundRules.get(uid) != FIREWALL_RULE_ALLOW) {
1604                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because it is in background");
1605                 return true;
1606             }
1607             if (mUseMeteredFirewallChains) {
1608                 if (getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_USER)
1609                         && mUidMeteredFirewallDenyUserRules.get(uid) == FIREWALL_RULE_DENY) {
1610                     if (DBG) {
1611                         Slog.d(TAG, "Uid " + uid + " restricted because of user-restricted metered"
1612                                 + " data in the background");
1613                     }
1614                     return true;
1615                 }
1616                 if (getFirewallChainState(FIREWALL_CHAIN_METERED_DENY_ADMIN)
1617                         && mUidMeteredFirewallDenyAdminRules.get(uid) == FIREWALL_RULE_DENY) {
1618                     if (DBG) {
1619                         Slog.d(TAG, "Uid " + uid + " restricted because of admin-restricted metered"
1620                                 + " data in the background");
1621                     }
1622                     return true;
1623                 }
1624                 if (getFirewallChainState(FIREWALL_CHAIN_METERED_ALLOW)
1625                         && mUidMeteredFirewallAllowRules.get(uid) != FIREWALL_RULE_ALLOW) {
1626                     if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
1627                     return true;
1628                 }
1629             } else {
1630                 if (mUidRejectOnMetered.get(uid)) {
1631                     if (DBG) {
1632                         Slog.d(TAG, "Uid " + uid
1633                                 + " restricted because of no metered data in the background");
1634                     }
1635                     return true;
1636                 }
1637                 if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
1638                     if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
1639                     return true;
1640                 }
1641             }
1642             return false;
1643         }
1644     }
1645 
setFirewallChainState(int chain, boolean state)1646     private void setFirewallChainState(int chain, boolean state) {
1647         synchronized (mRulesLock) {
1648             mFirewallChainStates.put(chain, state);
1649         }
1650     }
1651 
getFirewallChainState(int chain)1652     private boolean getFirewallChainState(int chain) {
1653         synchronized (mRulesLock) {
1654             return mFirewallChainStates.get(chain);
1655         }
1656     }
1657 
1658     private class LocalService extends NetworkManagementInternal {
1659         @Override
isNetworkRestrictedForUid(int uid)1660         public boolean isNetworkRestrictedForUid(int uid) {
1661             return isNetworkRestrictedInternal(uid);
1662         }
1663     }
1664 }
1665