summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt20
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java4
-rw-r--r--core/java/android/app/ApplicationPackageManager.java30
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl9
-rw-r--r--core/java/android/content/pm/PackageManager.java112
-rw-r--r--core/java/android/widget/AppSecurityPermissions.java2
-rw-r--r--services/core/java/com/android/server/pm/BasePermission.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java148
-rw-r--r--services/core/java/com/android/server/pm/PermissionsState.java415
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java6
-rw-r--r--services/core/java/com/android/server/pm/Settings.java173
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java12
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java21
13 files changed, 726 insertions, 228 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 79908fa..53db75d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9505,6 +9505,7 @@ package android.content.pm {
method public abstract android.content.pm.PackageInstaller getPackageInstaller();
method public abstract java.lang.String[] getPackagesForUid(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
+ method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, java.lang.String);
@@ -9522,7 +9523,7 @@ package android.content.pm {
method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
- method public abstract void grantPermission(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -9538,10 +9539,11 @@ package android.content.pm {
method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
- method public abstract void revokePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
method public abstract void verifyPendingInstall(int, int);
field public static final java.lang.String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
@@ -9627,6 +9629,10 @@ package android.content.pm {
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
+ field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
+ field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
+ field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2
+ field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
@@ -9679,6 +9685,7 @@ package android.content.pm {
field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
field public static final int INSTALL_SUCCEEDED = 1; // 0x1
+ field public static final int MASK_PERMISSION_FLAGS = 15; // 0xf
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
@@ -9699,6 +9706,9 @@ package android.content.pm {
ctor public PackageManager.NameNotFoundException(java.lang.String);
}
+ public static abstract class PackageManager.PermissionFlags implements java.lang.annotation.Annotation {
+ }
+
public class PackageStats implements android.os.Parcelable {
ctor public PackageStats(java.lang.String);
ctor public PackageStats(android.os.Parcel);
@@ -34042,6 +34052,7 @@ package android.test.mock {
method public android.content.pm.PackageInstaller getPackageInstaller();
method public java.lang.String[] getPackagesForUid(int);
method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
+ method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, java.lang.String);
@@ -34059,7 +34070,7 @@ package android.test.mock {
method public android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
- method public void grantPermission(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean hasSystemFeature(java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -34075,11 +34086,12 @@ package android.test.mock {
method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
- method public void revokePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
method public void verifyPendingInstall(int, int);
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 39de1dc7..eb834f2 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1609,9 +1609,9 @@ public final class Pm {
try {
if (grant) {
- mPm.grantPermission(pkg, perm, userId);
+ mPm.grantRuntimePermission(pkg, perm, userId);
} else {
- mPm.revokePermission(pkg, perm, userId);
+ mPm.revokeRuntimePermission(pkg, perm, userId);
}
return 0;
} catch (RemoteException e) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 07eee12..04f6430 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -446,18 +446,40 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
- public void grantPermission(String packageName, String permissionName, UserHandle user) {
+ public void grantRuntimePermission(String packageName, String permissionName,
+ UserHandle user) {
+ try {
+ mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String permissionName,
+ UserHandle user) {
+ try {
+ mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
+ public int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
try {
- mPM.grantPermission(packageName, permissionName, user.getIdentifier());
+ return mPM.getPermissionFlags(permissionName, packageName, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
@Override
- public void revokePermission(String packageName, String permissionName, UserHandle user) {
+ public void updatePermissionFlags(String permissionName, String packageName,
+ int flagMask, int flagValues, UserHandle user) {
try {
- mPM.revokePermission(packageName, permissionName, user.getIdentifier());
+ mPM.updatePermissionFlags(permissionName, packageName, flagMask,
+ flagValues, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 94b0223..ddff782 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -96,9 +96,14 @@ interface IPackageManager {
void removePermission(String name);
- void grantPermission(String packageName, String permissionName, int userId);
+ void grantRuntimePermission(String packageName, String permissionName, int userId);
- void revokePermission(String packageName, String permissionName, int userId);
+ void revokeRuntimePermission(String packageName, String permissionName, int userId);
+
+ int getPermissionFlags(String permissionName, String packageName, int userId);
+
+ void updatePermissionFlags(String permissionName, String packageName, int flagMask,
+ int flagValues, int userId);
boolean isProtectedBroadcast(String actionName);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 51fa075..6401fe6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1888,6 +1888,57 @@ public abstract class PackageManager {
public static final String EXTRA_FAILURE_EXISTING_PERMISSION
= "android.content.pm.extra.FAILURE_EXISTING_PERMISSION";
+ /**
+ * Permission flag: The permission is set in its current state
+ * by the user and apps can still request it at runtime.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_USER_SET = 1 << 0;
+
+ /**
+ * Permission flag: The permission is set in its current state
+ * by the user and it is fixed, i.e. apps can no longer request
+ * this permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_USER_FIXED = 1 << 1;
+
+ /**
+ * Permission flag: The permission is set in its current state
+ * by device policy and neither apps nor the user can change
+ * its state.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_POLICY_FIXED = 1 << 2;
+
+ /**
+ * Permission flag: The permission is set in a granted state but
+ * access to resources it guards is restricted by other means to
+ * enable revoking a permission on legacy apps that do not support
+ * runtime permissions. If this permission is upgraded to runtime
+ * because the app was updated to support runtime permissions, the
+ * the permission will be revoked in the upgrade process.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3;
+
+
+ /**
+ * Mask for all permission flags.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int MASK_PERMISSION_FLAGS = 0xF;
+
/**
* Retrieve overall information about an application package that is
* installed on the system.
@@ -2374,6 +2425,20 @@ public abstract class PackageManager {
*/
public abstract void removePermission(String name);
+
+ /**
+ * Permission flags set when granting or revoking a permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @IntDef({FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_FIXED,
+ FLAG_PERMISSION_POLICY_FIXED,
+ FLAG_PERMISSION_REVOKE_ON_UPGRADE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionFlags {}
+
/**
* Grant a runtime permission to an application which the application does not
* already have. The permission must have been requested by the application.
@@ -2389,19 +2454,20 @@ public abstract class PackageManager {
* @param permissionName The permission name to grant.
* @param user The user for which to grant the permission.
*
- * @see #revokePermission(String, String, android.os.UserHandle)
+ * @see #revokeRuntimePermission(String, String, android.os.UserHandle)
+ * @see android.content.pm.PackageManager.PermissionFlags
*
* @hide
*/
@SystemApi
- public abstract void grantPermission(@NonNull String packageName,
+ public abstract void grantRuntimePermission(@NonNull String packageName,
@NonNull String permissionName, @NonNull UserHandle user);
/**
* Revoke a runtime permission that was previously granted by {@link
- * #grantPermission(String, String, android.os.UserHandle)}. The permission
- * must have been requested by and granted to the application. If the
- * application is not allowed to hold the permission, a {@link
+ * #grantRuntimePermission(String, String, android.os.UserHandle)}. The
+ * permission must have been requested by and granted to the application.
+ * If the application is not allowed to hold the permission, a {@link
* java.lang.SecurityException} is thrown.
* <p>
* <strong>Note: </strong>Using this API requires holding
@@ -2413,15 +2479,47 @@ public abstract class PackageManager {
* @param permissionName The permission name to revoke.
* @param user The user for which to revoke the permission.
*
- * @see #grantPermission(String, String, android.os.UserHandle)
+ * @see #grantRuntimePermission(String, String, android.os.UserHandle)
+ * @see android.content.pm.PackageManager.PermissionFlags
*
* @hide
*/
@SystemApi
- public abstract void revokePermission(@NonNull String packageName,
+ public abstract void revokeRuntimePermission(@NonNull String packageName,
@NonNull String permissionName, @NonNull UserHandle user);
/**
+ * Gets the state flags associated with a permission.
+ *
+ * @param permissionName The permission for which to get the flags.
+ * @param packageName The package name for which to get the flags.
+ * @param user The user for which to get permission flags.
+ * @return The permission flags.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract @PermissionFlags int getPermissionFlags(String permissionName,
+ String packageName, @NonNull UserHandle user);
+
+ /**
+ * Updates the flags associated with a permission by replacing the flags in
+ * the specified mask with the provided flag values.
+ *
+ * @param permissionName The permission for which to update the flags.
+ * @param packageName The package name for which to update the flags.
+ * @param flagMask The flags which to replace.
+ * @param flagValues The flags with which to replace.
+ * @param user The user for which to update the permission flags.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract void updatePermissionFlags(String permissionName,
+ String packageName, @PermissionFlags int flagMask, int flagValues,
+ @NonNull UserHandle user);
+
+ /**
* Returns an {@link android.content.Intent} suitable for passing to
* {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
* which prompts the user to grant permissions to this application.
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 6feb94b..bb4a948 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -244,7 +244,7 @@ public class AppSecurityPermissions {
@Override
public void onClick(DialogInterface dialog, int which) {
PackageManager pm = getContext().getPackageManager();
- pm.revokePermission(mPackageName, mPerm.name,
+ pm.revokeRuntimePermission(mPackageName, mPerm.name,
new UserHandle(mContext.getUserId()));
PermissionItemView.this.setVisibility(View.GONE);
}
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 30f8b37..18407c9 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -20,8 +20,6 @@ import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
import android.os.UserHandle;
-import com.android.internal.util.ArrayUtils;
-
final class BasePermission {
final static int TYPE_NORMAL = 0;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a120c1f..aeaa272 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -206,6 +206,7 @@ import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.storage.DeviceStorageMonitorInternal;
import org.xmlpull.v1.XmlPullParser;
@@ -304,6 +305,8 @@ public class PackageManagerService extends IPackageManager.Stub {
static final int REMOVE_CHATTY = 1<<16;
+ private static final int[] EMPTY_INT_ARRAY = new int[0];
+
/**
* Timeout (in milliseconds) after which the watchdog should declare that
* our handler thread is wedged. The usual default for such things is one
@@ -3139,18 +3142,26 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private static void enforceOnlySystemUpdatesPermissionPolicyFlags(int flagMask, int flagValues) {
+ if (((flagMask & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0
+ || (flagValues & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0)
+ && getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system can modify policy flags");
+ }
+ }
+
@Override
- public void grantPermission(String packageName, String name, int userId) {
+ public void grantRuntimePermission(String packageName, String name, int userId) {
if (!sUserManager.exists(userId)) {
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
- "grantPermission");
+ "grantRuntimePermission");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
- "grantPermission");
+ "grantRuntimePermission");
boolean gidsChanged = false;
final SettingBase sb;
@@ -3197,17 +3208,17 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public void revokePermission(String packageName, String name, int userId) {
+ public void revokeRuntimePermission(String packageName, String name, int userId) {
if (!sUserManager.exists(userId)) {
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
- "revokePermission");
+ "revokeRuntimePermission");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
- "revokePermission");
+ "revokeRuntimePermission");
final SettingBase sb;
@@ -3236,7 +3247,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
- // Critical, after this call all should never have the permission.
+ // Critical, after this call app should never have the permission.
mSettings.writeRuntimePermissionsForUserLPr(userId, true);
}
@@ -3244,6 +3255,86 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public int getPermissionFlags(String name, String packageName, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return 0;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "getPermissionFlags");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "getPermissionFlags");
+
+ synchronized (mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ final BasePermission bp = mSettings.mPermissions.get(name);
+ if (bp == null) {
+ throw new IllegalArgumentException("Unknown permission: " + name);
+ }
+
+ SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ PermissionsState permissionsState = sb.getPermissionsState();
+ return permissionsState.getPermissionFlags(name, userId);
+ }
+ }
+
+ @Override
+ public void updatePermissionFlags(String name, String packageName, int flagMask,
+ int flagValues, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "updatePermissionFlags");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "updatePermissionFlags");
+
+ enforceOnlySystemUpdatesPermissionPolicyFlags(flagMask, flagValues);
+
+ synchronized (mPackages) {
+ final PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ final BasePermission bp = mSettings.mPermissions.get(name);
+ if (bp == null) {
+ throw new IllegalArgumentException("Unknown permission: " + name);
+ }
+
+ SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ PermissionsState permissionsState = sb.getPermissionsState();
+
+ if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) {
+ // Install and runtime permissions are stored in different places,
+ // so figure out what permission changed and persist the change.
+ if (permissionsState.getInstallPermissionState(name) != null) {
+ scheduleWriteSettingsLocked();
+ } else if (permissionsState.getRuntimePermissionState(name, userId) != null) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+ }
+ }
+
+ @Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
return mProtectedBroadcasts.contains(actionName);
@@ -7530,8 +7621,8 @@ public class PackageManagerService extends IPackageManager.Stub {
final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
- int[] upgradeUserIds = PermissionsState.USERS_NONE;
- int[] changedRuntimePermissionUserIds = PermissionsState.USERS_NONE;
+ int[] upgradeUserIds = EMPTY_INT_ARRAY;
+ int[] changedRuntimePermissionUserIds = EMPTY_INT_ARRAY;
boolean changedInstallPermission = false;
@@ -7657,11 +7748,18 @@ public class PackageManagerService extends IPackageManager.Stub {
// Grant previously granted runtime permissions.
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.hasRuntimePermission(bp.name, userId)) {
+ PermissionState permissionState = origPermissions
+ .getRuntimePermissionState(bp.name, userId);
+ final int flags = permissionState.getFlags();
if (permissionsState.grantRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_FAILURE) {
// If we cannot put the permission as it was, we have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
+ } else {
+ // Propagate the permission flags.
+ permissionsState.updatePermissionFlags(bp, userId,
+ flags, flags);
}
}
}
@@ -7669,13 +7767,28 @@ public class PackageManagerService extends IPackageManager.Stub {
case GRANT_UPGRADE: {
// Grant runtime permissions for a previously held install permission.
- permissionsState.revokeInstallPermission(bp);
- for (int userId : upgradeUserIds) {
- if (permissionsState.grantRuntimePermission(bp, userId) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // If we granted the permission, we have to write.
- changedRuntimePermissionUserIds = ArrayUtils.appendInt(
- changedRuntimePermissionUserIds, userId);
+ PermissionState permissionState = origPermissions
+ .getInstallPermissionState(bp.name);
+ final int flags = permissionState != null ? permissionState.getFlags() : 0;
+
+ origPermissions.revokeInstallPermission(bp);
+ // We will be transferring the permission flags, so clear them.
+ origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+
+ // If the permission is not to be promoted to runtime we ignore it and
+ // also its other flags as they are not applicable to install permissions.
+ if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
+ for (int userId : upgradeUserIds) {
+ if (permissionsState.grantRuntimePermission(bp, userId) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ // Transfer the permission flags.
+ permissionsState.updatePermissionFlags(bp, userId,
+ flags, flags);
+ // If we granted the permission, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
}
}
} break;
@@ -7692,6 +7805,9 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
if (permissionsState.revokeInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ // Also drop the permission flags.
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
changedInstallPermission = true;
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 3749957..171a50d 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -20,10 +20,13 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
@@ -55,15 +58,8 @@ public final class PermissionsState {
/** The permission operation failed. */
public static final int PERMISSION_OPERATION_FAILURE = 3;
- public static final int[] USERS_ALL = {UserHandle.USER_ALL};
-
- public static final int[] USERS_NONE = {};
-
private static final int[] NO_GIDS = {};
- private static final int FLAG_INSTALL_PERMISSIONS = 1 << 0;
- private static final int FLAG_RUNTIME_PERMISSIONS = 1 << 1;
-
private ArrayMap<String, PermissionData> mPermissions;
private int[] mGlobalGids = NO_GIDS;
@@ -147,14 +143,16 @@ public final class PermissionsState {
}
/**
- * Grant a runtime permission.
+ * Grant a runtime permission for a given device user.
*
* @param permission The permission to grant.
+ * @param userId The device user id.
* @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
* or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
* #PERMISSION_OPERATION_FAILURE}.
*/
public int grantRuntimePermission(BasePermission permission, int userId) {
+ enforceValidUserId(userId);
if (userId == UserHandle.USER_ALL) {
return PERMISSION_OPERATION_FAILURE;
}
@@ -162,15 +160,18 @@ public final class PermissionsState {
}
/**
- * Revoke a runtime permission for a given device user.
+ * Revoke a runtime permission for a given device user.
*
* @param permission The permission to revoke.
* @param userId The device user id.
* @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
* or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
* #PERMISSION_OPERATION_FAILURE}.
+ *
+ * @see android.content.pm.PackageManager.PermissionFlags
*/
public int revokeRuntimePermission(BasePermission permission, int userId) {
+ enforceValidUserId(userId);
if (userId == UserHandle.USER_ALL) {
return PERMISSION_OPERATION_FAILURE;
}
@@ -178,17 +179,6 @@ public final class PermissionsState {
}
/**
- * Gets whether this state has a given permission, regardless if
- * it is install time or runtime one.
- *
- * @param name The permission name.
- * @return Whether this state has the permission.
- */
- public boolean hasPermission(String name) {
- return mPermissions != null && mPermissions.get(name) != null;
- }
-
- /**
* Gets whether this state has a given runtime permission for a
* given device user id.
*
@@ -197,6 +187,7 @@ public final class PermissionsState {
* @return Whether this state has the permission.
*/
public boolean hasRuntimePermission(String name, int userId) {
+ enforceValidUserId(userId);
return !hasInstallPermission(name) && hasPermission(name, userId);
}
@@ -211,36 +202,6 @@ public final class PermissionsState {
}
/**
- * Revokes a permission for all users regardless if it is an install or
- * a runtime permission.
- *
- * @param permission The permission to revoke.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int revokePermission(BasePermission permission) {
- if (!hasPermission(permission.name)) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- int result = PERMISSION_OPERATION_SUCCESS;
-
- PermissionData permissionData = mPermissions.get(permission.name);
- for (int userId : permissionData.getUserIds()) {
- if (revokePermission(permission, userId)
- == PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
- result = PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
- break;
- }
- }
-
- mPermissions.remove(permission.name);
-
- return result;
- }
-
- /**
* Gets whether the state has a given permission for the specified
* user, regardless if this is an install or a runtime permission.
*
@@ -256,49 +217,133 @@ public final class PermissionsState {
}
PermissionData permissionData = mPermissions.get(name);
- return permissionData != null && permissionData.hasUserId(userId);
+ return permissionData != null && permissionData.isGranted(userId);
}
/**
- * Gets all permissions regardless if they are install or runtime.
+ * Gets all permissions for a given device user id regardless if they
+ * are install time or runtime permissions.
*
+ * @param userId The device user id.
* @return The permissions or an empty set.
*/
- public Set<String> getPermissions() {
- if (mPermissions != null) {
- return mPermissions.keySet();
+ public Set<String> getPermissions(int userId) {
+ enforceValidUserId(userId);
+
+ if (mPermissions == null) {
+ return Collections.emptySet();
}
- return Collections.emptySet();
+ Set<String> permissions = new ArraySet<>();
+
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ String permission = mPermissions.keyAt(i);
+
+ if (hasInstallPermission(permission)) {
+ permissions.add(permission);
+ }
+
+ if (userId != UserHandle.USER_ALL) {
+ if (hasRuntimePermission(permission, userId)) {
+ permissions.add(permission);
+ }
+ }
+ }
+
+ return permissions;
}
/**
- * Gets all permissions for a given device user id regardless if they
- * are install time or runtime permissions.
+ * Gets the state for an install permission or null if no such.
*
+ * @param name The permission name.
+ * @return The permission state.
+ */
+ public PermissionState getInstallPermissionState(String name) {
+ return getPermissionState(name, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Gets the state for a runtime permission or null if no such.
+ *
+ * @param name The permission name.
* @param userId The device user id.
- * @return The permissions or an empty set.
+ * @return The permission state.
*/
- public Set<String> getPermissions(int userId) {
- return getPermissionsInternal(FLAG_INSTALL_PERMISSIONS | FLAG_RUNTIME_PERMISSIONS, userId);
+ public PermissionState getRuntimePermissionState(String name, int userId) {
+ enforceValidUserId(userId);
+ return getPermissionState(name, userId);
}
/**
- * Gets all runtime permissions.
+ * Gets all install permission states.
*
- * @return The permissions or an empty set.
+ * @return The permission states or an empty set.
*/
- public Set<String> getRuntimePermissions(int userId) {
- return getPermissionsInternal(FLAG_RUNTIME_PERMISSIONS, userId);
+ public List<PermissionState> getInstallPermissionStates() {
+ return getPermissionStatesInternal(UserHandle.USER_ALL);
}
/**
- * Gets all install permissions.
+ * Gets all runtime permission states.
*
- * @return The permissions or an empty set.
+ * @return The permission states or an empty set.
+ */
+ public List<PermissionState> getRuntimePermissionStates(int userId) {
+ enforceValidUserId(userId);
+ return getPermissionStatesInternal(userId);
+ }
+
+ /**
+ * Gets the flags for a permission regardless if it is install or
+ * runtime permission.
+ *
+ * @param name The permission name.
+ * @return The permission state or null if no such.
*/
- public Set<String> getInstallPermissions() {
- return getPermissionsInternal(FLAG_INSTALL_PERMISSIONS, UserHandle.USER_ALL);
+ public int getPermissionFlags(String name, int userId) {
+ PermissionState installPermState = getInstallPermissionState(name);
+ if (installPermState != null) {
+ return installPermState.getFlags();
+ }
+ PermissionState runtimePermState = getRuntimePermissionState(name, userId);
+ if (runtimePermState != null) {
+ return runtimePermState.getFlags();
+ }
+ return 0;
+ }
+
+ /**
+ * Update the flags associated with a given permission.
+ * @param permission The permission whose flags to update.
+ * @param userId The user for which to update.
+ * @param flagMask Mask for which flags to change.
+ * @param flagValues New values for the mask flags.
+ * @return Whether the permission flags changed.
+ */
+ public boolean updatePermissionFlags(BasePermission permission, int userId,
+ int flagMask, int flagValues) {
+ enforceValidUserId(userId);
+
+ final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
+
+ if (mPermissions == null) {
+ if (!mayChangeFlags) {
+ return false;
+ }
+ ensurePermissionData(permission);
+ }
+
+ PermissionData permissionData = mPermissions.get(permission.name);
+ if (permissionData == null) {
+ if (!mayChangeFlags) {
+ return false;
+ }
+ permissionData = ensurePermissionData(permission);
+ }
+
+ return permissionData.updateFlags(userId, flagMask, flagValues);
}
/**
@@ -357,36 +402,37 @@ public final class PermissionsState {
mPermissions = null;
}
- private Set<String> getPermissionsInternal(int flags, int userId) {
- enforceValidUserId(userId);
-
+ private PermissionState getPermissionState(String name, int userId) {
if (mPermissions == null) {
- return Collections.emptySet();
+ return null;
}
+ PermissionData permissionData = mPermissions.get(name);
+ if (permissionData == null) {
+ return null;
+ }
+ return permissionData.getPermissionState(userId);
+ }
- if (userId == UserHandle.USER_ALL) {
- flags = FLAG_INSTALL_PERMISSIONS;
+ private List<PermissionState> getPermissionStatesInternal(int userId) {
+ enforceValidUserId(userId);
+
+ if (mPermissions == null) {
+ return Collections.emptyList();
}
- Set<String> permissions = new ArraySet<>();
+ List<PermissionState> permissionStates = new ArrayList<>();
final int permissionCount = mPermissions.size();
for (int i = 0; i < permissionCount; i++) {
- String permission = mPermissions.keyAt(i);
+ PermissionData permissionData = mPermissions.valueAt(i);
- if ((flags & FLAG_INSTALL_PERMISSIONS) != 0) {
- if (hasInstallPermission(permission)) {
- permissions.add(permission);
- }
- }
- if ((flags & FLAG_RUNTIME_PERMISSIONS) != 0) {
- if (hasRuntimePermission(permission, userId)) {
- permissions.add(permission);
- }
+ PermissionState permissionState = permissionData.getPermissionState(userId);
+ if (permissionState != null) {
+ permissionStates.add(permissionState);
}
}
- return permissions;
+ return permissionStates;
}
private int grantPermission(BasePermission permission, int userId) {
@@ -397,17 +443,9 @@ public final class PermissionsState {
final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
-
- PermissionData permissionData = mPermissions.get(permission.name);
- if (permissionData == null) {
- permissionData = new PermissionData(permission);
- mPermissions.put(permission.name, permissionData);
- }
+ PermissionData permissionData = ensurePermissionData(permission);
- if (!permissionData.addUserId(userId)) {
+ if (!permissionData.grant(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
@@ -431,16 +469,12 @@ public final class PermissionsState {
PermissionData permissionData = mPermissions.get(permission.name);
- if (!permissionData.removeUserId(userId)) {
+ if (!permissionData.revoke(userId)) {
return PERMISSION_OPERATION_FAILURE;
}
- if (permissionData.getUserIds() == USERS_NONE) {
- mPermissions.remove(permission.name);
- }
-
- if (mPermissions.isEmpty()) {
- mPermissions = null;
+ if (permissionData.isDefault()) {
+ ensureNoPermissionData(permission.name);
}
if (hasGids) {
@@ -468,9 +502,31 @@ public final class PermissionsState {
}
}
+ private PermissionData ensurePermissionData(BasePermission permission) {
+ if (mPermissions == null) {
+ mPermissions = new ArrayMap<>();
+ }
+ PermissionData permissionData = mPermissions.get(permission.name);
+ if (permissionData == null) {
+ permissionData = new PermissionData(permission);
+ mPermissions.put(permission.name, permissionData);
+ }
+ return permissionData;
+ }
+
+ private void ensureNoPermissionData(String name) {
+ if (mPermissions == null) {
+ return;
+ }
+ mPermissions.remove(name);
+ if (mPermissions.isEmpty()) {
+ mPermissions = null;
+ }
+ }
+
private static final class PermissionData {
private final BasePermission mPerm;
- private int[] mUserIds = USERS_NONE;
+ private SparseArray<PermissionState> mUserStates = new SparseArray<>();
public PermissionData(BasePermission perm) {
mPerm = perm;
@@ -478,11 +534,11 @@ public final class PermissionsState {
public PermissionData(PermissionData other) {
this(other.mPerm);
-
- if (other.mUserIds == USERS_ALL || other.mUserIds == USERS_NONE) {
- mUserIds = other.mUserIds;
- } else {
- mUserIds = Arrays.copyOf(other.mUserIds, other.mUserIds.length);
+ final int otherStateCount = other.mUserStates.size();
+ for (int i = 0; i < otherStateCount; i++) {
+ final int otherUserId = other.mUserStates.keyAt(i);
+ PermissionState otherState = other.mUserStates.valueAt(i);
+ mUserStates.put(otherUserId, new PermissionState(otherState));
}
}
@@ -490,53 +546,146 @@ public final class PermissionsState {
return mPerm.computeGids(userId);
}
- public int[] getUserIds() {
- return mUserIds;
- }
-
- public boolean hasUserId(int userId) {
- if (mUserIds == USERS_ALL) {
- return true;
+ public boolean isGranted(int userId) {
+ if (isInstallPermission()) {
+ userId = UserHandle.USER_ALL;
}
- if (userId != UserHandle.USER_ALL) {
- return ArrayUtils.contains(mUserIds, userId);
+ PermissionState userState = mUserStates.get(userId);
+ if (userState == null) {
+ return false;
}
- return false;
+ return userState.mGranted;
}
- public boolean addUserId(int userId) {
- if (hasUserId(userId)) {
+ public boolean grant(int userId) {
+ if (!isCompatibleUserId(userId)) {
return false;
}
- if (userId == UserHandle.USER_ALL) {
- mUserIds = USERS_ALL;
- return true;
+ if (isGranted(userId)) {
+ return false;
}
- mUserIds = ArrayUtils.appendInt(mUserIds, userId);
+ PermissionState userState = mUserStates.get(userId);
+ if (userState == null) {
+ userState = new PermissionState(mPerm.name);
+ mUserStates.put(userId, userState);
+ }
+
+ userState.mGranted = true;
return true;
}
- public boolean removeUserId(int userId) {
- if (!hasUserId(userId)) {
+ public boolean revoke(int userId) {
+ if (!isCompatibleUserId(userId)) {
return false;
}
- if (mUserIds == USERS_ALL) {
- mUserIds = UserManagerService.getInstance().getUserIds();
+ if (!isGranted(userId)) {
+ return false;
}
- mUserIds = ArrayUtils.removeInt(mUserIds, userId);
+ PermissionState userState = mUserStates.get(userId);
+ userState.mGranted = false;
- if (mUserIds.length == 0) {
- mUserIds = USERS_NONE;
+ if (userState.isDefault()) {
+ mUserStates.remove(userId);
}
return true;
}
+
+ public PermissionState getPermissionState(int userId) {
+ return mUserStates.get(userId);
+ }
+
+ public int getFlags(int userId) {
+ PermissionState userState = mUserStates.get(userId);
+ if (userState != null) {
+ return userState.mFlags;
+ }
+ return 0;
+ }
+
+ public boolean isDefault() {
+ return mUserStates.size() <= 0;
+ }
+
+ public static boolean isInstallPermissionKey(int userId) {
+ return userId == UserHandle.USER_ALL;
+ }
+
+ public boolean updateFlags(int userId, int flagMask, int flagValues) {
+ if (isInstallPermission()) {
+ userId = UserHandle.USER_ALL;
+ }
+
+ if (!isCompatibleUserId(userId)) {
+ return false;
+ }
+
+ final int newFlags = flagValues & flagMask;
+
+ PermissionState userState = mUserStates.get(userId);
+ if (userState != null) {
+ final int oldFlags = userState.mFlags;
+ userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
+ if (userState.isDefault()) {
+ mUserStates.remove(userId);
+ }
+ return userState.mFlags != oldFlags;
+ } else if (newFlags != 0) {
+ userState = new PermissionState(mPerm.name);
+ userState.mFlags = newFlags;
+ mUserStates.put(userId, userState);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean isCompatibleUserId(int userId) {
+ return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
+ }
+
+ private boolean isInstallPermission() {
+ return mUserStates.size() == 1
+ && mUserStates.get(UserHandle.USER_ALL) != null;
+ }
+ }
+
+ public static final class PermissionState {
+ private final String mName;
+ private boolean mGranted;
+ private int mFlags;
+
+ public PermissionState(String name) {
+ mName = name;
+ }
+
+ public PermissionState(PermissionState other) {
+ mName = other.mName;
+ mGranted = other.mGranted;
+ mFlags = other.mFlags;
+ }
+
+ public boolean isDefault() {
+ return !mGranted && mFlags == 0;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public boolean isGranted() {
+ return mGranted;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 0c7f79d..c35258a 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -21,11 +21,13 @@ import android.content.pm.ApplicationInfo;
import java.util.Arrays;
abstract class SettingBase {
+ private static final int[] USERS_NONE = new int[0];
+
int pkgFlags;
int pkgPrivateFlags;
protected final PermissionsState mPermissionsState;
- private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE;
+ private int[] mPermissionsUpdatedForUserIds = USERS_NONE;
SettingBase(int pkgFlags, int pkgPrivateFlags) {
setFlags(pkgFlags);
@@ -53,7 +55,7 @@ abstract class SettingBase {
return;
}
- if (userIds == PermissionsState.USERS_NONE || userIds == PermissionsState.USERS_ALL) {
+ if (userIds == USERS_NONE) {
mPermissionsUpdatedForUserIds = userIds;
} else {
mPermissionsUpdatedForUserIds = Arrays.copyOf(userIds, userIds.length);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index fd70ce1..2e9656a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -60,6 +60,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.PackageManagerService.DumpState;
+import com.android.server.pm.PermissionsState.PermissionState;
import java.io.FileNotFoundException;
import java.util.Collection;
@@ -178,6 +179,8 @@ final class Settings {
private static final String ATTR_CODE = "code";
private static final String ATTR_NOT_LAUNCHED = "nl";
private static final String ATTR_ENABLED = "enabled";
+ private static final String ATTR_GRANTED = "granted";
+ private static final String ATTR_FLAGS = "flags";
private static final String ATTR_ENABLED_CALLER = "enabledCaller";
private static final String ATTR_STOPPED = "stopped";
// Legacy, here for reading older versions of the package-restrictions.
@@ -820,14 +823,20 @@ final class Settings {
}
if (!used) {
+ PermissionsState permissionsState = sus.getPermissionsState();
+
// Try to revoke as an install permission which is for all users.
- if (sus.getPermissionsState().revokeInstallPermission(bp) ==
+ // The package is gone - no need to keep flags for applying policy.
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+
+ if (permissionsState.revokeInstallPermission(bp) ==
PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
return UserHandle.USER_ALL;
}
// Try to revoke as an install permission which is per user.
- if (sus.getPermissionsState().revokeRuntimePermission(bp, userId) ==
+ if (permissionsState.revokeRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
return userId;
}
@@ -1724,10 +1733,32 @@ final class Settings {
continue;
}
- if (permissionsState.grantInstallPermission(bp) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
- XmlUtils.skipCurrentTag(parser);
+ String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
+ final boolean granted = grantedStr == null
+ || Boolean.parseBoolean(grantedStr);
+
+ String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
+ final int flags = (flagsStr != null)
+ ? Integer.parseInt(flagsStr, 16) : 0;
+
+ if (granted) {
+ if (permissionsState.grantInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ }
+ } else {
+ if (permissionsState.revokeInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ }
}
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
@@ -1737,17 +1768,19 @@ final class Settings {
}
}
- void writePermissionsLPr(XmlSerializer serializer, Set<String> permissions)
+ void writePermissionsLPr(XmlSerializer serializer, List<PermissionState> permissionStates)
throws IOException {
- if (permissions.isEmpty()) {
+ if (permissionStates.isEmpty()) {
return;
}
serializer.startTag(null, TAG_PERMISSIONS);
- for (String permission : permissions) {
+ for (PermissionState permissionState : permissionStates) {
serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, permission);
+ serializer.attribute(null, ATTR_NAME, permissionState.getName());
+ serializer.attribute(null, ATTR_GRANTED, String.valueOf(permissionState.isGranted()));
+ serializer.attribute(null, ATTR_FLAGS, Integer.toHexString(permissionState.getFlags()));
serializer.endTag(null, TAG_ITEM);
}
@@ -1945,7 +1978,8 @@ final class Settings {
serializer.attribute(null, "userId",
Integer.toString(usr.userId));
usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
- writePermissionsLPr(serializer, usr.getPermissionsState().getInstallPermissions());
+ writePermissionsLPr(serializer, usr.getPermissionsState()
+ .getInstallPermissionStates());
serializer.endTag(null, "shared-user");
}
@@ -2120,7 +2154,8 @@ final class Settings {
// If this is a shared user, the permissions will be written there.
if (pkg.sharedUser == null) {
- writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions());
+ writePermissionsLPr(serializer, pkg.getPermissionsState()
+ .getInstallPermissionStates());
}
serializer.endTag(null, "updated-package");
@@ -2175,9 +2210,9 @@ final class Settings {
serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
}
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
- if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions());
- }
+
+ writePermissionsLPr(serializer, pkg.getPermissionsState()
+ .getInstallPermissionStates());
writeSigningKeySetLPr(serializer, pkg.keySetData);
writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
@@ -3922,7 +3957,7 @@ final class Settings {
PermissionsState permissionsState = ps.getPermissionsState();
dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id));
dumpRuntimePermissionsLPr(pw, prefix + " ", permissionsState
- .getRuntimePermissions(user.id));
+ .getRuntimePermissionStates(user.id));
}
ArraySet<String> cmp = ps.getDisabledComponents(user.id);
@@ -4071,7 +4106,8 @@ final class Settings {
for (int userId : UserManagerService.getInstance().getUserIds()) {
final int[] gids = permissionsState.computeGids(userId);
- Set<String> permissions = permissionsState.getRuntimePermissions(userId);
+ List<PermissionState> permissions = permissionsState
+ .getRuntimePermissionStates(userId);
if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
dumpGidsLPr(pw, prefix + " ", gids);
@@ -4120,22 +4156,29 @@ final class Settings {
}
}
- void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, Set<String> permissions) {
- if (!permissions.isEmpty()) {
+ void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix,
+ List<PermissionState> permissionStates) {
+ if (!permissionStates.isEmpty()) {
pw.print(prefix); pw.println("runtime permissions:");
- for (String permission : permissions) {
- pw.print(prefix); pw.print(" "); pw.println(permission);
+ for (PermissionState permissionState : permissionStates) {
+ pw.print(prefix); pw.print(" "); pw.print(permissionState.getName());
+ pw.print(", granted="); pw.print(permissionState.isGranted());
+ pw.print(", flags=0x"); pw.println(Integer.toHexString(
+ permissionState.getFlags()));
}
}
}
void dumpInstallPermissionsLPr(PrintWriter pw, String prefix,
PermissionsState permissionsState) {
- Set<String> permissions = permissionsState.getInstallPermissions();
- if (!permissions.isEmpty()) {
+ List<PermissionState> permissionStates = permissionsState.getInstallPermissionStates();
+ if (!permissionStates.isEmpty()) {
pw.print(prefix); pw.println("install permissions:");
- for (String permission : permissions) {
- pw.print(prefix); pw.print(" "); pw.println(permission);
+ for (PermissionState permissionState : permissionStates) {
+ pw.print(prefix); pw.print(" "); pw.print(permissionState.getName());
+ pw.print(", granted="); pw.print(permissionState.isGranted());
+ pw.print(", flags=0x"); pw.println(Integer.toHexString(
+ permissionState.getFlags()));
}
}
}
@@ -4207,8 +4250,8 @@ final class Settings {
private void writePermissionsSync(int userId) {
AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));
- ArrayMap<String, Set<String>> permissionsForPackage = new ArrayMap<>();
- ArrayMap<String, Set<String>> permissionsForSharedUser = new ArrayMap<>();
+ ArrayMap<String, List<PermissionState>> permissionsForPackage = new ArrayMap<>();
+ ArrayMap<String, List<PermissionState>> permissionsForSharedUser = new ArrayMap<>();
synchronized (mLock) {
mWriteScheduled.delete(userId);
@@ -4219,9 +4262,10 @@ final class Settings {
PackageSetting packageSetting = mPackages.valueAt(i);
if (packageSetting.sharedUser == null) {
PermissionsState permissionsState = packageSetting.getPermissionsState();
- Set<String> permissions = permissionsState.getRuntimePermissions(userId);
- if (!permissions.isEmpty()) {
- permissionsForPackage.put(packageName, permissions);
+ List<PermissionState> permissionsStates = permissionsState
+ .getRuntimePermissionStates(userId);
+ if (!permissionsStates.isEmpty()) {
+ permissionsForPackage.put(packageName, permissionsStates);
}
}
}
@@ -4231,9 +4275,10 @@ final class Settings {
String sharedUserName = mSharedUsers.keyAt(i);
SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
PermissionsState permissionsState = sharedUser.getPermissionsState();
- Set<String> permissions = permissionsState.getRuntimePermissions(userId);
- if (!permissions.isEmpty()) {
- permissionsForSharedUser.put(sharedUserName, permissions);
+ List<PermissionState> permissionsStates = permissionsState
+ .getRuntimePermissionStates(userId);
+ if (!permissionsStates.isEmpty()) {
+ permissionsForSharedUser.put(sharedUserName, permissionsStates);
}
}
}
@@ -4252,20 +4297,20 @@ final class Settings {
final int packageCount = permissionsForPackage.size();
for (int i = 0; i < packageCount; i++) {
String packageName = permissionsForPackage.keyAt(i);
- Set<String> permissions = permissionsForPackage.valueAt(i);
+ List<PermissionState> permissionStates = permissionsForPackage.valueAt(i);
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, packageName);
- writePermissions(serializer, permissions);
+ writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_PACKAGE);
}
final int sharedUserCount = permissionsForSharedUser.size();
for (int i = 0; i < sharedUserCount; i++) {
String packageName = permissionsForSharedUser.keyAt(i);
- Set<String> permissions = permissionsForSharedUser.valueAt(i);
+ List<PermissionState> permissionStates = permissionsForSharedUser.valueAt(i);
serializer.startTag(null, TAG_SHARED_USER);
serializer.attribute(null, ATTR_NAME, packageName);
- writePermissions(serializer, permissions);
+ writePermissions(serializer, permissionStates);
serializer.endTag(null, TAG_SHARED_USER);
}
@@ -4290,20 +4335,23 @@ final class Settings {
mHandler.removeMessages(userId);
for (SettingBase sb : mPackages.values()) {
- revokeRuntimePermissions(sb, userId);
+ revokeRuntimePermissionsAndClearFlags(sb, userId);
}
for (SettingBase sb : mSharedUsers.values()) {
- revokeRuntimePermissions(sb, userId);
+ revokeRuntimePermissionsAndClearFlags(sb, userId);
}
}
- private void revokeRuntimePermissions(SettingBase sb, int userId) {
+ private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) {
PermissionsState permissionsState = sb.getPermissionsState();
- for (String permission : permissionsState.getRuntimePermissions(userId)) {
- BasePermission bp = mPermissions.get(permission);
+ for (PermissionState permissionState
+ : permissionsState.getRuntimePermissionStates(userId)) {
+ BasePermission bp = mPermissions.get(permissionState.getName());
if (bp != null) {
permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
}
}
}
@@ -4391,20 +4439,47 @@ final class Settings {
continue;
}
- if (permissionsState.grantRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name);
+ String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
+ final boolean granted = grantedStr == null
+ || Boolean.parseBoolean(grantedStr);
+
+ String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
+ final int flags = (flagsStr != null)
+ ? Integer.parseInt(flagsStr, 16) : 0;
+
+ if (granted) {
+ if (permissionsState.grantRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name);
+ } else {
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+
+ }
+ } else {
+ if (permissionsState.revokeRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name);
+ } else {
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, flags);
+ }
}
+
} break;
}
}
}
- private void writePermissions(XmlSerializer serializer, Set<String> permissions)
- throws IOException {
- for (String permission : permissions) {
+ private void writePermissions(XmlSerializer serializer,
+ List<PermissionState> permissionStates) throws IOException {
+ for (PermissionState permissionState : permissionStates) {
serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, permission);
+ serializer.attribute(null, ATTR_NAME,permissionState.getName());
+ serializer.attribute(null, ATTR_GRANTED,
+ String.valueOf(permissionState.isGranted()));
+ serializer.attribute(null, ATTR_FLAGS,
+ Integer.toHexString(permissionState.getFlags()));
serializer.endTag(null, TAG_ITEM);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 67c198f..c6816b0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6344,10 +6344,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
long ident = Binder.clearCallingIdentity();
try {
+ PackageManager packageManager = mContext.getPackageManager();
if (granted) {
- mContext.getPackageManager().grantPermission(packageName, permission, user);
+ packageManager.grantRuntimePermission(packageName, permission, user);
+ packageManager.updatePermissionFlags(permission, packageName,
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
} else {
- mContext.getPackageManager().revokePermission(packageName, permission, user);
+ packageManager.revokeRuntimePermission(packageName,
+ permission, user);
+ packageManager.updatePermissionFlags(permission, packageName,
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
}
return true;
} catch (SecurityException se) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 9efea0d..bf1ea4d 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -44,14 +44,12 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.PackageManager.MoveCallback;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
-import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
@@ -195,13 +193,28 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public void grantPermission(String packageName, String permissionName, UserHandle user) {
+ public void grantRuntimePermission(String packageName, String permissionName,
+ UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public void revokeRuntimePermission(String packageName, String permissionName,
+ UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public void revokePermission(String packageName, String permissionName, UserHandle user) {
+ public void updatePermissionFlags(String permissionName, String packageName,
+ int flagMask, int flagValues, UserHandle user) {
throw new UnsupportedOperationException();
}