OSDN Git Service

Merge "Fix MediaCodec FLAC Javadoc" into oc-mr1-dev am: 546c644f27 am: af521c4ced
[android-x86/frameworks-base.git] / services / core / java / com / android / server / connectivity / PermissionMonitor.java
1 /*
2  * Copyright (C) 2014 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.connectivity;
18
19 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
20 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
21 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
22 import static android.Manifest.permission.INTERNET;
23 import static android.Manifest.permission.NETWORK_STACK;
24 import static android.Manifest.permission.UPDATE_DEVICE_STATS;
25 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
26 import static android.content.pm.PackageManager.GET_PERMISSIONS;
27 import static android.content.pm.PackageManager.MATCH_ANY_USER;
28 import static android.os.Process.INVALID_UID;
29 import static android.os.Process.SYSTEM_UID;
30
31 import android.annotation.NonNull;
32 import android.content.Context;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.PackageInfo;
35 import android.content.pm.PackageManager;
36 import android.content.pm.PackageManager.NameNotFoundException;
37 import android.content.pm.PackageManagerInternal;
38 import android.content.pm.UserInfo;
39 import android.net.INetd;
40 import android.net.UidRange;
41 import android.os.Build;
42 import android.os.RemoteException;
43 import android.os.ServiceSpecificException;
44 import android.os.UserHandle;
45 import android.os.UserManager;
46 import android.system.OsConstants;
47 import android.util.ArraySet;
48 import android.util.Log;
49 import android.util.SparseArray;
50 import android.util.SparseIntArray;
51
52 import com.android.internal.annotations.GuardedBy;
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.util.ArrayUtils;
55 import com.android.internal.util.IndentingPrintWriter;
56 import com.android.server.LocalServices;
57 import com.android.server.SystemConfig;
58
59 import java.util.ArrayList;
60 import java.util.Collection;
61 import java.util.HashMap;
62 import java.util.HashSet;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Map.Entry;
66 import java.util.Set;
67
68
69 /**
70  * A utility class to inform Netd of UID permisisons.
71  * Does a mass update at boot and then monitors for app install/remove.
72  *
73  * @hide
74  */
75 public class PermissionMonitor {
76     private static final String TAG = "PermissionMonitor";
77     private static final boolean DBG = true;
78     protected static final Boolean SYSTEM = Boolean.TRUE;
79     protected static final Boolean NETWORK = Boolean.FALSE;
80     private static final int VERSION_Q = Build.VERSION_CODES.Q;
81
82     private final PackageManager mPackageManager;
83     private final UserManager mUserManager;
84     private final INetd mNetd;
85
86     // Values are User IDs.
87     @GuardedBy("this")
88     private final Set<Integer> mUsers = new HashSet<>();
89
90     // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
91     @GuardedBy("this")
92     private final Map<Integer, Boolean> mApps = new HashMap<>();
93
94     // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
95     // for apps under the VPN
96     @GuardedBy("this")
97     private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>();
98
99     // A set of appIds for apps across all users on the device. We track appIds instead of uids
100     // directly to reduce its size and also eliminate the need to update this set when user is
101     // added/removed.
102     @GuardedBy("this")
103     private final Set<Integer> mAllApps = new HashSet<>();
104
105     private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
106
107         private int getPermissionForUid(int uid) {
108             int permission = 0;
109             // Check all the packages for this UID. The UID has the permission if any of the
110             // packages in it has the permission.
111             String[] packages = mPackageManager.getPackagesForUid(uid);
112             if (packages != null && packages.length > 0) {
113                 for (String name : packages) {
114                     final PackageInfo app = getPackageInfo(name);
115                     if (app != null && app.requestedPermissions != null) {
116                         permission |= getNetdPermissionMask(app.requestedPermissions,
117                               app.requestedPermissionsFlags);
118                     }
119                 }
120             } else {
121                 // The last package of this uid is removed from device. Clean the package up.
122                 permission = INetd.PERMISSION_UNINSTALLED;
123             }
124             return permission;
125         }
126
127         @Override
128         public void onPackageAdded(String packageName, int uid) {
129             sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
130         }
131
132         @Override
133         public void onPackageRemoved(String packageName, int uid) {
134             sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
135         }
136     }
137
138     public PermissionMonitor(Context context, INetd netd) {
139         mPackageManager = context.getPackageManager();
140         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
141         mNetd = netd;
142     }
143
144     // Intended to be called only once at startup, after the system is ready. Installs a broadcast
145     // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
146     public synchronized void startMonitoring() {
147         log("Monitoring");
148
149         PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
150         if (pmi != null) {
151             pmi.getPackageList(new PackageListObserver());
152         } else {
153             loge("failed to get the PackageManagerInternal service");
154         }
155         List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
156                 | MATCH_ANY_USER);
157         if (apps == null) {
158             loge("No apps");
159             return;
160         }
161
162         SparseIntArray netdPermsUids = new SparseIntArray();
163
164         for (PackageInfo app : apps) {
165             int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
166             if (uid < 0) {
167                 continue;
168             }
169             mAllApps.add(UserHandle.getAppId(uid));
170
171             boolean isNetwork = hasNetworkPermission(app);
172             boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
173
174             if (isNetwork || hasRestrictedPermission) {
175                 Boolean permission = mApps.get(uid);
176                 // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
177                 // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
178                 if (permission == null || permission == NETWORK) {
179                     mApps.put(uid, hasRestrictedPermission);
180                 }
181             }
182
183             //TODO: unify the management of the permissions into one codepath.
184             int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
185                     app.requestedPermissionsFlags);
186             netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
187         }
188
189         List<UserInfo> users = mUserManager.getUsers(true);  // exclude dying users
190         if (users != null) {
191             for (UserInfo user : users) {
192                 mUsers.add(user.id);
193             }
194         }
195
196         final SparseArray<ArraySet<String>> systemPermission =
197                 SystemConfig.getInstance().getSystemPermissions();
198         for (int i = 0; i < systemPermission.size(); i++) {
199             ArraySet<String> perms = systemPermission.valueAt(i);
200             int uid = systemPermission.keyAt(i);
201             int netdPermission = 0;
202             // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
203             if (perms != null) {
204                 netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
205                         ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
206                 netdPermission |= perms.contains(INTERNET)
207                         ? INetd.PERMISSION_INTERNET : 0;
208             }
209             netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
210         }
211         log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
212         update(mUsers, mApps, true);
213         sendPackagePermissionsToNetd(netdPermsUids);
214     }
215
216     @VisibleForTesting
217     static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
218         return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
219     }
220
221     @VisibleForTesting
222     protected int getDeviceFirstSdkInt() {
223         return Build.VERSION.FIRST_SDK_INT;
224     }
225
226     @VisibleForTesting
227     boolean hasPermission(PackageInfo app, String permission) {
228         if (app.requestedPermissions != null) {
229             for (String p : app.requestedPermissions) {
230                 if (permission.equals(p)) {
231                     return true;
232                 }
233             }
234         }
235         return false;
236     }
237
238     private boolean hasNetworkPermission(PackageInfo app) {
239         return hasPermission(app, CHANGE_NETWORK_STATE);
240     }
241
242     private boolean hasRestrictedNetworkPermission(PackageInfo app) {
243         // TODO : remove this check in the future(b/31479477). All apps should just
244         // request the appropriate permission for their use case since android Q.
245         if (app.applicationInfo != null) {
246             // Backward compatibility for b/114245686, on devices that launched before Q daemons
247             // and apps running as the system UID are exempted from this check.
248             if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) {
249                 return true;
250             }
251
252             if (app.applicationInfo.targetSdkVersion < VERSION_Q
253                     && isVendorApp(app.applicationInfo)) {
254                 return true;
255             }
256         }
257         return hasPermission(app, CONNECTIVITY_INTERNAL)
258                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
259     }
260
261     private boolean hasUseBackgroundNetworksPermission(PackageInfo app) {
262         // This function defines what it means to hold the permission to use
263         // background networks.
264         return hasPermission(app, CHANGE_NETWORK_STATE)
265                 || hasPermission(app, NETWORK_STACK)
266                 || hasRestrictedNetworkPermission(app);
267     }
268
269     public boolean hasUseBackgroundNetworksPermission(int uid) {
270         final String[] names = mPackageManager.getPackagesForUid(uid);
271         if (null == names || names.length == 0) return false;
272         try {
273             // Only using the first package name. There may be multiple names if multiple
274             // apps share the same UID, but in that case they also share permissions so
275             // querying with any of the names will return the same results.
276             int userId = UserHandle.getUserId(uid);
277             final PackageInfo app = mPackageManager.getPackageInfoAsUser(
278                     names[0], GET_PERMISSIONS, userId);
279             return hasUseBackgroundNetworksPermission(app);
280         } catch (NameNotFoundException e) {
281             // App not found.
282             loge("NameNotFoundException " + names[0], e);
283             return false;
284         }
285     }
286
287     private int[] toIntArray(Collection<Integer> list) {
288         int[] array = new int[list.size()];
289         int i = 0;
290         for (Integer item : list) {
291             array[i++] = item;
292         }
293         return array;
294     }
295
296     private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
297         List<Integer> network = new ArrayList<>();
298         List<Integer> system = new ArrayList<>();
299         for (Entry<Integer, Boolean> app : apps.entrySet()) {
300             List<Integer> list = app.getValue() ? system : network;
301             for (int user : users) {
302                 list.add(UserHandle.getUid(user, app.getKey()));
303             }
304         }
305         try {
306             if (add) {
307                 mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
308                 mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
309             } else {
310                 mNetd.networkClearPermissionForUser(toIntArray(network));
311                 mNetd.networkClearPermissionForUser(toIntArray(system));
312             }
313         } catch (RemoteException e) {
314             loge("Exception when updating permissions: " + e);
315         }
316     }
317
318     /**
319      * Called when a user is added. See {link #ACTION_USER_ADDED}.
320      *
321      * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
322      *
323      * @hide
324      */
325     public synchronized void onUserAdded(int user) {
326         if (user < 0) {
327             loge("Invalid user in onUserAdded: " + user);
328             return;
329         }
330         mUsers.add(user);
331
332         Set<Integer> users = new HashSet<>();
333         users.add(user);
334         update(users, mApps, true);
335     }
336
337     /**
338      * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
339      *
340      * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
341      *
342      * @hide
343      */
344     public synchronized void onUserRemoved(int user) {
345         if (user < 0) {
346             loge("Invalid user in onUserRemoved: " + user);
347             return;
348         }
349         mUsers.remove(user);
350
351         Set<Integer> users = new HashSet<>();
352         users.add(user);
353         update(users, mApps, false);
354     }
355
356     @VisibleForTesting
357     protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
358         if (currentPermission == SYSTEM) {
359             return currentPermission;
360         }
361         try {
362             final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
363             final boolean isNetwork = hasNetworkPermission(app);
364             final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
365             if (isNetwork || hasRestrictedPermission) {
366                 currentPermission = hasRestrictedPermission;
367             }
368         } catch (NameNotFoundException e) {
369             // App not found.
370             loge("NameNotFoundException " + name);
371         }
372         return currentPermission;
373     }
374
375     /**
376      * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}.
377      *
378      * @param packageName The name of the new package.
379      * @param uid The uid of the new package.
380      *
381      * @hide
382      */
383     public synchronized void onPackageAdded(String packageName, int uid) {
384         // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
385         // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
386         final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
387         if (permission != mApps.get(uid)) {
388             mApps.put(uid, permission);
389
390             Map<Integer, Boolean> apps = new HashMap<>();
391             apps.put(uid, permission);
392             update(mUsers, apps, true);
393         }
394
395         // If the newly-installed package falls within some VPN's uid range, update Netd with it.
396         // This needs to happen after the mApps update above, since removeBypassingUids() depends
397         // on mApps to check if the package can bypass VPN.
398         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
399             if (UidRange.containsUid(vpn.getValue(), uid)) {
400                 final Set<Integer> changedUids = new HashSet<>();
401                 changedUids.add(uid);
402                 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
403                 updateVpnUids(vpn.getKey(), changedUids, true);
404             }
405         }
406         mAllApps.add(UserHandle.getAppId(uid));
407     }
408
409     /**
410      * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}.
411      *
412      * @param uid containing the integer uid previously assigned to the package.
413      *
414      * @hide
415      */
416     public synchronized void onPackageRemoved(int uid) {
417         // If the newly-removed package falls within some VPN's uid range, update Netd with it.
418         // This needs to happen before the mApps update below, since removeBypassingUids() depends
419         // on mApps to check if the package can bypass VPN.
420         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
421             if (UidRange.containsUid(vpn.getValue(), uid)) {
422                 final Set<Integer> changedUids = new HashSet<>();
423                 changedUids.add(uid);
424                 removeBypassingUids(changedUids, /* vpnAppUid */ -1);
425                 updateVpnUids(vpn.getKey(), changedUids, false);
426             }
427         }
428         // If the package has been removed from all users on the device, clear it form mAllApps.
429         if (mPackageManager.getNameForUid(uid) == null) {
430             mAllApps.remove(UserHandle.getAppId(uid));
431         }
432
433         Map<Integer, Boolean> apps = new HashMap<>();
434         Boolean permission = null;
435         String[] packages = mPackageManager.getPackagesForUid(uid);
436         if (packages != null && packages.length > 0) {
437             for (String name : packages) {
438                 permission = highestPermissionForUid(permission, name);
439                 if (permission == SYSTEM) {
440                     // An app with this UID still has the SYSTEM permission.
441                     // Therefore, this UID must already have the SYSTEM permission.
442                     // Nothing to do.
443                     return;
444                 }
445             }
446         }
447         if (permission == mApps.get(uid)) {
448             // The permissions of this UID have not changed. Nothing to do.
449             return;
450         } else if (permission != null) {
451             mApps.put(uid, permission);
452             apps.put(uid, permission);
453             update(mUsers, apps, true);
454         } else {
455             mApps.remove(uid);
456             apps.put(uid, NETWORK);  // doesn't matter which permission we pick here
457             update(mUsers, apps, false);
458         }
459     }
460
461     private static int getNetdPermissionMask(String[] requestedPermissions,
462                                              int[] requestedPermissionsFlags) {
463         int permissions = 0;
464         if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
465         for (int i = 0; i < requestedPermissions.length; i++) {
466             if (requestedPermissions[i].equals(INTERNET)
467                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
468                 permissions |= INetd.PERMISSION_INTERNET;
469             }
470             if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
471                     && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
472                 permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
473             }
474         }
475         return permissions;
476     }
477
478     private PackageInfo getPackageInfo(String packageName) {
479         try {
480             PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
481                     | MATCH_ANY_USER);
482             return app;
483         } catch (NameNotFoundException e) {
484             return null;
485         }
486     }
487
488     /**
489      * Called when a new set of UID ranges are added to an active VPN network
490      *
491      * @param iface The active VPN network's interface name
492      * @param rangesToAdd The new UID ranges to be added to the network
493      * @param vpnAppUid The uid of the VPN app
494      */
495     public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd,
496             int vpnAppUid) {
497         // Calculate the list of new app uids under the VPN due to the new UID ranges and update
498         // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
499         // be an overestimation if an app is not installed on the user on which the VPN is running,
500         // but that's safe.
501         final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
502         removeBypassingUids(changedUids, vpnAppUid);
503         updateVpnUids(iface, changedUids, true);
504         if (mVpnUidRanges.containsKey(iface)) {
505             mVpnUidRanges.get(iface).addAll(rangesToAdd);
506         } else {
507             mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
508         }
509     }
510
511     /**
512      * Called when a set of UID ranges are removed from an active VPN network
513      *
514      * @param iface The VPN network's interface name
515      * @param rangesToRemove Existing UID ranges to be removed from the VPN network
516      * @param vpnAppUid The uid of the VPN app
517      */
518     public synchronized void onVpnUidRangesRemoved(@NonNull String iface,
519             Set<UidRange> rangesToRemove, int vpnAppUid) {
520         // Calculate the list of app uids that are no longer under the VPN due to the removed UID
521         // ranges and update Netd about them.
522         final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
523         removeBypassingUids(changedUids, vpnAppUid);
524         updateVpnUids(iface, changedUids, false);
525         Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
526         if (existingRanges == null) {
527             loge("Attempt to remove unknown vpn uid Range iface = " + iface);
528             return;
529         }
530         existingRanges.removeAll(rangesToRemove);
531         if (existingRanges.size() == 0) {
532             mVpnUidRanges.remove(iface);
533         }
534     }
535
536     /**
537      * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
538      * that satisfies:
539      *   1. falls into one of the UidRange
540      *   2. matches one of the appIds
541      */
542     private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
543         Set<Integer> result = new HashSet<>();
544         for (UidRange range : ranges) {
545             for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
546                 for (int appId : appIds) {
547                     final int uid = UserHandle.getUid(userId, appId);
548                     if (range.contains(uid)) {
549                         result.add(uid);
550                     }
551                 }
552             }
553         }
554         return result;
555     }
556
557     /**
558      * Remove all apps which can elect to bypass the VPN from the list of uids
559      *
560      * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
561      * app itself.
562      *
563      * @param uids The list of uids to operate on
564      * @param vpnAppUid The uid of the VPN app
565      */
566     private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
567         uids.remove(vpnAppUid);
568         uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM);
569     }
570
571     /**
572      * Update netd about the list of uids that are under an active VPN connection which they cannot
573      * bypass.
574      *
575      * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
576      * can only receive ingress packets from the VPN's tunnel interface (and loopback).
577      *
578      * @param iface the interface name of the active VPN connection
579      * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
580      *        are to be removed from the interface.
581      */
582     private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
583         if (uids.size() == 0) {
584             return;
585         }
586         try {
587             if (add) {
588                 mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids));
589             } else {
590                 mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids));
591             }
592         } catch (ServiceSpecificException e) {
593             // Silently ignore exception when device does not support eBPF, otherwise just log
594             // the exception and do not crash
595             if (e.errorCode != OsConstants.EOPNOTSUPP) {
596                 loge("Exception when updating permissions: ", e);
597             }
598         } catch (RemoteException e) {
599             loge("Exception when updating permissions: ", e);
600         }
601     }
602
603     /**
604      * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
605      * permission information to netd.
606      *
607      * @param uid the app uid of the package installed
608      * @param permissions the permissions the app requested and netd cares about.
609      *
610      * @hide
611      */
612     @VisibleForTesting
613     void sendPackagePermissionsForUid(int uid, int permissions) {
614         SparseIntArray netdPermissionsAppIds = new SparseIntArray();
615         netdPermissionsAppIds.put(uid, permissions);
616         sendPackagePermissionsToNetd(netdPermissionsAppIds);
617     }
618
619     /**
620      * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
621      * and/or UPDATE_DEVICE_STATS permission of the uids in array.
622      *
623      * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
624      * permission is 0, revoke all permissions of that uid.
625      *
626      * @hide
627      */
628     @VisibleForTesting
629     void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
630         if (mNetd == null) {
631             Log.e(TAG, "Failed to get the netd service");
632             return;
633         }
634         ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
635         ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
636         ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
637         ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
638         ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
639         for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
640             int permissions = netdPermissionsAppIds.valueAt(i);
641             switch(permissions) {
642                 case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
643                     allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
644                     break;
645                 case INetd.PERMISSION_INTERNET:
646                     internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
647                     break;
648                 case INetd.PERMISSION_UPDATE_DEVICE_STATS:
649                     updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
650                     break;
651                 case INetd.PERMISSION_NONE:
652                     noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
653                     break;
654                 case INetd.PERMISSION_UNINSTALLED:
655                     uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
656                 default:
657                     Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
658                             + netdPermissionsAppIds.keyAt(i));
659             }
660         }
661         try {
662             // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
663             if (allPermissionAppIds.size() != 0) {
664                 mNetd.trafficSetNetPermForUids(
665                         INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
666                         ArrayUtils.convertToIntArray(allPermissionAppIds));
667             }
668             if (internetPermissionAppIds.size() != 0) {
669                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
670                         ArrayUtils.convertToIntArray(internetPermissionAppIds));
671             }
672             if (updateStatsPermissionAppIds.size() != 0) {
673                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
674                         ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
675             }
676             if (noPermissionAppIds.size() != 0) {
677                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
678                         ArrayUtils.convertToIntArray(noPermissionAppIds));
679             }
680             if (uninstalledAppIds.size() != 0) {
681                 mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
682                         ArrayUtils.convertToIntArray(uninstalledAppIds));
683             }
684         } catch (RemoteException e) {
685             Log.e(TAG, "Pass appId list of special permission failed." + e);
686         }
687     }
688
689     /** Should only be used by unit tests */
690     @VisibleForTesting
691     public Set<UidRange> getVpnUidRanges(String iface) {
692         return mVpnUidRanges.get(iface);
693     }
694
695     /** Dump info to dumpsys */
696     public void dump(IndentingPrintWriter pw) {
697         pw.println("Interface filtering rules:");
698         pw.increaseIndent();
699         for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
700             pw.println("Interface: " + vpn.getKey());
701             pw.println("UIDs: " + vpn.getValue().toString());
702             pw.println();
703         }
704         pw.decreaseIndent();
705     }
706
707     private static void log(String s) {
708         if (DBG) {
709             Log.d(TAG, s);
710         }
711     }
712
713     private static void loge(String s) {
714         Log.e(TAG, s);
715     }
716
717     private static void loge(String s, Throwable e) {
718         Log.e(TAG, s, e);
719     }
720 }