23

I'm looking for a possibility to retrieve both, the package names and the common names of apps installed on an Android device via ADB – or at least to retrieve the common name if the package name is known. A quick search on our site brought up two related questions, but they don't solve my issue:

I'm looking for a way to retrieve the information directly from the device, if possible – not "any" way (including "web lookups" or "via an app") as those two questions have it.

I know there are multiple tools available to obtain package details:

  • adb dumpsys package: While this lists all packages with a bunch of details, the "common name" is not shown
  • adb shell pm list: only gives the package names
  • aapt would be able to obtain the common name, but would require to first pull the .apk file from the device, which is not really convenient (and obviously will be pretty slow with many and/or large apps installed)

Did I miss something? I know the information must be on the device (how else could it show the app names in the GUI? I doubt Android parses the .apk file each time the GUI need the "common name"). So is there a way to get hold of it, using ADB directly?


TL;DR

Background (if somebody's curious): I want to be able to quickly obtain a list of user-apps from any of my devices, without having to revert to acrobatics. A list of their package names I can retrieve using adb shell pm list -3, but as those are package names only, recognizing apps is a guess-work. So if there were some ADB command to retrieve the common name for a given package name, I could simply use a loop like for pkg in $(adb shell pm list -3); do echo "- $(adb <whatever_the_command_is> $pkg) ($pkg)"; done – and get a listing of all the installed user-apps in a "human readable format" together with their package names.

Use-cases:

  • See what "superflous" apps are installed (which I could remove)
  • Cross-check lists from multiple devices
  • Documentation ;)
  • and probably more (but the above 3 are what I need it for)
Izzy
  • 91,166
  • 73
  • 343
  • 943
  • Just an ideea (I think you tried already?). Why you just don't compile aapt for android and run instead from shell? :D – ares777 May 13 '15 at 10:15
  • 1
    @user3344236 I'm aware of that possibility; but it is not always an option to install something to the device in question, especially not a self-compiled binary (I sometimes get handed-in devices which are not rooted, and have to keep "forensics-like conditions" – i.e. "do not alter the device, just explore it"). – Izzy May 13 '15 at 10:37
  • So the second idea is to write yourself a tool which runs via adb shell... without using modified adbd on device and without pushing some files there. I think it will take you some time to accomplish this (if ever you succeed) :D – ares777 May 13 '15 at 10:50
  • @user3344236 too worrysome, especially as I'm not an Android dev. I currently use a "web based solution" (similar to that "Google Play lookup"), as there doesn't seem to be a native solution here (yet?). – Izzy May 13 '15 at 12:22
  • Hi Izzy! Considering the comments (above), does it mean that you need a solution considering a non-rooted device in mind? – Firelord Jun 24 '15 at 15:13
  • @Firelord Preferably yes, though root-only solutions would be better than none at all ;) – Izzy Jun 24 '15 at 15:16
  • It's not that it would be the desired solution, but it's safe to assume that a non-rooted device probably would have an active Google Play Store, and if that's the case then you can get at least few <APP_NAME> and <PKG_NAME> from the databases (localappstate.db) inside it. Have you tried it? I've not verified whether ADB backup covers Play Store or not. – Firelord Jul 07 '15 at 19:44
  • Nice idea, @Firelord – but sure that would also apply to apps installed by other means (Aptoide, F-Droid, adb install) which the playstore doesn't know? And secondly, assuming a not-rooted device: would that database be accessible via ADB in some way? "From the databases inside it" surely means somewhere below /data/data, which is not "openly accessible" without root. Need to check whether that database would be accessible from an ADB backup – which still would require having the SSL libs available to decrypt that. – Izzy Jul 07 '15 at 20:47
  • @Izzy I've three confirmations: If the non-root device has Aptoide or F-Droid installed, then consider them as gold mine, since their databases are covered by ADB backup, and they individually have <APP_NAME> and <PKG_NAME> of all system+user apps. Talking about Play Store, its database is also covered by ADB backup, but it would give <APP_NAME> only for those apps which are installed using Play Store. The rest are listed by <PKG_NAMES> only. // It could help I guess. – Firelord Jul 07 '15 at 21:40
  • Yeah, but it would mean to puzzle a lot, checking for all kind of app stores possibly installed until you've got all apps covered. Not really feasible. There must be some "central place" feeding things like the app drawer. That then would be the place to find my diamonds :) – Izzy Jul 07 '15 at 23:13
  • It seems aapt is included with Android ROMs from 4.4 (Kitkat) onwards, see this answer. Can anyone confirm this for stock ROMs? – Izzy Jul 18 '15 at 14:37

