Move mPermissionTrees to permission settings
Move more state / logic into the permission sub-package. We're
close to being able to wholesale move large amounts of code from
package manager into the permission manager.
Bug: 63539144
Test: Manual. Builds and runs
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.PermissionsHostTest
Test: cts-tradefed run commandAndExit cts-dev -m CtsPermissionTestCases
Test: cts-tradefed run commandAndExit cts-dev -m CtsPermission2TestCases
Test: bit FrameworksServicesTests:com.android.server.pm.PackageManagerSettingsTests
Change-Id: Id292441ff22b14665fd77f700ad934bf2c5a3357
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 6c031a6..062aa33 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -69,6 +69,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
/**
* Manages all permissions and handles permissions related tasks.
@@ -260,7 +261,7 @@
// }
final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
+ for (BasePermission bp : mSettings.mPermissions.values()) {
final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
if (pi != null) {
out.add(pi);
@@ -305,7 +306,98 @@
return protectionLevel;
}
- private boolean addPermission(
+ private void addAllPermissions(PackageParser.Package pkg, boolean chatty) {
+ final int N = pkg.permissions.size();
+ for (int i=0; i<N; i++) {
+ PackageParser.Permission p = pkg.permissions.get(i);
+
+ // Assume by default that we did not install this permission into the system.
+ p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
+
+ // Now that permission groups have a special meaning, we ignore permission
+ // groups for legacy apps to prevent unexpected behavior. In particular,
+ // permissions for one app being granted to someone just because they happen
+ // to be in a group defined by another app (before this had no implications).
+ if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
+ p.group = mPackageManagerInt.getPermissionGroupTEMP(p.info.group);
+ // Warn for a permission in an unknown group.
+ if (PackageManagerService.DEBUG_PERMISSIONS
+ && p.info.group != null && p.group == null) {
+ Slog.i(TAG, "Permission " + p.info.name + " from package "
+ + p.info.packageName + " in an unknown group " + p.info.group);
+ }
+ }
+
+ synchronized (PermissionManagerService.this.mLock) {
+ if (p.tree) {
+ final BasePermission bp = BasePermission.createOrUpdate(
+ mSettings.getPermissionTreeLocked(p.info.name), p, pkg,
+ mSettings.getAllPermissionTreesLocked(), chatty);
+ mSettings.putPermissionTreeLocked(p.info.name, bp);
+ } else {
+ final BasePermission bp = BasePermission.createOrUpdate(
+ mSettings.getPermissionLocked(p.info.name),
+ p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
+ mSettings.putPermissionLocked(p.info.name, bp);
+ }
+ }
+ }
+ }
+
+ private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
+ synchronized (mLock) {
+ int N = pkg.permissions.size();
+ StringBuilder r = null;
+ for (int i=0; i<N; i++) {
+ PackageParser.Permission p = pkg.permissions.get(i);
+ BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name);
+ if (bp == null) {
+ bp = mSettings.mPermissionTrees.get(p.info.name);
+ }
+ if (bp != null && bp.isPermission(p)) {
+ bp.setPermission(null);
+ if (PackageManagerService.DEBUG_REMOVE && chatty) {
+ if (r == null) {
+ r = new StringBuilder(256);
+ } else {
+ r.append(' ');
+ }
+ r.append(p.info.name);
+ }
+ }
+ if (p.isAppOp()) {
+ ArraySet<String> appOpPkgs =
+ mSettings.mAppOpPermissionPackages.get(p.info.name);
+ if (appOpPkgs != null) {
+ appOpPkgs.remove(pkg.packageName);
+ }
+ }
+ }
+ if (r != null) {
+ if (PackageManagerService.DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
+ }
+
+ N = pkg.requestedPermissions.size();
+ r = null;
+ for (int i=0; i<N; i++) {
+ String perm = pkg.requestedPermissions.get(i);
+ if (mSettings.isPermissionAppOp(perm)) {
+ ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm);
+ if (appOpPkgs != null) {
+ appOpPkgs.remove(pkg.packageName);
+ if (appOpPkgs.isEmpty()) {
+ mSettings.mAppOpPermissionPackages.remove(perm);
+ }
+ }
+ }
+ }
+ if (r != null) {
+ if (PackageManagerService.DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
+ }
+ }
+ }
+
+ private boolean addDynamicPermission(
PermissionInfo info, int callingUid, PermissionCallback callback) {
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
throw new SecurityException("Instant apps can't add permissions");
@@ -313,8 +405,7 @@
if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
throw new SecurityException("Label must be specified in permission");
}
- final BasePermission tree = (BasePermission) mPackageManagerInt.enforcePermissionTreeTEMP(
- info.name, callingUid);
+ final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid);
final boolean added;
final boolean changed;
synchronized (mLock) {
@@ -341,13 +432,12 @@
return added;
}
- private void removePermission(
+ private void removeDynamicPermission(
String permName, int callingUid, PermissionCallback callback) {
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
throw new SecurityException("Instant applications don't have access to this method");
}
- final BasePermission tree = (BasePermission) mPackageManagerInt.enforcePermissionTreeTEMP(
- permName, callingUid);
+ final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid);
synchronized (mLock) {
final BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
@@ -713,7 +803,21 @@
return runtimePermissionChangedUserIds;
}
- private int getPermissionFlags(String permName, String packageName, int callingUid, int userId) {
+ private String[] getAppOpPermissionPackages(String permName) {
+ if (mPackageManagerInt.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ final ArraySet<String> pkgs = mSettings.mAppOpPermissionPackages.get(permName);
+ if (pkgs == null) {
+ return null;
+ }
+ return pkgs.toArray(new String[pkgs.size()]);
+ }
+ }
+
+ private int getPermissionFlags(
+ String permName, String packageName, int callingUid, int userId) {
if (!mUserManagerInt.exists(userId)) {
return 0;
}
@@ -741,6 +845,96 @@
return permissionsState.getPermissionFlags(permName, userId);
}
+ private int updatePermissions(String packageName, PackageParser.Package pkgInfo, int flags) {
+ Set<BasePermission> needsUpdate = null;
+ synchronized (mLock) {
+ final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator();
+ while (it.hasNext()) {
+ final BasePermission bp = it.next();
+ if (bp.isDynamic()) {
+ bp.updateDynamicPermission(mSettings.mPermissionTrees.values());
+ }
+ if (bp.getSourcePackageSetting() != null) {
+ if (packageName != null && packageName.equals(bp.getSourcePackageName())
+ && (pkgInfo == null || !hasPermission(pkgInfo, bp.getName()))) {
+ Slog.i(TAG, "Removing old permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
+ flags |= PackageManagerService.UPDATE_PERMISSIONS_ALL;
+ it.remove();
+ }
+ continue;
+ }
+ if (needsUpdate == null) {
+ needsUpdate = new ArraySet<>(mSettings.mPermissions.size());
+ }
+ needsUpdate.add(bp);
+ }
+ }
+ if (needsUpdate != null) {
+ for (final BasePermission bp : needsUpdate) {
+ final PackageParser.Package pkg =
+ mPackageManagerInt.getPackage(bp.getSourcePackageName());
+ synchronized (mLock) {
+ if (pkg != null && pkg.mExtras != null) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (bp.getSourcePackageSetting() == null) {
+ bp.setSourcePackageSetting(ps);
+ }
+ continue;
+ }
+ Slog.w(TAG, "Removing dangling permission: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
+ mSettings.removePermissionLocked(bp.getName());
+ }
+ }
+ }
+ return flags;
+ }
+
+ private int updatePermissionTrees(String packageName, PackageParser.Package pkgInfo,
+ int flags) {
+ Set<BasePermission> needsUpdate = null;
+ synchronized (mLock) {
+ final Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
+ while (it.hasNext()) {
+ final BasePermission bp = it.next();
+ if (bp.getSourcePackageSetting() != null) {
+ if (packageName != null && packageName.equals(bp.getSourcePackageName())
+ && (pkgInfo == null || !hasPermission(pkgInfo, bp.getName()))) {
+ Slog.i(TAG, "Removing old permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
+ flags |= PackageManagerService.UPDATE_PERMISSIONS_ALL;
+ it.remove();
+ }
+ continue;
+ }
+ if (needsUpdate == null) {
+ needsUpdate = new ArraySet<>(mSettings.mPermissionTrees.size());
+ }
+ needsUpdate.add(bp);
+ }
+ }
+ if (needsUpdate != null) {
+ for (final BasePermission bp : needsUpdate) {
+ final PackageParser.Package pkg =
+ mPackageManagerInt.getPackage(bp.getSourcePackageName());
+ synchronized (mLock) {
+ if (pkg != null && pkg.mExtras != null) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (bp.getSourcePackageSetting() == null) {
+ bp.setSourcePackageSetting(ps);
+ }
+ continue;
+ }
+ Slog.w(TAG, "Removing dangling permission tree: " + bp.getName()
+ + " from package " + bp.getSourcePackageName());
+ mSettings.removePermissionLocked(bp.getName());
+ }
+ }
+ }
+ return flags;
+ }
+
private void updatePermissionFlags(String permName, String packageName, int flagMask,
int flagValues, int callingUid, int userId, PermissionCallback callback) {
if (!mUserManagerInt.exists(userId)) {
@@ -872,7 +1066,7 @@
private int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
int size = 0;
- for (BasePermission perm : mSettings.getAllPermissionsLocked()) {
+ for (BasePermission perm : mSettings.mPermissions.values()) {
size += tree.calculateFootprint(perm);
}
return size;
@@ -889,6 +1083,15 @@
}
}
+ private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) {
+ for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
+ if (pkgInfo.permissions.get(i).info.name.equals(permName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Get the first event id for the permission.
*
@@ -951,14 +1154,22 @@
private class PermissionManagerInternalImpl extends PermissionManagerInternal {
@Override
- public boolean addPermission(PermissionInfo info, boolean async, int callingUid,
- PermissionCallback callback) {
- return PermissionManagerService.this.addPermission(info, callingUid, callback);
+ public void addAllPermissions(Package pkg, boolean chatty) {
+ PermissionManagerService.this.addAllPermissions(pkg, chatty);
}
@Override
- public void removePermission(String permName, int callingUid,
+ public void removeAllPermissions(Package pkg, boolean chatty) {
+ PermissionManagerService.this.removeAllPermissions(pkg, chatty);
+ }
+ @Override
+ public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid,
PermissionCallback callback) {
- PermissionManagerService.this.removePermission(permName, callingUid, callback);
+ return PermissionManagerService.this.addDynamicPermission(info, callingUid, callback);
+ }
+ @Override
+ public void removeDynamicPermission(String permName, int callingUid,
+ PermissionCallback callback) {
+ PermissionManagerService.this.removeDynamicPermission(permName, callingUid, callback);
}
@Override
public void grantRuntimePermission(String permName, String packageName,
@@ -993,12 +1204,26 @@
(SharedUserSetting) suSetting, allUserIds);
}
@Override
+ public String[] getAppOpPermissionPackages(String permName) {
+ return PermissionManagerService.this.getAppOpPermissionPackages(permName);
+ }
+ @Override
public int getPermissionFlags(String permName, String packageName, int callingUid,
int userId) {
return PermissionManagerService.this.getPermissionFlags(permName, packageName,
callingUid, userId);
}
@Override
+ public int updatePermissions(String packageName,
+ PackageParser.Package pkgInfo, int flags) {
+ return PermissionManagerService.this.updatePermissions(packageName, pkgInfo, flags);
+ }
+ @Override
+ public int updatePermissionTrees(String packageName,
+ PackageParser.Package pkgInfo, int flags) {
+ return PermissionManagerService.this.updatePermissionTrees(packageName, pkgInfo, flags);
+ }
+ @Override
public void updatePermissionFlags(String permName, String packageName, int flagMask,
int flagValues, int callingUid, int userId, PermissionCallback callback) {
PermissionManagerService.this.updatePermissionFlags(
@@ -1038,20 +1263,6 @@
return PermissionManagerService.this.getPermissionInfoByGroup(group, flags, callingUid);
}
@Override
- public boolean isPermissionInstant(String permName) {
- synchronized (PermissionManagerService.this.mLock) {
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- return (bp != null && bp.isInstant());
- }
- }
- @Override
- public boolean isPermissionAppOp(String permName) {
- synchronized (PermissionManagerService.this.mLock) {
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- return (bp != null && bp.isAppOp());
- }
- }
- @Override
public PermissionSettings getPermissionSettings() {
return mSettings;
}