• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
20 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
21 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
22 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
23 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
24 import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
25 import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
26 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
27 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
28 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
29 import static android.net.INetd.PERMISSION_INTERNET;
30 import static android.net.INetd.PERMISSION_NONE;
31 import static android.net.INetd.PERMISSION_UNINSTALLED;
32 import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
33 import static android.system.OsConstants.EINVAL;
34 import static android.system.OsConstants.ENODEV;
35 import static android.system.OsConstants.ENOENT;
36 import static android.system.OsConstants.EOPNOTSUPP;
37 
38 import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO;
39 
40 import android.app.StatsManager;
41 import android.content.Context;
42 import android.net.INetd;
43 import android.os.RemoteException;
44 import android.os.ServiceSpecificException;
45 import android.provider.DeviceConfig;
46 import android.system.ErrnoException;
47 import android.system.Os;
48 import android.util.ArraySet;
49 import android.util.IndentingPrintWriter;
50 import android.util.Log;
51 import android.util.Pair;
52 import android.util.StatsEvent;
53 
54 import com.android.internal.annotations.VisibleForTesting;
55 import com.android.modules.utils.BackgroundThread;
56 import com.android.modules.utils.build.SdkLevel;
57 import com.android.net.module.util.BpfDump;
58 import com.android.net.module.util.BpfMap;
59 import com.android.net.module.util.DeviceConfigUtils;
60 import com.android.net.module.util.IBpfMap;
61 import com.android.net.module.util.Struct;
62 import com.android.net.module.util.Struct.S32;
63 import com.android.net.module.util.Struct.U32;
64 import com.android.net.module.util.Struct.U8;
65 import com.android.net.module.util.bpf.CookieTagMapKey;
66 import com.android.net.module.util.bpf.CookieTagMapValue;
67 
68 import java.io.FileDescriptor;
69 import java.io.IOException;
70 import java.util.Arrays;
71 import java.util.List;
72 import java.util.Set;
73 import java.util.StringJoiner;
74 
75 /**
76  * BpfNetMaps is responsible for providing traffic controller relevant functionality.
77  *
78  * {@hide}
79  */
80 public class BpfNetMaps {
81     private static final boolean PRE_T = !SdkLevel.isAtLeastT();
82     static {
83         if (!PRE_T) {
84             System.loadLibrary("service-connectivity");
85         }
86     }
87 
88     private static final String TAG = "BpfNetMaps";
89     private final INetd mNetd;
90     private final Dependencies mDeps;
91     // Use legacy netd for releases before T.
92     private static boolean sInitialized = false;
93 
94     private static Boolean sEnableJavaBpfMap = null;
95     private static final String BPF_NET_MAPS_ENABLE_JAVA_BPF_MAP =
96             "bpf_net_maps_enable_java_bpf_map";
97 
98     // Lock for sConfigurationMap entry for UID_RULES_CONFIGURATION_KEY.
99     // This entry is not accessed by others.
100     // BpfNetMaps acquires this lock while sequence of read, modify, and write.
101     private static final Object sUidRulesConfigBpfMapLock = new Object();
102 
103     // Lock for sConfigurationMap entry for CURRENT_STATS_MAP_CONFIGURATION_KEY.
104     // BpfNetMaps acquires this lock while sequence of read, modify, and write.
105     // BpfNetMaps is an only writer of this entry.
106     private static final Object sCurrentStatsMapConfigLock = new Object();
107 
108     private static final String CONFIGURATION_MAP_PATH =
109             "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
110     private static final String UID_OWNER_MAP_PATH =
111             "/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
112     private static final String UID_PERMISSION_MAP_PATH =
113             "/sys/fs/bpf/netd_shared/map_netd_uid_permission_map";
114     private static final String COOKIE_TAG_MAP_PATH =
115             "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
116     private static final S32 UID_RULES_CONFIGURATION_KEY = new S32(0);
117     private static final S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new S32(1);
118     private static final long UID_RULES_DEFAULT_CONFIGURATION = 0;
119     private static final long STATS_SELECT_MAP_A = 0;
120     private static final long STATS_SELECT_MAP_B = 1;
121 
122     private static IBpfMap<S32, U32> sConfigurationMap = null;
123     // BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
124     private static IBpfMap<S32, UidOwnerValue> sUidOwnerMap = null;
125     private static IBpfMap<S32, U8> sUidPermissionMap = null;
126     private static IBpfMap<CookieTagMapKey, CookieTagMapValue> sCookieTagMap = null;
127 
128     // LINT.IfChange(match_type)
129     @VisibleForTesting public static final long NO_MATCH = 0;
130     @VisibleForTesting public static final long HAPPY_BOX_MATCH = (1 << 0);
131     @VisibleForTesting public static final long PENALTY_BOX_MATCH = (1 << 1);
132     @VisibleForTesting public static final long DOZABLE_MATCH = (1 << 2);
133     @VisibleForTesting public static final long STANDBY_MATCH = (1 << 3);
134     @VisibleForTesting public static final long POWERSAVE_MATCH = (1 << 4);
135     @VisibleForTesting public static final long RESTRICTED_MATCH = (1 << 5);
136     @VisibleForTesting public static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
137     @VisibleForTesting public static final long IIF_MATCH = (1 << 7);
138     @VisibleForTesting public static final long LOCKDOWN_VPN_MATCH = (1 << 8);
139     @VisibleForTesting public static final long OEM_DENY_1_MATCH = (1 << 9);
140     @VisibleForTesting public static final long OEM_DENY_2_MATCH = (1 << 10);
141     @VisibleForTesting public static final long OEM_DENY_3_MATCH = (1 << 11);
142     // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h)
143 
144     private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList(
145             Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"),
146             Pair.create(PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS")
147     );
148     private static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList(
149             Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"),
150             Pair.create(PENALTY_BOX_MATCH, "PENALTY_BOX_MATCH"),
151             Pair.create(DOZABLE_MATCH, "DOZABLE_MATCH"),
152             Pair.create(STANDBY_MATCH, "STANDBY_MATCH"),
153             Pair.create(POWERSAVE_MATCH, "POWERSAVE_MATCH"),
154             Pair.create(RESTRICTED_MATCH, "RESTRICTED_MATCH"),
155             Pair.create(LOW_POWER_STANDBY_MATCH, "LOW_POWER_STANDBY_MATCH"),
156             Pair.create(IIF_MATCH, "IIF_MATCH"),
157             Pair.create(LOCKDOWN_VPN_MATCH, "LOCKDOWN_VPN_MATCH"),
158             Pair.create(OEM_DENY_1_MATCH, "OEM_DENY_1_MATCH"),
159             Pair.create(OEM_DENY_2_MATCH, "OEM_DENY_2_MATCH"),
160             Pair.create(OEM_DENY_3_MATCH, "OEM_DENY_3_MATCH")
161     );
162 
163     /**
164      * Set sEnableJavaBpfMap for test.
165      */
166     @VisibleForTesting
setEnableJavaBpfMapForTest(boolean enable)167     public static void setEnableJavaBpfMapForTest(boolean enable) {
168         sEnableJavaBpfMap = enable;
169     }
170 
171     /**
172      * Set configurationMap for test.
173      */
174     @VisibleForTesting
setConfigurationMapForTest(IBpfMap<S32, U32> configurationMap)175     public static void setConfigurationMapForTest(IBpfMap<S32, U32> configurationMap) {
176         sConfigurationMap = configurationMap;
177     }
178 
179     /**
180      * Set uidOwnerMap for test.
181      */
182     @VisibleForTesting
setUidOwnerMapForTest(IBpfMap<S32, UidOwnerValue> uidOwnerMap)183     public static void setUidOwnerMapForTest(IBpfMap<S32, UidOwnerValue> uidOwnerMap) {
184         sUidOwnerMap = uidOwnerMap;
185     }
186 
187     /**
188      * Set uidPermissionMap for test.
189      */
190     @VisibleForTesting
setUidPermissionMapForTest(IBpfMap<S32, U8> uidPermissionMap)191     public static void setUidPermissionMapForTest(IBpfMap<S32, U8> uidPermissionMap) {
192         sUidPermissionMap = uidPermissionMap;
193     }
194 
195     /**
196      * Set cookieTagMap for test.
197      */
198     @VisibleForTesting
setCookieTagMapForTest( IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap)199     public static void setCookieTagMapForTest(
200             IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap) {
201         sCookieTagMap = cookieTagMap;
202     }
203 
getConfigurationMap()204     private static IBpfMap<S32, U32> getConfigurationMap() {
205         try {
206             return new BpfMap<>(
207                     CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, U32.class);
208         } catch (ErrnoException e) {
209             throw new IllegalStateException("Cannot open netd configuration map", e);
210         }
211     }
212 
getUidOwnerMap()213     private static IBpfMap<S32, UidOwnerValue> getUidOwnerMap() {
214         try {
215             return new BpfMap<>(
216                     UID_OWNER_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, UidOwnerValue.class);
217         } catch (ErrnoException e) {
218             throw new IllegalStateException("Cannot open uid owner map", e);
219         }
220     }
221 
getUidPermissionMap()222     private static IBpfMap<S32, U8> getUidPermissionMap() {
223         try {
224             return new BpfMap<>(
225                     UID_PERMISSION_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, U8.class);
226         } catch (ErrnoException e) {
227             throw new IllegalStateException("Cannot open uid permission map", e);
228         }
229     }
230 
getCookieTagMap()231     private static IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() {
232         try {
233             return new BpfMap<>(COOKIE_TAG_MAP_PATH, BpfMap.BPF_F_RDWR,
234                     CookieTagMapKey.class, CookieTagMapValue.class);
235         } catch (ErrnoException e) {
236             throw new IllegalStateException("Cannot open cookie tag map", e);
237         }
238     }
239 
initBpfMaps()240     private static void initBpfMaps() {
241         if (sConfigurationMap == null) {
242             sConfigurationMap = getConfigurationMap();
243         }
244         try {
245             sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY,
246                     new U32(UID_RULES_DEFAULT_CONFIGURATION));
247         } catch (ErrnoException e) {
248             throw new IllegalStateException("Failed to initialize uid rules configuration", e);
249         }
250         try {
251             sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY,
252                     new U32(STATS_SELECT_MAP_A));
253         } catch (ErrnoException e) {
254             throw new IllegalStateException("Failed to initialize current stats configuration", e);
255         }
256 
257         if (sUidOwnerMap == null) {
258             sUidOwnerMap = getUidOwnerMap();
259         }
260         try {
261             sUidOwnerMap.clear();
262         } catch (ErrnoException e) {
263             throw new IllegalStateException("Failed to initialize uid owner map", e);
264         }
265 
266         if (sUidPermissionMap == null) {
267             sUidPermissionMap = getUidPermissionMap();
268         }
269 
270         if (sCookieTagMap == null) {
271             sCookieTagMap = getCookieTagMap();
272         }
273     }
274 
275     /**
276      * Initializes the class if it is not already initialized. This method will open maps but not
277      * cause any other effects. This method may be called multiple times on any thread.
278      */
ensureInitialized(final Context context)279     private static synchronized void ensureInitialized(final Context context) {
280         if (sInitialized) return;
281         if (sEnableJavaBpfMap == null) {
282             sEnableJavaBpfMap = SdkLevel.isAtLeastU() ||
283                     DeviceConfigUtils.isFeatureEnabled(context,
284                             DeviceConfig.NAMESPACE_TETHERING, BPF_NET_MAPS_ENABLE_JAVA_BPF_MAP,
285                             DeviceConfigUtils.TETHERING_MODULE_NAME, false /* defaultValue */);
286         }
287         Log.d(TAG, "BpfNetMaps is initialized with sEnableJavaBpfMap=" + sEnableJavaBpfMap);
288 
289         initBpfMaps();
290         native_init(!sEnableJavaBpfMap /* startSkDestroyListener */);
291         sInitialized = true;
292     }
293 
isSkDestroyListenerRunning()294     public boolean isSkDestroyListenerRunning() {
295         return !sEnableJavaBpfMap;
296     }
297 
298     /**
299      * Dependencies of BpfNetMaps, for injection in tests.
300      */
301     @VisibleForTesting
302     public static class Dependencies {
303         /**
304          * Get interface index.
305          */
getIfIndex(final String ifName)306         public int getIfIndex(final String ifName) {
307             return Os.if_nametoindex(ifName);
308         }
309 
310         /**
311          * Call synchronize_rcu()
312          */
synchronizeKernelRCU()313         public int synchronizeKernelRCU() {
314             return native_synchronizeKernelRCU();
315         }
316 
317         /**
318          * Build Stats Event for NETWORK_BPF_MAP_INFO atom
319          */
buildStatsEvent(final int cookieTagMapSize, final int uidOwnerMapSize, final int uidPermissionMapSize)320         public StatsEvent buildStatsEvent(final int cookieTagMapSize, final int uidOwnerMapSize,
321                 final int uidPermissionMapSize) {
322             return ConnectivityStatsLog.buildStatsEvent(NETWORK_BPF_MAP_INFO, cookieTagMapSize,
323                     uidOwnerMapSize, uidPermissionMapSize);
324         }
325 
326         /**
327          * Call native_dump
328          */
nativeDump(final FileDescriptor fd, final boolean verbose)329         public void nativeDump(final FileDescriptor fd, final boolean verbose) {
330             native_dump(fd, verbose);
331         }
332     }
333 
334     /** Constructor used after T that doesn't need to use netd anymore. */
BpfNetMaps(final Context context)335     public BpfNetMaps(final Context context) {
336         this(context, null);
337 
338         if (PRE_T) throw new IllegalArgumentException("BpfNetMaps need to use netd before T");
339     }
340 
BpfNetMaps(final Context context, final INetd netd)341     public BpfNetMaps(final Context context, final INetd netd) {
342         this(context, netd, new Dependencies());
343     }
344 
345     @VisibleForTesting
BpfNetMaps(final Context context, final INetd netd, final Dependencies deps)346     public BpfNetMaps(final Context context, final INetd netd, final Dependencies deps) {
347         if (!PRE_T) {
348             ensureInitialized(context);
349         }
350         mNetd = netd;
351         mDeps = deps;
352     }
353 
354     /**
355      * Get corresponding match from firewall chain.
356      */
357     @VisibleForTesting
getMatchByFirewallChain(final int chain)358     public long getMatchByFirewallChain(final int chain) {
359         switch (chain) {
360             case FIREWALL_CHAIN_DOZABLE:
361                 return DOZABLE_MATCH;
362             case FIREWALL_CHAIN_STANDBY:
363                 return STANDBY_MATCH;
364             case FIREWALL_CHAIN_POWERSAVE:
365                 return POWERSAVE_MATCH;
366             case FIREWALL_CHAIN_RESTRICTED:
367                 return RESTRICTED_MATCH;
368             case FIREWALL_CHAIN_LOW_POWER_STANDBY:
369                 return LOW_POWER_STANDBY_MATCH;
370             case FIREWALL_CHAIN_OEM_DENY_1:
371                 return OEM_DENY_1_MATCH;
372             case FIREWALL_CHAIN_OEM_DENY_2:
373                 return OEM_DENY_2_MATCH;
374             case FIREWALL_CHAIN_OEM_DENY_3:
375                 return OEM_DENY_3_MATCH;
376             default:
377                 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
378         }
379     }
380 
381     /**
382      * Get if the chain is allow list or not.
383      *
384      * ALLOWLIST means the firewall denies all by default, uids must be explicitly allowed
385      * DENYLIST means the firewall allows all by default, uids must be explicitly denyed
386      */
isFirewallAllowList(final int chain)387     public boolean isFirewallAllowList(final int chain) {
388         switch (chain) {
389             case FIREWALL_CHAIN_DOZABLE:
390             case FIREWALL_CHAIN_POWERSAVE:
391             case FIREWALL_CHAIN_RESTRICTED:
392             case FIREWALL_CHAIN_LOW_POWER_STANDBY:
393                 return true;
394             case FIREWALL_CHAIN_STANDBY:
395             case FIREWALL_CHAIN_OEM_DENY_1:
396             case FIREWALL_CHAIN_OEM_DENY_2:
397             case FIREWALL_CHAIN_OEM_DENY_3:
398                 return false;
399             default:
400                 throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
401         }
402     }
403 
maybeThrow(final int err, final String msg)404     private void maybeThrow(final int err, final String msg) {
405         if (err != 0) {
406             throw new ServiceSpecificException(err, msg + ": " + Os.strerror(err));
407         }
408     }
409 
throwIfPreT(final String msg)410     private void throwIfPreT(final String msg) {
411         if (PRE_T) {
412             throw new UnsupportedOperationException(msg);
413         }
414     }
415 
removeRule(final int uid, final long match, final String caller)416     private void removeRule(final int uid, final long match, final String caller) {
417         try {
418             synchronized (sUidOwnerMap) {
419                 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new S32(uid));
420 
421                 if (oldMatch == null) {
422                     throw new ServiceSpecificException(ENOENT,
423                             "sUidOwnerMap does not have entry for uid: " + uid);
424                 }
425 
426                 final UidOwnerValue newMatch = new UidOwnerValue(
427                         (match == IIF_MATCH) ? 0 : oldMatch.iif,
428                         oldMatch.rule & ~match
429                 );
430 
431                 if (newMatch.rule == 0) {
432                     sUidOwnerMap.deleteEntry(new S32(uid));
433                 } else {
434                     sUidOwnerMap.updateEntry(new S32(uid), newMatch);
435                 }
436             }
437         } catch (ErrnoException e) {
438             throw new ServiceSpecificException(e.errno,
439                     caller + " failed to remove rule: " + Os.strerror(e.errno));
440         }
441     }
442 
addRule(final int uid, final long match, final int iif, final String caller)443     private void addRule(final int uid, final long match, final int iif, final String caller) {
444         if (match != IIF_MATCH && iif != 0) {
445             throw new ServiceSpecificException(EINVAL,
446                     "Non-interface match must have zero interface index");
447         }
448 
449         try {
450             synchronized (sUidOwnerMap) {
451                 final UidOwnerValue oldMatch = sUidOwnerMap.getValue(new S32(uid));
452 
453                 final UidOwnerValue newMatch;
454                 if (oldMatch != null) {
455                     newMatch = new UidOwnerValue(
456                             (match == IIF_MATCH) ? iif : oldMatch.iif,
457                             oldMatch.rule | match
458                     );
459                 } else {
460                     newMatch = new UidOwnerValue(
461                             iif,
462                             match
463                     );
464                 }
465                 sUidOwnerMap.updateEntry(new S32(uid), newMatch);
466             }
467         } catch (ErrnoException e) {
468             throw new ServiceSpecificException(e.errno,
469                     caller + " failed to add rule: " + Os.strerror(e.errno));
470         }
471     }
472 
addRule(final int uid, final long match, final String caller)473     private void addRule(final int uid, final long match, final String caller) {
474         addRule(uid, match, 0 /* iif */, caller);
475     }
476 
477     /**
478      * Add naughty app bandwidth rule for specific app
479      *
480      * @param uid uid of target app
481      * @throws ServiceSpecificException in case of failure, with an error code indicating the
482      *                                  cause of the failure.
483      */
addNaughtyApp(final int uid)484     public void addNaughtyApp(final int uid) {
485         throwIfPreT("addNaughtyApp is not available on pre-T devices");
486 
487         if (sEnableJavaBpfMap) {
488             addRule(uid, PENALTY_BOX_MATCH, "addNaughtyApp");
489         } else {
490             final int err = native_addNaughtyApp(uid);
491             maybeThrow(err, "Unable to add naughty app");
492         }
493     }
494 
495     /**
496      * Remove naughty app bandwidth rule for specific app
497      *
498      * @param uid uid of target app
499      * @throws ServiceSpecificException in case of failure, with an error code indicating the
500      *                                  cause of the failure.
501      */
removeNaughtyApp(final int uid)502     public void removeNaughtyApp(final int uid) {
503         throwIfPreT("removeNaughtyApp is not available on pre-T devices");
504 
505         if (sEnableJavaBpfMap) {
506             removeRule(uid, PENALTY_BOX_MATCH, "removeNaughtyApp");
507         } else {
508             final int err = native_removeNaughtyApp(uid);
509             maybeThrow(err, "Unable to remove naughty app");
510         }
511     }
512 
513     /**
514      * Add nice app bandwidth rule for specific app
515      *
516      * @param uid uid of target app
517      * @throws ServiceSpecificException in case of failure, with an error code indicating the
518      *                                  cause of the failure.
519      */
addNiceApp(final int uid)520     public void addNiceApp(final int uid) {
521         throwIfPreT("addNiceApp is not available on pre-T devices");
522 
523         if (sEnableJavaBpfMap) {
524             addRule(uid, HAPPY_BOX_MATCH, "addNiceApp");
525         } else {
526             final int err = native_addNiceApp(uid);
527             maybeThrow(err, "Unable to add nice app");
528         }
529     }
530 
531     /**
532      * Remove nice app bandwidth rule for specific app
533      *
534      * @param uid uid of target app
535      * @throws ServiceSpecificException in case of failure, with an error code indicating the
536      *                                  cause of the failure.
537      */
removeNiceApp(final int uid)538     public void removeNiceApp(final int uid) {
539         throwIfPreT("removeNiceApp is not available on pre-T devices");
540 
541         if (sEnableJavaBpfMap) {
542             removeRule(uid, HAPPY_BOX_MATCH, "removeNiceApp");
543         } else {
544             final int err = native_removeNiceApp(uid);
545             maybeThrow(err, "Unable to remove nice app");
546         }
547     }
548 
549     /**
550      * Set target firewall child chain
551      *
552      * @param childChain target chain to enable
553      * @param enable     whether to enable or disable child chain.
554      * @throws UnsupportedOperationException if called on pre-T devices.
555      * @throws ServiceSpecificException in case of failure, with an error code indicating the
556      *                                  cause of the failure.
557      */
setChildChain(final int childChain, final boolean enable)558     public void setChildChain(final int childChain, final boolean enable) {
559         throwIfPreT("setChildChain is not available on pre-T devices");
560 
561         if (sEnableJavaBpfMap) {
562             final long match = getMatchByFirewallChain(childChain);
563             try {
564                 synchronized (sUidRulesConfigBpfMapLock) {
565                     final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
566                     final long newConfig = enable ? (config.val | match) : (config.val & ~match);
567                     sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
568                 }
569             } catch (ErrnoException e) {
570                 throw new ServiceSpecificException(e.errno,
571                         "Unable to set child chain: " + Os.strerror(e.errno));
572             }
573         } else {
574             final int err = native_setChildChain(childChain, enable);
575             maybeThrow(err, "Unable to set child chain");
576         }
577     }
578 
579     /**
580      * Get the specified firewall chain's status.
581      *
582      * @param childChain target chain
583      * @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
584      * @throws UnsupportedOperationException if called on pre-T devices.
585      * @throws ServiceSpecificException in case of failure, with an error code indicating the
586      *                                  cause of the failure.
587      */
isChainEnabled(final int childChain)588     public boolean isChainEnabled(final int childChain) {
589         throwIfPreT("isChainEnabled is not available on pre-T devices");
590 
591         final long match = getMatchByFirewallChain(childChain);
592         try {
593             final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
594             return (config.val & match) != 0;
595         } catch (ErrnoException e) {
596             throw new ServiceSpecificException(e.errno,
597                     "Unable to get firewall chain status: " + Os.strerror(e.errno));
598         }
599     }
600 
asSet(final int[] uids)601     private Set<Integer> asSet(final int[] uids) {
602         final Set<Integer> uidSet = new ArraySet<>();
603         for (final int uid: uids) {
604             uidSet.add(uid);
605         }
606         return uidSet;
607     }
608 
609     /**
610      * Replaces the contents of the specified UID-based firewall chain.
611      * Enables the chain for specified uids and disables the chain for non-specified uids.
612      *
613      * @param chain       Target chain.
614      * @param uids        The list of UIDs to allow/deny.
615      * @throws UnsupportedOperationException if called on pre-T devices.
616      * @throws IllegalArgumentException if {@code chain} is not a valid chain.
617      */
replaceUidChain(final int chain, final int[] uids)618     public void replaceUidChain(final int chain, final int[] uids) {
619         throwIfPreT("replaceUidChain is not available on pre-T devices");
620 
621         if (sEnableJavaBpfMap) {
622             final long match;
623             try {
624                 match = getMatchByFirewallChain(chain);
625             } catch (ServiceSpecificException e) {
626                 // Throws IllegalArgumentException to keep the behavior of
627                 // ConnectivityManager#replaceFirewallChain API
628                 throw new IllegalArgumentException("Invalid firewall chain: " + chain);
629             }
630             final Set<Integer> uidSet = asSet(uids);
631             final Set<Integer> uidSetToRemoveRule = new ArraySet<>();
632             try {
633                 synchronized (sUidOwnerMap) {
634                     sUidOwnerMap.forEach((uid, config) -> {
635                         // config could be null if there is a concurrent entry deletion.
636                         // http://b/220084230. But sUidOwnerMap update must be done while holding a
637                         // lock, so this should not happen.
638                         if (config == null) {
639                             Log.wtf(TAG, "sUidOwnerMap entry was deleted while holding a lock");
640                         } else if (!uidSet.contains((int) uid.val) && (config.rule & match) != 0) {
641                             uidSetToRemoveRule.add((int) uid.val);
642                         }
643                     });
644 
645                     for (final int uid : uidSetToRemoveRule) {
646                         removeRule(uid, match, "replaceUidChain");
647                     }
648                     for (final int uid : uids) {
649                         addRule(uid, match, "replaceUidChain");
650                     }
651                 }
652             } catch (ErrnoException | ServiceSpecificException e) {
653                 Log.e(TAG, "replaceUidChain failed: " + e);
654             }
655         } else {
656             final int err;
657             switch (chain) {
658                 case FIREWALL_CHAIN_DOZABLE:
659                     err = native_replaceUidChain("fw_dozable", true /* isAllowList */, uids);
660                     break;
661                 case FIREWALL_CHAIN_STANDBY:
662                     err = native_replaceUidChain("fw_standby", false /* isAllowList */, uids);
663                     break;
664                 case FIREWALL_CHAIN_POWERSAVE:
665                     err = native_replaceUidChain("fw_powersave", true /* isAllowList */, uids);
666                     break;
667                 case FIREWALL_CHAIN_RESTRICTED:
668                     err = native_replaceUidChain("fw_restricted", true /* isAllowList */, uids);
669                     break;
670                 case FIREWALL_CHAIN_LOW_POWER_STANDBY:
671                     err = native_replaceUidChain(
672                             "fw_low_power_standby", true /* isAllowList */, uids);
673                     break;
674                 case FIREWALL_CHAIN_OEM_DENY_1:
675                     err = native_replaceUidChain("fw_oem_deny_1", false /* isAllowList */, uids);
676                     break;
677                 case FIREWALL_CHAIN_OEM_DENY_2:
678                     err = native_replaceUidChain("fw_oem_deny_2", false /* isAllowList */, uids);
679                     break;
680                 case FIREWALL_CHAIN_OEM_DENY_3:
681                     err = native_replaceUidChain("fw_oem_deny_3", false /* isAllowList */, uids);
682                     break;
683                 default:
684                     throw new IllegalArgumentException("replaceFirewallChain with invalid chain: "
685                             + chain);
686             }
687             if (err != 0) {
688                 Log.e(TAG, "replaceUidChain failed: " + Os.strerror(-err));
689             }
690         }
691     }
692 
693     /**
694      * Set firewall rule for uid
695      *
696      * @param childChain   target chain
697      * @param uid          uid to allow/deny
698      * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
699      * @throws ServiceSpecificException in case of failure, with an error code indicating the
700      *                                  cause of the failure.
701      */
setUidRule(final int childChain, final int uid, final int firewallRule)702     public void setUidRule(final int childChain, final int uid, final int firewallRule) {
703         throwIfPreT("setUidRule is not available on pre-T devices");
704 
705         if (sEnableJavaBpfMap) {
706             final long match = getMatchByFirewallChain(childChain);
707             final boolean isAllowList = isFirewallAllowList(childChain);
708             final boolean add = (firewallRule == FIREWALL_RULE_ALLOW && isAllowList)
709                     || (firewallRule == FIREWALL_RULE_DENY && !isAllowList);
710 
711             if (add) {
712                 addRule(uid, match, "setUidRule");
713             } else {
714                 removeRule(uid, match, "setUidRule");
715             }
716         } else {
717             final int err = native_setUidRule(childChain, uid, firewallRule);
718             maybeThrow(err, "Unable to set uid rule");
719         }
720     }
721 
722     /**
723      * Get firewall rule of specified firewall chain on specified uid.
724      *
725      * @param childChain target chain
726      * @param uid        target uid
727      * @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
728      * @throws UnsupportedOperationException if called on pre-T devices.
729      * @throws ServiceSpecificException in case of failure, with an error code indicating the
730      *                                  cause of the failure.
731      */
getUidRule(final int childChain, final int uid)732     public int getUidRule(final int childChain, final int uid) {
733         throwIfPreT("isUidChainEnabled is not available on pre-T devices");
734 
735         final long match = getMatchByFirewallChain(childChain);
736         final boolean isAllowList = isFirewallAllowList(childChain);
737         try {
738             final UidOwnerValue uidMatch = sUidOwnerMap.getValue(new S32(uid));
739             final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0;
740             return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
741         } catch (ErrnoException e) {
742             throw new ServiceSpecificException(e.errno,
743                     "Unable to get uid rule status: " + Os.strerror(e.errno));
744         }
745     }
746 
getUidsMatchEnabled(final int childChain)747     private Set<Integer> getUidsMatchEnabled(final int childChain) throws ErrnoException {
748         final long match = getMatchByFirewallChain(childChain);
749         Set<Integer> uids = new ArraySet<>();
750         synchronized (sUidOwnerMap) {
751             sUidOwnerMap.forEach((uid, val) -> {
752                 if (val == null) {
753                     Log.wtf(TAG, "sUidOwnerMap entry was deleted while holding a lock");
754                 } else {
755                     if ((val.rule & match) != 0) {
756                         uids.add(uid.val);
757                     }
758                 }
759             });
760         }
761         return uids;
762     }
763 
764     /**
765      * Get uids that has FIREWALL_RULE_ALLOW on allowlist chain.
766      * Allowlist means the firewall denies all by default, uids must be explicitly allowed.
767      *
768      * Note that uids that has FIREWALL_RULE_DENY on allowlist chain can not be computed from the
769      * bpf map, since all the uids that does not have explicit FIREWALL_RULE_ALLOW rule in bpf map
770      * are determined to have FIREWALL_RULE_DENY.
771      *
772      * @param childChain target chain
773      * @return Set of uids
774      */
getUidsWithAllowRuleOnAllowListChain(final int childChain)775     public Set<Integer> getUidsWithAllowRuleOnAllowListChain(final int childChain)
776             throws ErrnoException {
777         if (!isFirewallAllowList(childChain)) {
778             throw new IllegalArgumentException("getUidsWithAllowRuleOnAllowListChain is called with"
779                     + " denylist chain:" + childChain);
780         }
781         // Corresponding match is enabled for uids that has FIREWALL_RULE_ALLOW on allowlist chain.
782         return getUidsMatchEnabled(childChain);
783     }
784 
785     /**
786      * Get uids that has FIREWALL_RULE_DENY on denylist chain.
787      * Denylist means the firewall allows all by default, uids must be explicitly denyed
788      *
789      * Note that uids that has FIREWALL_RULE_ALLOW on denylist chain can not be computed from the
790      * bpf map, since all the uids that does not have explicit FIREWALL_RULE_DENY rule in bpf map
791      * are determined to have the FIREWALL_RULE_ALLOW.
792      *
793      * @param childChain target chain
794      * @return Set of uids
795      */
getUidsWithDenyRuleOnDenyListChain(final int childChain)796     public Set<Integer> getUidsWithDenyRuleOnDenyListChain(final int childChain)
797             throws ErrnoException {
798         if (isFirewallAllowList(childChain)) {
799             throw new IllegalArgumentException("getUidsWithDenyRuleOnDenyListChain is called with"
800                     + " allowlist chain:" + childChain);
801         }
802         // Corresponding match is enabled for uids that has FIREWALL_RULE_DENY on denylist chain.
803         return getUidsMatchEnabled(childChain);
804     }
805 
806     /**
807      * Add ingress interface filtering rules to a list of UIDs
808      *
809      * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
810      * allowed interface and loopback to be sent to the list of UIDs.
811      *
812      * Calling this method on one or more UIDs with an existing filtering rule but a different
813      * interface name will result in the filtering rule being updated to allow the new interface
814      * instead. Otherwise calling this method will not affect existing rules set on other UIDs.
815      *
816      * @param ifName the name of the interface on which the filtering rules will allow packets to
817      *               be received.
818      * @param uids   an array of UIDs which the filtering rules will be set
819      * @throws RemoteException when netd has crashed.
820      * @throws ServiceSpecificException in case of failure, with an error code indicating the
821      *                                  cause of the failure.
822      */
addUidInterfaceRules(final String ifName, final int[] uids)823     public void addUidInterfaceRules(final String ifName, final int[] uids) throws RemoteException {
824         if (PRE_T) {
825             mNetd.firewallAddUidInterfaceRules(ifName, uids);
826             return;
827         }
828 
829         if (sEnableJavaBpfMap) {
830             // Null ifName is a wildcard to allow apps to receive packets on all interfaces and
831             // ifIndex is set to 0.
832             final int ifIndex;
833             if (ifName == null) {
834                 ifIndex = 0;
835             } else {
836                 ifIndex = mDeps.getIfIndex(ifName);
837                 if (ifIndex == 0) {
838                     throw new ServiceSpecificException(ENODEV,
839                             "Failed to get index of interface " + ifName);
840                 }
841             }
842             for (final int uid : uids) {
843                 try {
844                     addRule(uid, IIF_MATCH, ifIndex, "addUidInterfaceRules");
845                 } catch (ServiceSpecificException e) {
846                     Log.e(TAG, "addRule failed uid=" + uid + " ifName=" + ifName + ", " + e);
847                 }
848             }
849         } else {
850             final int err = native_addUidInterfaceRules(ifName, uids);
851             maybeThrow(err, "Unable to add uid interface rules");
852         }
853     }
854 
855     /**
856      * Remove ingress interface filtering rules from a list of UIDs
857      *
858      * Clear the ingress interface filtering rules from the list of UIDs which were previously set
859      * by addUidInterfaceRules(). Ignore any uid which does not have filtering rule.
860      *
861      * @param uids an array of UIDs from which the filtering rules will be removed
862      * @throws RemoteException when netd has crashed.
863      * @throws ServiceSpecificException in case of failure, with an error code indicating the
864      *                                  cause of the failure.
865      */
removeUidInterfaceRules(final int[] uids)866     public void removeUidInterfaceRules(final int[] uids) throws RemoteException {
867         if (PRE_T) {
868             mNetd.firewallRemoveUidInterfaceRules(uids);
869             return;
870         }
871 
872         if (sEnableJavaBpfMap) {
873             for (final int uid : uids) {
874                 try {
875                     removeRule(uid, IIF_MATCH, "removeUidInterfaceRules");
876                 } catch (ServiceSpecificException e) {
877                     Log.e(TAG, "removeRule failed uid=" + uid + ", " + e);
878                 }
879             }
880         } else {
881             final int err = native_removeUidInterfaceRules(uids);
882             maybeThrow(err, "Unable to remove uid interface rules");
883         }
884     }
885 
886     /**
887      * Update lockdown rule for uid
888      *
889      * @param  uid          target uid to add/remove the rule
890      * @param  add          {@code true} to add the rule, {@code false} to remove the rule.
891      * @throws ServiceSpecificException in case of failure, with an error code indicating the
892      *                                  cause of the failure.
893      */
updateUidLockdownRule(final int uid, final boolean add)894     public void updateUidLockdownRule(final int uid, final boolean add) {
895         throwIfPreT("updateUidLockdownRule is not available on pre-T devices");
896 
897         if (sEnableJavaBpfMap) {
898             if (add) {
899                 addRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
900             } else {
901                 removeRule(uid, LOCKDOWN_VPN_MATCH, "updateUidLockdownRule");
902             }
903         } else {
904             final int err = native_updateUidLockdownRule(uid, add);
905             maybeThrow(err, "Unable to update lockdown rule");
906         }
907     }
908 
909     /**
910      * Request netd to change the current active network stats map.
911      *
912      * @throws UnsupportedOperationException if called on pre-T devices.
913      * @throws ServiceSpecificException in case of failure, with an error code indicating the
914      *                                  cause of the failure.
915      */
swapActiveStatsMap()916     public void swapActiveStatsMap() {
917         throwIfPreT("swapActiveStatsMap is not available on pre-T devices");
918 
919         if (sEnableJavaBpfMap) {
920             try {
921                 synchronized (sCurrentStatsMapConfigLock) {
922                     final long config = sConfigurationMap.getValue(
923                             CURRENT_STATS_MAP_CONFIGURATION_KEY).val;
924                     final long newConfig = (config == STATS_SELECT_MAP_A)
925                             ? STATS_SELECT_MAP_B : STATS_SELECT_MAP_A;
926                     sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY,
927                             new U32(newConfig));
928                 }
929             } catch (ErrnoException e) {
930                 throw new ServiceSpecificException(e.errno, "Failed to swap active stats map");
931             }
932 
933             // After changing the config, it's needed to make sure all the current running eBPF
934             // programs are finished and all the CPUs are aware of this config change before the old
935             // map is modified. So special hack is needed here to wait for the kernel to do a
936             // synchronize_rcu(). Once the kernel called synchronize_rcu(), the updated config will
937             // be available to all cores and the next eBPF programs triggered inside the kernel will
938             // use the new map configuration. So once this function returns it is safe to modify the
939             // old stats map without concerning about race between the kernel and userspace.
940             final int err = mDeps.synchronizeKernelRCU();
941             maybeThrow(err, "synchronizeKernelRCU failed");
942         } else {
943             final int err = native_swapActiveStatsMap();
944             maybeThrow(err, "Unable to swap active stats map");
945         }
946     }
947 
948     /**
949      * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids
950      * specified. Or remove all permissions from the uids.
951      *
952      * @param permissions The permission to grant, it could be either PERMISSION_INTERNET and/or
953      *                    PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
954      *                    revoke all permissions for the uids.
955      * @param uids        uid of users to grant permission
956      * @throws RemoteException when netd has crashed.
957      */
setNetPermForUids(final int permissions, final int[] uids)958     public void setNetPermForUids(final int permissions, final int[] uids) throws RemoteException {
959         if (PRE_T) {
960             mNetd.trafficSetNetPermForUids(permissions, uids);
961             return;
962         }
963 
964         if (sEnableJavaBpfMap) {
965             // Remove the entry if package is uninstalled or uid has only INTERNET permission.
966             if (permissions == PERMISSION_UNINSTALLED || permissions == PERMISSION_INTERNET) {
967                 for (final int uid : uids) {
968                     try {
969                         sUidPermissionMap.deleteEntry(new S32(uid));
970                     } catch (ErrnoException e) {
971                         Log.e(TAG, "Failed to remove uid " + uid + " from permission map: " + e);
972                     }
973                 }
974                 return;
975             }
976 
977             for (final int uid : uids) {
978                 try {
979                     sUidPermissionMap.updateEntry(new S32(uid), new U8((short) permissions));
980                 } catch (ErrnoException e) {
981                     Log.e(TAG, "Failed to set permission "
982                             + permissions + " to uid " + uid + ": " + e);
983                 }
984             }
985         } else {
986             native_setPermissionForUids(permissions, uids);
987         }
988     }
989 
990     /** Register callback for statsd to pull atom. */
setPullAtomCallback(final Context context)991     public void setPullAtomCallback(final Context context) {
992         throwIfPreT("setPullAtomCallback is not available on pre-T devices");
993 
994         final StatsManager statsManager = context.getSystemService(StatsManager.class);
995         statsManager.setPullAtomCallback(NETWORK_BPF_MAP_INFO, null /* metadata */,
996                 BackgroundThread.getExecutor(), this::pullBpfMapInfoAtom);
997     }
998 
getMapSize(IBpfMap<K, V> map)999     private <K extends Struct, V extends Struct> int getMapSize(IBpfMap<K, V> map)
1000             throws ErrnoException {
1001         // forEach could restart iteration from the beginning if there is a concurrent entry
1002         // deletion. netd and skDestroyListener could delete CookieTagMap entry concurrently.
1003         // So using Set to count the number of entry in the map.
1004         Set<K> keySet = new ArraySet<>();
1005         map.forEach((k, v) -> keySet.add(k));
1006         return keySet.size();
1007     }
1008 
1009     /** Callback for StatsManager#setPullAtomCallback */
1010     @VisibleForTesting
pullBpfMapInfoAtom(final int atomTag, final List<StatsEvent> data)1011     public int pullBpfMapInfoAtom(final int atomTag, final List<StatsEvent> data) {
1012         if (atomTag != NETWORK_BPF_MAP_INFO) {
1013             Log.e(TAG, "Unexpected atom tag: " + atomTag);
1014             return StatsManager.PULL_SKIP;
1015         }
1016 
1017         try {
1018             data.add(mDeps.buildStatsEvent(getMapSize(sCookieTagMap), getMapSize(sUidOwnerMap),
1019                     getMapSize(sUidPermissionMap)));
1020         } catch (ErrnoException e) {
1021             Log.e(TAG, "Failed to pull NETWORK_BPF_MAP_INFO atom: " + e);
1022             return StatsManager.PULL_SKIP;
1023         }
1024         return StatsManager.PULL_SUCCESS;
1025     }
1026 
permissionToString(int permissionMask)1027     private String permissionToString(int permissionMask) {
1028         if (permissionMask == PERMISSION_NONE) {
1029             return "PERMISSION_NONE";
1030         }
1031         if (permissionMask == PERMISSION_UNINSTALLED) {
1032             // PERMISSION_UNINSTALLED should never appear in the map
1033             return "PERMISSION_UNINSTALLED error!";
1034         }
1035 
1036         final StringJoiner sj = new StringJoiner(" ");
1037         for (Pair<Integer, String> permission: PERMISSION_LIST) {
1038             final int permissionFlag = permission.first;
1039             final String permissionName = permission.second;
1040             if ((permissionMask & permissionFlag) != 0) {
1041                 sj.add(permissionName);
1042                 permissionMask &= ~permissionFlag;
1043             }
1044         }
1045         if (permissionMask != 0) {
1046             sj.add("PERMISSION_UNKNOWN(" + permissionMask + ")");
1047         }
1048         return sj.toString();
1049     }
1050 
matchToString(long matchMask)1051     private String matchToString(long matchMask) {
1052         if (matchMask == NO_MATCH) {
1053             return "NO_MATCH";
1054         }
1055 
1056         final StringJoiner sj = new StringJoiner(" ");
1057         for (Pair<Long, String> match: MATCH_LIST) {
1058             final long matchFlag = match.first;
1059             final String matchName = match.second;
1060             if ((matchMask & matchFlag) != 0) {
1061                 sj.add(matchName);
1062                 matchMask &= ~matchFlag;
1063             }
1064         }
1065         if (matchMask != 0) {
1066             sj.add("UNKNOWN_MATCH(" + matchMask + ")");
1067         }
1068         return sj.toString();
1069     }
1070 
dumpOwnerMatchConfig(final IndentingPrintWriter pw)1071     private void dumpOwnerMatchConfig(final IndentingPrintWriter pw) {
1072         try {
1073             final long match = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
1074             pw.println("current ownerMatch configuration: " + match + " " + matchToString(match));
1075         } catch (ErrnoException e) {
1076             pw.println("Failed to read ownerMatch configuration: " + e);
1077         }
1078     }
1079 
dumpCurrentStatsMapConfig(final IndentingPrintWriter pw)1080     private void dumpCurrentStatsMapConfig(final IndentingPrintWriter pw) {
1081         try {
1082             final long config = sConfigurationMap.getValue(CURRENT_STATS_MAP_CONFIGURATION_KEY).val;
1083             final String currentStatsMap =
1084                     (config == STATS_SELECT_MAP_A) ? "SELECT_MAP_A" : "SELECT_MAP_B";
1085             pw.println("current statsMap configuration: " + config + " " + currentStatsMap);
1086         } catch (ErrnoException e) {
1087             pw.println("Falied to read current statsMap configuration: " + e);
1088         }
1089     }
1090 
1091     /**
1092      * Dump BPF maps
1093      *
1094      * @param pw print writer
1095      * @param fd file descriptor to output
1096      * @param verbose verbose dump flag, if true dump the BpfMap contents
1097      * @throws IOException when file descriptor is invalid.
1098      * @throws ServiceSpecificException when the method is called on an unsupported device.
1099      */
dump(final IndentingPrintWriter pw, final FileDescriptor fd, boolean verbose)1100     public void dump(final IndentingPrintWriter pw, final FileDescriptor fd, boolean verbose)
1101             throws IOException, ServiceSpecificException {
1102         if (PRE_T) {
1103             throw new ServiceSpecificException(
1104                     EOPNOTSUPP, "dumpsys connectivity trafficcontroller dump not available on pre-T"
1105                     + " devices, use dumpsys netd trafficcontroller instead.");
1106         }
1107         mDeps.nativeDump(fd, verbose);
1108 
1109         pw.println();
1110         pw.println("sEnableJavaBpfMap: " + sEnableJavaBpfMap);
1111         if (verbose) {
1112             pw.println();
1113             pw.println("BPF map content:");
1114             pw.increaseIndent();
1115 
1116             dumpOwnerMatchConfig(pw);
1117             dumpCurrentStatsMapConfig(pw);
1118             pw.println();
1119 
1120             // TODO: Remove CookieTagMap content dump
1121             // NetworkStatsService also dumps CookieTagMap and NetworkStatsService is a right place
1122             // to dump CookieTagMap. But the TagSocketTest in CTS depends on this dump so the tests
1123             // need to be updated before remove the dump from BpfNetMaps.
1124             BpfDump.dumpMap(sCookieTagMap, pw, "sCookieTagMap",
1125                     (key, value) -> "cookie=" + key.socketCookie
1126                             + " tag=0x" + Long.toHexString(value.tag)
1127                             + " uid=" + value.uid);
1128             BpfDump.dumpMap(sUidOwnerMap, pw, "sUidOwnerMap",
1129                     (uid, match) -> {
1130                         if ((match.rule & IIF_MATCH) != 0) {
1131                             // TODO: convert interface index to interface name by IfaceIndexNameMap
1132                             return uid.val + " " + matchToString(match.rule) + " " + match.iif;
1133                         } else {
1134                             return uid.val + " " + matchToString(match.rule);
1135                         }
1136                     });
1137             BpfDump.dumpMap(sUidPermissionMap, pw, "sUidPermissionMap",
1138                     (uid, permission) -> uid.val + " " + permissionToString(permission.val));
1139             pw.decreaseIndent();
1140         }
1141     }
1142 
native_init(boolean startSkDestroyListener)1143     private static native void native_init(boolean startSkDestroyListener);
native_addNaughtyApp(int uid)1144     private native int native_addNaughtyApp(int uid);
native_removeNaughtyApp(int uid)1145     private native int native_removeNaughtyApp(int uid);
native_addNiceApp(int uid)1146     private native int native_addNiceApp(int uid);
native_removeNiceApp(int uid)1147     private native int native_removeNiceApp(int uid);
native_setChildChain(int childChain, boolean enable)1148     private native int native_setChildChain(int childChain, boolean enable);
native_replaceUidChain(String name, boolean isAllowlist, int[] uids)1149     private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids);
native_setUidRule(int childChain, int uid, int firewallRule)1150     private native int native_setUidRule(int childChain, int uid, int firewallRule);
native_addUidInterfaceRules(String ifName, int[] uids)1151     private native int native_addUidInterfaceRules(String ifName, int[] uids);
native_removeUidInterfaceRules(int[] uids)1152     private native int native_removeUidInterfaceRules(int[] uids);
native_updateUidLockdownRule(int uid, boolean add)1153     private native int native_updateUidLockdownRule(int uid, boolean add);
native_swapActiveStatsMap()1154     private native int native_swapActiveStatsMap();
native_setPermissionForUids(int permissions, int[] uids)1155     private native void native_setPermissionForUids(int permissions, int[] uids);
native_dump(FileDescriptor fd, boolean verbose)1156     private static native void native_dump(FileDescriptor fd, boolean verbose);
native_synchronizeKernelRCU()1157     private static native int native_synchronizeKernelRCU();
1158 }
1159