Note: Everything described in this post is based off the Android 'M' Developer Preview, Release 2. As new releases (and the source code) are made available, behaviors are subject to change and the contents of this post may change along with them.
Well, it finally happened. Google announced that the upcoming Android 'M' release will include a runtime permissions system. This means users are not required to fully accept the list of permissions an application declares in order to install it. Instead, users will have the opportunity to approve (or deny) each discrete permission separately. Information for developers on the mechanics of using this new model is described pretty well in the documentation.
During the live sessions describing this feature at Google I/O, information about what happens to legacy applications (i.e. applications that aren't yet tested against the new model) was a bit scant. Although the docs do describe some basic information about legacy compatibility, my aim here is to try and provide some additional clarity to what has been set forth so far.
Legacy Applications
What defines a "legacy application"? Anything that is built with a target SDK below Android 'M' (so...everything in the marketplace today). These applications will have all their requested permissions granted up front, at install-time; just the way it has always been. Google Play will even show the same dialog to users. However, all applications (including legacy) can have their permissions revoked by the user after the initial install. This is the case most developers are concerned with when they first hear of the new model.
What if the user revokes a permission while I am using the feature?
To avoid odd states that may present by a feature being revoked while in use, Android will terminate a legacy application's process if the user enters Settings and disables one or more permissions. This kill is not a new state, it's the same mechanism Android has always used to terminate dormant applications when under memory pressure.
Will devices start throwing SecurityExceptions at my application, causing it to crash?
No. In almost every case of a user revoking a permission to a legacy application,
the framework will pass empty state data back. We will look at what this might
entail for each permissions category shortly.
The moment you update your application to target the 'M' SDK, denied permissions
will indeed cause a SecurityException
—the same way the framework has always
done in cases where you forgot to ask for the permission in the first place.
What is Revocable?
The following screenshot indicates all the permissions "groups" that the current release allows users to control:
Notice that not ALL permissions are in this list. At the present time,
there is no category to deny the INTERNET
1 or WRITE_EXTERNAL_STORAGE
1
permissions, for example.
How are Denials Handled?
Using a greedy sample application, we can perform some basic tests on how common operations in each category are handled inside a legacy application:
Note: As mentioned before, this is empirical observation. Until the source code is released, we cannot make deterministic statements about the overall behavior of the new system.
Calendar
- When querying the CalendarProvider, cursors returned will always be empty (count = 0).
- Attempts to write data into the CalendarProvider are taken and silently ignored.
Camera
- Requests to enumerate the set of cameras on the device will still return a valid set
I consider this to be a bug in the current preview, which I have filed here.- Based on the Preview 2 updates, this seems to be the intended behavior.
- Using
android.hardware.camera
, accessingCamera.open()
will throw aRuntimeException
. - Using
android.hardware.camera2
, accessingCameraManager.openCamera()
will throw aCameraAccessException
. - These behaviors are consistent with what a developer should otherwise expect if the camera was not accessible due to a device policy change (device administrator) or hardware failure.
Contacts
- When querying the ContactsProvider, cursors returned will always be empty (count = 0).
- Attempts to write data into the ContactsProvider are taken and silently ignored.
Location
- Registered location listeners will not receive any update events
- Requests for the last known location will return null (the same as they would if no fix were yet available)
Microphone
- Requests to record audio will successfully complete, but no recording will take place and the output file (if audio only) will be empty.
Phone
- Requests for the device's id will report null (the same as they would on a device without telephone hardware)
- Attempts to send a call Intent still succeed
- This is likely a bug, which I have filed here.
SMS
- Attempts to send an SMS message report as failed
- Listeners for incoming SMS messages are never triggered.
Sensors
- On-device sensors (accelerometer, etc.) are not be affected by this.
- I did not test this state with Android Wear, which is the only sensor requiring permissions so far.
Storage
- In the current preview, this group is not exposed for a legacy application. Users cannot revoke storage permissions.
What About Custom Permissions?
Google indicated in the linked documentation that permissions declared with
protection level PROTECTION_NORMAL
will be granted at install-time to applications,
even in the new permissions model. This would indicate that anything declared as
PROTECTION_DANGEROUS
must be user-granted separately. If you define your own
permissions, this rule does indeed hold true.
Note: The framework isn't quite following this rule at the moment. Permissions like
INTERNET
1 andWRITE_EXTERNAL_STORAGE
1 (mentioned earlier) are indeed marked as "dangerous" in the platform manifest, but they are not revocable by the user.
Since these permissions do not fall into one of the pre-defined groups, users cannot revoke them from a legacy application. Dangerous custom permissions in updated applications, however, do become revocable discretely by the user in Settings. There is still a bit of work to be done here, as the custom permissions description (or any other label) is not included in the user's confirm dialog for an app targeting the new permissions model:
Conclusion
I'm hopeful this makes some of the behaviors you can expect a bit more clear. Google's advice to test your existing applications against the new permissions model is important. However, hopefully now it is more clear that perhaps the landscape for legacy applications isn't as dire as it might have sounded to you initially.
-
It has been pointed out to me by a few of the folks at Google since publishing that
INTERNET
has been downgraded to a "normal" permission in 'M'. The storage permissions were given a revocable group in Preview 2. ↩︎