diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java index ef0de18ee3ef7..704b4258eeffa 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java @@ -105,6 +105,21 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface } } + @Override + public SparseIntArray getNonDefaultPackageModes(String packageName, int userId) { + synchronized (mLock) { + ArrayMap packageModes = mUserPackageModes.get(userId); + if (packageModes == null) { + return new SparseIntArray(); + } + SparseIntArray opModes = packageModes.get(packageName); + if (opModes == null) { + return new SparseIntArray(); + } + return opModes.clone(); + } + } + @Override public int getUidMode(int uid, int op) { synchronized (mLock) { diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java index d8d0d48965eac..9a564fc22eee1 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java @@ -38,6 +38,15 @@ public interface AppOpsCheckingServiceInterface { */ SparseIntArray getNonDefaultUidModes(int uid); + /** + * Returns a copy of non-default app-ops with op as keys and their modes as values for a package + * and user. + * Returns an empty SparseIntArray if nothing is set. + * @param packageName for which we need the app-ops and their modes. + * @param userId for which the package is installed in. + */ + SparseIntArray getNonDefaultPackageModes(String packageName, int userId); + /** * Returns the app-op mode for a particular app-op of a uid. * Returns default op mode if the op mode for particular uid and op is not set. diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java index ac479b2a63c4a..b8326ade98bbd 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java @@ -45,6 +45,13 @@ public class AppOpsCheckingServiceLoggingDecorator implements AppOpsCheckingServ return mService.getNonDefaultUidModes(uid); } + @Override + public SparseIntArray getNonDefaultPackageModes(String packageName, int userId) { + Log.i(LOG_TAG, "getNonDefaultPackageModes(" + + "packageName = " + packageName + ", userId = " + userId + ") "); + return mService.getNonDefaultPackageModes(packageName, userId); + } + @Override public int getUidMode(int uid, int op) { Log.i(LOG_TAG, "getUidMode(uid = " + uid + ", op = " + op + ")"); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index c50f2b789f98a..af6470f114dbc 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -98,6 +98,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; +import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION; import android.net.Uri; @@ -162,6 +163,7 @@ import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; +import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.component.ParsedAttribution; import com.android.server.policy.AppOpsPolicy; @@ -383,6 +385,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch /** Package Manager internal. Access via {@link #getPackageManagerInternal()} */ private @Nullable PackageManagerInternal mPackageManagerInternal; + /** User Manager internal. Access via {@link #getUserManagerInternal()} */ + private @Nullable UserManagerInternal mUserManagerInternal; + /** Interface for app-op modes.*/ @VisibleForTesting AppOpsCheckingServiceInterface mAppOpsCheckingService; @@ -525,22 +530,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch pkgOps = null; } - public boolean isDefault() { - boolean areAllPackageModesDefault = true; - if (pkgOps != null) { - for (String packageName : pkgOps.keySet()) { - if (!mAppOpsCheckingService.arePackageModesDefault(packageName, - UserHandle.getUserId(uid))) { - areAllPackageModesDefault = false; - break; - } - } - } - return (pkgOps == null || pkgOps.isEmpty()) - && mAppOpsCheckingService.areUidModesDefault(uid) - && areAllPackageModesDefault; - } - // Functions for uid mode access and manipulation. public SparseIntArray getNonDefaultUidModes() { return mAppOpsCheckingService.getNonDefaultUidModes(uid); @@ -1076,6 +1065,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch synchronized (this) { upgradeLocked(mVersionAtBoot); } + initializeUidStates(); + + getUserManagerInternal().addUserLifecycleListener( + new UserManagerInternal.UserLifecycleListener() { + @Override + public void onUserCreated(UserInfo user, Object token) { + initializeUserUidStates(user.id); + } + + // onUserRemoved handled by #removeUser + }); mConstants.startMonitoring(mContext.getContentResolver()); mHistoricalRegistry.systemReady(mContext.getContentResolver()); @@ -1202,6 +1202,49 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); } + /** + * Initialize uid state objects for state contained in the checking service. + */ + private void initializeUidStates() { + UserManagerInternal umi = getUserManagerInternal(); + int[] userIds = umi.getUserIds(); + synchronized (this) { + for (int i = 0; i < userIds.length; i++) { + int userId = userIds[i]; + initializeUserUidStatesLocked(userId); + } + } + } + + private void initializeUserUidStates(int userId) { + synchronized (this) { + initializeUserUidStatesLocked(userId); + } + } + + private void initializeUserUidStatesLocked(int userId) { + ArrayMap packageStates = + getPackageManagerInternal().getPackageStates(); + for (int j = 0; j < packageStates.size(); j++) { + PackageStateInternal packageState = packageStates.valueAt(j); + int uid = UserHandle.getUid(userId, packageState.getAppId()); + UidState uidState = getUidStateLocked(uid, true); + if (uidState.pkgOps == null) { + uidState.pkgOps = new ArrayMap<>(); + } + String packageName = packageStates.keyAt(j); + Ops ops = new Ops(packageName, uidState); + uidState.pkgOps.put(packageName, ops); + + SparseIntArray packageModes = + mAppOpsCheckingService.getNonDefaultPackageModes(packageName, userId); + for (int k = 0; k < packageModes.size(); k++) { + int code = packageModes.get(k); + ops.put(code, new Op(uidState, packageName, code, uid)); + } + } + } + /** * Sets a policy for handling app ops. * @@ -1687,13 +1730,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch pkgOps.remove(ops.packageName); mAppOpsCheckingService.removePackage(ops.packageName, UserHandle.getUserId(uidState.uid)); - if (pkgOps.isEmpty()) { - uidState.pkgOps = null; - } - if (uidState.isDefault()) { - uidState.clear(); - mUidStates.remove(uid); - } } } } @@ -2147,10 +2183,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch UserHandle.getUserId(uidState.uid)); } } - if (uidState.isDefault()) { - uidState.clear(); - mUidStates.remove(uidState.uid); - } if (uidChanged) { uidState.evalForegroundOps(); } @@ -3587,6 +3619,20 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch return mPackageManagerInternal; } + /** + * @return {@link UserManagerInternal} + */ + private @NonNull UserManagerInternal getUserManagerInternal() { + if (mUserManagerInternal == null) { + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); + } + if (mUserManagerInternal == null) { + throw new IllegalStateException("UserManagerInternal not loaded"); + } + + return mUserManagerInternal; + } + /** * Create a restriction description matching the properties of the package. * diff --git a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt index f2cff62d3b8ce..a26b2ac6ec209 100644 --- a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt +++ b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt @@ -71,6 +71,10 @@ class AppOpService( return opNameMapToOpIntMap(getUidModes(uid)) } + override fun getNonDefaultPackageModes(packageName: String, userId: Int): SparseIntArray { + return opNameMapToOpIntMap(getPackageModes(packageName, userId)) + } + override fun getUidMode(uid: Int, op: Int): Int { val appId = UserHandle.getAppId(uid) val userId = UserHandle.getUserId(uid) diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java index 9eed6ada3a372..d1f7f9374011d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java @@ -42,6 +42,7 @@ import android.content.pm.PackageManagerInternal; import android.content.res.AssetManager; import android.os.Handler; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; @@ -51,12 +52,14 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.util.ArrayUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.server.LocalServices; import com.android.server.SystemServerInitThreadPool; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal; +import com.android.server.pm.pkg.PackageStateInternal; import org.junit.After; import org.junit.Before; @@ -188,6 +191,11 @@ public class AppOpsUpgradeTest { // Stub out package calls to disable AppOpsService#updatePermissionRevokedCompat doReturn(null).when(mPackageManager).getPackagesForUid(anyInt()); + + doReturn(new ArrayMap()).when(mPackageManagerInternal) + .getPackageStates(); + + doReturn(new int[] {0}).when(mUserManagerInternal).getUserIds(); } @After