[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
This commit is contained in:
paulhu
2020-06-03 10:46:58 +08:00
parent d9b1b9daeb
commit 1daf973605
2 changed files with 122 additions and 80 deletions

View File

@@ -56,7 +56,6 @@ import android.system.OsConstants;
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 class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
}
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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
}
// 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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
? 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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
* 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 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
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 {

View File

@@ -28,11 +28,17 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
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.net.UidRange;
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 @@ public class PermissionMonitorTest {
// 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 @@ public class PermissionMonitorTest {
// 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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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 @@ public class PermissionMonitorTest {
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