summaryrefslogtreecommitdiffstats
path: root/src/com/android/packageinstaller/permission/model
diff options
context:
space:
mode:
authorSvet Ganov <svetoslavganov@google.com>2015-05-09 19:47:27 -0700
committerSvetoslav <svetoslavganov@google.com>2015-05-11 17:09:40 -0700
commit785a9b6369db4c46a389a43ae30e1f6e8003366b (patch)
treed1e3b969ebb7a71c7e7409148278493a690da6b6 /src/com/android/packageinstaller/permission/model
parenta8717e68410873ec51d3fa5fa805f3d3587fb743 (diff)
downloadandroid_packages_apps_PackageInstaller-785a9b6369db4c46a389a43ae30e1f6e8003366b.tar.gz
android_packages_apps_PackageInstaller-785a9b6369db4c46a389a43ae30e1f6e8003366b.tar.bz2
android_packages_apps_PackageInstaller-785a9b6369db4c46a389a43ae30e1f6e8003366b.zip
Add support for permissions gran/revoke policy - package installer.
Change-Id: Id2d5733db0978e909d7159b0eade2b85ec838924
Diffstat (limited to 'src/com/android/packageinstaller/permission/model')
-rw-r--r--src/com/android/packageinstaller/permission/model/AppPermissions.java24
-rw-r--r--src/com/android/packageinstaller/permission/model/Permission.java51
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionApps.java8
-rw-r--r--src/com/android/packageinstaller/permission/model/PermissionGroup.java173
4 files changed, 220 insertions, 36 deletions
diff --git a/src/com/android/packageinstaller/permission/model/AppPermissions.java b/src/com/android/packageinstaller/permission/model/AppPermissions.java
index 9480ce90..8258126a 100644
--- a/src/com/android/packageinstaller/permission/model/AppPermissions.java
+++ b/src/com/android/packageinstaller/permission/model/AppPermissions.java
@@ -18,6 +18,7 @@ package com.android.packageinstaller.permission.model;
import android.content.Context;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.util.ArrayMap;
import com.android.internal.util.ArrayUtils;
@@ -31,17 +32,21 @@ public final class AppPermissions {
private final Context mContext;
- private final PackageInfo mPackageInfo;
-
private final String[] mFilterPermissions;
private final CharSequence mAppLabel;
- public AppPermissions(Context context, PackageInfo packageInfo, String[] permissions) {
+ private final Runnable mOnErrorCallback;
+
+ private PackageInfo mPackageInfo;
+
+ public AppPermissions(Context context, PackageInfo packageInfo, String[] permissions,
+ Runnable onErrorCallback) {
mContext = context;
mPackageInfo = packageInfo;
mFilterPermissions = permissions;
mAppLabel = packageInfo.applicationInfo.loadLabel(context.getPackageManager());
+ mOnErrorCallback = onErrorCallback;
loadPermissionGroups();
}
@@ -50,6 +55,7 @@ public final class AppPermissions {
}
public void refresh() {
+ loadPackageInfo();
loadPermissionGroups();
}
@@ -65,6 +71,18 @@ public final class AppPermissions {
return new ArrayList<>(mGroups.values());
}
+
+ private void loadPackageInfo() {
+ try {
+ mPackageInfo = mContext.getPackageManager().getPackageInfo(
+ mPackageInfo.packageName, PackageManager.GET_PERMISSIONS);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (mOnErrorCallback != null) {
+ mOnErrorCallback.run();
+ }
+ }
+ }
+
private void loadPermissionGroups() {
List<PermissionGroup> groups = new ArrayList<>();
diff --git a/src/com/android/packageinstaller/permission/model/Permission.java b/src/com/android/packageinstaller/permission/model/Permission.java
index 1f51fea9..bfe44af7 100644
--- a/src/com/android/packageinstaller/permission/model/Permission.java
+++ b/src/com/android/packageinstaller/permission/model/Permission.java
@@ -16,19 +16,24 @@
package com.android.packageinstaller.permission.model;
+import android.app.AppOpsManager;
+import android.content.pm.PackageManager;
+
public final class Permission {
private final String mName;
private final int mAppOp;
private boolean mGranted;
private boolean mAppOpAllowed;
+ private int mFlags;
public Permission(String name, boolean granted,
- int appOp, boolean appOpAllowed) {
+ int appOp, boolean appOpAllowed, int flags) {
mName = name;
mGranted = granted;
mAppOp = appOp;
mAppOpAllowed = appOpAllowed;
+ mFlags = flags;
}
public String getName() {
@@ -39,6 +44,10 @@ public final class Permission {
return mAppOp;
}
+ public boolean hasAppOp() {
+ return mAppOp != AppOpsManager.OP_NONE;
+ }
+
public boolean isGranted() {
return mGranted;
}
@@ -51,6 +60,46 @@ public final class Permission {
return mAppOpAllowed;
}
+ public boolean isUserFixed() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_USER_FIXED) != 0;
+ }
+
+ public void setUserFixed(boolean userFixed) {
+ if (userFixed) {
+ mFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_USER_FIXED;
+ }
+ }
+
+ public boolean isPolicyFixed() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
+ }
+
+ public boolean isUserSet() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
+ }
+
+ public void setUserSet(boolean userSet) {
+ if (userSet) {
+ mFlags |= PackageManager.FLAG_PERMISSION_USER_SET;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_USER_SET;
+ }
+ }
+
+ public boolean shouldRevokeOnUpgrade() {
+ return (mFlags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
+ }
+
+ public void setRevokeOnUpgrade(boolean revokeOnUpgrade) {
+ if (revokeOnUpgrade) {
+ mFlags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ } else {
+ mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ }
+ }
+
public void setAppOpAllowed(boolean mAppOpAllowed) {
this.mAppOpAllowed = mAppOpAllowed;
}
diff --git a/src/com/android/packageinstaller/permission/model/PermissionApps.java b/src/com/android/packageinstaller/permission/model/PermissionApps.java
index 8f28433b..2ea2092d 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionApps.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionApps.java
@@ -130,11 +130,15 @@ public class PermissionApps {
}
public void grantRuntimePermissions() {
- mPermissionGroup.grantRuntimePermissions();
+ mPermissionGroup.grantRuntimePermissions(false);
}
public void revokeRuntimePermissions() {
- mPermissionGroup.revokeRuntimePermissions();
+ mPermissionGroup.revokeRuntimePermissions(false);
+ }
+
+ public boolean isPolicyFixed() {
+ return mPermissionGroup.isPolicyFixed();
}
@Override
diff --git a/src/com/android/packageinstaller/permission/model/PermissionGroup.java b/src/com/android/packageinstaller/permission/model/PermissionGroup.java
index 9a5291d8..749ac29e 100644
--- a/src/com/android/packageinstaller/permission/model/PermissionGroup.java
+++ b/src/com/android/packageinstaller/permission/model/PermissionGroup.java
@@ -37,6 +37,8 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed";
private final Context mContext;
+ private final UserHandle mUserHandle;
+ private final PackageManager mPackageManager;
private final AppOpsManager mAppOps;
private final ActivityManager mActivityManager;
@@ -130,28 +132,24 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
continue;
}
-
final boolean granted = (packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
- final int appOp;
- final boolean appOpAllowed;
+ final int appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
+ ? AppOpsManager.permissionToOpCode(requestedPermissionInfo.name)
+ : AppOpsManager.OP_NONE;
- if (group.mAppSupportsRuntimePermissions) {
- appOp = AppOpsManager.OP_NONE;
- appOpAllowed = false;
- } else {
- appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
- ? AppOpsManager.permissionToOpCode(requestedPermissionInfo.name)
- : AppOpsManager.OP_NONE;
- appOpAllowed = appOp != AppOpsManager.OP_NONE
- && context.getSystemService(AppOpsManager.class).checkOp(appOp,
- packageInfo.applicationInfo.uid, packageInfo.packageName)
- == AppOpsManager.MODE_ALLOWED;
- }
+ final boolean appOpAllowed = appOp != AppOpsManager.OP_NONE
+ && context.getSystemService(AppOpsManager.class).checkOp(appOp,
+ packageInfo.applicationInfo.uid, packageInfo.packageName)
+ == AppOpsManager.MODE_ALLOWED;
+
+ final int flags = context.getPackageManager().getPermissionFlags(
+ requestedPermission, packageInfo.packageName,
+ new UserHandle(context.getUserId()));
Permission permission = new Permission(requestedPermission, granted,
- appOp, appOpAllowed);
+ appOp, appOpAllowed, flags);
group.addPermission(permission);
}
@@ -161,6 +159,8 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
private PermissionGroup(Context context, PackageInfo packageInfo, String name,
CharSequence label, String iconPkg, int iconResId) {
mContext = context;
+ mUserHandle = new UserHandle(mContext.getUserId());
+ mPackageManager = mContext.getPackageManager();
mPackageInfo = packageInfo;
mAppSupportsRuntimePermissions = packageInfo.applicationInfo
.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
@@ -212,7 +212,7 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
return true;
}
- public boolean grantRuntimePermissions() {
+ public boolean grantRuntimePermissions(boolean fixedByTheUser) {
final boolean isSharedUser = mPackageInfo.sharedUserId != null;
final int uid = mPackageInfo.applicationInfo.uid;
@@ -221,41 +221,76 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
if (mAppSupportsRuntimePermissions) {
+ // Grant the permission if needed.
if (!permission.isGranted()) {
- mContext.getPackageManager().grantPermission(mPackageInfo.packageName,
- permission.getName(), new UserHandle(mContext.getUserId()));
permission.setGranted(true);
+ mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), new UserHandle(mContext.getUserId()));
+ }
+
+ // Update the permission flags.
+ if (!fixedByTheUser) {
+ // Now the apps can ask for the permission as the user
+ // no longer has it fixed in a denied state.
+ if (permission.isUserFixed() || !permission.isUserSet()) {
+ permission.setUserFixed(false);
+ permission.setUserSet(true);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_USER_FIXED
+ | PackageManager.FLAG_PERMISSION_USER_SET,
+ PackageManager.FLAG_PERMISSION_USER_SET,
+ mUserHandle);
+ }
+ }
+
+ // Enable the permission app op.
+ if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(true);
+ mAppOps.setMode(permission.getAppOp(), android.os.Process.myUid(),
+ mPackageInfo.packageName, AppOpsManager.MODE_ALLOWED);
}
} else {
// Legacy apps cannot have a not granted permission but just in case.
// Also if the permissions has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
- if (!permission.isGranted() || permission.getAppOp() == AppOpsManager.OP_NONE) {
+ if (!permission.isGranted() || !permission.hasAppOp()) {
continue;
}
if (!permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(true);
// It this is a shared user we want to enable the app op for all
// packages in the shared user to match the behavior of this
// shared user having a runtime permission.
if (isSharedUser) {
- String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+ // Enable the app op.
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
for (String packageName : packageNames) {
mAppOps.setMode(permission.getAppOp(), uid, packageName,
AppOpsManager.MODE_ALLOWED);
}
} else {
+ // Enable the app op.
mAppOps.setMode(permission.getAppOp(), uid, mPackageInfo.packageName,
AppOpsManager.MODE_ALLOWED);
}
+ // Mark that the permission should not be be granted on upgrade
+ // when the app begins supporting runtime permissions.
+ if (permission.shouldRevokeOnUpgrade()) {
+ permission.setRevokeOnUpgrade(false);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ 0, mUserHandle);
+ }
+
// Legacy apps do not know that they have to retry access to a
// resource due to changes in runtime permissions (app ops in this
// case). Therefore, we restart them on app op change, so they
// can pick up the change.
mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
-
- permission.setAppOpAllowed(true);
}
}
}
@@ -263,7 +298,7 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
return true;
}
- public boolean revokeRuntimePermissions() {
+ public boolean revokeRuntimePermissions(boolean fixedByTheUser) {
final boolean isSharedUser = mPackageInfo.sharedUserId != null;
final int uid = mPackageInfo.applicationInfo.uid;
@@ -272,40 +307,85 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
if (mAppSupportsRuntimePermissions) {
+ // Revoke the permission if needed.
if (permission.isGranted()) {
- mContext.getPackageManager().revokePermission(mPackageInfo.packageName,
- permission.getName(), new UserHandle(mContext.getUserId()));
permission.setGranted(false);
+ mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
+ permission.getName(), mUserHandle);
+ }
+
+ // Update the permission flags.
+ if (fixedByTheUser) {
+ // Take a note that the user fixed the permission.
+ if (permission.isUserSet() || !permission.isUserFixed()) {
+ permission.setUserSet(false);
+ permission.setUserFixed(true);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_USER_SET
+ | PackageManager.FLAG_PERMISSION_USER_FIXED,
+ PackageManager.FLAG_PERMISSION_USER_FIXED,
+ mUserHandle);
+ }
+ } else {
+ if (!permission.isUserSet()) {
+ permission.setUserSet(true);
+ // Take a note that the user already chose once.
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_USER_SET,
+ PackageManager.FLAG_PERMISSION_USER_SET,
+ mUserHandle);
+ }
+ }
+
+ // Disable the permission app op.
+ if (permission.hasAppOp() && permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(false);
+ mAppOps.setMode(permission.getAppOp(), android.os.Process.myUid(),
+ mPackageInfo.packageName, AppOpsManager.MODE_IGNORED);
}
} else {
// Legacy apps cannot have a non-granted permission but just in case.
// Also if the permission has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
- if (!permission.isGranted() || permission.getAppOp() == AppOpsManager.OP_NONE) {
+ if (!permission.isGranted() || !permission.hasAppOp()) {
continue;
}
if (permission.isAppOpAllowed()) {
+ permission.setAppOpAllowed(false);
// It this is a shared user we want to enable the app op for all
// packages the the shared user to match the behavior of this
// shared user having a runtime permission.
if (isSharedUser) {
- String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
for (String packageName : packageNames) {
+ // Disable the app op.
mAppOps.setMode(permission.getAppOp(), uid,
packageName, AppOpsManager.MODE_IGNORED);
}
} else {
+ // Disable the app op.
mAppOps.setMode(permission.getAppOp(), uid,
mPackageInfo.packageName, AppOpsManager.MODE_IGNORED);
}
+ // Mark that the permission should not be granted on upgrade
+ // when the app begins supporting runtime permissions.
+ if (!permission.shouldRevokeOnUpgrade()) {
+ permission.setRevokeOnUpgrade(true);
+ mPackageManager.updatePermissionFlags(permission.getName(),
+ mPackageInfo.packageName,
+ PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
+ mUserHandle);
+ }
+
// Disabling an app op may put the app in a situation in which it
// has a handle to state it shouldn't have, so we have to kill the
// app. This matches the revoke runtime permission behavior.
mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
-
- permission.setAppOpAllowed(false);
}
}
}
@@ -317,6 +397,39 @@ public final class PermissionGroup implements Comparable<PermissionGroup> {
return new ArrayList<>(mPermissions.values());
}
+ public boolean isUserFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (!permission.isUserFixed()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isPolicyFixed() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (permission.isPolicyFixed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isUserSet() {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ Permission permission = mPermissions.valueAt(i);
+ if (!permission.isUserSet()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
public int compareTo(PermissionGroup another) {
final int result = mLabel.toString().compareTo(another.mLabel.toString());