4 Answers4

12

Here is my solution for a non-rooted phone which needed some slight changes from above which I ran on a Moto G 2nd gen running Android 5.0.2.

I didn't have aapt binary in /system/bin, so I first tried downloading from https://android.izzysoft.de/downloads

but when I tried to run it, I got an error saying:

error: only position independent executables (PIE) are supported.

So then I searched for a PIE version and found: https://github.com/Calsign/APDE/blob/fdc22eb31048862e1484f4b6eca229accda61466/APDE/src/main/assets/aapt-binaries/aapt-arm-pie

and this worked by copying binary to /data/local/tmp:

adb push aapt-arm-pie /data/local/tmp
adb shell chmod 0755 /data/local/tmp/aapt-arm-pie

So then:

adb shell pm list packages -3 -f

gets a list of 3rd party apps (apps you have installed, not system apps) and then you can use the package from the command above in aapt to get information on the package - example:

adb shell /data/local/tmp/aapt-arm-pie d badging /data/app/com.facebook.katana-3/base.apk

So, below is a script (for a Linux client) to get just "common" name for 3rd party apps:

for pkg in `adb shell pm list packages -3 -f | awk -F= '{sub("package:","");print $1}'`
do
  adb shell /data/local/tmp/aapt-arm-pie d badging $pkg | awk -F: '
      $1 == "application-label" {print $2}'
done

If you want package and version too, then change last but one line from:

$1 == "application-label" {print $2}'

to:

$1 == "package" { split($2,space," ")
name=space[1];version=space[3]}
$1 == "application-label" {print name, version, $2 }'

Example output:

name='com.ultimarom.launchnavigation' versionName='1.28' 'Navigation'
name='com.enhanced.skineditorstudio' versionName='3.3' 'Custom Skin Creator'
name='com.mojang.minecraftpe' versionName='1.2.6.60' 'Minecraft'
name='org.videolan.vlc' versionName='2.5.13' 'VLC'
name='com.jrustonapps.myauroraforecast' versionName='1.7.2' 'My Aurora Forecast'
name='de.j4velin.wifiAutoOff' versionName='1.7.6' 'WiFi Automatic'
name='com.facebook.katana' versionName='153.0.0.54.88' 'Facebook'
name='com.metago.astro' versionName='6.0.5' 'ASTRO File Manager'
name='za.co.hardrive.smartinfo.parkrun' versionName='2.0.2' 'My 5krun'
name='com.PYOPYO.StarTrackerVR' versionName='1.0.1' 'StarTracker VR'
name='cz.aponia.bor3.offlinemaps' versionName='1.1.19' 'Offline Maps'
name='com.groupon' versionName='16.11.63973' 'Groupon'
name='com.ebay.mobile' versionName='5.16.1.2' 'eBay'
name='com.runtastic.android' versionName='8.1.1' 'Runtastic
name='com.google.android.diskusage' versionName='3.8.3' 'DiskUsage'
Mike Bounds
  • 131
  • 1
  • 6
  • PS: My download page now also links to the source you've specified – just "one level up", so folks can chose between ARM and x86 builds. – Izzy Jan 06 '18 at 16:14
7

This is not a final answer, as it is not generic (only works on some devices) – but it's a start at least:

As we've figured out, at least CM based ROMs with Kitkat (Android 4.4) and above ship with the aapt binary available in /system/bin1. If your ROM doesn't have it, and installing the binary on the device is an option, you can find it here.

Using aapt, retrieving the app name is possible with

aapt d badging <path to apk> | grep "application: label" |awk '{print $2}'

The output will be something like label='Funny App', which you then easily can parse for the app name, e.g.

aapt d badging <path to apk> | grep 'application: label' | sed -n \"s/.*label\='\([^']*\)'.*/\1/p\"

(not good if the app name contains single quotes, but that might count as cosmetics – or you figure how to improve the sed part to deal with that).


1: we didn't find this in the Kitkat-and-above stock ROMs we've checked, so it might be CM based ROMs only

