Add ModernPermissionManagerServiceImpl skeleton and two methods.
Also allow compatibility layer to talk to policy directly by
introducing scopes for getting and mutating state, because
compatibility layer shouldn't have direct access to states, while
scope also allows getting rid of a lot of boilerplate for passing
states around.
Bug: 182523293
Test: presubmit
Change-Id: I36f53383c261b51372178d8c183c190bdb3c7132
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 9ec63fc..cefe9cd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -467,7 +467,7 @@
@Override
public PermissionInfo getPermissionInfo(String permissionName, String packageName, int flags) {
- return mPermissionManagerServiceImpl.getPermissionInfo(permissionName, packageName, flags);
+ return mPermissionManagerServiceImpl.getPermissionInfo(permissionName, flags, packageName);
}
@Override
@@ -792,14 +792,14 @@
@NonNull
@Override
- public ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+ public List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection) {
return mPermissionManagerServiceImpl.getAllPermissionsWithProtection(protection);
}
@NonNull
@Override
- public ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+ public List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags) {
return mPermissionManagerServiceImpl
.getAllPermissionsWithProtectionFlags(protectionFlags);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 5ffbbdc..e56edeb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -559,8 +559,8 @@
@Override
@Nullable
- public PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
- @PackageManager.PermissionInfoFlags int flags) {
+ public PermissionInfo getPermissionInfo(@NonNull String permName,
+ @PackageManager.PermissionInfoFlags int flags, @NonNull String opPackageName) {
final int callingUid = Binder.getCallingUid();
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return null;
@@ -2127,7 +2127,7 @@
for (int i = 0; i < numRequestedPermissions; i++) {
PermissionInfo permInfo = getPermissionInfo(
newPackage.getRequestedPermissions().get(i),
- newPackage.getPackageName(), 0);
+ 0, newPackage.getPackageName());
if (permInfo == null) {
continue;
}
@@ -5204,9 +5204,9 @@
@NonNull
@Override
- public ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+ public List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection) {
- ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+ List<PermissionInfo> matchingPermissions = new ArrayList<>();
synchronized (mLock) {
for (final Permission permission : mRegistry.getPermissions()) {
@@ -5221,9 +5221,9 @@
@NonNull
@Override
- public ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+ public List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags) {
- ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+ List<PermissionInfo> matchingPermissions = new ArrayList<>();
synchronized (mLock) {
for (final Permission permission : mRegistry.getPermissions()) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 930936b..d9caec7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -32,7 +32,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -77,8 +76,8 @@
* @return a {@link PermissionInfo} containing information about the permission, or {@code null}
* if not found
*/
- PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
- @PackageManager.PermissionInfoFlags int flags);
+ PermissionInfo getPermissionInfo(@NonNull String permName,
+ @PackageManager.PermissionInfoFlags int flags, @NonNull String opPackageName);
/**
* Query for all of the permissions associated with a particular group.
@@ -487,11 +486,11 @@
/** Get all permissions that have a certain protection */
@NonNull
- ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+ List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection);
/** Get all permissions that have certain protection flags */
- @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+ @NonNull List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags);
/**
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f20620e..97ac749 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -164,11 +164,12 @@
/** Get all permissions that have a certain protection */
@NonNull
- ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+ List<PermissionInfo> getAllPermissionsWithProtection(
@PermissionInfo.Protection int protection);
- /** Get all permissions that have certain protection flags */
- @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+ /** Get all permissions that have certain protection flags
+ * @return*/
+ @NonNull List<PermissionInfo> getAllPermissionsWithProtectionFlags(
@PermissionInfo.ProtectionFlags int protectionFlags);
/**
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index e61effa..d6cac33 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -232,7 +232,7 @@
}
};
- final ArrayList<PermissionInfo> dangerousPerms =
+ final List<PermissionInfo> dangerousPerms =
mPermissionManagerInternal.getAllPermissionsWithProtection(
PermissionInfo.PROTECTION_DANGEROUS);
try {
diff --git a/services/permission/Android.bp b/services/permission/Android.bp
index b03f17b..dc9b558 100644
--- a/services/permission/Android.bp
+++ b/services/permission/Android.bp
@@ -29,6 +29,8 @@
],
static_libs: [
"kotlin-stdlib",
+ // Adds reflection-less suppressed exceptions and AutoCloseable.use().
+ "kotlin-stdlib-jdk7",
],
jarjar_rules: "jarjar-rules.txt",
kotlincflags: [
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index c6ccc0f..7b96d42 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -40,46 +40,53 @@
}
fun getDecision(subject: AccessUri, `object`: AccessUri): Int =
- policy.getDecision(subject, `object`, state)
+ getState {
+ with(policy) { getDecision(subject, `object`) }
+ }
fun setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
- mutateState { oldState, newState ->
- policy.setDecision(subject, `object`, decision, oldState, newState)
+ mutateState {
+ with(policy) { setDecision(subject, `object`, decision) }
}
}
fun onUserAdded(userId: Int) {
- mutateState { oldState, newState ->
- policy.onUserAdded(userId, oldState, newState)
+ mutateState {
+ with(policy) { onUserAdded(userId) }
}
}
fun onUserRemoved(userId: Int) {
- mutateState { oldState, newState ->
- policy.onUserRemoved(userId, oldState, newState)
+ mutateState {
+ with(policy) { onUserRemoved(userId) }
}
}
fun onPackageAdded(packageState: PackageState) {
- mutateState { oldState, newState ->
- policy.onPackageAdded(packageState, oldState, newState)
+ mutateState {
+ with(policy) { onPackageAdded(packageState) }
}
}
fun onPackageRemoved(packageState: PackageState) {
- mutateState { oldState, newState ->
- policy.onPackageRemoved(packageState, oldState, newState)
+ mutateState {
+ with(policy) { onPackageRemoved(packageState) }
}
}
- // TODO: Replace (oldState, newState) with Kotlin context receiver once it's stabilized.
- private inline fun mutateState(action: (oldState: AccessState, newState: AccessState) -> Unit) {
+ internal inline fun <T> getState(action: GetStateScope.() -> T): T =
+ GetStateScope(state).action()
+
+ internal inline fun mutateState(action: MutateStateScope.() -> Unit) {
synchronized(stateLock) {
val oldState = state
val newState = oldState.copy()
- action(oldState, newState)
+ MutateStateScope(oldState, newState).action()
persistence.write(newState)
state = newState
}
}
+
+ internal fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
+ policy.getSchemePolicy(subjectScheme, objectScheme)
}
diff --git a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
index 0efc1bd..022f09a 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
@@ -44,13 +44,13 @@
systemFile.parse {
// This is the canonical way to call an extension function in a different class.
// TODO(b/259469752): Use context receiver for this when it becomes stable.
- with(policy) { this@parse.parseSystemState(systemState) }
+ with(policy) { parseSystemState(systemState) }
}
}
private fun readUserState(userId: Int, userState: UserState) {
getUserFile(userId).parse {
- with(policy) { this@parse.parseUserState(userId, userState) }
+ with(policy) { parseUserState(userId, userState) }
}
}
@@ -82,13 +82,13 @@
private fun writeSystemState(systemState: SystemState) {
systemFile.serialize {
- with(policy) { this@serialize.serializeSystemState(systemState) }
+ with(policy) { serializeSystemState(systemState) }
}
}
private fun writeUserState(userId: Int, userState: UserState) {
getUserFile(userId).serialize {
- with(policy) { this@serialize.serializeUserState(userId, userState) }
+ with(policy) { serializeUserState(userId, userState) }
}
}
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 4e53ce0..e9741c6 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -41,38 +41,35 @@
}
)
- fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int =
- getSchemePolicy(subject, `object`).getDecision(subject, `object`, state)
-
- fun setDecision(
- subject: AccessUri,
- `object`: AccessUri,
- decision: Int,
- oldState: AccessState,
- newState: AccessState
- ) {
- getSchemePolicy(subject, `object`)
- .setDecision(subject, `object`, decision, oldState, newState)
- }
-
- private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
- checkNotNull(schemePolicies[subject.scheme]?.get(`object`.scheme)) {
- "Scheme policy for subject=$subject object=$`object` does not exist"
+ fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
+ checkNotNull(schemePolicies[subjectScheme]?.get(objectScheme)) {
+ "Scheme policy for $subjectScheme and $objectScheme does not exist"
}
- fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {
+ fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int =
+ with(getSchemePolicy(subject, `object`)){ getDecision(subject, `object`) }
+
+ fun MutateStateScope.setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
+ with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
+ }
+
+ fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.userIds += userId
newState.userStates[userId] = UserState()
- forEachSchemePolicy { it.onUserAdded(userId, oldState, newState) }
+ forEachSchemePolicy {
+ with(it) { onUserAdded(userId) }
+ }
}
- fun onUserRemoved(userId: Int, oldState: AccessState, newState: AccessState) {
+ fun MutateStateScope.onUserRemoved(userId: Int) {
newState.systemState.userIds -= userId
newState.userStates -= userId
- forEachSchemePolicy { it.onUserRemoved(userId, oldState, newState) }
+ forEachSchemePolicy {
+ with(it) { onUserRemoved(userId) }
+ }
}
- fun onPackageAdded(packageState: PackageState, oldState: AccessState, newState: AccessState) {
+ fun MutateStateScope.onPackageAdded(packageState: PackageState) {
var isAppIdAdded = false
newState.systemState.apply {
packageStates[packageState.packageName] = packageState
@@ -82,12 +79,16 @@
}.add(packageState.packageName)
}
if (isAppIdAdded) {
- forEachSchemePolicy { it.onAppIdAdded(packageState.appId, oldState, newState) }
+ forEachSchemePolicy {
+ with(it) { onAppIdAdded(packageState.appId) }
+ }
}
- forEachSchemePolicy { it.onPackageAdded(packageState, oldState, newState) }
+ forEachSchemePolicy {
+ with(it) { onPackageAdded(packageState) }
+ }
}
- fun onPackageRemoved(packageState: PackageState, oldState: AccessState, newState: AccessState) {
+ fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
var isAppIdRemoved = false
newState.systemState.apply {
packageStates -= packageState.packageName
@@ -101,9 +102,13 @@
}
}
}
- forEachSchemePolicy { it.onPackageRemoved(packageState, oldState, newState) }
+ forEachSchemePolicy {
+ with(it) { onPackageRemoved(packageState) }
+ }
if (isAppIdRemoved) {
- forEachSchemePolicy { it.onAppIdRemoved(packageState.appId, oldState, newState) }
+ forEachSchemePolicy {
+ with(it) { onAppIdRemoved(packageState.appId) }
+ }
}
}
@@ -113,7 +118,7 @@
TAG_ACCESS -> {
forEachTag {
forEachSchemePolicy {
- with(it) { this@parseSystemState.parseSystemState(systemState) }
+ with(it) { parseSystemState(systemState) }
}
}
}
@@ -125,7 +130,7 @@
fun BinaryXmlSerializer.serializeSystemState(systemState: SystemState) {
tag(TAG_ACCESS) {
forEachSchemePolicy {
- with(it) { this@serializeSystemState.serializeSystemState(systemState) }
+ with(it) { serializeSystemState(systemState) }
}
}
}
@@ -136,7 +141,7 @@
TAG_ACCESS -> {
forEachTag {
forEachSchemePolicy {
- with(it) { this@parseUserState.parseUserState(userId, userState) }
+ with(it) { parseUserState(userId, userState) }
}
}
}
@@ -153,11 +158,14 @@
fun BinaryXmlSerializer.serializeUserState(userId: Int, userState: UserState) {
tag(TAG_ACCESS) {
forEachSchemePolicy {
- with(it) { this@serializeUserState.serializeUserState(userId, userState) }
+ with(it) { serializeUserState(userId, userState) }
}
}
}
+ private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
+ getSchemePolicy(subject.scheme, `object`.scheme)
+
private inline fun forEachSchemePolicy(action: (SchemePolicy) -> Unit) {
schemePolicies.forEachValueIndexed { _, objectSchemePolicies ->
objectSchemePolicies.forEachValueIndexed { _, schemePolicy ->
@@ -182,14 +190,12 @@
abstract val objectScheme: String
- abstract fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int
+ abstract fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int
- abstract fun setDecision(
+ abstract fun MutateStateScope.setDecision(
subject: AccessUri,
`object`: AccessUri,
- decision: Int,
- oldState: AccessState,
- newState: AccessState
+ decision: Int
)
fun addOnDecisionChangedListener(listener: OnDecisionChangedListener) {
@@ -216,25 +222,17 @@
}
}
- open fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {}
+ open fun MutateStateScope.onUserAdded(userId: Int) {}
- open fun onUserRemoved(userId: Int, oldState: AccessState, newState: AccessState) {}
+ open fun MutateStateScope.onUserRemoved(userId: Int) {}
- open fun onAppIdAdded(appId: Int, oldState: AccessState, newState: AccessState) {}
+ open fun MutateStateScope.onAppIdAdded(appId: Int) {}
- open fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {}
+ open fun MutateStateScope.onAppIdRemoved(appId: Int) {}
- open fun onPackageAdded(
- packageState: PackageState,
- oldState: AccessState,
- newState: AccessState
- ) {}
+ open fun MutateStateScope.onPackageAdded(packageState: PackageState) {}
- open fun onPackageRemoved(
- packageState: PackageState,
- oldState: AccessState,
- newState: AccessState
- ) {}
+ open fun MutateStateScope.onPackageRemoved(packageState: PackageState) {}
open fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {}
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index f496dbd..cf8f383 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -124,3 +124,12 @@
}
}
}
+
+class GetStateScope(
+ val state: AccessState
+)
+
+class MutateStateScope(
+ val oldState: AccessState,
+ val newState: AccessState
+)
diff --git a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
index 0b052f9..a1a5e2d 100644
--- a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
@@ -19,44 +19,43 @@
import android.app.AppOpsManager
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
abstract class BaseAppOpPolicy(private val persistence: BaseAppOpPersistence) : SchemePolicy() {
- override fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int {
+ override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
`object` as AppOpUri
- return getModes(subject, state)
+ return getModes(subject)
.getWithDefault(`object`.appOpName, opToDefaultMode(`object`.appOpName))
}
- override fun setDecision(
+ override fun MutateStateScope.setDecision(
subject: AccessUri,
`object`: AccessUri,
- decision: Int,
- oldState: AccessState,
- newState: AccessState
+ decision: Int
) {
`object` as AppOpUri
- val modes = getOrCreateModes(subject, newState)
+ val modes = getOrCreateModes(subject)
val oldMode = modes.putWithDefault(`object`.appOpName, decision,
opToDefaultMode(`object`.appOpName))
if (modes.isEmpty()) {
- removeModes(subject, newState)
+ removeModes(subject)
}
if (oldMode != decision) {
notifyOnDecisionChangedListeners(subject, `object`, oldMode, decision)
}
}
- abstract fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>?
+ abstract fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>?
- abstract fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>
+ abstract fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int>
- abstract fun removeModes(subject: AccessUri, state: AccessState)
+ abstract fun MutateStateScope.removeModes(subject: AccessUri)
// TODO need to check that [AppOpsManager.getSystemAlertWindowDefault] works; likely no issue
// since running in system process.
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
index 7c3c14c..966489f 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
@@ -16,9 +16,10 @@
package com.android.server.permission.access.appop
-import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PackageUri
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
@@ -31,27 +32,23 @@
override val objectScheme: String
get() = AppOpUri.SCHEME
- override fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>? {
+ override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
subject as PackageUri
return state.userStates[subject.userId]?.packageAppOpModes?.get(subject.packageName)
}
- override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int> {
+ override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
subject as PackageUri
- return state.userStates.getOrPut(subject.userId) { UserState() }
+ return newState.userStates.getOrPut(subject.userId) { UserState() }
.packageAppOpModes.getOrPut(subject.packageName) { IndexedMap() }
}
- override fun removeModes(subject: AccessUri, state: AccessState) {
+ override fun MutateStateScope.removeModes(subject: AccessUri) {
subject as PackageUri
- state.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
+ newState.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
}
- override fun onPackageRemoved(
- packageState: PackageState,
- oldState: AccessState,
- newState: AccessState
- ) {
+ override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.packageAppOpModes -= packageState.packageName
}
diff --git a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
index 26d0114..862db8f 100644
--- a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
@@ -16,9 +16,10 @@
package com.android.server.permission.access.appop
-import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.UidUri
import com.android.server.permission.access.UserState
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
@@ -30,23 +31,23 @@
override val objectScheme: String
get() = AppOpUri.SCHEME
- override fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>? {
+ override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
subject as UidUri
return state.userStates[subject.userId]?.uidAppOpModes?.get(subject.appId)
}
- override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int> {
+ override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
subject as UidUri
- return state.userStates.getOrPut(subject.userId) { UserState() }
+ return newState.userStates.getOrPut(subject.userId) { UserState() }
.uidAppOpModes.getOrPut(subject.appId) { IndexedMap() }
}
- override fun removeModes(subject: AccessUri, state: AccessState) {
+ override fun MutateStateScope.removeModes(subject: AccessUri) {
subject as UidUri
- state.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
+ newState.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
}
- override fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {
+ override fun MutateStateScope.onAppIdRemoved(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.uidAppOpModes -= appId
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt b/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt
new file mode 100644
index 0000000..cc51866
--- /dev/null
+++ b/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.permission.access.permission
+
+import android.content.pm.PackageManager
+import android.content.pm.PackageManagerInternal
+import android.content.pm.PermissionGroupInfo
+import android.content.pm.PermissionInfo
+import android.content.pm.permission.SplitPermissionInfoParcelable
+import android.os.Binder
+import android.os.Build
+import android.os.Process
+import android.os.UserHandle
+import android.permission.IOnPermissionsChangeListener
+import com.android.server.LocalManagerRegistry
+import com.android.server.LocalServices
+import com.android.server.pm.PackageManagerLocal
+import com.android.server.pm.permission.PermissionManagerServiceInterface
+import com.android.server.permission.access.AccessCheckingService
+import com.android.server.permission.access.PermissionUri
+import com.android.server.permission.access.UidUri
+import com.android.server.permission.access.data.Permission
+import com.android.server.permission.access.util.hasBits
+import com.android.server.pm.permission.LegacyPermission
+import com.android.server.pm.permission.LegacyPermissionSettings
+import com.android.server.pm.permission.LegacyPermissionState
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.pm.pkg.AndroidPackage
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+/**
+ * Modern implementation of [PermissionManagerServiceInterface].
+ */
+class ModernPermissionManagerServiceImpl(
+ private val service: AccessCheckingService
+) : PermissionManagerServiceInterface {
+ private val policy =
+ service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as UidPermissionPolicy
+
+ private val packageManagerInternal =
+ LocalServices.getService(PackageManagerInternal::class.java)
+
+ private val packageManagerLocal =
+ LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
+
+ override fun getAllPermissionGroups(flags: Int): List<PermissionGroupInfo> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getPermissionGroupInfo(
+ permissionGroupName: String,
+ flags: Int
+ ): PermissionGroupInfo? {
+ val permissionGroup: PermissionGroupInfo
+ packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
+ val callingUid = Binder.getCallingUid()
+ if (snapshot.isUidInstantApp(callingUid)) {
+ return null
+ }
+
+ permissionGroup = service.getState {
+ with(policy) { getPermissionGroup(permissionGroupName) }
+ } ?: return null
+
+ val isPermissionGroupVisible =
+ snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)
+ if (!isPermissionGroupVisible) {
+ return null
+ }
+ }
+
+ return permissionGroup.generatePermissionGroupInfo(flags)
+ }
+
+ /**
+ * Generate a new [PermissionGroupInfo] from [PermissionGroupInfo] and adjust it accordingly.
+ */
+ private fun PermissionGroupInfo.generatePermissionGroupInfo(flags: Int): PermissionGroupInfo =
+ @Suppress("DEPRECATION")
+ PermissionGroupInfo(this).apply {
+ if (!flags.hasBits(PackageManager.GET_META_DATA)) {
+ metaData = null
+ }
+ }
+
+ override fun getPermissionInfo(
+ permissionName: String,
+ flags: Int,
+ opPackageName: String
+ ): PermissionInfo? {
+ val permission: Permission
+ val targetSdkVersion: Int
+ packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
+ val callingUid = Binder.getCallingUid()
+ if (snapshot.isUidInstantApp(callingUid)) {
+ return null
+ }
+
+ permission = service.getState {
+ with(policy) { getPermission(permissionName) }
+ } ?: return null
+
+ val isPermissionVisible =
+ snapshot.isPackageVisibleToUid(permission.packageName, callingUid)
+ if (!isPermissionVisible) {
+ return null
+ }
+
+ val callingAppId = UserHandle.getAppId(callingUid)
+ val opPackage = snapshot.packageStates[opPackageName]?.androidPackage
+ targetSdkVersion = when {
+ // System sees all flags.
+ callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID ||
+ callingAppId == Process.SHELL_UID -> Build.VERSION_CODES.CUR_DEVELOPMENT
+ opPackage != null -> opPackage.targetSdkVersion
+ else -> Build.VERSION_CODES.CUR_DEVELOPMENT
+ }
+ }
+
+ return permission.generatePermissionInfo(flags, targetSdkVersion)
+ }
+
+ /**
+ * Generate a new [PermissionInfo] from [Permission] and adjust it accordingly.
+ */
+ private fun Permission.generatePermissionInfo(
+ flags: Int,
+ targetSdkVersion: Int
+ ): PermissionInfo =
+ @Suppress("DEPRECATION")
+ PermissionInfo(permissionInfo).apply {
+ if (!flags.hasBits(PackageManager.GET_META_DATA)) {
+ metaData = null
+ }
+ if (targetSdkVersion < Build.VERSION_CODES.O) {
+ val protection = protection
+ // Signature permission's protection flags are always reported.
+ if (protection != PermissionInfo.PROTECTION_SIGNATURE) {
+ protectionLevel = protection
+ }
+ }
+ }
+
+ override fun queryPermissionsByGroup(
+ permissionGroupName: String,
+ flags: Int
+ ): List<PermissionInfo> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllPermissionsWithProtection(protection: Int): List<PermissionInfo> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllPermissionsWithProtectionFlags(protectionFlags: Int): List<PermissionInfo> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getPermissionGids(permissionName: String, userId: Int): IntArray {
+ TODO("Not yet implemented")
+ }
+
+ override fun addPermission(permissionInfo: PermissionInfo, async: Boolean): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun removePermission(permissionName: String) {
+ TODO("Not yet implemented")
+ }
+
+ override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
+ TODO("Not yet implemented")
+ }
+
+ override fun checkUidPermission(uid: Int, permissionName: String): Int {
+ TODO("Not yet implemented")
+ }
+
+ override fun getGrantedPermissions(packageName: String, userId: Int): Set<String> {
+ TODO("Not yet implemented")
+ }
+
+ override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun revokeRuntimePermission(
+ packageName: String,
+ permissionName: String,
+ userId: Int,
+ reason: String?
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun revokePostNotificationPermissionWithoutKillForTest(
+ packageName: String,
+ userId: Int
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
+ TODO("Not yet implemented")
+ }
+
+ override fun removeOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
+ TODO("Not yet implemented")
+ }
+
+ override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
+ TODO("Not yet implemented")
+ }
+
+ override fun isPermissionRevokedByPolicy(
+ packageName: String,
+ permissionName: String,
+ userId: Int
+ ): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun isPermissionsReviewRequired(packageName: String, userId: Int): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun shouldShowRequestPermissionRationale(
+ packageName: String,
+ permissionName: String,
+ userId: Int
+ ): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun updatePermissionFlags(
+ packageName: String,
+ permissionName: String,
+ flagMask: Int,
+ flagValues: Int,
+ checkAdjustPolicyFlagPermission: Boolean,
+ userId: Int
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun updatePermissionFlagsForAllApps(flagMask: Int, flagValues: Int, userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun addAllowlistedRestrictedPermission(
+ packageName: String,
+ permissionName: String,
+ flags: Int,
+ userId: Int
+ ): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllowlistedRestrictedPermissions(
+ packageName: String,
+ flags: Int,
+ userId: Int
+ ): MutableList<String> {
+ TODO("Not yet implemented")
+ }
+
+ override fun removeAllowlistedRestrictedPermission(
+ packageName: String,
+ permissionName: String,
+ flags: Int,
+ userId: Int
+ ): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun resetRuntimePermissions(androidPackage: AndroidPackage, userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun resetRuntimePermissionsForUser(userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun addOnRuntimePermissionStateChangedListener(
+ listener: PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun removeOnRuntimePermissionStateChangedListener(
+ listener: PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun getSplitPermissions(): List<SplitPermissionInfoParcelable> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAllAppOpPermissionPackages(): Map<String, Set<String>> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getGidsForUid(uid: Int): IntArray {
+ TODO("Not yet implemented")
+ }
+
+ override fun backupRuntimePermissions(userId: Int): ByteArray? {
+ TODO("Not yet implemented")
+ }
+
+ override fun restoreRuntimePermissions(backup: ByteArray, userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun restoreDelayedRuntimePermissions(packageName: String, userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>?) {
+ TODO("Not yet implemented")
+ }
+
+ override fun getPermissionTEMP(
+ permissionName: String
+ ): com.android.server.pm.permission.Permission? {
+ TODO("Not yet implemented")
+ }
+
+ override fun getLegacyPermissions(): List<LegacyPermission> {
+ TODO("Not yet implemented")
+ }
+
+ override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
+ TODO("Not yet implemented")
+ }
+
+ override fun writeLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
+ TODO("Not yet implemented")
+ }
+
+ override fun getLegacyPermissionState(appId: Int): LegacyPermissionState {
+ TODO("Not yet implemented")
+ }
+
+ override fun readLegacyPermissionStateTEMP() {
+ TODO("Not yet implemented")
+ }
+
+ override fun writeLegacyPermissionStateTEMP() {
+ TODO("Not yet implemented")
+ }
+
+ override fun onSystemReady() {
+ TODO("Not yet implemented")
+ }
+
+ override fun onUserCreated(userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onUserRemoved(userId: Int) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onStorageVolumeMounted(volumeUuid: String, fingerprintChanged: Boolean) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onPackageAdded(
+ androidPackage: AndroidPackage,
+ isInstantApp: Boolean,
+ oldPackage: AndroidPackage?
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onPackageInstalled(
+ androidPackage: AndroidPackage,
+ previousAppId: Int,
+ params: PermissionManagerServiceInternal.PackageInstalledParams,
+ userId: Int
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onPackageUninstalled(
+ packageName: String,
+ appId: Int,
+ androidPackage: AndroidPackage?,
+ sharedUserPkgs: MutableList<AndroidPackage>,
+ userId: Int
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun onPackageRemoved(androidPackage: AndroidPackage) {
+ TODO("Not yet implemented")
+ }
+
+ /**
+ * Check whether a UID belongs to an instant app.
+ */
+ private fun PackageManagerLocal.UnfilteredSnapshot.isUidInstantApp(uid: Int): Boolean {
+ if (Process.isIsolatedUid(uid)) {
+ // Unfortunately we don't have the API for getting the owner UID of an isolated UID yet,
+ // so for now we just keep calling the old API.
+ return packageManagerInternal.getInstantAppPackageName(uid) != null
+ }
+ val appId = UserHandle.getAppId(uid)
+ // Instant apps can't have shared UIDs, so we can just take the first package.
+ val firstPackageState = packageStates.values.firstOrNull { it.appId == appId }
+ ?: return false
+ val userId = UserHandle.getUserId(uid)
+ return firstPackageState.getUserStateOrDefault(userId).isInstantApp
+ }
+
+ /**
+ * Check whether a package is visible to a UID within the same user as the UID.
+ */
+ private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
+ packageName: String,
+ uid: Int
+ ): Boolean = isPackageVisibleToUid(packageName, UserHandle.getUserId(uid), uid)
+
+ /**
+ * Check whether a package in a particular user is visible to a UID.
+ */
+ private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
+ packageName: String,
+ userId: Int,
+ uid: Int
+ ): Boolean {
+ val user = UserHandle.of(userId)
+ return filtered(uid, user).use { it.getPackageState(packageName) != null }
+ }
+}
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
index 6479e6a..e081924 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
@@ -18,6 +18,7 @@
import android.Manifest
import android.content.pm.PackageManager
+import android.content.pm.PermissionGroupInfo
import android.content.pm.PermissionInfo
import android.os.Build
import android.os.UserHandle
@@ -26,6 +27,8 @@
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AccessUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.SchemePolicy
import com.android.server.permission.access.SystemState
@@ -52,19 +55,17 @@
override val objectScheme: String
get() = PermissionUri.SCHEME
- override fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int {
+ override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
subject as UidUri
`object` as PermissionUri
return state.userStates[subject.userId]?.permissionFlags?.get(subject.appId)
?.get(`object`.permissionName) ?: 0
}
- override fun setDecision(
+ override fun MutateStateScope.setDecision(
subject: AccessUri,
`object`: AccessUri,
- decision: Int,
- oldState: AccessState,
- newState: AccessState
+ decision: Int
) {
subject as UidUri
`object` as PermissionUri
@@ -73,64 +74,58 @@
uidFlags[`object`.permissionName] = decision
}
- override fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {
+ override fun MutateStateScope.onUserAdded(userId: Int) {
newState.systemState.packageStates.forEachValueIndexed { _, packageState ->
- evaluateAllPermissionStatesForPackageAndUser(
- packageState, null, userId, oldState, newState
- )
- grantImplicitPermissions(packageState, userId, oldState, newState)
+ evaluateAllPermissionStatesForPackageAndUser(packageState, null, userId)
+ grantImplicitPermissions(packageState, userId)
}
}
- override fun onAppIdAdded(appId: Int, oldState: AccessState, newState: AccessState) {
+ override fun MutateStateScope.onAppIdAdded(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState ->
userState.permissionFlags.getOrPut(appId) { IndexedMap() }
}
}
- override fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {
+ override fun MutateStateScope.onAppIdRemoved(appId: Int) {
newState.userStates.forEachIndexed { _, _, userState -> userState.permissionFlags -= appId }
}
- override fun onPackageAdded(
- packageState: PackageState,
- oldState: AccessState,
- newState: AccessState
- ) {
+ override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
val changedPermissionNames = IndexedSet<String>()
- adoptPermissions(packageState, changedPermissionNames, newState)
- addPermissionGroups(packageState, newState)
- addPermissions(packageState, changedPermissionNames, newState)
+ adoptPermissions(packageState, changedPermissionNames)
+ addPermissionGroups(packageState)
+ addPermissions(packageState, changedPermissionNames)
// TODO: revokeStoragePermissionsIfScopeExpandedInternal()
- trimPermissions(packageState.packageName, newState)
- changedPermissionNames.forEachIndexed { _, it ->
- evaluatePermissionStateForAllPackages(it, packageState, oldState, newState)
+ trimPermissions(packageState.packageName)
+ changedPermissionNames.forEachIndexed { _, permissionName ->
+ evaluatePermissionStateForAllPackages(permissionName, packageState)
}
- evaluateAllPermissionStatesForPackage(packageState, packageState, oldState, newState)
- newState.systemState.userIds.forEachIndexed { _, it ->
- grantImplicitPermissions(packageState, it, oldState, newState)
+ evaluateAllPermissionStatesForPackage(packageState, packageState)
+ newState.systemState.userIds.forEachIndexed { _, userId ->
+ grantImplicitPermissions(packageState, userId)
}
// TODO: add trimPermissionStates() here for removing the permission states that are
// no longer requested. (equivalent to revokeUnusedSharedUserPermissionsLocked())
}
- private fun adoptPermissions(
+ private fun MutateStateScope.adoptPermissions(
packageState: PackageState,
- changedPermissionNames: IndexedSet<String>,
- newState: AccessState
+ changedPermissionNames: IndexedSet<String>
) {
val `package` = packageState.androidPackage!!
`package`.adoptPermissions.forEachIndexed { _, originalPackageName ->
val packageName = `package`.packageName
- if (!canAdoptPermissions(packageName, originalPackageName, newState)) {
+ if (!canAdoptPermissions(packageName, originalPackageName)) {
return@forEachIndexed
}
newState.systemState.permissions.let { permissions ->
- permissions.forEachIndexed { i, permissionName, oldPermission ->
+ permissions.forEachIndexed permissions@ {
+ permissionIndex, permissionName, oldPermission ->
if (oldPermission.packageName != originalPackageName) {
- return@forEachIndexed
+ return@permissions
}
@Suppress("DEPRECATION")
val newPermissionInfo = PermissionInfo().apply {
@@ -140,16 +135,15 @@
}
val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
changedPermissionNames += permissionName
- permissions.setValueAt(i, newPermission)
+ permissions.setValueAt(permissionIndex, newPermission)
}
}
}
}
- private fun canAdoptPermissions(
+ private fun MutateStateScope.canAdoptPermissions(
packageName: String,
- originalPackageName: String,
- newState: AccessState
+ originalPackageName: String
): Boolean {
val originalPackageState = newState.systemState.packageStates[originalPackageName]
?: return false
@@ -170,7 +164,7 @@
return true
}
- private fun addPermissionGroups(packageState: PackageState, newState: AccessState) {
+ private fun MutateStateScope.addPermissionGroups(packageState: PackageState) {
// Different from the old implementation, which decides whether the app is an instant app by
// the install flags, now for consistent behavior we allow adding permission groups if the
// app is non-instant in at least one user.
@@ -202,10 +196,9 @@
}
}
- private fun addPermissions(
+ private fun MutateStateScope.addPermissions(
packageState: PackageState,
- changedPermissionNames: IndexedSet<String>,
- newState: AccessState
+ changedPermissionNames: IndexedSet<String>
) {
packageState.androidPackage!!.permissions.forEachIndexed { _, parsedPermission ->
// TODO:
@@ -229,7 +222,7 @@
// Different from the old implementation, which may add an (incomplete) signature
// permission inside another package's permission tree, we now consistently ignore such
// permissions.
- val permissionTree = getPermissionTree(permissionName, newState)
+ val permissionTree = getPermissionTree(permissionName)
val newPackageName = newPermissionInfo.packageName
if (permissionTree != null && newPackageName != permissionTree.packageName) {
Log.w(
@@ -294,10 +287,7 @@
}
}
- private fun trimPermissions(
- packageName: String,
- newState: AccessState,
- ) {
+ private fun MutateStateScope.trimPermissions(packageName: String) {
val packageState = newState.systemState.packageStates[packageName]
val androidPackage = packageState?.androidPackage
if (packageState != null && androidPackage == null) {
@@ -314,20 +304,20 @@
}
newState.systemState.permissions.removeAllIndexed { i, permissionName, permission ->
- val updatedPermission = updatePermissionIfDynamic(permission, newState)
+ val updatedPermission = updatePermissionIfDynamic(permission)
newState.systemState.permissions.setValueAt(i, updatedPermission)
if (updatedPermission.packageName == packageName && (
packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
!it.isTree && it.name == permissionName
}
)) {
- if (!isPermissionDeclaredByDisabledSystemPackage(permission, newState)) {
+ if (!isPermissionDeclaredByDisabledSystemPackage(permission)) {
newState.userStates.forEachIndexed { _, userId, userState ->
userState.permissionFlags.forEachKeyIndexed { _, appId ->
setPermissionFlags(
appId, permissionName, getPermissionFlags(
- appId, permissionName, userId, newState
- ) and PermissionFlags.INSTALL_REVOKED, userId, newState
+ appId, permissionName, userId
+ ) and PermissionFlags.INSTALL_REVOKED, userId
)
}
}
@@ -339,9 +329,8 @@
}
}
- private fun isPermissionDeclaredByDisabledSystemPackage(
- permission: Permission,
- newState: AccessState
+ private fun MutateStateScope.isPermissionDeclaredByDisabledSystemPackage(
+ permission: Permission
): Boolean {
val disabledSystemPackage = newState.systemState
.disabledSystemPackageStates[permission.packageName]?.androidPackage ?: return false
@@ -350,14 +339,11 @@
}
}
- private fun updatePermissionIfDynamic(
- permission: Permission,
- newState: AccessState
- ): Permission {
+ private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
if (!permission.isDynamic) {
return permission
}
- val permissionTree = getPermissionTree(permission.name, newState) ?: return permission
+ val permissionTree = getPermissionTree(permission.name) ?: return permission
@Suppress("DEPRECATION")
return permission.copy(
permissionInfo = PermissionInfo(permission.permissionInfo).apply {
@@ -366,7 +352,7 @@
)
}
- private fun getPermissionTree(permissionName: String, newState: AccessState): Permission? =
+ private fun MutateStateScope.getPermissionTree(permissionName: String): Permission? =
newState.systemState.permissionTrees.firstNotNullOfOrNullIndexed {
_, permissionTreeName, permissionTree ->
if (permissionName.startsWith(permissionTreeName) &&
@@ -378,58 +364,48 @@
}
}
- private fun evaluatePermissionStateForAllPackages(
+ private fun MutateStateScope.evaluatePermissionStateForAllPackages(
permissionName: String,
- installedPackageState: PackageState?,
- oldState: AccessState,
- newState: AccessState
+ installedPackageState: PackageState?
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
oldState.userStates[userId]?.permissionFlags?.forEachIndexed {
_, appId, permissionFlags ->
if (permissionName in permissionFlags) {
- evaluatePermissionState(
- appId, permissionName, installedPackageState, userId, oldState, newState
- )
+ evaluatePermissionState(appId, permissionName, installedPackageState, userId)
}
}
}
}
- private fun evaluateAllPermissionStatesForPackage(
+ private fun MutateStateScope.evaluateAllPermissionStatesForPackage(
packageState: PackageState,
- installedPackageState: PackageState?,
- oldState: AccessState,
- newState: AccessState
+ installedPackageState: PackageState?
) {
newState.systemState.userIds.forEachIndexed { _, userId ->
evaluateAllPermissionStatesForPackageAndUser(
- packageState, installedPackageState, userId, oldState, newState
+ packageState, installedPackageState, userId
)
}
}
- private fun evaluateAllPermissionStatesForPackageAndUser(
+ private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
packageState: PackageState,
installedPackageState: PackageState?,
- userId: Int,
- oldState: AccessState,
- newState: AccessState
+ userId: Int
) {
- packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, it ->
+ packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
evaluatePermissionState(
- packageState.appId, it, installedPackageState, userId, oldState, newState
+ packageState.appId, permissionName, installedPackageState, userId
)
}
}
- private fun evaluatePermissionState(
+ private fun MutateStateScope.evaluatePermissionState(
appId: Int,
permissionName: String,
installedPackageState: PackageState?,
- userId: Int,
- oldState: AccessState,
- newState: AccessState
+ userId: Int
) {
val packageNames = newState.systemState.appIds[appId]
val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
@@ -440,17 +416,17 @@
return
}
val permission = newState.systemState.permissions[permissionName] ?: return
- val oldFlags = getPermissionFlags(appId, permissionName, userId, newState)
+ val oldFlags = getPermissionFlags(appId, permissionName, userId)
if (permission.isNormal) {
val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
if (!wasGranted) {
val wasRevoked = oldFlags.hasBits(PermissionFlags.INSTALL_REVOKED)
val isRequestedByInstalledPackage = installedPackageState != null &&
permissionName in installedPackageState.androidPackage!!.requestedPermissions
- val isRequestedBySystemPackage = anyPackageInAppId(appId, newState) {
+ val isRequestedBySystemPackage = anyPackageInAppId(appId) {
it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
}
- val isCompatibilityPermission = anyPackageInAppId(appId, newState) {
+ val isCompatibilityPermission = anyPackageInAppId(appId) {
isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
}
// If this is an existing, non-system package,
@@ -462,7 +438,7 @@
} else {
PermissionFlags.INSTALL_REVOKED
}
- setPermissionFlags(appId, permissionName, newFlags, userId, newState)
+ setPermissionFlags(appId, permissionName, newFlags, userId)
}
} else if (permission.isSignature || permission.isInternal) {
val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
@@ -471,17 +447,17 @@
PermissionFlags.PROTECTION_GRANTED
} else {
val mayGrantByPrivileged = !permission.isPrivileged || (
- anyPackageInAppId(appId, newState) {
- checkPrivilegedPermissionAllowlist(it, permission, newState)
+ anyPackageInAppId(appId) {
+ checkPrivilegedPermissionAllowlist(it, permission)
}
)
val shouldGrantBySignature = permission.isSignature && (
- anyPackageInAppId(appId, newState) {
- shouldGrantPermissionBySignature(it, permission, newState)
+ anyPackageInAppId(appId) {
+ shouldGrantPermissionBySignature(it, permission)
}
)
- val shouldGrantByProtectionFlags = anyPackageInAppId(appId, newState) {
- shouldGrantPermissionByProtectionFlags(it, permission, newState)
+ val shouldGrantByProtectionFlags = anyPackageInAppId(appId) {
+ shouldGrantPermissionByProtectionFlags(it, permission)
}
if (mayGrantByPrivileged &&
(shouldGrantBySignature || shouldGrantByProtectionFlags)) {
@@ -501,7 +477,7 @@
if (permission.isRole) {
newFlags = newFlags or (oldFlags and PermissionFlags.ROLE_GRANTED)
}
- setPermissionFlags(appId, permissionName, newFlags, userId, newState)
+ setPermissionFlags(appId, permissionName, newFlags, userId)
} else if (permission.isRuntime) {
// TODO: add runtime permissions
} else {
@@ -513,12 +489,7 @@
// TODO: revokePermissionsNoLongerImplicitLocked() for runtime permissions
}
- private fun grantImplicitPermissions(
- packageState: PackageState,
- userId: Int,
- oldState: AccessState,
- newState: AccessState
- ) {
+ private fun MutateStateScope.grantImplicitPermissions(packageState: PackageState, userId: Int) {
val appId = packageState.appId
val androidPackage = packageState.androidPackage ?: return
androidPackage.implicitPermissions.forEachIndexed implicitPermissions@ {
@@ -530,6 +501,7 @@
if (!implicitPermission.isRuntime) {
return@implicitPermissions
}
+ // Explicitly check against the old state to determine if this permission is new.
val isNewPermission = getPermissionFlags(
appId, implicitPermissionName, userId, oldState
) == 0
@@ -544,7 +516,7 @@
checkNotNull(sourcePermission) {
"Unknown source permission $sourcePermissionName in split permissions"
}
- val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId, newState)
+ val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId)
val isSourceGranted = sourceFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isNewGranted = newFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
@@ -559,23 +531,22 @@
}
}
newFlags = newFlags or PermissionFlags.IMPLICIT
- setPermissionFlags(appId, implicitPermissionName, newFlags, userId, newState)
+ setPermissionFlags(appId, implicitPermissionName, newFlags, userId)
}
}
- private fun getPermissionFlags(
+ private fun MutateStateScope.getPermissionFlags(
appId: Int,
permissionName: String,
userId: Int,
- state: AccessState
+ state: AccessState = newState
): Int = state.userStates[userId].permissionFlags[appId].getWithDefault(permissionName, 0)
- private fun setPermissionFlags(
+ private fun MutateStateScope.setPermissionFlags(
appId: Int,
permissionName: String,
flags: Int,
- userId: Int,
- newState: AccessState
+ userId: Int
) {
newState.userStates[userId].permissionFlags[appId]!!
.putWithDefault(permissionName, flags, 0)
@@ -585,8 +556,9 @@
androidPackage: AndroidPackage,
permissionName: String
): Boolean {
- for (info: CompatibilityPermissionInfo in CompatibilityPermissionInfo.COMPAT_PERMS) {
- if (info.name == permissionName && androidPackage.targetSdkVersion < info.sdkVersion) {
+ for (compatibilityPermission in CompatibilityPermissionInfo.COMPAT_PERMS) {
+ if (compatibilityPermission.name == permissionName &&
+ androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion) {
Log.i(
LOG_TAG, "Auto-granting $permissionName to old package" +
" ${androidPackage.packageName}"
@@ -597,10 +569,9 @@
return false
}
- private fun shouldGrantPermissionBySignature(
+ private fun MutateStateScope.shouldGrantPermissionBySignature(
packageState: PackageState,
- permission: Permission,
- newState: AccessState
+ permission: Permission
): Boolean {
// check if the package is allow to use this signature permission. A package is allowed to
// use a signature permission if:
@@ -622,10 +593,9 @@
SigningDetails.CertCapabilities.PERMISSION)
}
- private fun checkPrivilegedPermissionAllowlist(
+ private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
packageState: PackageState,
- permission: Permission,
- newState: AccessState
+ permission: Permission
): Boolean {
if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
return true
@@ -641,10 +611,10 @@
newState.systemState.privilegedPermissionAllowlistSourcePackageNames) {
return true
}
- if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name, newState)) {
+ if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name)) {
return true
}
- if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name, newState)) {
+ if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name)) {
return false
}
// Updated system apps do not need to be allowlisted
@@ -655,10 +625,9 @@
return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE
}
- private fun isInSystemConfigPrivAppPermissions(
+ private fun MutateStateScope.isInSystemConfigPrivAppPermissions(
androidPackage: AndroidPackage,
- permissionName: String,
- newState: AccessState
+ permissionName: String
): Boolean {
val apexModuleName = androidPackage.apexModuleName
val systemState = newState.systemState
@@ -682,10 +651,9 @@
return permissionNames?.contains(permissionName) == true
}
- private fun isInSystemConfigPrivAppDenyPermissions(
+ private fun MutateStateScope.isInSystemConfigPrivAppDenyPermissions(
androidPackage: AndroidPackage,
- permissionName: String,
- newState: AccessState
+ permissionName: String
): Boolean {
// Different from the previous implementation, which may incorrectly use the APEX package
// name, we now use the APEX module name to be consistent with the allowlist.
@@ -713,22 +681,21 @@
return permissionNames?.contains(permissionName) == true
}
- private fun anyPackageInAppId(
+ private fun MutateStateScope.anyPackageInAppId(
appId: Int,
- newState: AccessState,
+ state: AccessState = newState,
predicate: (PackageState) -> Boolean
): Boolean {
- val packageNames = newState.systemState.appIds[appId]
+ val packageNames = state.systemState.appIds[appId]
return packageNames.anyIndexed { _, packageName ->
- val packageState = newState.systemState.packageStates[packageName]!!
+ val packageState = state.systemState.packageStates[packageName]!!
packageState.androidPackage != null && predicate(packageState)
}
}
- private fun shouldGrantPermissionByProtectionFlags(
+ private fun MutateStateScope.shouldGrantPermissionByProtectionFlags(
packageState: PackageState,
- permission: Permission,
- newState: AccessState
+ permission: Permission
): Boolean {
val androidPackage = packageState.androidPackage!!
val knownPackages = newState.systemState.knownPackages
@@ -741,11 +708,9 @@
.disabledSystemPackageStates[packageState.packageName]?.androidPackage
disabledSystemPackage != null &&
permission.name in disabledSystemPackage.requestedPermissions &&
- shouldGrantPrivilegedOrOemPermission(
- disabledSystemPackage, permission, newState
- )
+ shouldGrantPrivilegedOrOemPermission(disabledSystemPackage, permission)
} else {
- shouldGrantPrivilegedOrOemPermission(androidPackage, permission, newState)
+ shouldGrantPrivilegedOrOemPermission(androidPackage, permission)
}
if (shouldGrant) {
return true
@@ -815,7 +780,7 @@
}
if (permission.isRetailDemo &&
packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO] &&
- isDeviceOrProfileOwnerUid(packageState.appId, newState)) {
+ isDeviceOrProfileOwnerUid(packageState.appId)) {
// Special permission granted only to the OEM specified retail demo app.
// Note that the original code was passing app ID as UID, so this behavior is kept
// unchanged.
@@ -829,10 +794,9 @@
return false
}
- private fun shouldGrantPrivilegedOrOemPermission(
+ private fun MutateStateScope.shouldGrantPrivilegedOrOemPermission(
androidPackage: AndroidPackage,
- permission: Permission,
- state: AccessState
+ permission: Permission
): Boolean {
val permissionName = permission.name
val packageName = androidPackage.packageName
@@ -855,7 +819,7 @@
}
permission.isOem -> {
if (androidPackage.isOem) {
- val isOemAllowlisted = state.systemState
+ val isOemAllowlisted = newState.systemState
.oemPermissions[packageName]?.get(permissionName)
checkNotNull(isOemAllowlisted) {
"OEM permission $permissionName requested by package" +
@@ -868,19 +832,15 @@
return false
}
- private fun isDeviceOrProfileOwnerUid(uid: Int, state: AccessState): Boolean {
+ private fun MutateStateScope.isDeviceOrProfileOwnerUid(uid: Int): Boolean {
val userId = UserHandle.getUserId(uid)
- val ownerPackageName = state.systemState.deviceAndProfileOwners[userId] ?: return false
- val ownerPackageState = state.systemState.packageStates[ownerPackageName] ?: return false
+ val ownerPackageName = newState.systemState.deviceAndProfileOwners[userId] ?: return false
+ val ownerPackageState = newState.systemState.packageStates[ownerPackageName] ?: return false
val ownerUid = UserHandle.getUid(userId, ownerPackageState.appId)
return uid == ownerUid
}
- override fun onPackageRemoved(
- packageState: PackageState,
- oldState: AccessState,
- newState: AccessState
- ) {
+ override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
// TODO
}
@@ -892,6 +852,12 @@
with(persistence) { this@serializeSystemState.serializeSystemState(systemState) }
}
+ fun GetStateScope.getPermissionGroup(permissionGroupName: String): PermissionGroupInfo? =
+ state.systemState.permissionGroups[permissionGroupName]
+
+ fun GetStateScope.getPermission(permissionName: String): Permission? =
+ state.systemState.permissions[permissionName]
+
companion object {
private val LOG_TAG = UidPermissionPolicy::class.java.simpleName