diff options
| author | 2020-03-05 16:03:35 -0800 | |
|---|---|---|
| committer | 2020-04-13 15:46:36 -0700 | |
| commit | a7c60c045719eb7f90ed49b9bd3b712471f822f8 (patch) | |
| tree | b37823265bfb7efb0a19eeef523bf168c0ca2d54 | |
| parent | bba1891e80420c4f064d8da8a212a7220f8595ed (diff) | |
Reset mode for app op permission when app no longer requests it.
Fixes: 149765004
Test: Ensure the same set of tests pass with the following command:
Test: atest ExternalStorageHostTest StorageHostTest
Change-Id: Ic3847f136e059e3517154b909d07b68553ebf82b
3 files changed, 138 insertions, 12 deletions
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index b7c9ecb604f8..49de68f6b0f4 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -4607,11 +4607,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection( + public @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection( @PermissionInfo.Protection int protection) { ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>(); - synchronized (PermissionManagerService.this.mLock) { + synchronized (mLock) { int numTotalPermissions = mSettings.mPermissions.size(); for (int i = 0; i < numTotalPermissions; i++) { @@ -4628,6 +4628,28 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override + public @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags( + @PermissionInfo.ProtectionFlags int protectionFlags) { + ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>(); + + synchronized (mLock) { + int numTotalPermissions = mSettings.mPermissions.size(); + + for (int i = 0; i < numTotalPermissions; i++) { + BasePermission bp = mSettings.mPermissions.valueAt(i); + + if (bp.perm != null && (bp.perm.getProtectionFlags() & protectionFlags) + == protectionFlags) { + matchingPermissions.add( + PackageInfoUtils.generatePermissionInfo(bp.perm, 0)); + } + } + } + + return matchingPermissions; + } + + @Override public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) { return PermissionManagerService.this.backupRuntimePermissions(user); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 356d0abc1d19..57a25eddf7ce 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -302,10 +302,14 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */ public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName); - /** Get all permission that have a certain protection level */ - public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection( + /** Get all permissions that have a certain protection */ + public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection( @PermissionInfo.Protection int protection); + /** Get all permissions that have certain protection flags */ + public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags( + @PermissionInfo.ProtectionFlags int protectionFlags); + /** * Returns the delegate used to influence permission checking. * diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 27288d852fb2..adc653f60251 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -72,6 +72,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -107,6 +108,15 @@ public final class PermissionPolicyService extends SystemService { @GuardedBy("mLock") private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>(); + /** + * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently + * scheduled for a uid. + */ + @GuardedBy("mLock") + private final SparseBooleanArray mIsUidSyncScheduled = new SparseBooleanArray(); + + private List<String> mAppOpPermissions; + public PermissionPolicyService(@NonNull Context context) { super(context); @@ -117,7 +127,7 @@ public final class PermissionPolicyService extends SystemService { public void onStart() { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); - final PermissionManagerServiceInternal permManagerInternal = LocalServices.getService( + final PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService( PermissionManagerServiceInternal.class); final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); @@ -125,38 +135,44 @@ public final class PermissionPolicyService extends SystemService { packageManagerInternal.getPackageList(new PackageListObserver() { @Override public void onPackageAdded(String packageName, int uid) { - onPackageChanged(packageName, uid); + final int userId = UserHandle.getUserId(uid); + if (isStarted(userId)) { + synchronizePackagePermissionsAndAppOpsForUser(packageName, userId); + } } @Override public void onPackageChanged(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); - if (isStarted(userId)) { synchronizePackagePermissionsAndAppOpsForUser(packageName, userId); + resetAppOpPermissionsIfNotRequestedForUid(uid); } } @Override public void onPackageRemoved(String packageName, int uid) { - /* do nothing */ + final int userId = UserHandle.getUserId(uid); + if (isStarted(userId)) { + resetAppOpPermissionsIfNotRequestedForUid(uid); + } } }); - permManagerInternal.addOnRuntimePermissionStateChangedListener( + permissionManagerInternal.addOnRuntimePermissionStateChangedListener( this::synchronizePackagePermissionsAndAppOpsAsyncForUser); mAppOpsCallback = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, String packageName) { synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName, UserHandle.getUserId(uid)); + resetAppOpPermissionsIfNotRequestedForUidAsync(uid); } }; final ArrayList<PermissionInfo> dangerousPerms = - permManagerInternal.getAllPermissionWithProtection( + permissionManagerInternal.getAllPermissionsWithProtection( PermissionInfo.PROTECTION_DANGEROUS); - try { int numDangerousPerms = dangerousPerms.size(); for (int i = 0; i < numDangerousPerms; i++) { @@ -179,6 +195,26 @@ public final class PermissionPolicyService extends SystemService { Slog.wtf(LOG_TAG, "Cannot set up app-ops listener"); } + final List<PermissionInfo> appOpPermissionInfos = + permissionManagerInternal.getAllPermissionsWithProtectionFlags( + PermissionInfo.PROTECTION_FLAG_APPOP); + mAppOpPermissions = new ArrayList<>(); + final int appOpPermissionInfosSize = appOpPermissionInfos.size(); + for (int i = 0; i < appOpPermissionInfosSize; i++) { + final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i); + + final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermissionInfo.name); + if (appOpCode != OP_NONE) { + mAppOpPermissions.add(appOpPermissionInfo.name); + + try { + appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback); + } catch (RemoteException e) { + Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e); + } + } + } + IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); @@ -445,6 +481,70 @@ public final class PermissionPolicyService extends SystemService { synchronizer.syncPackages(); } + private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) { + if (isStarted(UserHandle.getUserId(uid))) { + synchronized (mLock) { + if (!mIsUidSyncScheduled.get(uid)) { + mIsUidSyncScheduled.put(uid, true); + FgThread.getHandler().sendMessage(PooledLambda.obtainMessage( + PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid, + this, uid)); + } + } + } + } + + private void resetAppOpPermissionsIfNotRequestedForUid(int uid) { + synchronized (mLock) { + mIsUidSyncScheduled.delete(uid); + } + + final Context context = getContext(); + final PackageManager userPackageManager = getUserContext(context, + UserHandle.getUserHandleForUid(uid)).getPackageManager(); + final String[] packageNames = userPackageManager.getPackagesForUid(uid); + if (packageNames == null || packageNames.length == 0) { + return; + } + + final ArraySet<String> requestedPermissions = new ArraySet<>(); + for (String packageName : packageNames) { + final PackageInfo packageInfo; + try { + packageInfo = userPackageManager.getPackageInfo(packageName, GET_PERMISSIONS); + } catch (NameNotFoundException e) { + continue; + } + if (packageInfo == null || packageInfo.requestedPermissions == null) { + continue; + } + Collections.addAll(requestedPermissions, packageInfo.requestedPermissions); + } + + final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + final AppOpsManagerInternal appOpsManagerInternal = LocalServices.getService( + AppOpsManagerInternal.class); + final int appOpPermissionsSize = mAppOpPermissions.size(); + for (int i = 0; i < appOpPermissionsSize; i++) { + final String appOpPermission = mAppOpPermissions.get(i); + + if (!requestedPermissions.contains(appOpPermission)) { + final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermission); + final int defaultAppOpMode = AppOpsManager.opToDefaultMode(appOpCode); + for (String packageName : packageNames) { + final int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpCode, uid, + packageName); + if (appOpMode != defaultAppOpMode) { + appOpsManagerInternal.setUidModeFromPermissionPolicy(appOpCode, uid, + defaultAppOpMode, mAppOpsCallback); + appOpsManagerInternal.setModeFromPermissionPolicy(appOpCode, uid, + packageName, defaultAppOpMode, mAppOpsCallback); + } + } + } + } + } + /** * Synchronizes permission to app ops. You *must* always sync all packages * in a shared UID at the same time to ensure proper synchronization. @@ -499,7 +599,7 @@ public final class PermissionPolicyService extends SystemService { PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService( PermissionManagerServiceInternal.class); List<PermissionInfo> permissionInfos = - permissionManagerInternal.getAllPermissionWithProtection( + permissionManagerInternal.getAllPermissionsWithProtection( PermissionInfo.PROTECTION_DANGEROUS); int permissionInfosSize = permissionInfos.size(); for (int i = 0; i < permissionInfosSize; i++) { |