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 9ec63fcf7125b..cefe9cdec6c76 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 @@ public class PermissionManagerService extends IPermissionManager.Stub { @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 @@ public class PermissionManagerService extends IPermissionManager.Stub { @NonNull @Override - public ArrayList getAllPermissionsWithProtection( + public List getAllPermissionsWithProtection( @PermissionInfo.Protection int protection) { return mPermissionManagerServiceImpl.getAllPermissionsWithProtection(protection); } @NonNull @Override - public ArrayList getAllPermissionsWithProtectionFlags( + public List 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 5ffbbdcfbb0b5..e56edeb73ad77 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 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt @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 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt 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 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt @NonNull @Override - public ArrayList getAllPermissionsWithProtection( + public List getAllPermissionsWithProtection( @PermissionInfo.Protection int protection) { - ArrayList matchingPermissions = new ArrayList<>(); + List matchingPermissions = new ArrayList<>(); synchronized (mLock) { for (final Permission permission : mRegistry.getPermissions()) { @@ -5221,9 +5221,9 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt @NonNull @Override - public ArrayList getAllPermissionsWithProtectionFlags( + public List getAllPermissionsWithProtectionFlags( @PermissionInfo.ProtectionFlags int protectionFlags) { - ArrayList matchingPermissions = new ArrayList<>(); + List 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 930936be9ec66..d9caec7089bee 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 com.android.server.pm.pkg.AndroidPackage; 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 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte * @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 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte /** Get all permissions that have a certain protection */ @NonNull - ArrayList getAllPermissionsWithProtection( + List getAllPermissionsWithProtection( @PermissionInfo.Protection int protection); /** Get all permissions that have certain protection flags */ - @NonNull ArrayList getAllPermissionsWithProtectionFlags( + @NonNull List 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 f20620ed6eec9..97ac749781d0c 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 @@ public interface PermissionManagerServiceInternal extends PermissionManagerInter /** Get all permissions that have a certain protection */ @NonNull - ArrayList getAllPermissionsWithProtection( + List getAllPermissionsWithProtection( @PermissionInfo.Protection int protection); - /** Get all permissions that have certain protection flags */ - @NonNull ArrayList getAllPermissionsWithProtectionFlags( + /** Get all permissions that have certain protection flags + * @return*/ + @NonNull List 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 e61effa13a601..d6cac33523212 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 @@ public final class PermissionPolicyService extends SystemService { } }; - final ArrayList dangerousPerms = + final List dangerousPerms = mPermissionManagerInternal.getAllPermissionsWithProtection( PermissionInfo.PROTECTION_DANGEROUS); try { diff --git a/services/permission/Android.bp b/services/permission/Android.bp index b03f17b1bef7b..dc9b5585cbf25 100644 --- a/services/permission/Android.bp +++ b/services/permission/Android.bp @@ -29,6 +29,8 @@ java_library_static { ], 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 c6ccc0fb1cff0..7b96d42c8abe4 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 @@ class AccessCheckingService { } 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 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 0efc1bd00de29..022f09a028db9 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 @@ class AccessPersistence( 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 @@ class AccessPersistence( 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 4e53ce06f3eb7..e9741c69aa5be 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 @@ class AccessPolicy private constructor( } ) - 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 @@ class AccessPolicy private constructor( }.add(packageState.packageName) } if (isAppIdAdded) { - forEachSchemePolicy { it.onAppIdAdded(packageState.appId, oldState, newState) } + forEachSchemePolicy { + with(it) { onAppIdAdded(packageState.appId) } + } + } + forEachSchemePolicy { + with(it) { onPackageAdded(packageState) } } - forEachSchemePolicy { it.onPackageAdded(packageState, oldState, newState) } } - 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 @@ class AccessPolicy private constructor( } } } - 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 @@ class AccessPolicy private constructor( TAG_ACCESS -> { forEachTag { forEachSchemePolicy { - with(it) { this@parseSystemState.parseSystemState(systemState) } + with(it) { parseSystemState(systemState) } } } } @@ -125,7 +130,7 @@ class AccessPolicy private constructor( fun BinaryXmlSerializer.serializeSystemState(systemState: SystemState) { tag(TAG_ACCESS) { forEachSchemePolicy { - with(it) { this@serializeSystemState.serializeSystemState(systemState) } + with(it) { serializeSystemState(systemState) } } } } @@ -136,7 +141,7 @@ class AccessPolicy private constructor( TAG_ACCESS -> { forEachTag { forEachSchemePolicy { - with(it) { this@parseUserState.parseUserState(userId, userState) } + with(it) { parseUserState(userId, userState) } } } } @@ -153,11 +158,14 @@ class AccessPolicy private constructor( 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 class SchemePolicy { 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 @@ abstract class SchemePolicy { } } - 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 f496dbd03130e..cf8f38360cffa 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 @@ abstract class WritableState { } } } + +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 0b052f918a20d..a1a5e2d900918 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 @@ package com.android.server.permission.access.appop 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? + abstract fun GetStateScope.getModes(subject: AccessUri): IndexedMap? - abstract fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap + abstract fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap - 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 7c3c14c1d753e..966489f72aa22 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 @@ class PackageAppOpPolicy : BaseAppOpPolicy(PackageAppOpPersistence()) { override val objectScheme: String get() = AppOpUri.SCHEME - override fun getModes(subject: AccessUri, state: AccessState): IndexedMap? { + override fun GetStateScope.getModes(subject: AccessUri): IndexedMap? { subject as PackageUri return state.userStates[subject.userId]?.packageAppOpModes?.get(subject.packageName) } - override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap { + override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap { 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 26d01144609af..862db8f353900 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 @@ class UidAppOpPolicy : BaseAppOpPolicy(UidAppOpPersistence()) { override val objectScheme: String get() = AppOpUri.SCHEME - override fun getModes(subject: AccessUri, state: AccessState): IndexedMap? { + override fun GetStateScope.getModes(subject: AccessUri): IndexedMap? { subject as UidUri return state.userStates[subject.userId]?.uidAppOpModes?.get(subject.appId) } - override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap { + override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap { 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 0000000000000..cc51866b46954 --- /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 { + 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 { + TODO("Not yet implemented") + } + + override fun getAllPermissionsWithProtection(protection: Int): List { + TODO("Not yet implemented") + } + + override fun getAllPermissionsWithProtectionFlags(protectionFlags: Int): List { + 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 { + 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 { + 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 { + TODO("Not yet implemented") + } + + override fun getAppOpPermissionPackages(permissionName: String): Array { + TODO("Not yet implemented") + } + + override fun getAllAppOpPermissionPackages(): Map> { + 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?) { + TODO("Not yet implemented") + } + + override fun getPermissionTEMP( + permissionName: String + ): com.android.server.pm.permission.Permission? { + TODO("Not yet implemented") + } + + override fun getLegacyPermissions(): List { + 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, + 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 6479e6ad88e39..e08192444d676 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 @@ package com.android.server.permission.access.permission 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.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.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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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() - 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, - newState: AccessState + changedPermissionNames: IndexedSet ) { 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 @@ class UidPermissionPolicy : SchemePolicy() { } 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { } } - private fun addPermissions( + private fun MutateStateScope.addPermissions( packageState: PackageState, - changedPermissionNames: IndexedSet, - newState: AccessState + changedPermissionNames: IndexedSet ) { packageState.androidPackage!!.permissions.forEachIndexed { _, parsedPermission -> // TODO: @@ -229,7 +222,7 @@ class UidPermissionPolicy : SchemePolicy() { // 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 @@ class UidPermissionPolicy : SchemePolicy() { } } - 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 @@ class UidPermissionPolicy : SchemePolicy() { } 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 @@ class UidPermissionPolicy : SchemePolicy() { } } - 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 @@ class UidPermissionPolicy : SchemePolicy() { } } - 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 @@ class UidPermissionPolicy : SchemePolicy() { ) } - 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 @@ class UidPermissionPolicy : SchemePolicy() { } } - 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { } 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { // 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { } } 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { .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 @@ class UidPermissionPolicy : SchemePolicy() { } 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { } 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 @@ class UidPermissionPolicy : SchemePolicy() { 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 @@ class UidPermissionPolicy : SchemePolicy() { 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