Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df9b0d63 authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by Android (Google) Code Review
Browse files

Merge changes I7b7a0e4b,Ifc4a7f3f,I379f91fe,I444123e1 into rvc-dev

* changes:
  Re-use methods to create whitelistings
  Only load group data is needed
  Combine whitelisting of system apps and permission changes on upgrade
  Parallelize data gathering of RuntimePermissionsUpgradeController#onUpgradeLocked
parents 60aac0b1 7720a98c
Loading
Loading
Loading
Loading
+141 −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.content.pm.PackageManager
import android.util.Log
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermInfo
import com.android.permissioncontroller.permission.utils.Utils.OS_PKG
import com.android.permissioncontroller.permission.utils.Utils.isRuntimePlatformPermission
import kotlinx.coroutines.Job

/**
 * LiveData for a LightPermInfo.
 *
 * @param app current Application
 * @param permissionName name of the permission this LiveData will watch for mode changes for
 */
class LightPermInfoLiveData private constructor(
    private val app: Application,
    private val permissionName: String
) : SmartAsyncMediatorLiveData<LightPermInfo>(),
    PackageBroadcastReceiver.PackageBroadcastListener {

    private val LOG_TAG = LightPermInfoLiveData::class.java.simpleName

    /** Is this liveData currently listing for changes */
    private var isListeningForChanges = false

    /**
     * Callback from the PackageBroadcastReceiver.
     *
     * <p>Package updates might change permission properties
     */
    override fun onPackageUpdate(ignored: String) {
        updateAsync()
    }

    override fun updateAsync() {
        // No need to update if the value can never change
        if (value != null && isImmutable()) {
            return
        }

        super.updateAsync()
    }

    override suspend fun loadDataAndPostValue(job: Job) {
        if (job.isCancelled) {
            return
        }

        val newValue = try {
            LightPermInfo(app.packageManager.getPermissionInfo(permissionName, 0))
        } catch (e: PackageManager.NameNotFoundException) {
            Log.w(LOG_TAG, "Permission \"$permissionName\" not found")
            invalidateSingle(permissionName)
            null
        }

        if (isImmutable()) {
            stopListeningForChanges()
        }

        postValue(newValue)
    }

    /**
     * @return if the permission state can never change
     */
    private fun isImmutable(): Boolean {
        // The os package never changes
        value?.let {
            if (it.packageName == OS_PKG) {
                return true
            }
        }

        // Platform permissions never change
        return isRuntimePlatformPermission(permissionName)
    }

    /**
     * Start listing for changes to this permission if needed
     */
    private fun startListeningForChanges() {
        if (!isListeningForChanges && !isImmutable()) {
            isListeningForChanges = true
            PackageBroadcastReceiver.addAllCallback(this)
        }
    }

    /**
     * Stop listing for changes to this permission
     */
    private fun stopListeningForChanges() {
        if (isListeningForChanges) {
            PackageBroadcastReceiver.removeAllCallback(this)
            isListeningForChanges = false
        }
    }

    override fun onActive() {
        super.onActive()

        startListeningForChanges()
        updateAsync()
    }

    override fun onInactive() {
        super.onInactive()

        stopListeningForChanges()
    }

    /**
     * Repository for LightPermInfoLiveData
     *
     * <p>Key value is a string permission name, value is its corresponding LiveData.
     */
    companion object : DataRepositoryForPackage<String, LightPermInfoLiveData>() {
        override fun newValue(key: String): LightPermInfoLiveData {
            return LightPermInfoLiveData(PermissionControllerApplication.get(), key)
        }
    }
}
+72 −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.content.pm.PackageManager.GET_PERMISSIONS
import android.content.pm.PackageManager.MATCH_FACTORY_ONLY
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
import android.os.UserHandle
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import kotlinx.coroutines.Job

/**
 * A LiveData which returns all of the preinstalled packageinfos. For packages that are preinstalled
 * and then updated, the preinstalled (i.e. old) version is returned.
 *
 * @param app The current application
 * @param user The user whose packages are desired
 */
class PreinstalledUserPackageInfosLiveData private constructor(
    private val app: Application,
    private val user: UserHandle
) : SmartAsyncMediatorLiveData<@kotlin.jvm.JvmSuppressWildcards List<LightPackageInfo>>() {

    /**
     * Get all of the preinstalled packages in the system for this user
     */
    override suspend fun loadDataAndPostValue(job: Job) {
        if (job.isCancelled) {
            return
        }
        val packageInfos = app.applicationContext.packageManager
                .getInstalledPackagesAsUser(GET_PERMISSIONS or MATCH_UNINSTALLED_PACKAGES
                        or MATCH_FACTORY_ONLY, user.identifier)
        postValue(packageInfos.map { packageInfo -> LightPackageInfo(packageInfo) })
    }

    override fun onActive() {
        super.onActive()

        // Data never changes, hence no need to reload
        if (value == null) {
            updateAsync()
        }
    }

    /**
     * Repository for PreinstalledUserPackageInfosLiveData.
     *
     * <p>Key value is a UserHandle, value is its corresponding LiveData.
     */
    companion object : DataRepository<UserHandle, PreinstalledUserPackageInfosLiveData>() {
        override fun newValue(key: UserHandle): PreinstalledUserPackageInfosLiveData {
            return PreinstalledUserPackageInfosLiveData(PermissionControllerApplication.get(), key)
        }
    }
}