• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.permission.access.appop
18 
19 import android.app.AppOpsManager
20 import android.companion.virtual.VirtualDeviceManager
21 import android.os.Binder
22 import android.os.Handler
23 import android.os.UserHandle
24 import android.permission.PermissionManager
25 import android.permission.flags.Flags
26 import android.util.ArrayMap
27 import android.util.ArraySet
28 import android.util.LongSparseArray
29 import android.util.Slog
30 import android.util.SparseArray
31 import android.util.SparseBooleanArray
32 import android.util.SparseIntArray
33 import com.android.internal.annotations.VisibleForTesting
34 import com.android.internal.util.IntPair
35 import com.android.server.appop.AppOpsCheckingServiceInterface
36 import com.android.server.appop.AppOpsCheckingServiceInterface.AppOpsModeChangedListener
37 import com.android.server.permission.access.AccessCheckingService
38 import com.android.server.permission.access.AppOpUri
39 import com.android.server.permission.access.DevicePermissionUri
40 import com.android.server.permission.access.GetStateScope
41 import com.android.server.permission.access.PackageUri
42 import com.android.server.permission.access.PermissionUri
43 import com.android.server.permission.access.UidUri
44 import com.android.server.permission.access.appop.AppOpModes.MODE_ALLOWED
45 import com.android.server.permission.access.appop.AppOpModes.MODE_FOREGROUND
46 import com.android.server.permission.access.appop.AppOpModes.MODE_IGNORED
47 import com.android.server.permission.access.collection.forEachIndexed
48 import com.android.server.permission.access.collection.set
49 import com.android.server.permission.access.permission.AppIdPermissionPolicy
50 import com.android.server.permission.access.permission.DevicePermissionPolicy
51 import com.android.server.permission.access.permission.PermissionFlags
52 import com.android.server.permission.access.permission.PermissionService
53 
54 class AppOpService(private val service: AccessCheckingService) : AppOpsCheckingServiceInterface {
55     private val packagePolicy =
56         service.getSchemePolicy(PackageUri.SCHEME, AppOpUri.SCHEME) as PackageAppOpPolicy
57     private val appIdPolicy =
58         service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as AppIdAppOpPolicy
59     private val permissionPolicy =
60         service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
61     private val devicePermissionPolicy =
62         service.getSchemePolicy(UidUri.SCHEME, DevicePermissionUri.SCHEME) as DevicePermissionPolicy
63 
64     private val context = service.context
65 
66     // Maps appop code to its runtime permission
67     private val runtimeAppOpToPermissionNames = SparseArray<String>()
68 
69     // Maps runtime permission to its appop codes
70     private val runtimePermissionNameToAppOp = ArrayMap<String, Int>()
71 
72     private var foregroundableOps = SparseBooleanArray()
73 
74     /* Maps foreground permissions to their background permission. Background permissions aren't
75     required to be runtime */
76     private val foregroundToBackgroundPermissionName = ArrayMap<String, String>()
77 
78     /* Maps background permissions to their foreground permissions. Background permissions aren't
79     required to be runtime */
80     private val backgroundToForegroundPermissionNames = ArrayMap<String, ArraySet<String>>()
81 
82     private lateinit var handler: Handler
83 
84     @Volatile private var listeners = ArraySet<AppOpsModeChangedListener>()
85     private val listenersLock = Any()
86 
87     fun initialize() {
88         // TODO(b/252883039): Wrong handler. Inject main thread handler here.
89         handler = Handler(context.mainLooper)
90 
91         appIdPolicy.addOnAppOpModeChangedListener(OnAppIdAppOpModeChangedListener())
92         packagePolicy.addOnAppOpModeChangedListener(OnPackageAppOpModeChangedListener())
93     }
94 
95     @VisibleForTesting
96     override fun writeState() {
97         // Not implemented because writes are handled automatically.
98     }
99 
100     override fun readState() {
101         // Not implemented because reads are handled automatically.
102     }
103 
104     @VisibleForTesting
105     override fun shutdown() {
106         // Not implemented because writes are handled automatically.
107     }
108 
109     override fun systemReady() {
110         if (Flags.runtimePermissionAppopsMappingEnabled()) {
111             createPermissionAppOpMapping()
112             val permissionListener = OnPermissionFlagsChangedListener()
113             permissionPolicy.addOnPermissionFlagsChangedListener(permissionListener)
114             devicePermissionPolicy.addOnPermissionFlagsChangedListener(permissionListener)
115         }
116     }
117 
118     private fun createPermissionAppOpMapping() {
119         val permissions = service.getState { with(permissionPolicy) { getPermissions() } }
120 
121         for (appOpCode in 0 until AppOpsManager._NUM_OP) {
122             // Ops that default to MODE_FOREGROUND are foregroundable.
123             if (AppOpsManager.opToDefaultMode(appOpCode) == AppOpsManager.MODE_FOREGROUND) {
124                 foregroundableOps[appOpCode] = true
125             }
126             AppOpsManager.opToPermission(appOpCode)?.let { permissionName ->
127                 // Multiple ops might map to a single permission but only one is considered the
128                 // runtime appop calculations.
129                 if (appOpCode == AppOpsManager.permissionToOpCode(permissionName)) {
130                     val permission = permissions[permissionName]!!
131                     if (permission.isRuntime) {
132                         runtimePermissionNameToAppOp[permissionName] = appOpCode
133                         runtimeAppOpToPermissionNames[appOpCode] = permissionName
134                         permission.permissionInfo.backgroundPermission?.let {
135                             backgroundPermissionName ->
136                             // Note: background permission may not be runtime,
137                             // e.g. microphone/camera.
138                             foregroundableOps[appOpCode] = true
139                             foregroundToBackgroundPermissionName[permissionName] =
140                                 backgroundPermissionName
141                             backgroundToForegroundPermissionNames
142                                 .getOrPut(backgroundPermissionName, ::ArraySet)
143                                 .add(permissionName)
144                         }
145                     }
146                 }
147             }
148         }
149     }
150 
151     override fun getNonDefaultUidModes(uid: Int, deviceId: String): SparseIntArray {
152         val appId = UserHandle.getAppId(uid)
153         val userId = UserHandle.getUserId(uid)
154         service.getState {
155             val modes =
156                 with(appIdPolicy) { opNameMapToOpSparseArray(getAppOpModes(appId, userId)?.map) }
157             if (Flags.runtimePermissionAppopsMappingEnabled()) {
158                 runtimePermissionNameToAppOp.forEachIndexed { _, permissionName, appOpCode ->
159                     val mode =
160                         getUidModeFromPermissionState(appId, userId, permissionName, deviceId)
161                     if (mode != AppOpsManager.opToDefaultMode(appOpCode)) {
162                         modes[appOpCode] = mode
163                     }
164                 }
165             }
166 
167             return modes
168         }
169     }
170 
171     override fun getNonDefaultPackageModes(packageName: String, userId: Int): SparseIntArray {
172         return opNameMapToOpSparseArray(getPackageModes(packageName, userId))
173     }
174 
175     override fun getUidMode(uid: Int, deviceId: String, op: Int): Int {
176         val appId = UserHandle.getAppId(uid)
177         val userId = UserHandle.getUserId(uid)
178         val opName = AppOpsManager.opToPublicName(op)
179         val permissionName = runtimeAppOpToPermissionNames[op]
180 
181         return if (!Flags.runtimePermissionAppopsMappingEnabled() || permissionName == null) {
182             service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, opName) } }
183         } else {
184             service.getState {
185                 getUidModeFromPermissionState(appId, userId, permissionName, deviceId)
186             }
187         }
188     }
189 
190     private fun getUidModes(uid: Int): ArrayMap<String, Int>? {
191         val appId = UserHandle.getAppId(uid)
192         val userId = UserHandle.getUserId(uid)
193         return service.getState { with(appIdPolicy) { getAppOpModes(appId, userId) } }?.map
194     }
195 
196     private fun GetStateScope.getUidModeFromPermissionState(
197         appId: Int,
198         userId: Int,
199         permissionName: String,
200         deviceId: String
201     ): Int {
202         val checkDevicePermissionFlags =
203             deviceId != VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT &&
204                 permissionName in PermissionManager.DEVICE_AWARE_PERMISSIONS
205         val permissionFlags =
206             if (checkDevicePermissionFlags) {
207                 with(devicePermissionPolicy) {
208                     getPermissionFlags(appId, deviceId, userId, permissionName)
209                 }
210             } else {
211                 with(permissionPolicy) { getPermissionFlags(appId, userId, permissionName) }
212             }
213         val backgroundPermissionName = foregroundToBackgroundPermissionName[permissionName]
214         val backgroundPermissionFlags =
215             if (backgroundPermissionName != null) {
216                 if (checkDevicePermissionFlags) {
217                     with(devicePermissionPolicy) {
218                         getPermissionFlags(appId, deviceId, userId, backgroundPermissionName)
219                     }
220                 } else {
221                     with(permissionPolicy) {
222                         getPermissionFlags(appId, userId, backgroundPermissionName)
223                     }
224                 }
225             } else {
226                 PermissionFlags.RUNTIME_GRANTED
227             }
228         val result = evaluateModeFromPermissionFlags(permissionFlags, backgroundPermissionFlags)
229         if (result != MODE_IGNORED) {
230             return result
231         }
232 
233         val fullerPermissionName =
234             PermissionService.getFullerPermission(permissionName) ?: return result
235         return getUidModeFromPermissionState(appId, userId, fullerPermissionName, deviceId)
236     }
237 
238     private fun evaluateModeFromPermissionFlags(
239         foregroundFlags: Int,
240         backgroundFlags: Int = PermissionFlags.RUNTIME_GRANTED
241     ): Int =
242         if (PermissionFlags.isAppOpGranted(foregroundFlags)) {
243             if (PermissionFlags.isAppOpGranted(backgroundFlags)) {
244                 MODE_ALLOWED
245             } else {
246                 MODE_FOREGROUND
247             }
248         } else {
249             MODE_IGNORED
250         }
251 
252     override fun setUidMode(uid: Int, deviceId: String, code: Int, mode: Int): Boolean {
253         val appId = UserHandle.getAppId(uid)
254         val userId = UserHandle.getUserId(uid)
255         val appOpName = AppOpsManager.opToPublicName(code)
256 
257         if (
258             Flags.runtimePermissionAppopsMappingEnabled() && code in runtimeAppOpToPermissionNames
259         ) {
260             val oldMode =
261                 service.getState { with(appIdPolicy) { getAppOpMode(appId, userId, appOpName) } }
262             val wouldHaveChanged = oldMode != mode
263             val logMessage =
264                 (if (wouldHaveChanged) "Blocked" else "Ignored") +
265                     " setUidMode call for runtime permission app op:" +
266                     " uid = $uid," +
267                     " code = ${AppOpsManager.opToName(code)}," +
268                     " mode = ${AppOpsManager.modeToName(mode)}," +
269                     " callingUid = ${Binder.getCallingUid()}," +
270                     " oldMode = ${AppOpsManager.modeToName(oldMode)}"
271             if (wouldHaveChanged) {
272                 Slog.e(LOG_TAG, logMessage, RuntimeException())
273             } else {
274                 Slog.w(LOG_TAG, logMessage)
275             }
276             return false
277         }
278 
279         var wasChanged: Boolean
280         service.mutateState {
281             wasChanged = with(appIdPolicy) { setAppOpMode(appId, userId, appOpName, mode) }
282         }
283         return wasChanged
284     }
285 
286     override fun getPackageMode(packageName: String, op: Int, userId: Int): Int {
287         val opName = AppOpsManager.opToPublicName(op)
288         return service.getState {
289             with(packagePolicy) { getAppOpMode(packageName, userId, opName) }
290         }
291     }
292 
293     private fun getPackageModes(packageName: String, userId: Int): ArrayMap<String, Int>? =
294         service.getState { with(packagePolicy) { getAppOpModes(packageName, userId) } }?.map
295 
296     override fun setPackageMode(packageName: String, appOpCode: Int, mode: Int, userId: Int) {
297         val appOpName = AppOpsManager.opToPublicName(appOpCode)
298 
299         if (
300             Flags.runtimePermissionAppopsMappingEnabled() &&
301                 appOpCode in runtimeAppOpToPermissionNames
302         ) {
303             Slog.w(
304                 LOG_TAG,
305                 "(packageName=$packageName, userId=$userId)'s appop state" +
306                     " for runtime op $appOpName should not be set directly.",
307                 RuntimeException()
308             )
309             return
310         }
311         service.mutateState {
312             with(packagePolicy) { setAppOpMode(packageName, userId, appOpName, mode) }
313         }
314     }
315 
316     override fun removeUid(uid: Int) {
317         val appId = UserHandle.getAppId(uid)
318         val userId = UserHandle.getUserId(uid)
319         service.mutateState { with(appIdPolicy) { removeAppOpModes(appId, userId) } }
320     }
321 
322     override fun removePackage(packageName: String, userId: Int): Boolean {
323         var wasChanged: Boolean
324         service.mutateState {
325             wasChanged = with(packagePolicy) { removeAppOpModes(packageName, userId) }
326         }
327         return wasChanged
328     }
329 
330     private fun opNameMapToOpSparseArray(modes: ArrayMap<String, Int>?): SparseIntArray =
331         if (modes == null) {
332             SparseIntArray()
333         } else {
334             val opSparseArray = SparseIntArray(modes.size)
335             modes.forEachIndexed { _, opName, opMode ->
336                 opSparseArray.put(AppOpsManager.strOpToOp(opName), opMode)
337             }
338             opSparseArray
339         }
340 
341     override fun clearAllModes() {
342         // We don't need to implement this because it's only called in AppOpsService#readState
343         // and we have our own persistence.
344     }
345 
346     override fun getForegroundOps(uid: Int, deviceId: String): SparseBooleanArray {
347         return SparseBooleanArray().apply {
348             getUidModes(uid)?.forEachIndexed { _, op, mode ->
349                 if (mode == AppOpsManager.MODE_FOREGROUND) {
350                     this[AppOpsManager.strOpToOp(op)] = true
351                 }
352             }
353             if (Flags.runtimePermissionAppopsMappingEnabled()) {
354                 foregroundableOps.forEachIndexed { _, op, _ ->
355                     if (getUidMode(uid, deviceId, op) == AppOpsManager.MODE_FOREGROUND) {
356                         this[op] = true
357                     }
358                 }
359             }
360         }
361     }
362 
363     override fun getForegroundOps(packageName: String, userId: Int): SparseBooleanArray {
364         return SparseBooleanArray().apply {
365             getPackageModes(packageName, userId)?.forEachIndexed { _, op, mode ->
366                 if (mode == AppOpsManager.MODE_FOREGROUND) {
367                     this[AppOpsManager.strOpToOp(op)] = true
368                 }
369             }
370             if (Flags.runtimePermissionAppopsMappingEnabled()) {
371                 foregroundableOps.forEachIndexed { _, op, _ ->
372                     if (getPackageMode(packageName, op, userId) == AppOpsManager.MODE_FOREGROUND) {
373                         this[op] = true
374                     }
375                 }
376             }
377         }
378     }
379 
380     override fun addAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean {
381         synchronized(listenersLock) {
382             val newListeners = ArraySet(listeners)
383             val result = newListeners.add(listener)
384             listeners = newListeners
385             return result
386         }
387     }
388 
389     override fun removeAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean {
390         synchronized(listenersLock) {
391             val newListeners = ArraySet(listeners)
392             val result = newListeners.remove(listener)
393             listeners = newListeners
394             return result
395         }
396     }
397 
398     private inner class OnAppIdAppOpModeChangedListener :
399         AppIdAppOpPolicy.OnAppOpModeChangedListener() {
400         // (uid, appOpCode) -> newMode
401         private val pendingChanges = LongSparseArray<Int>()
402 
403         override fun onAppOpModeChanged(
404             appId: Int,
405             userId: Int,
406             appOpName: String,
407             oldMode: Int,
408             newMode: Int
409         ) {
410             val uid = UserHandle.getUid(userId, appId)
411             val appOpCode = AppOpsManager.strOpToOp(appOpName)
412             val key = IntPair.of(uid, appOpCode)
413 
414             pendingChanges[key] = newMode
415         }
416 
417         override fun onStateMutated() {
418             val listenersLocal = listeners
419             pendingChanges.forEachIndexed { _, key, mode ->
420                 listenersLocal.forEachIndexed { _, listener ->
421                     val uid = IntPair.first(key)
422                     val appOpCode = IntPair.second(key)
423 
424                     listener.onUidModeChanged(
425                         uid,
426                         appOpCode,
427                         mode,
428                         VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT
429                     )
430                 }
431             }
432 
433             pendingChanges.clear()
434         }
435     }
436 
437     private inner class OnPackageAppOpModeChangedListener :
438         PackageAppOpPolicy.OnAppOpModeChangedListener() {
439         // (packageName, userId, appOpCode) -> newMode
440         private val pendingChanges = ArrayMap<Triple<String, Int, Int>, Int>()
441 
442         override fun onAppOpModeChanged(
443             packageName: String,
444             userId: Int,
445             appOpName: String,
446             oldMode: Int,
447             newMode: Int
448         ) {
449             val appOpCode = AppOpsManager.strOpToOp(appOpName)
450             val key = Triple(packageName, userId, appOpCode)
451 
452             pendingChanges[key] = newMode
453         }
454 
455         override fun onStateMutated() {
456             val listenersLocal = listeners
457             pendingChanges.forEachIndexed { _, key, mode ->
458                 listenersLocal.forEachIndexed { _, listener ->
459                     val packageName = key.first
460                     val userId = key.second
461                     val appOpCode = key.third
462 
463                     listener.onPackageModeChanged(packageName, userId, appOpCode, mode)
464                 }
465             }
466 
467             pendingChanges.clear()
468         }
469     }
470 
471     private inner class OnPermissionFlagsChangedListener :
472         AppIdPermissionPolicy.OnPermissionFlagsChangedListener,
473         DevicePermissionPolicy.OnDevicePermissionFlagsChangedListener {
474         // (uid, deviceId, appOpCode) -> newMode
475         private val pendingChanges = ArrayMap<Triple<Int, String, Int>, Int>()
476 
477         override fun onPermissionFlagsChanged(
478             appId: Int,
479             userId: Int,
480             permissionName: String,
481             oldFlags: Int,
482             newFlags: Int
483         ) {
484             onDevicePermissionFlagsChanged(
485                 appId,
486                 userId,
487                 VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT,
488                 permissionName,
489                 oldFlags,
490                 newFlags
491             )
492         }
493 
494         override fun onDevicePermissionFlagsChanged(
495             appId: Int,
496             userId: Int,
497             deviceId: String,
498             permissionName: String,
499             oldFlags: Int,
500             newFlags: Int
501         ) {
502             backgroundToForegroundPermissionNames[permissionName]?.let { foregroundPermissions ->
503                 // This is a background permission; there may be multiple foreground permissions
504                 // affected.
505                 foregroundPermissions.forEachIndexed { _, foregroundPermissionName ->
506                     runtimePermissionNameToAppOp[foregroundPermissionName]?.let { appOpCode ->
507                         val foregroundPermissionFlags =
508                             getPermissionFlags(appId, userId, foregroundPermissionName)
509                         addPendingChangedModeIfNeeded(
510                             appId,
511                             userId,
512                             deviceId,
513                             appOpCode,
514                             foregroundPermissionFlags,
515                             oldFlags,
516                             foregroundPermissionFlags,
517                             newFlags
518                         )
519                     }
520                 }
521             }
522                 ?: foregroundToBackgroundPermissionName[permissionName]?.let { backgroundPermission
523                     ->
524                     runtimePermissionNameToAppOp[permissionName]?.let { appOpCode ->
525                         val backgroundPermissionFlags =
526                             getPermissionFlags(appId, userId, backgroundPermission)
527                         addPendingChangedModeIfNeeded(
528                             appId,
529                             userId,
530                             deviceId,
531                             appOpCode,
532                             oldFlags,
533                             backgroundPermissionFlags,
534                             newFlags,
535                             backgroundPermissionFlags
536                         )
537                     }
538                 }
539                     ?: runtimePermissionNameToAppOp[permissionName]?.let { appOpCode ->
540                     addPendingChangedModeIfNeeded(
541                         appId,
542                         userId,
543                         deviceId,
544                         appOpCode,
545                         oldFlags,
546                         PermissionFlags.RUNTIME_GRANTED,
547                         newFlags,
548                         PermissionFlags.RUNTIME_GRANTED
549                     )
550                 }
551         }
552 
553         private fun getPermissionFlags(appId: Int, userId: Int, permissionName: String): Int =
554             service.getState {
555                 with(permissionPolicy) { getPermissionFlags(appId, userId, permissionName) }
556             }
557 
558         private fun addPendingChangedModeIfNeeded(
559             appId: Int,
560             userId: Int,
561             deviceId: String,
562             appOpCode: Int,
563             oldForegroundFlags: Int,
564             oldBackgroundFlags: Int,
565             newForegroundFlags: Int,
566             newBackgroundFlags: Int,
567         ) {
568             val oldMode = evaluateModeFromPermissionFlags(oldForegroundFlags, oldBackgroundFlags)
569             val newMode = evaluateModeFromPermissionFlags(newForegroundFlags, newBackgroundFlags)
570 
571             if (oldMode != newMode) {
572                 val uid = UserHandle.getUid(userId, appId)
573                 pendingChanges[Triple(uid, deviceId, appOpCode)] = newMode
574             }
575         }
576 
577         override fun onStateMutated() {
578             val listenersLocal = listeners
579             pendingChanges.forEachIndexed { _, key, mode ->
580                 listenersLocal.forEachIndexed { _, listener ->
581                     val uid = key.first
582                     val deviceId = key.second
583                     val appOpCode = key.third
584 
585                     listener.onUidModeChanged(uid, appOpCode, mode, deviceId)
586                 }
587             }
588 
589             pendingChanges.clear()
590         }
591     }
592 
593     companion object {
594         private val LOG_TAG = AppOpService::class.java.simpleName
595     }
596 }
597