From 2adf56309b5794f842a5f58fa70acc131eaa6123 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 5 Mar 2021 15:40:11 +0800 Subject: [PATCH] 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 --- .../connectivity/PermissionMonitor.java | 66 +++++++++++-------- .../connectivity/PermissionMonitorTest.java | 48 +++++++++++--- 2 files changed, 78 insertions(+), 36 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 9411e33434..488677ac1b 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -31,14 +31,17 @@ import static android.os.Process.SYSTEM_UID; import static com.android.net.module.util.CollectionUtils.toIntArray; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PackageManagerInternal; import android.net.INetd; import android.net.UidRange; +import android.net.Uri; import android.os.Build; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -54,7 +57,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.CollectionUtils; -import com.android.server.LocalServices; import java.util.ArrayList; import java.util.HashMap; @@ -71,7 +73,7 @@ import java.util.Set; * * @hide */ -public class PermissionMonitor implements PackageManagerInternal.PackageListObserver { +public class PermissionMonitor { private static final String TAG = "PermissionMonitor"; private static final boolean DBG = true; protected static final Boolean SYSTEM = Boolean.TRUE; @@ -83,6 +85,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse private final SystemConfigManager mSystemConfigManager; private final INetd mNetd; private final Dependencies mDeps; + private final Context mContext; @GuardedBy("this") private final Set mUsers = new HashSet<>(); @@ -102,6 +105,25 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse @GuardedBy("this") private final Set 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. */ @@ -127,6 +149,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse mSystemConfigManager = context.getSystemService(SystemConfigManager.class); mNetd = netd; mDeps = deps; + mContext = context; } // 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() { log("Monitoring"); - PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); - if (pmi != null) { - pmi.getPackageList(this); - } else { - loge("failed to get the PackageManagerInternal service"); - } + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addDataScheme("package"); + mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver( + mIntentReceiver, intentFilter, null /* broadcastPermission */, + null /* scheduler */); + List apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS | MATCH_ANY_USER); if (apps == null) { @@ -347,9 +372,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse * * @hide */ - @Override 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 // 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 */ - @Override 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. // 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, int[] requestedPermissionsFlags) { int permissions = 0; diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index e4e24b4648..fec5ef3937 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -48,18 +48,22 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.net.INetd; import android.net.UidRange; +import android.net.Uri; import android.os.Build; import android.os.SystemConfigManager; import android.os.UserHandle; @@ -70,12 +74,11 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.server.LocalServices; -import com.android.server.pm.PackageList; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.AdditionalAnswers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @@ -112,7 +115,6 @@ public class PermissionMonitorTest { @Mock private Context mContext; @Mock private PackageManager mPackageManager; @Mock private INetd mNetdService; - @Mock private PackageManagerInternal mMockPmi; @Mock private UserManager mUserManager; @Mock private PermissionMonitor.Dependencies mDeps; @Mock private SystemConfigManager mSystemConfigManager; @@ -131,16 +133,14 @@ public class PermissionMonitorTest { when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE)) .thenReturn(mSystemConfigManager); 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)); - LocalServices.removeServiceForTest(PackageManagerInternal.class); - LocalServices.addService(PackageManagerInternal.class, mMockPmi); - when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList(), - /* observer */ null)); when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null); mPermissionMonitor.startMonitoring(); - verify(mMockPmi).getPackageList(mPermissionMonitor); } private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid, @@ -770,4 +770,32 @@ public class PermissionMonitorTest { INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{ MOCK_UID2 }); } + + @Test + public void testIntentReceiver() throws Exception { + final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); + final ArgumentCaptor 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 }); + } + }