Loading src/com/android/permissioncontroller/permission/data/AutoRevokeStateLiveData.kt +12 −9 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.permissioncontroller.permission.data.PackagePermissionsLiveDa import com.android.permissioncontroller.permission.model.livedatatypes.AutoRevokeState import com.android.permissioncontroller.permission.service.isAutoRevokeEnabled import com.android.permissioncontroller.permission.service.isPackageAutoRevokeExempt import com.android.permissioncontroller.permission.service.isPackageAutoRevokePermanentlyExempt import kotlinx.coroutines.Job /** Loading Loading @@ -88,18 +89,20 @@ class AutoRevokeStateLiveData private constructor( } val revocable = !isPackageAutoRevokeExempt(app, packageLiveData.value!!) val autoRevokeState = mutableListOf<String>() val revocableGroups = mutableListOf<String>() if (!isPackageAutoRevokePermanentlyExempt(packageLiveData.value!!, user)) { permStateLiveDatas.forEach { (groupName, liveData) -> val default = liveData.value?.any { (_, permState) -> permState.permFlags and (FLAG_PERMISSION_GRANTED_BY_DEFAULT or FLAG_PERMISSION_GRANTED_BY_ROLE) != 0 } ?: false if (!default) { autoRevokeState.add(groupName) revocableGroups.add(groupName) } } } postValue(AutoRevokeState(isAutoRevokeEnabled(app), revocable, autoRevokeState)) postValue(AutoRevokeState(isAutoRevokeEnabled(app), revocable, revocableGroups)) } override fun onOpChanged(op: String?, packageName: String?) { Loading src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.permissioncontroller.permission.data import android.app.Application import android.telephony.TelephonyManager import com.android.permissioncontroller.PermissionControllerApplication /** * A LiveData which represents the carrier privileged status for a package * * @param app The current application * @param uid The uid of the package */ class CarrierPrivilegedStatusLiveData private constructor( private val app: Application, private val uid: Int ) : SmartUpdateMediatorLiveData<Int>() { val telephonyManager = app.getSystemService(TelephonyManager::class.java)!! override fun onUpdate() { value = telephonyManager.getCarrierPrivilegeStatus(uid) } /** * Repository for [CarrierPrivilegedStatusLiveData]. * <p> Key value is a package uid, value is its corresponding LiveData. */ companion object : DataRepository<Int, CarrierPrivilegedStatusLiveData>() { override fun newValue(key: Int): CarrierPrivilegedStatusLiveData { return CarrierPrivilegedStatusLiveData(PermissionControllerApplication.get(), key) } } } No newline at end of file src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt +43 −6 Original line number Diff line number Diff line Loading @@ -66,6 +66,8 @@ import android.service.notification.NotificationListenerService import android.service.textclassifier.TextClassifierService import android.service.voice.VoiceInteractionService import android.service.wallpaper.WallpaperService import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS import android.util.Log import android.view.inputmethod.InputMethod import androidx.annotation.MainThread Loading @@ -86,6 +88,7 @@ import com.android.permissioncontroller.permission.data.AppOpLiveData import com.android.permissioncontroller.permission.data.AutoRevokeManifestExemptPackagesLiveData import com.android.permissioncontroller.permission.data.AutoRevokeStateLiveData import com.android.permissioncontroller.permission.data.BroadcastReceiverLiveData import com.android.permissioncontroller.permission.data.CarrierPrivilegedStatusLiveData import com.android.permissioncontroller.permission.data.DataRepositoryForPackage import com.android.permissioncontroller.permission.data.HasIntentAction import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData Loading @@ -111,6 +114,7 @@ import com.android.permissioncontroller.permission.utils.Utils.PROPERTY_AUTO_REV import com.android.permissioncontroller.permission.utils.Utils.PROPERTY_AUTO_REVOKE_UNUSED_THRESHOLD_MILLIS import com.android.permissioncontroller.permission.utils.application import com.android.permissioncontroller.permission.utils.forEachInParallel import com.android.permissioncontroller.permission.utils.getUid import com.android.permissioncontroller.permission.utils.updatePermissionFlags import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.GlobalScope Loading Loading @@ -306,11 +310,6 @@ private suspend fun revokePermissionsOnUnusedApps( val manifestExemptPackages = AutoRevokeManifestExemptPackagesLiveData[myUserHandle()] .getInitializedValue() // Exempt important system-bound services // TODO: Support more than the current user val exemptServicePackages = ExemptServicesLiveData[myUserHandle()] .getInitializedValue().keys val revokedApps = mutableListOf<Pair<String, UserHandle>>() val userManager = context.getSystemService(UserManager::class.java) for ((user, userApps) in unusedApps) { Loading @@ -323,7 +322,7 @@ private suspend fun revokePermissionsOnUnusedApps( return@forEachInParallel } if (pkg.packageName in exemptServicePackages) { if (isPackageAutoRevokePermanentlyExempt(pkg, user)) { return@forEachInParallel } Loading Loading @@ -443,6 +442,44 @@ private fun List<UsageStats>.lastTimeVisible(pkgName: String): Long { return result } /** * Checks if the given package is exempt from auto revoke in a way that's not user-overridable */ suspend fun isPackageAutoRevokePermanentlyExempt( pkg: LightPackageInfo, user: UserHandle ): Boolean { if (!ExemptServicesLiveData[user] .getInitializedValue()[pkg.packageName] .isNullOrEmpty()) { return true } if (Utils.isUserDisabledOrWorkProfile(user)) { if (DEBUG) { DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - $user is disabled or a work profile") } return true } val carrierPrivilegedStatus = CarrierPrivilegedStatusLiveData[user.getUid(pkg.uid)] .getInitializedValue() if (carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_HAS_ACCESS && carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { DumpableLog.w(LOG_TAG, "Error carrier privileged status for ${pkg.packageName}: " + carrierPrivilegedStatus) } if (carrierPrivilegedStatus == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DEBUG) { DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - carrier privileged") } return true } return false } /** * Checks if the given package is exempt from auto revoke in a way that's user-overridable */ suspend fun isPackageAutoRevokeExempt( context: Context, pkg: LightPackageInfo Loading src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt +7 −0 Original line number Diff line number Diff line Loading @@ -69,3 +69,10 @@ fun PackageManager.updatePermissionFlags( val value = flags.fold(0, { mask, (flag, flagValue) -> if (flagValue) mask or flag else mask }) updatePermissionFlags(permissionName, packageName, mask, value, user) } /** * @see UserHandle.getUid */ fun UserHandle.getUid(appId: Int): Int { return identifier * 100000 + (appId % 100000) } No newline at end of file src/com/android/permissioncontroller/permission/utils/Utils.java +16 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,8 @@ import androidx.core.util.Preconditions; import com.android.launcher3.icons.IconFactory; import com.android.permissioncontroller.Constants; import com.android.permissioncontroller.DeviceUtils; import com.android.permissioncontroller.PermissionControllerApplication; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.model.AppPermissionGroup; Loading Loading @@ -1111,4 +1113,18 @@ public final class Utils { @NonNull String packageName) throws NameNotFoundException { return getForegroundCapableType(context, packageName) != ForegroundCapableType.NONE; } /** * Determines if a given user is disabled, or is a work profile. * @param user The user to check * @return true if the user is disabled, or the user is a work profile */ public static boolean isUserDisabledOrWorkProfile(UserHandle user) { Application app = PermissionControllerApplication.get(); UserManager userManager = app.getSystemService(UserManager.class); // In android TV, parental control accounts are managed profiles return !userManager.getEnabledProfiles().contains(user) || (userManager.isManagedProfile(user.getIdentifier()) && !DeviceUtils.isTelevision(app)); } } Loading
src/com/android/permissioncontroller/permission/data/AutoRevokeStateLiveData.kt +12 −9 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.permissioncontroller.permission.data.PackagePermissionsLiveDa import com.android.permissioncontroller.permission.model.livedatatypes.AutoRevokeState import com.android.permissioncontroller.permission.service.isAutoRevokeEnabled import com.android.permissioncontroller.permission.service.isPackageAutoRevokeExempt import com.android.permissioncontroller.permission.service.isPackageAutoRevokePermanentlyExempt import kotlinx.coroutines.Job /** Loading Loading @@ -88,18 +89,20 @@ class AutoRevokeStateLiveData private constructor( } val revocable = !isPackageAutoRevokeExempt(app, packageLiveData.value!!) val autoRevokeState = mutableListOf<String>() val revocableGroups = mutableListOf<String>() if (!isPackageAutoRevokePermanentlyExempt(packageLiveData.value!!, user)) { permStateLiveDatas.forEach { (groupName, liveData) -> val default = liveData.value?.any { (_, permState) -> permState.permFlags and (FLAG_PERMISSION_GRANTED_BY_DEFAULT or FLAG_PERMISSION_GRANTED_BY_ROLE) != 0 } ?: false if (!default) { autoRevokeState.add(groupName) revocableGroups.add(groupName) } } } postValue(AutoRevokeState(isAutoRevokeEnabled(app), revocable, autoRevokeState)) postValue(AutoRevokeState(isAutoRevokeEnabled(app), revocable, revocableGroups)) } override fun onOpChanged(op: String?, packageName: String?) { Loading
src/com/android/permissioncontroller/permission/data/CarrierPrivilegedStatusLiveData.kt 0 → 100644 +50 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.permissioncontroller.permission.data import android.app.Application import android.telephony.TelephonyManager import com.android.permissioncontroller.PermissionControllerApplication /** * A LiveData which represents the carrier privileged status for a package * * @param app The current application * @param uid The uid of the package */ class CarrierPrivilegedStatusLiveData private constructor( private val app: Application, private val uid: Int ) : SmartUpdateMediatorLiveData<Int>() { val telephonyManager = app.getSystemService(TelephonyManager::class.java)!! override fun onUpdate() { value = telephonyManager.getCarrierPrivilegeStatus(uid) } /** * Repository for [CarrierPrivilegedStatusLiveData]. * <p> Key value is a package uid, value is its corresponding LiveData. */ companion object : DataRepository<Int, CarrierPrivilegedStatusLiveData>() { override fun newValue(key: Int): CarrierPrivilegedStatusLiveData { return CarrierPrivilegedStatusLiveData(PermissionControllerApplication.get(), key) } } } No newline at end of file
src/com/android/permissioncontroller/permission/service/AutoRevokePermissions.kt +43 −6 Original line number Diff line number Diff line Loading @@ -66,6 +66,8 @@ import android.service.notification.NotificationListenerService import android.service.textclassifier.TextClassifierService import android.service.voice.VoiceInteractionService import android.service.wallpaper.WallpaperService import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS import android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS import android.util.Log import android.view.inputmethod.InputMethod import androidx.annotation.MainThread Loading @@ -86,6 +88,7 @@ import com.android.permissioncontroller.permission.data.AppOpLiveData import com.android.permissioncontroller.permission.data.AutoRevokeManifestExemptPackagesLiveData import com.android.permissioncontroller.permission.data.AutoRevokeStateLiveData import com.android.permissioncontroller.permission.data.BroadcastReceiverLiveData import com.android.permissioncontroller.permission.data.CarrierPrivilegedStatusLiveData import com.android.permissioncontroller.permission.data.DataRepositoryForPackage import com.android.permissioncontroller.permission.data.HasIntentAction import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData Loading @@ -111,6 +114,7 @@ import com.android.permissioncontroller.permission.utils.Utils.PROPERTY_AUTO_REV import com.android.permissioncontroller.permission.utils.Utils.PROPERTY_AUTO_REVOKE_UNUSED_THRESHOLD_MILLIS import com.android.permissioncontroller.permission.utils.application import com.android.permissioncontroller.permission.utils.forEachInParallel import com.android.permissioncontroller.permission.utils.getUid import com.android.permissioncontroller.permission.utils.updatePermissionFlags import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.GlobalScope Loading Loading @@ -306,11 +310,6 @@ private suspend fun revokePermissionsOnUnusedApps( val manifestExemptPackages = AutoRevokeManifestExemptPackagesLiveData[myUserHandle()] .getInitializedValue() // Exempt important system-bound services // TODO: Support more than the current user val exemptServicePackages = ExemptServicesLiveData[myUserHandle()] .getInitializedValue().keys val revokedApps = mutableListOf<Pair<String, UserHandle>>() val userManager = context.getSystemService(UserManager::class.java) for ((user, userApps) in unusedApps) { Loading @@ -323,7 +322,7 @@ private suspend fun revokePermissionsOnUnusedApps( return@forEachInParallel } if (pkg.packageName in exemptServicePackages) { if (isPackageAutoRevokePermanentlyExempt(pkg, user)) { return@forEachInParallel } Loading Loading @@ -443,6 +442,44 @@ private fun List<UsageStats>.lastTimeVisible(pkgName: String): Long { return result } /** * Checks if the given package is exempt from auto revoke in a way that's not user-overridable */ suspend fun isPackageAutoRevokePermanentlyExempt( pkg: LightPackageInfo, user: UserHandle ): Boolean { if (!ExemptServicesLiveData[user] .getInitializedValue()[pkg.packageName] .isNullOrEmpty()) { return true } if (Utils.isUserDisabledOrWorkProfile(user)) { if (DEBUG) { DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - $user is disabled or a work profile") } return true } val carrierPrivilegedStatus = CarrierPrivilegedStatusLiveData[user.getUid(pkg.uid)] .getInitializedValue() if (carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_HAS_ACCESS && carrierPrivilegedStatus != CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { DumpableLog.w(LOG_TAG, "Error carrier privileged status for ${pkg.packageName}: " + carrierPrivilegedStatus) } if (carrierPrivilegedStatus == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DEBUG) { DumpableLog.i(LOG_TAG, "Exempted ${pkg.packageName} - carrier privileged") } return true } return false } /** * Checks if the given package is exempt from auto revoke in a way that's user-overridable */ suspend fun isPackageAutoRevokeExempt( context: Context, pkg: LightPackageInfo Loading
src/com/android/permissioncontroller/permission/utils/AndroidUtils.kt +7 −0 Original line number Diff line number Diff line Loading @@ -69,3 +69,10 @@ fun PackageManager.updatePermissionFlags( val value = flags.fold(0, { mask, (flag, flagValue) -> if (flagValue) mask or flag else mask }) updatePermissionFlags(permissionName, packageName, mask, value, user) } /** * @see UserHandle.getUid */ fun UserHandle.getUid(appId: Int): Int { return identifier * 100000 + (appId % 100000) } No newline at end of file
src/com/android/permissioncontroller/permission/utils/Utils.java +16 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,8 @@ import androidx.core.util.Preconditions; import com.android.launcher3.icons.IconFactory; import com.android.permissioncontroller.Constants; import com.android.permissioncontroller.DeviceUtils; import com.android.permissioncontroller.PermissionControllerApplication; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.model.AppPermissionGroup; Loading Loading @@ -1111,4 +1113,18 @@ public final class Utils { @NonNull String packageName) throws NameNotFoundException { return getForegroundCapableType(context, packageName) != ForegroundCapableType.NONE; } /** * Determines if a given user is disabled, or is a work profile. * @param user The user to check * @return true if the user is disabled, or the user is a work profile */ public static boolean isUserDisabledOrWorkProfile(UserHandle user) { Application app = PermissionControllerApplication.get(); UserManager userManager = app.getSystemService(UserManager.class); // In android TV, parental control accounts are managed profiles return !userManager.getEnabledProfiles().contains(user) || (userManager.isManagedProfile(user.getIdentifier()) && !DeviceUtils.isTelevision(app)); } }