Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

From where does the Android command pm take info?

This is my first question on StackOverflow, since it was off-topic for my original SE site.


Some background info

On Android, there exists a command, pm. This is short for Package Manager, and it can perform a various range of operations on APK files, such as installing and uninstalling apps, managing their permissions and listing the installed packages according to various criteria.

In my project, a shell script made for backing up Android apps' APK files, I heavily rely on pm to list the installed apps and obtain their APK's path. Simply listing them is a matter of roughly a second. To get each one's path, though, I spend one second per app, which, in my opinion, is too much.


The guess

I originally doubted that a heavily used tool such as pm had to rebuild from scratch the whole list of packages anytime I issued pm list packages to have a look, so I dug deeper and found a file that seems to contain the whole list of installed packages, both system and third-party. This file is located under the folder /data/system/, and is called packages.list (info found on a CyanogenMod 13 OS, powered by Android 6.0.1).

A line from the file looks as follows:

com.android.providers.telephony 1001 0 /data/data/com.android.providers.telephony platform 3002,3003,3001

. The parts I need, seems to be the first and the fourth field, although the fourth one is the path to the app's data, instead of being the path to the APK. This could possibly indicate that my guess is wrong.


The questions

My question is: does it exist a file from which the pm program loads the info about the packages, when an user wishes to look them up?

Since indexing more than 100 apps takes a mere second, in contrast with looking up a package's location (which also takes up a second, but on a per-app basis), could it be that the path is somehow "found" at runtime, rather than being retrieved from a database?

I was not able to find the source code for this binary. Thanks in advance.

like image 466
Death Mask Salesman Avatar asked May 20 '26 09:05

Death Mask Salesman


1 Answers

It turns out that my guess was wrong - the file in question was not /data/system/packages.list, but /data/system/packages.xml.

Amongst the entries in the file, I was able to find each package installed in my operating system, along with its APK's path. I then filtered the file with grep, in the following fashion:

cat /data/system/packages.xml | grep "package name" > packages.txt

, which yielded a pseudo-XML file with only the fields that concerned the installed packages. Next, I proceeded by creating the actual plaintext dictionary, with the following procedure:

IFS=$'\n'

packages="$(cat packages.txt)"
echo -n "$(cat /dev/null)" > packages.txt

for i on $packages; do
 package_name="${i//*package name=\"/}"
 package_name="${package_name//\"*/}"

 package_path="${i//*codePath=\"/}"
 package_path="${package_path//\"*/}"
 package_path="$package_path $(ls $package_path | grep "\.apk$")"

 echo "$package_name:$package_path" >> packages.txt
done

unset IFS packages i package_name package_path

. The boldness in my act of concatenating the output of ls $package_path | grep "\.apk$" to package_path is due to the fact that, for installed apps, only one APK file is present in the app's directory, so no errors are possible.


Leaving this knowledge here for future reference.

like image 55
Death Mask Salesman Avatar answered May 22 '26 01:05

Death Mask Salesman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!