1 /* <lambda>null2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permissioncontroller.permission.data.v31 18 19 import android.app.AppOpsManager 20 import android.app.AppOpsManager.HISTORY_FLAG_DISCRETE 21 import android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS 22 import android.app.AppOpsManager.HistoricalOps 23 import android.app.AppOpsManager.HistoricalOpsRequest 24 import android.app.AppOpsManager.OP_FLAG_SELF 25 import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED 26 import android.app.Application 27 import android.os.UserHandle 28 import android.os.UserManager 29 import com.android.modules.utils.build.SdkLevel 30 import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData 31 import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps 32 import java.util.concurrent.TimeUnit 33 import kotlin.coroutines.suspendCoroutine 34 import kotlinx.coroutines.Job 35 36 /** 37 * LiveData class tracking [LightHistoricalPackageOps] for all packages on the device and for the 38 * provided app ops. 39 * 40 * App ops data is retrieved from [AppOpsManager] and is updated whenever app ops data changes are 41 * heard. 42 */ 43 class AllLightHistoricalPackageOpsLiveData(app: Application, val opNames: Set<String>) : 44 SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, LightHistoricalPackageOps>>(), 45 AppOpsManager.OnOpActiveChangedListener, 46 AppOpsManager.OnOpNotedListener, 47 AppOpsManager.OnOpChangedListener { 48 49 private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!! 50 private val userManager = app.getSystemService(UserManager::class.java)!! 51 52 override fun onActive() { 53 super.onActive() 54 55 opNames.forEach { opName -> 56 // TODO(b/262035952): We watch each active op individually as startWatchingActive only 57 // registers the callback if all ops are valid. Fix this behavior so if one op is 58 // invalid it doesn't affect the other ops. 59 try { 60 appOpsManager.startWatchingActive(arrayOf(opName), { it.run() }, this) 61 } catch (ignored: IllegalArgumentException) { 62 // Older builds may not support all requested app ops. 63 } 64 65 try { 66 appOpsManager.startWatchingMode(opName, /* all packages */ null, this) 67 } catch (ignored: IllegalArgumentException) { 68 // Older builds may not support all requested app ops. 69 } 70 71 if (SdkLevel.isAtLeastU()) { 72 try { 73 appOpsManager.startWatchingNoted(arrayOf(opName), this) 74 } catch (ignored: IllegalArgumentException) { 75 // Older builds may not support all requested app ops. 76 } 77 } 78 } 79 } 80 81 override fun onInactive() { 82 super.onInactive() 83 84 appOpsManager.stopWatchingActive(this) 85 appOpsManager.stopWatchingMode(this) 86 } 87 88 override suspend fun loadDataAndPostValue(job: Job) { 89 if (job.isCancelled) { 90 return 91 } 92 93 val allLightHistoricalPackageOps = 94 mutableMapOf<Pair<String, UserHandle>, LightHistoricalPackageOps>() 95 96 val endTimeMillis = System.currentTimeMillis() 97 val beginTimeMillis = endTimeMillis - TimeUnit.DAYS.toMillis(7) 98 99 val allProfilesInCurrentUser = userManager.userProfiles 100 101 val request = 102 HistoricalOpsRequest.Builder(beginTimeMillis, endTimeMillis) 103 .setFlags(OP_FLAG_SELF or OP_FLAG_TRUSTED_PROXIED) 104 .setHistoryFlags(HISTORY_FLAG_DISCRETE or HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) 105 .build() 106 107 val historicalOps = suspendCoroutine { 108 appOpsManager.getHistoricalOps(request, { it.run() }) { ops: HistoricalOps -> 109 it.resumeWith(Result.success(ops)) 110 } 111 } 112 113 for (i in 0 until historicalOps.uidCount) { 114 val historicalUidOps = historicalOps.getUidOpsAt(i) 115 val userHandle = UserHandle.getUserHandleForUid(historicalUidOps.uid) 116 if (userHandle !in allProfilesInCurrentUser) { 117 continue 118 } 119 for (j in 0 until historicalUidOps.packageCount) { 120 val historicalPackageOps = historicalUidOps.getPackageOpsAt(j) 121 allLightHistoricalPackageOps[Pair(historicalPackageOps.packageName, userHandle)] = 122 LightHistoricalPackageOps(historicalPackageOps, userHandle, opNames) 123 } 124 } 125 126 postValue(allLightHistoricalPackageOps) 127 } 128 129 override fun onOpChanged(op: String?, packageName: String?) { 130 update() 131 } 132 133 override fun onOpActiveChanged(op: String, uid: Int, packageName: String, active: Boolean) { 134 update() 135 } 136 137 override fun onOpNoted( 138 code: String, 139 uid: Int, 140 packageName: String, 141 attributionTag: String?, 142 flags: Int, 143 result: Int 144 ) { 145 update() 146 } 147 } 148