Izzy
  • 91,166
  • 73
  • 343
  • 943
  • 5
    Note to readers: You need not to have a rooted device to use that aapt binary. You can very well download and rename the binary to aapt in PC, set Linux compatible executable permission on the binary and push it to /data/local/tmp, then use the absolute path /data/local/tmp/aapt to use the binary in those commands. – Firelord Jan 09 '16 at 18:48
  • So for the name of the package (first part of the original question), you would do aapt d badging <path to apk> | grep 'package: name' | awk '{print $2}' – gmoz22 Nov 14 '19 at 23:19
4

This can be achieved with Android Java API:

import android.app.ActivityThread;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Looper;

public class Main { public static void main(String[] args) { Looper.prepareMainLooper(); PackageManager pm = ActivityThread.systemMain().getSystemContext().getPackageManager(); for (ApplicationInfo appInfo : pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES)) { System.out.println(appInfo.uid + " " + appInfo.packageName + " " + pm.getApplicationLabel(appInfo)); } } }

Compile the code to a dex file, push it to /data/local/tmp/list_app_labels.dex, and run from ADB shell:

CLASSPATH=/data/local/tmp/list_app_labels.dex app_process / Main

It should print the UID, package name and app label of installed apps like this:

10099 com.android.packageinstaller Package installer
1002 com.android.bluetooth Bluetooth
1073 com.android.networkstack.permissionconfig com.android.server.NetworkPermissionConfig
10230 com.topjohnwu.magisk Magisk
10087 com.android.providers.blockednumber Blocked Numbers Storage
10176 com.termux.widget Termux:Widget
...

If you don't want to compile the code, here are convenience methods:

Option 1

Download the pre-compiled executable (for arm64 or arm), extract the zip file, push the binary to Android device, and run:

adb push list_app_labels /data/local/tmp/ && adb shell 'cd /data/local/tmp/ && chmod a+x list_app_labels && ./list_app_labels'

Option 2

Push the given script to Android device and run:

adb push list_app_labels.sh /data/local/tmp/ && adb shell sh /data/local/tmp/list_app_labels.sh

Tested on Android 7-13.

Note:

  • Do not change the script. tail extracts the dex from a hard-coded line number.
  • If you are on Windows, run dos2unix on the shell script before executing.

list_app_labels.sh:

#!/system/bin/sh

export CLASSPATH=/data/local/tmp/list_app_labels.dex trap 'rm $CLASSPATH' EXIT tail -n +10 "$0" | base64 -d >$CLASSPATH

app_process / Main exit

