Short and simple question:
rooted devices can grant apps with extra permissions during runtime (using "grant permission" command using the adb , as I recall). An example for this is the ability to read system logs , which became a non-user permission starting with API16 (link here) .
Is there a list of such permissions?
The command you may be thinking of is pm grant PACKAGE PERMISSION, which can be sent to an adb-connected device using adb shell pm grant PACKAGE PERMISSION.
However, only optional permissions can be granted or revoked this way. If you try to grant a permission not requested in the app's manifest, you'll get Operation not allowed: java.lang.SecurityException: Package PACKAGE has not requested permission PERMISSION. Likewise, if you try to revoke a permission not deemed optional, you'll get Operation not allowed: java.lang.SecurityException: Can't change PERMISSION. It is required by the application. Even for a rooted device or emulator.
Now, as far as what is deemed 'optional', as well as getting a list of such permissions, that's a little unclear. However, based on some experimentation, I believe these include at least the set of permissions assigned to permission group android.permission-group.DEVELOPMENT_TOOLS. You can see which these are on a running device using pm list permissions -g. On my API 19 emulator, as well as a Nexus 7 running AOSP 4.4.4, these are:
group:android.permission-group.DEVELOPMENT_TOOLS
permission:android.permission.ACCESS_ALL_EXTERNAL_STORAGE
permission:android.permission.SIGNAL_PERSISTENT_PROCESSES
permission:android.permission.READ_LOGS
permission:android.permission.SET_ALWAYS_FINISH
permission:android.permission.WRITE_SECURE_SETTINGS
permission:android.permission.SET_PROCESS_LIMIT
permission:android.permission.CHANGE_CONFIGURATION
permission:android.permission.DUMP
permission:android.permission.SET_DEBUG_AP
If (and only if) these are declared in the manifest, then you can grant/revoke them using the above command. Note that they are not granted automatically on installation; you must issue the pm grant command. I was able to observe and confirm this by using the Settings app and seeing the reported permissions change as I granted and revoked them.
There may be other permissions that behave like this, but I haven't found them. Normal permissions like android.permission.INTERNET cannot be granted or revoked in this manner.
Addendum: Per additional question in comment section regarding pm set-permission-enforced PERMISSION: As far as I know, the only permission which currently supports this is android.permission.READ_EXTERNAL_STORAGE. I'm basing this statement on my reading of the source code, which is also consistent with my experiences using the command. The purpose of the selective enforcement setting on this permission is to allow testing of apps under pre- and post-API 19 conditions as described here.
Related
I am developing a COSU/KIOSK application and I need to manually update the time on the device.
I am using AlertManager.setTime(Calendar) to do so, but I can't grant my application the SET_TIME permission that it is required.
The application is the device owner, and this allowed me to use many other system permissions, for example
android:name="android.permission.REBOOT"
android:name="android.permission.SHUTDOWN"
android:name="android.permission.WRITE_SETTINGS"
android:name="android.permission.INSTALL_PACKAGES"
android:name="android.permission.DELETE_PACKAGES"
All of these permissions were granted to my application, just by listing them in the manifest.xml
But SET_TIME does not work.
I also tried using the device policy manager
mDevicePolicyManager.setPermissionGrantState(mAdminComponentName, getPreferredPackageName(),
Manifest.permission.SET_TIME, DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
This function returned false meaning it couldn't grant permission.
How can I solve this problem without prompting the user to grant this permission to my application.
If you are targeting devices api 28+ (android 9 and higher) you can set it with setTime(ComponentName admin, long millis) function.
For lower android versions I had to rely on a device manufacturer api to set device time.
Manifest.permission.SET_TIME is proteced/system permission, sadly deviceOwner cannot grant any protected permissions with setPermissionGrantState() function.
There is very important word in its documentation:
Sets the grant state of a !runtime! permission for a specific application.
I am trying to upgrade my app's targetSDK to above 23 and I've run into a small problem. I have an activity that binds traffic to Wifi (to measure the network speed to the router, even if the router is not connected to the internet). In order for that to happen my app needs the CHANGE_NETWORK_STATE permission. That permission is usually granted directly if declared in the manifest. On Android 6.0 (exact, this was fixed in 6.0.1 IIRC) CHANGE_NETWORK_STATE is broken and won't be granted so you need the WRITE_SETTINGS permission instead. I've implemented a way for Android 6.0 Users to grant that permission but when I want to test my Activity using espresso I am unable to do so. Permissions are granted to tests by adding something like
#Rule
public GrantPermissionRule runtimePermissionRule = GrantPermissionRule.grant(Manifest.permission.CHANGE_NETWORK_STATE);
to the TestCase. That worked in other places in the app but for this I get
junit.framework.AssertionFailedError: Failed to grant permissions, see logcat for details in my test results. In logcat I find E/GrantPermissionCallable: Permission: android.permission.WRITE_SETTINGS cannot be granted! or the same with CHANGE_NETWORK_STATE, I've tried granting both and they both don't work. Is there any other way for me to grant the permission in the testing environment? Or am I unable to test this activity on 6.0 devices from now on?
I managed to get around this by granting the permission using UiAutomator and the shell appops command:
Instrumentation instrumentation = getInstrumentation();
UiDevice device = UiDevice.getInstance(instrumentation);
String targetPackageName = instrumentation.getTargetContext().getPackageName();
if (Build.VERSION.SDK_INT >= 23) {
String shellCommand = String.format("appops set %s WRITE_SETTINGS allow", targetPackageName);
device.executeShellCommand(shellCommand);
}
Because WRITE_SETTINGS is a sensitive permission, you won't be able to grant it using GrantPermissionRule in API 23. You will likely end up needing to use UIAutomator in your tests to select the appropriate response in the permissions management screen.
The application I am developing uses Bluetooth and Storage permissions, therefore my AndroidManifest.xml contains the following.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"></uses-permission>
However, when the app is installed, upon scanning for Bluetooth devices nothing is found until I manually switch on permission for Location in my device settings (Settings -> Apps -> [My App] -> Permissions). I have read somewhere that this permission is required for Android 6.0 (maybe 7.0) and above if you want to use the Bluetooth, but why is it not enabled upon installation with these permissions in the manifest file? Have I missed one out?
Location and Bluetooth are two different things.
You don't need to request permission to access Bluetooth as it is a normal permission, but you do need to request permission for Location as it is a dangerous permission.
You can find a list of all permissions that must be requested on runtime here.
From the official documentation.
System permissions are divided into two categories, normal and dangerous:
Normal permissions do not directly risk the user's privacy. If your app lists a normal permission in its manifest, the system grants the
permission automatically.
Dangerous permissions can give the app access to the user's confidential data. If your app lists a normal permission in its
manifest, the system grants the permission automatically. If you
list a dangerous permission, the user has to explicitly give
approval to your app.
And
If the device is running Android 5.1 or lower, or your app's target SDK is 22 or lower: If you list a dangerous permission in your
manifest, the user has to grant the permission when they install the
app; if they do not grant the permission, the system does not install
the app at all.
If the device is running Android 6.0 or higher, and your app's target SDK is 23 or higher: The app has to list the permissions in
the manifest, and it must request each dangerous permission it
needs while the app is running. The user can grant or deny each
permission, and the app can continue to run with limited
capabilities even if the user denies a permission request.
So, most likely you are testiong your app on device or emulator running API 23+ and have a request to location of the device.
Location permission is a dangerous one, so in Android 6.0 or higher user is forsed to allow location access manually. For this you have to add dangerous permissions programmatically. Take a look here for the good instruction for this.
P.S. To find out, which permissions are dangerous, and wich are normal, look here.
Certain permissions are classified as dangerous and they need to be asked for in runtime.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
Replace the READ_CONTACTS permission with location permission
After further research, i found that requestPermission only works on Android M. If i just include the permissions i needed in android manifest file, how does android ask user for the permission granted? For example, access fine location permission. I try including the requestPermission but never see the dialog.
Before Marshmallow, all the permissions are granted at installation time. That's why you don't see a dialog requesting permission on Lollipop and previous versions on runtime.
Check this out: Runtime Permissions. It only applies to Marshmallow and above.
I am currently playing around with android m's new permission system.
What i am planning is to add a screen to my in-app settings where the user can grant or revoke permissions.
The screen would look like the regular system settings screen, but will have additional information why my app needs the specific permission. This settings screen would be an addition to the regular permission handling as suggested in the Documentation.
The workflow would be:
granting permission: open the systems dialog to grant/revoke (like suggested here)
revoking permission: revoke it programmatically
So my question is, can permissions be revoked programatically?
I searched a lot, but didn't manage to get some results.
You can't do anything (at least until now). In addition, there isn't any intent action to open the activity system settings for your app. My suggestion is to open a "feature request" on the developer preview issue tracker.
You can revoke permission from ADB Shell.
if you consider writing shell script and doing all this under programatically then YES, else NO
Grant and revoke permissions
You can use new ADB package manager (pm) commands to grant and revoke permissions to an installed app. This functionality can be useful for automated testing.
To grant a permission, use the package manager's grant command:
$ adb shell pm grant <package_name> <permission_name>
For example, to grant the com.example.myapp package permission to record audio, use this command:
$ adb shell pm grant com.example.myapp android.permission.RECORD_AUDIO
To revoke a permission, use the package manager's revoke command:
$ adb shell pm revoke <package_name> <permission_name>
Starting API 33 (Android 13) you can programmatically revoke previously granted runtime permissions via the revokeSelfPermissionOnKill APIs. E.g.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.revokeSelfPermissionOnKill(Manifest.permission.POST_NOTIFICATIONS)
}
Triggers the asynchronous revocation of a runtime permission. If the
permission is not currently granted, nothing happens (even if later
granted by the user).
There is also a function which takes a collection of multiple permissions to revoke.
Be sure to also put a version code guard around this as there currently doesn't seem to be a warning in the IDE. Unfortunately this hasn't been added to ContextCompat yet.
No Programmatically it is not possible in Android M Preview with new permissions Model.
But Manually you can do as given.
revoke permissions manually
for some special permission like SYSTEM_ALERT_WINDOW.
you need this :
adb shell appops set <package_name> SYSTEM_ALERT_WINDOW allow