I've read around the internet for two options to check if an app is granted a permission or not.
Option 1:
getPackageManager().checkPermission(permission_string, packageName);
Option 2:
(PackageInfo.requestedPermissionsFlag[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
I'm running on Android 11. I'm implementing a mechanism that upon clicking an app, the permissions state will be checked and if a permission is not allowed, the user will be prompt to allow it. I'm only checking this for "advanced" permissions, meaning, permissions that requires the user to allow them from settings screen, such as manage external storage (for android 11), drawOverlay, writeSettings and such. Anyway, this is the code I'm using:
try {
PackageInfo pi = getPackageManager().getPackageInfo(currAppInfo.getName(), PackageManager.GET_PERMISSIONS);
for(int i=0; i<pi.requestedPermissions.length; i++)
{
String perm = pi.requestedPermissions[i];
PermissionInfo permi = getPackageManager().getPermissionInfo(perm, PackageManager.GET_META_DATA);
if(getPackageManager().checkPermission(perm, currAppInfo.getName()) == 0)
continue;
if(AdvancedPermissionHandler.isAdvancedPermission(permi))
{
AdvancedPermissionHandler.openSettingsPage(permi, currAppInfo.getName(), MainActivity.this);
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
The only problem I'm facing is that even if I'm using option 1 and even if I'm using option 2, I'm ALWAYS getting false on the check. Meaning, say I click an app that requires manage external storage and it's state is currently not allowed. I click the app, I get moved to the appropriate screen, I allow the permission, I go back to the main screen, when I click the app again, instead of opening, I'm being moved to the same permission screen. Debugger shows that
getPackageManager().checkPermission(permission_string, packageName);
is returning false, even though the permission is given. Same for when I'm using option 2.
So my question is, what other methods are available to determine if a different app is granted a permission or, what am I doing wrong here in this code.
After digging some more I've found AppOps.
This is the code I've used to work, Android 11:
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(currAppInfo.getName(), 0);
PackageInfo pi = getPackageManager().getPackageInfo(currAppInfo.getName(), PackageManager.GET_PERMISSIONS);
for(int i=0; i<pi.requestedPermissions.length; i++)
{
String perm = pi.requestedPermissions[i];
PermissionInfo permi = getPackageManager().getPermissionInfo(perm, PackageManager.GET_META_DATA);
if(AppOpsManager.permissionToOp(permi.name) == null)
continue;
boolean granted = (appOps.unsafeCheckOpNoThrow(AppOpsManager.permissionToOp(permi.name),applicationInfo.uid,currAppInfo.getName()) == AppOpsManager.MODE_ALLOWED);
if(granted)
continue;
}
This is due to Android 11 restrictions to prevent installed apps fingerprinting.
You need to add target package name (e.g com.termux) to queries element or declare QUERY_ALL_PACKAGES permission in AndroidManifest.xml if targetSdkVersion is 30+. Check Package Visibility or this article for more info. Otherwise, you will will get PackageSetting{...... com.termux/......} BLOCKED errors in logcat.
<manifest
<queries>
<package android:name="com.termux" />
</queries>
</manifest>
I'm wondering if an app has access to the info that shows the other apps on the phone and what permissions they have (i.e. access to your location, contacts, etc). Could I create an app with a feature that displays other apps and their permissions? I know the user can view this info via settings, but I'm wondering if it can be organized and displayed by an app.
Yes. Use the PackageManager. Call GetInstalledPackages to list the installed packages, and then check the requestedPermissions field to see the permissions for each package.
Note: the method below assumes this refers to an Activity.
private void getAppPermissions() {
List<PackageInfo> apps = this.getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS);
for (PackageInfo app : apps) {
String appInfo = app.packageName + ": ";
String[] permissions = app.requestedPermissions;
if (null == permissions) {
appInfo += "no permissions requested\n";
} else {
for (String permission : app.requestedPermissions) {
appInfo += "\n " + permission;
}
}
Log.v("App Permissions", appInfo);
}
}
You may wish to filter the list of returned packages as per this question.
Yes you can. For Android, you just go to Settings > Applications
And you just tap on the application that you want to check, and on the bottom it should say the permissions the app possesses.
For ios, you go to Settings > Privacy
And you tap on the desired type of permission, and you can see the apps that have that permission.
I am writing a service which needs to see if its caller holds a particular private permission. I do not want to prevent callers that lack this permission, I only want to know the status so that I can react accordingly. It would seem that the Context method checkCallingPermission() is perfect for what I need, returning 0 if the caller has the specified permission and -1 otherwise. I'm finding that -1 is returned in all cases though.
I wrote a test case (using the similar method checkCallingOrSelfPermission() where I pulled my package's PackageInfo from the system, enumerated each of my permissions (only one requested for the package), and display the result of checkCallingOrSelfPermission(). Since the permissions I'm checking against in this case are exactly the permissions I hold, I would expect checkCallingOrSelfPermission() to return 0 (PackageManager.PERMISSION_GRANTED) only... buy it only returns -1 (PackageManager.PERMISSION_DENIED).
I've checked this and received the same results on both a 4.0 emulator and a 2.3 device.
Any idea what I'm doing wrong to cause these calls to fail?
My test manifest includes:
<permission
android:protectionLevel="signatureOrSystem"
android:name="abcd" />
<uses-permission android:name="abcd" />
My test activity code is:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo("com.test.check", PackageManager.GET_PERMISSIONS);
if ((null == pi.requestedPermissions) ||
(pi.requestedPermissions.length == 0)) {
Log.d("CHECK", "Package has NO permissions!");
finish();
return;
}
for (int i = 0; i < pi.requestedPermissions.length; ++i) {
Log.d("CHECK", pi.requestedPermissions[i] + " " + checkCallingOrSelfPermission(pi.requestedPermissions[i]));
}
} catch (NameNotFoundException e) {
Log.d("CHECK", "Package name is wrong!");
}
finish();
}
and my test results are:
D/CHECK ( 3600): abcd -1
I have not been able to resolve this within the scope of my service needing to check permissions, but I have found a work-around for the service (and a problem in my test case).
My test case failed because the permission I created and checked with, "abcd", was renamed by Android in the <permission> entry, however Android failed to equally rename it in the <uses-permission> entry. It was renamed to have my package name prepended to it (and this renaming does not occur if I provide a name including a period in it, such as "test.abcd").
Though changing the permission name fixed my test case, my actual case within a service was already using a fully qualified permission name and checkCallingPermission() continues to fail. I discovered, however, that the PackageManager's checkPermission() method does work as expected (at the expense of my needing to retrieve the name of the caller's package).
So to summarize, the following does not work correctly (though I do not know why):
boolean permission = (PackageManager.PERMISSION_GRANTED == checkCallingPermission(PERMISSION_NAME));
while this seems to work correctly:
PackageManager pm = getPackageManager();
boolean permission = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(PERMISSION_NAME, pm.getNameForUid(getCallingUid())));
I have developed an application in which I have enabled that any application which we have can be installed manually
But my problem is that I only want to enable my own package name and rather not any other application package name.
Here is the code I have used.
try {
PackageManager pm1 = getPackageManager();
pm1.setComponentEnabledSetting(new ComponentName("com.service",
"com.service.EnableActivity"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
);
} catch (SecurityException e) {
e.printStackTrace();
}
here "com.service" is the package name that I install and "com.service.EnableActivity" is my first app launcherActivity.
Log
java.lang.SecurityException: Permission Denial: attempt to change component state from pid=3354, uid=10056, package uid=10058 at
android.os.Parcel.readException(Parcel.java:1322) at
android.os.Parcel.readException(Parcel.java:1276) at
android.content.pm.IPackageManager$Stub$Proxy.setComponentEnabledSettingIPackageManager.java:2217)
But when I use the same application packagename and classname then it's working fine.
Add this code in your both applications mainfest.
<manifest
.......
.......
.......
android:sharedUserLable="...."
android:sharedUserID="...">
because it need a userid to be same
This will help you.
Looking at the platform I see the following:
<!-- Allows an application to change whether an application component (other than its own) is
enabled or not. -->
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
android:label="#string/permlab_changeComponentState"
android:description="#string/permdesc_changeComponentState"
android:protectionLevel="signatureOrSystem" />
Note that because this is "signatureOrSystem" (and it is declared in the system) it can only be used by apps that are signed with the system signature, in other words you need to be an Android vendor (HTC, Samsung, Motorola, etc). See this for more info:
http://developer.android.com/guide/topics/manifest/permission-element.html
UPDATE:
Gurjinder Singh Pabla has the right answer, if you are trying to change the enabled state of your own components or applications then you need to ensure that they have the same user id, which is set in the AndroidManifest. You only need to be a Vendor if you want to disable other packages that have different user ids. You can see the check in the Android source in PackageManagerService.java is:
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
// ...
if (!allowedByPermission && (uid != pkgSetting.userId)) {
throw new SecurityException(
"Permission Denial: attempt to change component state from pid="
+ Binder.getCallingPid()
+ ", uid=" + uid + ", package uid=" + pkgSetting.userId);
}
I'm trying to get a list of valid Android permissions. I know the 'official' ones at http://developer.android.com/reference/android/Manifest.permission.html but it seems there are more out there.
Please do not answer by just repeating that link.
For example
android.permission.READ_SETTINGS
android.permission.ACCESS_LOCATION
android.permission.ACCESS_GPS
com.android.vending.CHECK_LICENSE
com.android.browser.permission.READ_HISTORY_BOOKMARKS
com.android.browser.permission.WRITE_HISTORY_BOOKMARKS
com.google.android.googleapps.permission.GOOGLE_AUTH
com.google.android.googleapps.permission.GOOGLE_AUTH.OTHER_SERVICES
com.google.android.c2dm.permission.RECEIVE
Where can I get such a list? Where do I get a description for these permissions?
adb shell pm list permissions -s
This might be what you're looking for.
There is no such thing as a comprehensive "list" for all permissions. New permissions can be defined by any application that wants to enforce its own: https://developer.android.com/guide/topics/security/security.html#declaring.
The Manifest.permission class lists the "system" permissions, and you're already aware of those. The other things you've listed aren't system permissions, but rather are specific to certain apps, and or are old names (ACCESS_LOCATION and ACCESS_GPS were pre 1.0 names, for example).
A grep for something like <permission android:name= in the source would reveal all the included app permissions (for the open source apps), but in general you should stick to the documented permission names.
Use the following snippet to get all the permissions declared on your device:
Context context = this;
PackageManager pm = context.getPackageManager();
CharSequence csPermissionGroupLabel;
CharSequence csPermissionLabel;
List<PermissionGroupInfo> lstGroups = pm.getAllPermissionGroups(0);
for (PermissionGroupInfo pgi : lstGroups) {
csPermissionGroupLabel = pgi.loadLabel(pm);
Log.e("perm", pgi.name + ": " + csPermissionGroupLabel.toString());
try {
List<PermissionInfo> lstPermissions = pm.queryPermissionsByGroup(pgi.name, 0);
for (PermissionInfo pi : lstPermissions) {
csPermissionLabel = pi.loadLabel(pm);
Log.e("perm", " " + pi.name + ": " + csPermissionLabel.toString());
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
To list all permissions on your phone
adb shell pm list permissions -g
The -s argument is a short summary
Where can I get such a list?
You can't.
Where do I get a description for these permissions?
Wherever those permissions are documented. In many cases, they are undocumented and therefore should not be used.
For example, your first three were removed from Android a couple of years ago, IIRC. The last one is documented in the C2DM documentation.
There are definitely "more permissions out there". The reference you've linked is just the "official list" – and even for that, it's quite incomplete. I've researched for existing permissions, what they are for, and what impacts they have on the end-user, for about a year now – and really wonder how developers find what they need. Good guessing seems to be part of it, as for many permissions a Google search just yielded content of several apps' Manifest files ("uses …").
Added to that, next to the "official permissions" (or rather "Android core permissions"), each developer can define its own for his app (as Charlie Collins already pointed out in his answer).
During my research, I've setup a list with my findings from several sources (which I listed along) – adding any explanations I could find. This list is rather focused on the end-user, but still might prove helpful to developers. You can find it at my site: Android Permissions explained – bi-lingual (English and German). The list includes the "core permission" as well as some selected app-specific ones (mostly those one encounters more frequently: declared by Google apps, or popular apps like Tasker and K-9 Mail). Again, this of course is far from being complete – a "complete list" being as likely as a unicorn (the day published it most likely would be outdated already).
Edit:
As it was asked for in another comment: If you installed a package with a new permission not yet covered by any list, and you want to know the "technical name" of that new permission, you can retrieve that information from your device via ADB:
adb shell dumpsys package com.foo.bar
(of course replace com.foo.bar with the name of the package in question). In the output, skip down to the line grantedPermissions:. Below that come the permissions in "full notation", e.g. android.permission.INTERNET, one per line. To make that easier:
adb shell dumpsys package com.foo.bar |egrep -A99999 "grantedPermissions:"
You can get all permissions on a device using the following code:
public static List<PermissionInfo> getAllPermissions(Context context) {
PackageManager pm = context.getPackageManager();
List<PermissionInfo> permissions = new ArrayList<>();
List<PermissionGroupInfo> groupList = pm.getAllPermissionGroups(0);
groupList.add(null); // ungrouped permissions
for (PermissionGroupInfo permissionGroup : groupList) {
String name = permissionGroup == null ? null : permissionGroup.name;
try {
permissions.addAll(pm.queryPermissionsByGroup(name, 0));
} catch (PackageManager.NameNotFoundException ignored) {
}
}
return permissions;
}
I know this is a late post, but this is more of a reference for people in the future who have the same question.
Here is a list of every single built-in permission in Android 7.0 (Nougat). However, it is possible to create your own permissions, so that list doesn't contain all of them out there.
Hope that helps :)
It depends on the Android version. The reason is that starting from some Android version, Google noticed (or just allowed) that OEMs would be able to change which permission belongs to which permission group. This occurs at least for some Chinese OEMs (not the first time they break behavior, as shown here), according to what I was told by Google on the issue tracker. They can even change it between simple updates to the OS.
So, here's what you have today:
Starting from Android 12 (API 31), you can use the new getPlatformPermissionsForGroup function.
On Android versions older than Android 10 (API 29 and below), you could use queryPermissionsByGroup.
On Android 10-11 (API 29-30), here are the methods:
The normal API (and the adb command of ./adb shell pm list permissions -s) won't work properly. It will put plenty of permissions
into "UNDEFINED" group. The reason is that Google said it might be
different across devices and OEMs
You can check on Android source code of these versions and hope that most devices use what's there. It used to be here, but the link is
dead now. I think this one can give you the same information
though (but you need to check on which Android version it's used
for).
Another way to handle this is to make your own sample POC to check for each permission - which permission group it belongs to. You will do it by having all permissions declared in the manifest (get from the code below), and then request a bunch of permissions. If you get a single dialog, it means that what you've chosen belong to a single group, and you can continue testing more permissions into it and see if they belong too. If not, at least one of them belong to another group.
To filter by the permissions that are only in the system and/or of Android itself, you could use a condition that the package name of the permission has to start with "android" or that the permission group name should start with "android.permission-group." or that the protection level of the permission is PermissionInfo.PROTECTION_SIGNATURE . It depends on what you wish to filter by.
So, a simple function to list them for all Android versions:
enum class PermissionGroup constructor(#param:Permission #field:Permission val permissions: Array<String>) {
//based on https://developer.android.com/reference/android/Manifest.permission_group.html, https://developer.android.com/guide/topics/permissions/requesting.html https://developer.android.com/reference/android/Manifest.permission
// get all permissions and groups here: https://stackoverflow.com/a/51156191/878126 https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
CALENDAR(arrayOf(permission.READ_CALENDAR, permission.WRITE_CALENDAR)),
CAMERA(arrayOf(permission.CAMERA)),
CONTACTS(arrayOf(permission.READ_CONTACTS, permission.WRITE_CONTACTS, permission.GET_ACCOUNTS)),
LOCATION(sequenceOf(permission.ACCESS_COARSE_LOCATION, permission.ACCESS_FINE_LOCATION, if (VERSION.SDK_INT >= VERSION_CODES.Q) permission.ACCESS_BACKGROUND_LOCATION else null)
.filterNotNull().asIterable().toList().toTypedArray()),
MICROPHONE(arrayOf(permission.RECORD_AUDIO, "android.permission.RECORD_BACKGROUND_AUDIO")),
PHONE(sequenceOf(permission.READ_PHONE_STATE, if (VERSION.SDK_INT >= VERSION_CODES.P) permission.ACCEPT_HANDOVER else null,
permission.CALL_PHONE, permission.ADD_VOICEMAIL, permission.USE_SIP,
if (VERSION.SDK_INT >= VERSION_CODES.O) permission.ANSWER_PHONE_CALLS else null, if (VERSION.SDK_INT < VERSION_CODES.P) permission.READ_CALL_LOG else null,
if (VERSION.SDK_INT < VERSION_CODES.P) permission.WRITE_CALL_LOG else null, if (VERSION.SDK_INT < VERSION_CODES.P) permission.PROCESS_OUTGOING_CALLS else null,
if (VERSION.SDK_INT >= VERSION_CODES.O) permission.READ_PHONE_NUMBERS else null).filterNotNull().asIterable().toList().toTypedArray()),
SENSORS(sequenceOf(if (VERSION.SDK_INT >= VERSION_CODES.KITKAT_WATCH) permission.BODY_SENSORS else null,
if (VERSION.SDK_INT >= VERSION_CODES.M && VERSION.SDK_INT < VERSION_CODES.P) permission.USE_FINGERPRINT else null, if (VERSION.SDK_INT >= VERSION_CODES.P) permission.USE_BIOMETRIC else null)
.filterNotNull().asIterable().toList().toTypedArray()),
SMS(sequenceOf(permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS, permission.RECEIVE_WAP_PUSH, permission.RECEIVE_MMS,"android.permission.READ_CELL_BROADCASTS")
.filterNotNull().asIterable().toList().toTypedArray()),
STORAGE(sequenceOf(permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE, if (VERSION.SDK_INT >= VERSION_CODES.Q) permission.ACCESS_MEDIA_LOCATION else null)
.filterNotNull().asIterable().toList().toTypedArray()),
CALL_LOG(if (VERSION.SDK_INT >= VERSION_CODES.P)
arrayOf(permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.PROCESS_OUTGOING_CALLS)
else emptyArray()),
ACTIVITY_RECOGNITION(if (VERSION.SDK_INT >= VERSION_CODES.Q) arrayOf(permission.ACTIVITY_RECOGNITION) else emptyArray()),
NEARBY_DEVICES(if (VERSION.SDK_INT >= VERSION_CODES.S) arrayOf(permission.BLUETOOTH_CONNECT, permission.BLUETOOTH_ADVERTISE, permission.UWB_RANGING, permission.BLUETOOTH_SCAN) else emptyArray())
;
#TargetApi(VERSION_CODES.S)
#StringDef(permission.READ_CALENDAR, permission.WRITE_CALENDAR, permission.CAMERA, permission.READ_CONTACTS, permission.WRITE_CONTACTS,
permission.GET_ACCOUNTS, permission.ACCEPT_HANDOVER, permission.ACCESS_COARSE_LOCATION, permission.ACCESS_FINE_LOCATION, permission.RECORD_AUDIO,
permission.USE_BIOMETRIC, permission.READ_PHONE_STATE, permission.CALL_PHONE, permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.ADD_VOICEMAIL,
permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS, permission.BODY_SENSORS, permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS, permission.RECEIVE_WAP_PUSH,
permission.RECEIVE_MMS, permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE, permission.ANSWER_PHONE_CALLS, permission.ACTIVITY_RECOGNITION,
permission.ACCESS_BACKGROUND_LOCATION, permission.ACCESS_MEDIA_LOCATION, "android.permission.RECORD_BACKGROUND_AUDIO",
permission.BLUETOOTH_CONNECT, permission.BLUETOOTH_ADVERTISE, permission.UWB_RANGING, permission.BLUETOOTH_SCAN,"android.permission.READ_CELL_BROADCASTS"
)
#Retention(AnnotationRetention.SOURCE)
annotation class Permission
}
And finding them:
fun checkPermissions() {
var permissionsCount = 0
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val permissionGroups = packageManager.getAllPermissionGroups(0)
var permissionsGroupsLeft = permissionGroups.size
permissionGroups.forEach { permissionGroup: PermissionGroupInfo ->
val permissionGroupName = permissionGroup.name
if (!permissionGroupName.startsWith("android.permission-group.")) {
if (--permissionsGroupsLeft == 0) {
Log.d("AppLog", "total permissions (of all permissions groups) count:$permissionsCount")
}
return#forEach
}
packageManager.getPlatformPermissionsForGroup(permissionGroupName, mainExecutor) { groupPermissions ->
if (groupPermissions.isNotEmpty()) {
Log.d("AppLog", "permissionGroup:$permissionGroupName")
groupPermissions.forEach { permissionName ->
Log.d("AppLog", "\t\t$permissionName")
++permissionsCount
}
}
if (--permissionsGroupsLeft == 0) {
Log.d("AppLog", "total permissions (of all permissions groups) count:$permissionsCount")
}
}
}
return
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
Log.d("AppLog", "cannot use API to query permissions, so guessing it is similar to what we have found about it:")
PermissionGroup.values().forEach { permissionGroup ->
val permissions = permissionGroup.permissions
if (permissions.isEmpty())
return#forEach
Log.d("AppLog", "permissionGroup:${permissionGroup.name}")
permissions.forEach { permissionName ->
Log.d("AppLog", "\t\t${permissionName}")
++permissionsCount
}
}
}
else -> {
val allPermissionGroups = packageManager.getAllPermissionGroups(0)
allPermissionGroups.forEach { permissionGroup ->
val permissionGroupName = permissionGroup.name
if (!permissionGroupName.startsWith("android.permission-group."))
return#forEach
val groupPermissions = packageManager.queryPermissionsByGroup(permissionGroupName, 0)
if (groupPermissions.isEmpty())
return#forEach
Log.d("AppLog", "permissionGroup:$permissionGroupName")
for (permission in groupPermissions) {
val permissionName = permission.name
Log.d("AppLog", "\t\t${permissionName}")
++permissionsCount
}
}
}
}
Log.d("AppLog", "total permissions (of all permissions groups) count:$permissionsCount")
}
A short answer without going in detail to get all permissions:
adb shell pm list permissions lists permissions that comes with
installed apps (false or true)
adb shell cmd appops get <package> lists permissions on
user level per app (allow, deny, ignore)
adb shell dumpsys <package> lists permissions per app on system
level (grant and revoke)