ZGV4CjAzNwAEZ8DOwPQFGurk/iOA5Ry9+z0tMCP1fzNMCAAAcAAAAHhWNBIAAAAAAAAAAKwHAAAx AAAAcAAAABQAAAA0AQAADwAAAIQBAAADAAAAOAIAABMAAABQAgAAAgAAAOgCAAAkBQAAKAMAAFoE AABdBAAAZQQAAGgEAABrBAAAbwQAAHMEAAB7BAAAmQQAALQEAADPBAAA9QQAABoFAAAvBQAAQQUA AFgFAAByBQAAhgUAAJoFAAC1BQAAyQUAAN8FAADxBQAA/AUAAP8FAAADBgAABgYAABsGAAAfBgAA JwYAAC0GAAAyBgAARwYAAGEGAAB0BgAAhgYAAI8GAACZBgAAnwYAAKUGAACqBgAAtwYAALsGAADO BgAA1wYAAOMGAADtBgAA8gYAAFkHAAACAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0A AAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABcAAAAZAAAAGgAAAAMAAAACAAAAAAAA AAMAAAADAAAAAAAAAAMAAAAGAAAAAAAAAAUAAAAKAAAANAQAAAMAAAALAAAAAAAAAAMAAAAMAAAA AAAAAAQAAAANAAAAPAQAAAUAAAANAAAARAQAAAUAAAANAAAATAQAAAMAAAAPAAAAAAAAAAQAAAAQ AAAAPAQAABcAAAARAAAAAAAAABgAAAARAAAATAQAABgAAAARAAAAVAQAABkAAAASAAAAAAAAAAUA DAAoAAAABQAAAC4AAAAOAAkAJwAAAAEACwABAAAAAQANACUAAAACAAEAIgAAAAIAAAAsAAAABAAC ACEAAAAGAAMAHwAAAAYACgAgAAAABwALACoAAAAIAAsAAQAAAAkADAArAAAACwALAAEAAAANAAsA AQAAAA0ABgAcAAAADQAHABwAAAANAAgAHAAAAA0ABQAtAAAADwAOACMAAAAPAAQAJgAAABAACQAk AAAAAQAAAAEAAAALAAAAAAAAABYAAAAAAAAAkQcAAAAAAAAIAAAAEQAAAAsAAAAAAAAA/////wAA AACfBwAAAAAAAAEAAQABAAAAEAQAAAQAAABwEAoAAAAOAAkAAQACAAAAFAQAAFMAAABxAAcAAABx AAMAAAAMAG4QAgAAAAwAbhAEAAAADAETAgAgbiAGACEADAJyEBIAAgAMAnIQEAACAAoDOAM1AHIQ EQACAAwDHwMFAGIEAgAiBQ0AcBALAAUAUjYBAG4gDABlAAwFGgYAAG4gDgBlAAwFVDcAAG4gDgB1 AAwFbiAOAGUADAVuIAUAMQAMBm4gDQBlAAwFbhAPAAUADAVuIAkAVAAoyA4AAAABAAEAAQAAAAAA AAAEAAAAcBAKAAAADgAHAA4ACgEeDjyIAwAfBUwDASoHARYPAwMcBgEsDwUDHgAAAAABAAAABQAA AAEAAAAAAAAAAQAAAAsAAAABAAAADAAAAAEAAAATAAEgAAY8aW5pdD4AAUkAAUwAAkxJAAJMTAAG TE1haW47ABxMYW5kcm9pZC9hcHAvQWN0aXZpdHlUaHJlYWQ7ABlMYW5kcm9pZC9hcHAvQ29udGV4 dEltcGw7ABlMYW5kcm9pZC9jb250ZW50L0NvbnRleHQ7ACRMYW5kcm9pZC9jb250ZW50L3BtL0Fw cGxpY2F0aW9uSW5mbzsAI0xhbmRyb2lkL2NvbnRlbnQvcG0vUGFja2FnZU1hbmFnZXI7ABNMYW5k cm9pZC9vcy9Mb29wZXI7ABBMY29tL21pcmZhdGlmL1I7ABVMamF2YS9pby9QcmludFN0cmVhbTsA GExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5n L1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAEkxqYXZhL2xhbmcvU3lzdGVtOwAU TGphdmEvdXRpbC9JdGVyYXRvcjsAEExqYXZhL3V0aWwvTGlzdDsACU1haW4uamF2YQABVgACVkwA AVoAE1tMamF2YS9sYW5nL1N0cmluZzsAAmFpAAZhcHBlbmQABGFyZ3MAA2N4dAATZ2V0QXBwbGlj YXRpb25MYWJlbAAYZ2V0SW5zdGFsbGVkQXBwbGljYXRpb25zABFnZXRQYWNrYWdlTWFuYWdlcgAQ Z2V0U3lzdGVtQ29udGV4dAAHaGFzTmV4dAAIaXRlcmF0b3IABG1haW4ABG5leHQAA291dAALcGFj a2FnZU5hbWUAAnBtABFwcmVwYXJlTWFpbkxvb3BlcgAHcHJpbnRsbgAKc3lzdGVtTWFpbgAIdG9T dHJpbmcAA3VpZABlfn5EOHsiYmFja2VuZCI6ImRleCIsImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1 ZyIsImhhcy1jaGVja3N1bXMiOnRydWUsIm1pbi1hcGkiOjI0LCJ2ZXJzaW9uIjoiMy4zLjgzIn0A Nn5+fnsiTE1haW47IjoiNzg1NDY5ZTYiLCJMY29tL21pcmZhdGlmL1I7IjoiNjExMjVkMjEifQAA AAIAAIGABKgGAQnABgAAAQAIgoAE+AcAAAANAAAAAAAAAAEAAAAAAAAAAQAAADEAAABwAAAAAgAA ABQAAAA0AQAAAwAAAA8AAACEAQAABAAAAAMAAAA4AgAABQAAABMAAABQAgAABgAAAAIAAADoAgAA ASAAAAMAAAAoAwAAAyAAAAIAAAAQBAAAARAAAAUAAAA0BAAAAiAAADEAAABaBAAAACAAAAIAAACR BwAAABAAAAEAAACsBwAA

