Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06697e0c authored by Paul Hu's avatar Paul Hu Committed by Gerrit Code Review
Browse files

Merge "[RFPM05] Add UidNetdPermissionInfo class"

parents bad5c4ec 26263b3c
Loading
Loading
Loading
Loading
+73 −38
Original line number Diff line number Diff line
@@ -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 {
+49 −42
Original line number Diff line number Diff line
@@ -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