[RFPM05] Add UidNetdPermissionInfo class
Add UidNetdPermissionInfo class to store netd permission info of
each uid. Use the bit mask for combining all netd permission into
one value which can update and get the uid permission easily.
Moreover, aosp/1340042 add carryover package info into this class
which centralizes all netd permissions relevant data.
Bug: 132784544
Test: atest FrameworksNetTests
Change-Id: I3b81ea2a5017e8f4d0d603144a33c9b08640d7ba
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 7202f0f..7f9b3c9 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -56,7 +56,6 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -130,7 +129,42 @@
}
}
- public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
+ /**
+ * A data class to store each uid Netd permission information. Netd permissions includes
+ * PERMISSION_NETWORK, PERMISSION_SYSTEM, PERMISSION_INTERNET, PERMISSION_UPDATE_DEVICE_STATS
+ * and OR'd with the others. Default permission is PERMISSION_NONE and PERMISSION_UNINSTALLED
+ * will be set if all packages are removed from the uid.
+ */
+ public static class UidNetdPermissionInfo {
+ private final int mNetdPermissions;
+
+ UidNetdPermissionInfo() {
+ this(PERMISSION_NONE);
+ }
+
+ UidNetdPermissionInfo(int permissions) {
+ mNetdPermissions = permissions;
+ }
+
+ /** Plus given permissions and return new UidNetdPermissionInfo instance. */
+ public UidNetdPermissionInfo plusNetdPermissions(int permissions) {
+ return new UidNetdPermissionInfo(mNetdPermissions | permissions);
+ }
+
+ /** Return whether package is uninstalled. */
+ public boolean isPackageUninstalled() {
+ return mNetdPermissions == PERMISSION_UNINSTALLED;
+ }
+
+ /** Check that uid has given permissions */
+ public boolean hasNetdPermissions(final int permissions) {
+ if (isPackageUninstalled()) return false;
+ if (permissions == PERMISSION_NONE) return true;
+ return (mNetdPermissions & permissions) == permissions;
+ }
+ }
+
+ public PermissionMonitor(Context context, INetd netd) {
this(context, netd, new Dependencies());
}
@@ -161,7 +195,7 @@
return;
}
- SparseIntArray netdPermsUids = new SparseIntArray();
+ final SparseArray<UidNetdPermissionInfo> netdPermsUids = new SparseArray<>();
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
@@ -183,9 +217,13 @@
}
}
+ // Skip already checked uid.
+ if (netdPermsUids.get(uid) != null) continue;
+
//TODO: unify the management of the permissions into one codepath.
- final int otherNetdPerms = getNetdPermissionMask(uid);
- netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
+ final UidNetdPermissionInfo permInfo =
+ new UidNetdPermissionInfo(getNetdPermissionMask(uid));
+ netdPermsUids.put(uid, permInfo);
}
List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
@@ -207,7 +245,10 @@
? PERMISSION_UPDATE_DEVICE_STATS : 0;
netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0;
}
- netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
+ final UidNetdPermissionInfo permInfo = netdPermsUids.get(uid);
+ netdPermsUids.put(uid, permInfo != null
+ ? permInfo.plusNetdPermissions(netdPermission)
+ : new UidNetdPermissionInfo(netdPermission));
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
@@ -341,15 +382,15 @@
return currentPermission;
}
- private int getPermissionForUid(final int uid) {
+ private UidNetdPermissionInfo getPermissionForUid(final int uid) {
// Check all the packages for this UID. The UID has the permission if any of the
// packages in it has the permission.
final String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages == null || packages.length <= 0) {
// The last package of this uid is removed from device. Clean the package up.
- return PERMISSION_UNINSTALLED;
+ return new UidNetdPermissionInfo(PERMISSION_UNINSTALLED);
}
- return getNetdPermissionMask(uid);
+ return new UidNetdPermissionInfo(getNetdPermissionMask(uid));
}
/**
@@ -599,28 +640,28 @@
* permission information to netd.
*
* @param uid the app uid of the package installed
- * @param permissions the permissions the app requested and netd cares about.
+ * @param permissionInfo the permission info of given uid.
*
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsForUid(int uid, int permissions) {
- SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(uid, permissions);
- sendPackagePermissionsToNetd(netdPermissionsAppIds);
+ void sendPackagePermissionsForUid(int uid, UidNetdPermissionInfo permissionInfo) {
+ final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>();
+ uidsPermInfo.put(uid, permissionInfo);
+ sendPackagePermissionsToNetd(uidsPermInfo);
}
/**
* Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
* and/or UPDATE_DEVICE_STATS permission of the uids in array.
*
- * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
- * permission is 0, revoke all permissions of that uid.
- *
+ * @param uidsPermInfo permission info array generated from each uid. If the uid permission is
+ * PERMISSION_NONE or PERMISSION_UNINSTALLED, revoke all permissions of that
+ * uid.
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
+ void sendPackagePermissionsToNetd(final SparseArray<UidNetdPermissionInfo> uidsPermInfo) {
if (mNetd == null) {
Log.e(TAG, "Failed to get the netd service");
return;
@@ -630,26 +671,20 @@
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
- for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
- int permissions = netdPermissionsAppIds.valueAt(i);
- switch(permissions) {
- case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS):
- allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case PERMISSION_INTERNET:
- internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case PERMISSION_UPDATE_DEVICE_STATS:
- updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case PERMISSION_NONE:
- noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case PERMISSION_UNINSTALLED:
- uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
- default:
- Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
- + netdPermissionsAppIds.keyAt(i));
+ for (int i = 0; i < uidsPermInfo.size(); i++) {
+ final int uid = uidsPermInfo.keyAt(i);
+ final UidNetdPermissionInfo permInfo = uidsPermInfo.valueAt(i);
+ if (permInfo.hasNetdPermissions(
+ PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)) {
+ allPermissionAppIds.add(uid);
+ } else if (permInfo.hasNetdPermissions(PERMISSION_INTERNET)) {
+ internetPermissionAppIds.add(uid);
+ } else if (permInfo.hasNetdPermissions(PERMISSION_UPDATE_DEVICE_STATS)) {
+ updateStatsPermissionAppIds.add(uid);
+ } else if (permInfo.isPackageUninstalled()) {
+ uninstalledAppIds.add(uid);
+ } else {
+ noPermissionAppIds.add(uid);
}
}
try {
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 79343de..912460a 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -28,11 +28,17 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NONE;
+import static android.net.INetd.PERMISSION_SYSTEM;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
+import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
+import static com.android.server.connectivity.PermissionMonitor.UidNetdPermissionInfo;
import static junit.framework.Assert.fail;
@@ -64,7 +70,7 @@
import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -312,7 +318,7 @@
// Add hook to verify and track result of setPermission.
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
+ final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM);
for (final int uid : (int[]) args[1]) {
// TODO: Currently, permission monitor will send duplicate commands for each uid
// corresponding to each user. Need to fix that and uncomment below test.
@@ -555,39 +561,40 @@
// SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
// SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
- SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
- netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
- netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>();
+ uidsPermInfo.put(MOCK_UID1, new UidNetdPermissionInfo(PERMISSION_INTERNET));
+ uidsPermInfo.put(MOCK_UID2, new UidNetdPermissionInfo(PERMISSION_NONE));
+ uidsPermInfo.put(SYSTEM_UID1, new UidNetdPermissionInfo(
+ PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS));
+ uidsPermInfo.put(SYSTEM_UID2, new UidNetdPermissionInfo(PERMISSION_UPDATE_DEVICE_STATS));
// Send the permission information to netd, expect permission updated.
- mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
+ mPermissionMonitor.sendPackagePermissionsToNetd(uidsPermInfo);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET,
new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_UPDATE_DEVICE_STATS,
new int[]{SYSTEM_UID2});
// Update permission of MOCK_UID1, expect new permission show up.
- mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, new UidNetdPermissionInfo(
+ PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS));
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Change permissions of SYSTEM_UID2, expect new permission show up and old permission
// revoked.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
- INetd.PERMISSION_INTERNET);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, new UidNetdPermissionInfo(
+ PERMISSION_INTERNET));
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
// Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, new UidNetdPermissionInfo(
+ PERMISSION_NONE));
+ mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{SYSTEM_UID1});
}
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
@@ -611,11 +618,11 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID2});
}
@Test
@@ -623,8 +630,8 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Install another package with the same uid and no permissions should not cause the UID to
// lose permissions.
@@ -633,8 +640,8 @@
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
}
@Test
@@ -642,12 +649,12 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
}
@Test
@@ -655,16 +662,16 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
removeAllPermissions(MOCK_UID1);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -672,10 +679,10 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID1});
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test
@@ -683,8 +690,8 @@
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET
+ | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
@@ -695,7 +702,7 @@
addPermissions(MOCK_UID1, INTERNET);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
@Test