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

Commit 2479cf7b authored by paulhu's avatar paulhu Committed by Paul Hu
Browse files

Stop using PackageManagerInternal in PermissionMonitor

- Replace the PackageManagerInternal#getPackageList() with
receiving PACKAGE_{ADDED|REMOVED} intent.
- Also remove the onPackageChanged method because the traffaic
permissions(INTERNET, UPDATE_DEVICE_STATS) are not changed after
package changed(Disable or enable package).

Bug: 176788468
Test: atest FrameworksNetTests
Change-Id: I5505d1c77db66a7e65fc336ea0e99846e78c6b36
parent 78a488cd
Loading
Loading
Loading
Loading
+40 −26
Original line number Original line Diff line number Diff line
@@ -31,14 +31,17 @@ import static android.os.Process.SYSTEM_UID;
import static com.android.net.module.util.CollectionUtils.toIntArray;
import static com.android.net.module.util.CollectionUtils.toIntArray;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.INetd;
import android.net.UidRange;
import android.net.UidRange;
import android.net.Uri;
import android.os.Build;
import android.os.Build;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.ServiceSpecificException;
@@ -54,7 +57,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.CollectionUtils;
import com.android.server.LocalServices;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
@@ -71,7 +73,7 @@ import java.util.Set;
 *
 *
 * @hide
 * @hide
 */
 */
public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
public class PermissionMonitor {
    private static final String TAG = "PermissionMonitor";
    private static final String TAG = "PermissionMonitor";
    private static final boolean DBG = true;
    private static final boolean DBG = true;
    protected static final Boolean SYSTEM = Boolean.TRUE;
    protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -83,6 +85,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
    private final SystemConfigManager mSystemConfigManager;
    private final SystemConfigManager mSystemConfigManager;
    private final INetd mNetd;
    private final INetd mNetd;
    private final Dependencies mDeps;
    private final Dependencies mDeps;
    private final Context mContext;


    @GuardedBy("this")
    @GuardedBy("this")
    private final Set<UserHandle> mUsers = new HashSet<>();
    private final Set<UserHandle> mUsers = new HashSet<>();
@@ -102,6 +105,25 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
    @GuardedBy("this")
    @GuardedBy("this")
    private final Set<Integer> mAllApps = new HashSet<>();
    private final Set<Integer> mAllApps = new HashSet<>();


    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
            final Uri packageData = intent.getData();
            final String packageName =
                    packageData != null ? packageData.getSchemeSpecificPart() : null;

            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                onPackageAdded(packageName, uid);
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                onPackageRemoved(packageName, uid);
            } else {
                Log.wtf(TAG, "received unexpected intent: " + action);
            }
        }
    };

    /**
    /**
     * Dependencies of PermissionMonitor, for injection in tests.
     * Dependencies of PermissionMonitor, for injection in tests.
     */
     */
@@ -127,6 +149,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
        mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
        mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
        mNetd = netd;
        mNetd = netd;
        mDeps = deps;
        mDeps = deps;
        mContext = context;
    }
    }


    // Intended to be called only once at startup, after the system is ready. Installs a broadcast
    // Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -134,12 +157,14 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
    public synchronized void startMonitoring() {
    public synchronized void startMonitoring() {
        log("Monitoring");
        log("Monitoring");


        PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
        final IntentFilter intentFilter = new IntentFilter();
        if (pmi != null) {
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
            pmi.getPackageList(this);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        } else {
        intentFilter.addDataScheme("package");
            loge("failed to get the PackageManagerInternal service");
        mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver(
        }
                mIntentReceiver, intentFilter, null /* broadcastPermission */,
                null /* scheduler */);

        List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
        List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
                | MATCH_ANY_USER);
                | MATCH_ANY_USER);
        if (apps == null) {
        if (apps == null) {
@@ -347,9 +372,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
     *
     *
     * @hide
     * @hide
     */
     */
    @Override
    public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
    public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
        // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
        //  using appId instead of uid actually
        sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));


        // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
        // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
        // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
        // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
@@ -384,9 +410,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
     *
     *
     * @hide
     * @hide
     */
     */
    @Override
    public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
    public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
        // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
        //  using appId instead of uid actually
        sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));


        // If the newly-removed package falls within some VPN's uid range, update Netd with it.
        // If the newly-removed package falls within some VPN's uid range, update Netd with it.
        // This needs to happen before the mApps update below, since removeBypassingUids() depends
        // This needs to happen before the mApps update below, since removeBypassingUids() depends
@@ -432,19 +459,6 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
        }
        }
    }
    }


    /**
     * Called when a package is changed.
     *
     * @param packageName The name of the changed package.
     * @param uid The uid of the changed package.
     *
     * @hide
     */
    @Override
    public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
        sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
    }

    private static int getNetdPermissionMask(String[] requestedPermissions,
    private static int getNetdPermissionMask(String[] requestedPermissions,
                                             int[] requestedPermissionsFlags) {
                                             int[] requestedPermissionsFlags) {
        int permissions = 0;
        int permissions = 0;
+38 −10
Original line number Original line Diff line number Diff line
@@ -48,18 +48,22 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.INetd;
import android.net.UidRange;
import android.net.UidRange;
import android.net.Uri;
import android.os.Build;
import android.os.Build;
import android.os.SystemConfigManager;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserHandle;
@@ -70,12 +74,11 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


import com.android.server.LocalServices;
import com.android.server.pm.PackageList;

import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.invocation.InvocationOnMock;
@@ -112,7 +115,6 @@ public class PermissionMonitorTest {
    @Mock private Context mContext;
    @Mock private Context mContext;
    @Mock private PackageManager mPackageManager;
    @Mock private PackageManager mPackageManager;
    @Mock private INetd mNetdService;
    @Mock private INetd mNetdService;
    @Mock private PackageManagerInternal mMockPmi;
    @Mock private UserManager mUserManager;
    @Mock private UserManager mUserManager;
    @Mock private PermissionMonitor.Dependencies mDeps;
    @Mock private PermissionMonitor.Dependencies mDeps;
    @Mock private SystemConfigManager mSystemConfigManager;
    @Mock private SystemConfigManager mSystemConfigManager;
@@ -131,16 +133,14 @@ public class PermissionMonitorTest {
        when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
        when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
                .thenReturn(mSystemConfigManager);
                .thenReturn(mSystemConfigManager);
        when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
        when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
        final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
        doReturn(UserHandle.ALL).when(asUserCtx).getUser();
        when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);


        mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
        mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));


        LocalServices.removeServiceForTest(PackageManagerInternal.class);
        LocalServices.addService(PackageManagerInternal.class, mMockPmi);
        when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
                  /* observer */ null));
        when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
        when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
        mPermissionMonitor.startMonitoring();
        mPermissionMonitor.startMonitoring();
        verify(mMockPmi).getPackageList(mPermissionMonitor);
    }
    }


    private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
    private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -770,4 +770,32 @@ public class PermissionMonitorTest {
                INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
                INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
                new int[]{ MOCK_UID2 });
                new int[]{ MOCK_UID2 });
    }
    }

    @Test
    public void testIntentReceiver() throws Exception {
        final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
        final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
        final BroadcastReceiver receiver = receiverCaptor.getValue();

        // Verify receiving PACKAGE_ADDED intent.
        final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
                Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
        addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
        setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
                new String[] { INTERNET, UPDATE_DEVICE_STATS });
        receiver.onReceive(mContext, addedIntent);
        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
                | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });

        // Verify receiving PACKAGE_REMOVED intent.
        when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
        final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
                Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
        removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
        receiver.onReceive(mContext, removedIntent);
        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
    }

}
}