4

Given some permission tld.developer.app.permission.PERMISSION how can I use adb/root shell to find all the installed packages that define/depend on it?

The permissions are defined in the manifest files and it is possible to transfer each apk over from /data/app, /system/app, /system/priv-app, etc., unpackage, and check, but is there a better way?

5

The first section is ideally supposed to be OS (on PC) independent. The solution heavily depends upon the output of package service. It has been successfully tested on Android 4.2.1, 5.0.2 and 5.1.1 - all these versions are not heavily modified from stock Android.

Dependencies

  • Requires to be setup in PC.
  • Requires busybox binary. If the device is rooted, install Busybox app. Else, download busybox binary from official source, rename the binary to busybox, set Linux compatible executable permission on that binary for everyone and move it into device using

    adb push LOCAL_FILE /data/local/tmp/   # LOCAL_FILE is the file path where busybox binary is located in PC
    
  • Requires aapt binary. If you're running a CM or its derivative ROM then ignore this requirement. Otherwise, for Android 4.x, you can consider downloading the binary from here, rename the binary to aapt, set Linux compatible executable permission on that binary for everyone and move it into device using

    adb push LOCAL_FILE /data/local/tmp/   # LOCAL_FILE is the file path where busybox binary is located in PC . 
    

    Android 5.x users: ask Google for assistance.

Here's my little script:

#!/system/bin/sh
# Check if the busybox binary exists under /data/local/tmp/ or /system/xbin. Set the detected binary's path into the variable busybox or exit if file doesn't exist or executable permission is not set
[[ -x /data/local/tmp/busybox ]] && busybox=/data/local/tmp/busybox || { [[ -x /system/xbin/busybox ]] && busybox=/system/xbin/busybox || { date +'busybox binary not found or executable permission is not set. Exiting' && exit; }; }

# Check if the aapt binary exists under /data/local/tmp or /system/bin or /system/xbin. Set the detected binary's path into the variable aapt or exit if file doesn't exist or executable permission is not set
[[ -x /data/local/tmp/aapt ]] && aapt=/data/local/tmp/aapt || { [[ -x /system/bin/aapt ]] && aapt=/system/bin/aapt || { [[ -x /system/xbin/aapt ]] && aapt=/system/xbin/aapt || { date +'aapt binary not found or executable permission is not set. Exiting' && exit; }; }; }

# Validate input
! [[ "$1" == +([0-9a-zA-Z._]) ]] && { $busybox printf 'Permission field should not be empty or contain anything beyond these characters: a-zA-Z0-9._' && exit; } || perm=$1;

# List package name of all the installed apps and save them in the file packages.txt under /sdcard
pm list packages | $busybox sed 's/^package://g' | $busybox sort -o /sdcard/packages.txt
$busybox printf "List of apps defining and/or depending on the permission $perm:\n\n";

# Take each line (a package name) from the file packages.txt. In the output of package service for that package name, see if the permission is granted or defined and set appropriate variable state. For different states, we're either dumping the label of the app using aapt, printing the status of define/granted permissions for package or simply moving on.
while read line; do 
    [[ `dumpsys package $line | grep -Eo "^[ ]+$perm"` ]] && granted=1 || granted=0;
    [[ `dumpsys package $line | grep -Eo "^[ ]+Permission[ ]+\[$perm\][ ]+\([a-zA-Z0-9]+\):"` ]] && defined=1 || defined=0;
    [[ $granted == 1 || $defined == 1 ]] && path=$(pm path $line | $busybox sed 's/^package://g') && label=$($aapt d badging $path 2>&1 | $busybox sed -ne '/application: label=/p' | $busybox cut -d "'" -f2);
    [[ $granted == 1 && $defined == 1 ]] && $busybox printf "$label ($line)\nDefined: Yes\nGranted: Yes\n\n";
    [[ $granted == 1 && $defined != 1 ]] && $busybox printf "$label ($line)\nDefined: No\nGranted: Yes\n\n";
    [[ $granted != 1 && $defined == 1 ]] && $busybox printf "$label ($line)\nDefined: Yes\nGranted: No\n\n";
done < /sdcard/packages.txt 

Save the script in PC into a file named perm_script.sh and move it into /sdcard using

adb push LOCAL_FILE /sdcard/   # LOCAL_FILE is the  path where you saved that file into PC

Run that file

adb shell sh /sdcard/perm_script.sh PERMISSION   # replace PERMISSION with the android permission for which apps are to be shown

Demo output:

List of apps defining and/or depending on the permission android.permission.FLASHLIGHT:

Android System (android)
Defined: Yes
Granted: No

Automagic Premium (ch.gridvision.ppam.androidautomagic)
Defined: No
Granted: Yes

MacroDroid (com.arlosoft.macrodroid)
Defined: No
Granted: Yes

Google+ (com.google.android.apps.plus)
Defined: No
Granted: Yes
...
Bluetooth (com.mediatek.bluetooth)
Defined: No
Granted: Yes

DS Battery Saver Pro (com.rootuninstaller.batrsaverpro)
Defined: No
Granted: Yes

Webkey (com.webkey)
Defined: No
Granted: Yes

Do note that all those apps and their permissions among other things can also be found in the file /data/system/packages.xml.


(To get app's label using its package name, use GAThrawn's answer - works if only the app is available in Play Store; use Izzy's answer - works for any installed app.)

  • got an error running your script, did i miss something? adb shell sh /sdcard/perm_script.sh PERMISSION /sdcard/perm_script.sh[6]: syntax error: '{' unmatched or directly running on the android 8 Script output Finished executing script file exit value:1 stdout: null stderr: /sdcard/perm_script.sh[6]: sysntax error: '{' unmatched – Gidabytes May 3 at 7:44
  • @Gidabytes I have just tested my script on Android 8.1 (in OnePlus 6), and it works. You might be doing something wrong in copying the script's content I suppose. You can answer a separate question for that, and reference my answer, if needed. – Firelord May 3 at 8:17
1

This worked for me (Android 8):

cmd appops query-op RUN_IN_BACKGROUND allow | sort

It shows which packages have RUN_IN_BACKGROUND mode enabled.

  • This is a good and easy to use solution, but it has some shortcomings too. First, it only allows querying dangerous permissions, because appops works only for that, so normal permissions cannot be queried with this. Second, it requires multiple executions to ascertain which apps have a said permission allowed, default, denied, or ignored. – Firelord May 3 at 8:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.