Irfan Latif
  • 20,353
  • 3
  • 70
  • 213
  • Hi! Just for the sake of curiosity and also clarity, do I get it right that the embedded Base64-encoded content is a Dalvik executable? – Andrew T. Feb 20 '23 at 02:30
  • @AndrewT. Yes.. – Irfan Latif Feb 20 '23 at 06:22
  • @IrfanLatif for transparency it would be nice to add the source code – Wanted Mar 29 '23 at 18:19
  • 1
    @Wanted Java isn't compiled to a binary format. Java bytecode is as transparent as its source code is. I even don't have the source code. It would be a simple two liner loop calling getInstalledApplications and printing the required info to the terminal. – Irfan Latif Mar 29 '23 at 20:55
  • 1
    Added decompiled code from @IrfanLatif for completness: https://gist.github.com/wanted0/6a54f08f78735ddfdec2622dc74c17fd – Wanted Mar 31 '23 at 17:08
  • I get app_process: command not found – user541686 Sep 09 '23 at 16:50
  • It looks like my shell doesn't have tail or base64 - note to anyone else, as it wasn't entirely obvious to start with - the first half of the script is just writing out to file the decoded form of the second half. I misread the tail as writing its directory to CLASSPATH (since it's a path, and this is what I've had to do with java before), but we are simply extracting the binary blob from the script. If your shell doesn't have base64, you can extract locally and transfer the blob. I think a heredoc or similar might make it clearer what is happening, as the tail is sensitive to line numbers. – stellarpower Oct 08 '23 at 16:39
  • To view all running processes with this from Termux, if list_app_labels is in ~, try: CLASSPATH="${HOME}/list_app_labels" su -c "/system/bin/app_process / Main; \"${PREFIX-}/bin/ps\" --no-headers ax -o user,pid,cmd" | gawk '$1 ~ /^[0-9]+/ { name = $0; sub(/^[0-9]+ +[^ ]+ /, "", name); apps[$2] = name; } $1 ~ /^u[0-9]+_/ && !($0 ~ /[()]/) { e = $0; sub(/^[^ ]+ +[^ ]+ +(.*\/)?/, "", e); sub(/[ :].*$/, "", e); if (e ~ /[.]/ && !a[e]++) { ++n; } } END { for (k in a) { name = k; result[j++] = name in apps ? apps[name] : name; } asort(result); for (i = 0; i < j; ++i) { print(result[i]); } }' – user541686 Jan 09 '24 at 08:58
2

None of the suggestions were particularly good for me, so after some fiddling, here's my 100% on-device solution using Termux:

Get Termux and install adb and aapt through its package manager:

pkg install android-tools aapt

You need to be connected to a Wi-Fi network - any network will do - to pair Termux's ADB to your phone for "wireless" debugging.

Now here's the script I've made, with comments to make it easier to read and tweak (and also for me to understand as I've never been that good at shell scripting):

# ,- list all packages including APK path, in the format: package:/data/.../path/to.apk=com.package.name
# |  note that the path to the APK includes equals signs
# |  
# |                                              ,- replace the last "=" (before the package name) with a ":"
# |                                              |
# |                                              |                       ,- remove leading "package:"
# |                                              |                       |                              ,- parse into shell vars $apk and $pkgname
# |                                              |                       |                              |
adb shell cmd package list packages -f | sed -e 's/=\([^=]*\)$/:\1/' -e 's/^package://' - | while IFS=: read -r apk pkgname; do
  # get label using aapt and filter out just the label with sed
  label=$(aapt dump badging $apk | sed --quiet --expression='s/^application-label://p')
  echo "pkgname: $pkgname"
  echo "apk: $apk"
  echo "label: $label"
  echo ""
done

Save this to a file somewhere in the termux home folder for easy access (e.g. ~/list.sh), and run it with sh list.sh

It takes about a second per app for aapt to process the apk, but it doesn't need to copy it anywhere - it accesses the apk directly where it is. The output is easily tweakable in the script as it's just a few echo commands. You can also change which files get listed by changing the arguments of adb shell cmd package, e.g. by adding -3, but be sure to keep the -f flag.

This may not be useful for the original question asker, but I do hope it would be useful to others!

vadcx
  • 3
  • 1
NeatNit
  • 173
  • 6