1<!--
2  Copyright (C) 2020 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# App-ops
18
19App-ops are used for two purposes: Access control and tracking.
20
21App-ops cover a wide variety of functionality from helping with runtime permissions to battery
22consumption tracking.
23
24App-ops are defined in `AppOpsManager` as `OP_...` and need to be continuously numbered. The
25integer values of the app-ops are not exposed. For app-ops visible to 3rd party apps,
26the name of the app-op might be exposed as `OPSTR_`. As the integers are not part of the API, they
27might (and have) changed between platform versions and OEM implementations.
28`AppOpsManager.opToPublicName` and `AppOpsManager.strOpToOp` allow for conversion between integer
29and string identifier for the op.
30
31## App-ops as access restrictions
32
33App-ops can either be controlled for each [uid](../os/Users.md#int-uid) or for each package. Which
34one is used depends on the API provider maintaining this app-op.
35
36For any security or privacy related app-ops the provider needs to control the app-op per uid
37as all security and privacy is based on uid in Android.
38
39App-op used for non-security related tasks are usually controlled per package to provide finer
40granularity.
41
42### Setting the app-op mode
43
44To control access the app-op can be set to:
45
46`MODE_DEFAULT`
47: Default behavior, might differ from app-op to app-op
48
49`MODE_ALLOWED`
50: Allow the access
51
52`MODE_FOREGROUND`
53: Allow the access but only if the app is currently in the [foreground](#foreground)
54
55`MODE_IGNORED`
56: Don't allow the access, i.e. don't perform the requested action or return placeholder data
57
58`MODE_ERRORED`
59: Throw a `SecurityException` on access. This can be suppressed by using a `...noThrow` method to
60check the mode
61
62The initial state of an app-op is defined in `AppOpsManager.sOpDefaultMode`. Confusingly the
63initial state is often not `MODE_DEFAULT`
64
65Per-package modes can be set using `AppOpsManager.setMode` and per-uid modes can be set using
66`AppOpsManager.setUidMode`.
67
68**Warning**: Do not use `setMode` and `setUidMode` for the same app-op. Due to the way the
69internal storage for the mode works this can lead to very confusing behavior. If this ever happened
70by accident this needs to be cleaned up for any affected user as the app-op mode is retained over
71reboot.
72
73App-ops can also be set via the shell using the `appops set` command. The target package/uid can be
74defined via parameters to this command.
75
76The current state of the app-op can be read via the `appops get` command or via `dumpsys appops`.
77If the app-op is not mentioned in the output the app-op is in it's initial state.
78
79For example `dumpsys appops`:
80```
81[...]
82  Uid 2000:
83    [...]
84      COARSE_LOCATION: mode=foreground
85      START_FOREGROUND: mode=foreground
86      LEGACY_STORAGE: mode=ignore
87    [...]
88```
89
90### Guarding access based on app-ops
91
92API providers need to check the mode returned by `AppOpsManager.noteOp` if they are are allowing
93access to operations gated by the app-op. `AppOpsManager.unsafeCheckOp` should be used to check the
94mode if no access is granted. E.g. this can be for displaying app-op state in the UI or when
95checking the state before later calling `noteOp` anyway.
96
97If an operation refers to a time span (e.g. a audio-recording session) the API provider should
98use `AppOpsManager.startOp` and `AppOpsManager.finishOp` instead of `noteOp`.
99
100`noteOp` and `startOp` take a `packageName` and `attributionTag` parameter. These need to be read
101from the calling app's context as `Context.getOpPackageName` and `Context.getAttributionTag`, then
102send to the data provider and then passed on the `noteOp`/`startOp` method.
103
104#### App-ops and permissions
105
106Access guarding is often done in combination with permissions using [runtime permissions
107](../permission/Permissions.md#runtime-permissions-and-app-ops) or [app-op permissions
108](../permission/Permissions.md#app-op-permissions). This is preferred over just using an app-op
109 as permissions a concept more familiar to app developers.
110
111### Foreground
112
113The `AppOpsService` tracks the apps' proc state (== foreground-ness) by following the
114`ActivityManagerService`'s proc state. It reduces the possible proc states to only those needed
115for app-ops. It also delays the changes by a _settle time_. This delay is needed as the proc state
116can fluctuate when switching apps. By delaying the change the appops service is not affected by
117those.
118
119In addition to proc state, the `AppOpsService` also receives process capability update from the
120`ActivityManagerService`. Proc capability specifies what while-in-use(`MODE_FOREGROUND`) operations
121 the proc is allowed to perform in its current proc state. There are three proc capabilities
122 defined so far:
123`PROCESS_CAPABILITY_FOREGROUND_LOCATION`, `PROCESS_CAPABILITY_FOREGROUND_CAMERA` and
124`PROCESS_CAPABILITY_FOREGROUND_MICROPHONE`, they correspond to the while-in-use operation of
125location, camera and microphone (microphone is `RECORD_AUDIO`).
126
127In `ActivityManagerService`, `PROCESS_STATE_TOP` and `PROCESS_STATE_PERSISTENT` have all
128three capabilities, `PROCESS_STATE_FOREGROUND_SERVICE` has capabilities defined by
129 `foregroundServiceType` that is specified in foreground service's manifest file. A client process
130 can pass its capabilities to service using `BIND_INCLUDE_CAPABILITIES` flag.
131
132The proc state and capability are used for two use cases: Firstly, Tracking remembers the proc state
133 for each tracked event. Secondly, `noteOp`/`checkOp` calls for app-op that are set to
134 `MODE_FOREGROUND` are translated using the `AppOpsService.UidState.evalMode` method into
135 `MODE_ALLOWED` when the app has the capability and `MODE_IGNORED` when the app does not have the
136 capability. `checkOpRaw` calls are not affected.
137
138The current proc state and capability for an app can be read from `dumpsys appops`.
139The tracking information can be read from `dumpsys appops`
140
141```
142Uid u0a118:
143  state=fg
144  capability=6
145```
146
147## Instantaneous and long running ops
148
149Some events such as reading the last known location as instantaneous ops, i.e. they happen
150without taking any relevant time. The data provider should use `noteOp` to signal to the system
151that such an event happened.
152
153For events that take some time (such as recording a video) the data provider should call `startOp`
154at the beginning of the event and `finishOp` at the end of th event. It is uncommon but possible
155that at a given time multiple such events are in progress and hence this is properly handled.
156While such an event is in progress the app-op is considered `active`.
157
158For some ops both instantaneous and long running ops are recorded, e.g. recoding a video and taking
159a picture.
160
161## Forwarding (==proxying) operations to another process
162
163Some apps are forwarding access to other apps. E.g. an app might get the location from the
164system's location provider and then send the location further to a 3rd app. In this case the
165app passing on the data needs to call `AppOpsManager.noteProxyOp` to signal the access proxying.
166This might also make sense inside of a single app if the access is forwarded between two
167attribution tags of the app. In this case an app-op is noted for the forwarding app (proxy) and
168the app that received the data (proxied). As any app can do it is important to track how much the
169system trusts this proxy-access-tracking. For more details see `AppOpService.noteProxyOperation`.
170
171## App-ops for tracking
172
173App-ops track many important events, including all accesses to runtime permission protected
174APIs. This is done by tracking when an app-op was noted or started. The tracked data can only be
175read by system components.
176
177**Note:** Only `noteOp`/`startOp` calls are tracked; `unsafeCheckOp` is not tracked. Hence it is
178important to eventually call `noteOp` or `startOp` when providing access to protected operations
179or data.
180
181The tracking information can be read from `dumpsys appops` split by attribution tag, proc state and
182proxying information with the syntax
183
184```
185Package THE_PACKAGE_NAME:
186  AN_APP_OP (CURRENT_MODE):
187    ATTRIBUTION_TAG (or null for default attribution)=[
188      ACCESS_OR_REJECT: [PROC_STATE-PROXYING_TAG] TIME proxy[INFO_ABOUT_PROXY IF_PROXY_ACCESS]
189```
190
191Example:
192
193```
194Package com.google.android.gms:
195  READ_CONTACTS (allow):
196    null=[
197      Access: [fgsvc-s] 2020-02-14 14:24:10.559 (-3d23h15m43s642ms)
198      Access: [fgsvc-tp] 2020-02-14 14:23:58.189 (-3d23h15m56s12ms)
199    ]
200    apkappcontext=[
201      Access: [fg-tp] 2020-02-17 14:24:54.721 (-23h14m59s480ms)
202    ]
203    com.google.android.gms.icing=[
204      Access: [fgsvc-tpd] 2020-02-14 14:26:27.018 (-3d23h13m27s183ms) proxy[uid=10070, pkg=com.android.providers.contacts, attributionTag=null]
205      Access: [fg-tpd] 2020-02-18 02:26:08.711 (-11h13m45s490ms) proxy[uid=10070, pkg=com.android.providers.contacts, attributionTag=null]
206      Access: [bg-tpd] 2020-02-14 14:34:55.310 (-3d23h4m58s891ms) proxy[uid=10070, pkg=com.android.providers.contacts, attributionTag=null]
207    ]
208  MANAGE_EXTERNAL_STORAGE (default):
209    null=[
210      Reject: [fg-s]2020-02-18 08:00:04.444 (-5h39m49s757ms)
211      Reject: [bg-s]2020-02-18 08:00:04.427 (-5h39m49s774ms)
212    ]
213```
214
215For in progress ops above command shows the amount of time the op is already in progress for and
216how many ops have been started and not yet finished for this package.
217
218```
219MONITOR_LOCATION (allow / switch COARSE_LOCATION=allow):
220  null=[
221    Access: [top-s] 2020-06-18 19:22:38.445 (-27s668ms) duration=+27s670ms
222    Running start at: +27s669ms
223    startNesting=2
224  ]
225```
226
227### Tracking an app's own private data accesses
228
229An app can register an `AppOpsManager.OnOpNotedCallback` to [get informed about what accesses the
230system is tracking for it](https://developer.android.com/preview/privacy/data-access-auditing).
231As each runtime permission has an associated app-op this API is particularly useful for an app
232that want to find unexpected private data accesses.
233
234#### Implementation
235
236The goal is to trigger a callback to `AppOpsManager.OnOpNotedCallback` any time a data provider
237declares that data was sent to the app (i.e. calls `AppOpsManager.noteOp`). There are four cases
238
239##### Synchronous data accesses
240
241This is the case where the client calls an API and the data is sent back as the return value of this
242API call. E.g. `LocationManager.getLastKnownLocation` returns the last known location as the return
243value of the method call.
244
245In this case
2461. The client calls into a Android API in the Android framework, e.g. `LocationManager`
2472. The framework code calls via a `Binder` call into the data provider, e.g. the
248`LocationManagerService` residing in the system server.
2493. Somewhere in the data provider the data provider calls `AppOpsManager.noteOp` and thereby
250declares that data was accessed. This data access is recorded in
251`AppOpsManager.sAppOpsNotedInThisBinderTransaction`
2524. When the binder call returns the RPC code (`Binder`/`Parcel`) calls
253`AppOpsManager.readAndLogNotedAppops` which checks is the binder return value contained any
254prefix indicating that data was accessed. If so the RPC code calls `onNoted` on the the currently
255registered `OnOpNotedCallback`.
2565. The rest of the implementation is up to the client, but one to use the callbacks is for  the
257client to take a stack trace in the `onNoted` implementation. This stack trace allows to pin point
258where in the app's code the data access came from.
259
260![Syncronous data access by a client via a binder call](sync-data-access.png)
261
262In above graphics you can see that
2631. an app (`com.app.A`, red) is calling into the android framework
264(blue).
2651. The call triggers a RPC call into the data provider (green).
2661. The data provider calls `AppOpsManager.noteOp` (first star)
2671. On the return from the RPC call the framework code (second star) realizes that there was a data
268access and calls `OnOpNotedCallback.onNoted`.
2691. If at this time the code in onNoted would take a stack trace it would get what is in the gray
270box, i.e.
271```
272com.app.A.a
273- com.app.A.b
274  - com.app.A.c
275    - com.app.A.d
276       - android...Manager
277         - several android internal RPC methods
278           - com.app.B.onNoted (extends OnOpNotedCallback.onNoted)
279```
280
281As `onNoted` also reports the attributionTag and the noted op the app can now build a mapping
282indicating what code accesses what private data.
283
284##### Self data accesses
285
286This is similar to the [synchronous data access](#synchronous-data-accesses) case only that the data
287provider and client are in the same process. In this case Android's RPC code is no involved and
288`AppOpsManager.noteOp` directly triggers `OnOpNotedCallback.onSelfNoted`. This should be a uncommon
289case as it is uncommon for an app to provide data, esp. to itself.
290
291If an app takes above suggestion and collects stack traces for synchronous accesses self-accesses
292can be treated in the same way.
293
294##### Async data accesses
295
296There are cases where the data access is not directly triggered via an API. E.g.
297`LocationManager.requestLocationUpdates(listener)` registers a callback. Once the location subsystem
298determines a location it calls the registered listener with the data. There can be quite significant
299time between registering the listener and getting the data. In some cases (e.g. Geo-fencing) it
300might take days and the app registering for the data and the app receiving the data might not even
301be the same process or even version.
302
303Hence above suggestion with taking the stack trace to determine what triggered the data access does
304not work. In this case it is recommended for data providers to come up with a way to help the app
305developer understand why a data access is triggered. E.g. in the case of
306`LocationManager.requestLocationUpdates(listener)` the data provider is setting the `message` field
307in`AppOpsManager.noteOp` to the system-identity hash code of the registered listener. There are
308convenience methods for that, e.g. `AppOpsManager.toReceiverId`. This `message` field is then
309delivered to the app inside the `AsyncNotedAppOp` parameter to `OnOpNotedCallback.onAsyncNoted`.
310
311While this case is not as elegant as the synchronous case, a properly set `message` can often be
312enough for the app to figure out where the data access comes from. Async data accesses are less
313common than synchronous data accesses but they come in more variations. E.g. registered listeners,
314pending-intents, manifest broadcast receivers, activity starts, etc... Hence there is no one perfect
315message format. This is why the message field is a free text string.
316
317It is very highly recommended for data providers to set appropriate `message` parameters for their
318`AppOpsManager.noteOp` calls for all times where there is async data access. If no `message`
319parameter is set, the system defaults to a stack trace of the data provider code which is often slow
320and not useful.
321
322Async data accesses also carry the attribution tag, but this can sometimes not be enough. Again, a
323properly set `message` parameter is the best choice.
324
325##### Data providers implemented in native code
326
327Some data providers (e.g. camera a microphone) are implemented using native code. As of now this is
328not properly hooked up to the Java logic. To make sure to always collect all data accesses all
329`AppOpsManager::noteOp` calls from native code trigger an [async data access](#async-data-accesses),
330no matter if the code is in a synchronous RPC or not.
331
332This is not ideal and should be improved.
333
334### Getting last data accesses via an API
335
336To get the last accesses for an op or package an app can use `AppOpsManager.getPackagesForOps`.
337
338## Listening to app-op events
339
340System apps (with the appropriate permissions) can listen to most app-op events, such as
341
342`noteOp`
343: `startWatchingNoted`
344
345`startOp`/`finishOp`
346: `startWatchingActive`
347
348mode changes
349: `startWatchingMode`
350
351[foreground](#foreground)-ness changes
352: `startWatchingMode` using the `WATCH_FOREGROUND_CHANGES` flag
353
354Watching such events is only ever as good as the tracked events. E.g. if the audio provider does
355not call `startOp` for a audio-session, the app's activeness for the record-audio app-op is not
356changed. Further there were cases where app-ops were noted even though no data was accessed or
357operation was performed. Hence before relying on the data from app-ops, double check if the data
358is actually reliable.
359