Skip to content

Device & systemSecurity & malware

Installed Apps: packages.xml and packages.list

Android's package manager state: packages.xml install and update times, installer and initiator, UIDs, signatures and permissions, packages.list and ABX.

Location
/data/system/packages.xml
Proves
Which apps are installed, when each was first installed and last updated, which app installed it (store, package installer, browser, adb), its UID, signing certificate and install-time permissions
Timestamps
Attributes ft, it and ut are hexadecimal Unix milliseconds (UTC): APK timestamp, first install, last update
Access
Full file system (root, exploit or agent); system device-encrypted storage, readable in BFU by a privileged extraction. Logical and bugreport: the same facts via pm and dumpsys package. Not in ADB backup.
Retention
Current state only: an uninstalled app disappears from packages.xml; traces remain in usagestats, Play Store databases and other logs
Collection
Full file system extraction, adb shell pm list packages -f -i -U, adb shell dumpsys package, adb bugreport, androidqf
  • Disk Image Parser: Reads ext4 only: not F2FS (used for userdata on many recent phones) and not Android sparse images. An image of an FBE userdata partition shows encrypted names and contents unless it was decrypted during extraction.

What it is

The Android package manager keeps its persistent state in /data/system/packages.xml: one <package> element per installed app (system and user), with its code path, version, UID, install source, timestamps, signing certificates and install-time permissions. A companion text file, packages.list, maps each package to its UID and data directory. Together they are the authoritative inventory of what can run on the phone, and the starting point of any malware or stalkerware triage.

Where it lives

ItemPathNotes
Package state/data/system/packages.xmlAndroid Binary XML (ABX) from Android 12 on most builds
Package list/data/system/packages.listPlain text
Per-user state/data/system/users/<user>/package-restrictions.xmlInstalled-for-user, enabled, stopped, hidden, suspended flags
Runtime permissions/data/system/users/<user>/runtime-permissions.xml (8 to 10), /data/misc_de/<user>/apexdata/com.android.permission/runtime-permissions.xml (11+)Dangerous permissions granted at runtime
Install sessions/data/system/install_sessions.xmlPending and recent install sessions
APKs/data/app/<pkg>-<random>/ (8 to 10), /data/app/~~<random>/<pkg>-<random>/ (11+)base.apk and split APKs
Transient backup/data/system/packages-backup.xmlPresent only if the system was interrupted while writing

What it proves

  • The full list of installed packages, including disabled system apps and apps installed for other users.
  • First install time (it) and last update time (ut) of each package.
  • The installer (installer): com.android.vending for Google Play, com.sec.android.app.samsungapps for Galaxy Store, com.google.android.packageinstaller or com.android.packageinstaller for a sideloaded APK opened from a file or browser, empty or the shell for adb install.
  • On Android 11 and later, the initiating app (installInitiator), for example the browser or file manager the APK was opened from, and the originating app.
  • The app's UID (matches packages.list, usagestats and file ownership), shared UID, signing certificate and install-time permissions.

It does not prove the user launched the app (usagestats does that) or chose to install it: an app with install permission can install others.

Key fields

Attribute or elementMeaning
name, codePathPackage name and APK folder
version, userId / sharedUserIdversionCode, UID or shared UID
ft, it, utAPK file timestamp, first install time, last update time (hex milliseconds)
installer, installInitiator, installOriginatorInstalling package, initiating package, originating package (the latter two on Android 11+)
packageSourceOn newer releases, a code for where the install came from (store, local file, downloaded file)
<sigs> / <cert>Signing certificate(s)
<perms> / <item name granted>Install-time permissions
packages.list line<package> <uid> <debuggable> <dataDir> <seinfo> <gids>

Timestamps

ft, it and ut are Unix epoch milliseconds written in hexadecimal. it survives updates; ut changes on every update, including silent Play Store updates.

# Android 12+: convert ABX first (on a device: abx2xml in out; offline: ccl_abx, see its README)
python3 ccl_abx.py packages.xml > packages_plain.xml
python3 - <<'PY'
import datetime as dt, xml.etree.ElementTree as ET
ts = lambda h: dt.datetime.fromtimestamp(int(h, 16) / 1000, dt.timezone.utc).isoformat() if h else None
for p in ET.parse("packages_plain.xml").getroot().iter("package"):
    print(p.get("name"), "installed", ts(p.get("it")), "updated", ts(p.get("ut")),
          "installer", p.get("installer"), "initiator", p.get("installInitiator"))
PY

Retention

packages.xml is rewritten with the current state after every change, so an uninstalled app vanishes from it. Evidence of a removed app survives elsewhere: usagestats events, the Play Store's own databases (library.db, localappstate.db in com.android.vending), raw contacts or accounts it created in contacts2.db, Wi-Fi networks it configured in WifiConfigStore.xml, and leftover folders in shared storage.

Collection

  • Full file system extraction: copy /data/system/ (packages files, users/) and ideally the APKs of suspicious packages. The files are in system device-encrypted storage.
  • Logical (no root): the package manager exposes the same facts.
adb shell pm list packages -f -i -U > packages.txt          # path, installer, UID
adb shell dumpsys package > dumpsys_package.txt              # install times, initiator, permissions
adb shell pm path com.suspicious.app                         # then adb pull the APK
  • Bugreport: dumpsys package is part of it. androidqf collects packages, their APKs and dumpsys output in one run.

Parsing

  • ALEAPP reports installed apps from packages.xml (ABX included) and packages.list.
  • MVT (mvt-android check-androidqf, check-bugreport or check-adb) flags sideloaded apps, apps with dangerous permissions and matches against spyware indicators.
  • jadx and Apktool decompile a suspicious APK to review its manifest, permissions and code.
  • Disk Image Parser can browse /data/system in an ext4 image of a decrypted userdata partition to export these files; it does not read F2FS.

Investigator tips

  • Sort by it and look at everything installed shortly before the incident; a sideload installer or installInitiator set to a browser, file manager or messaging app deserves a look.
  • Cross-check a sideloaded APK with its download in Chrome history and the link that led there in SMS.
  • Stalkerware often uses innocuous names ("System Service", "Sync"), hides its launcher icon, and holds accessibility, notification listener or device admin rights: review runtime permissions and special access next to the package list.
  • System apps updated through the Play Store appear with a /data/app code path and an update time: that is normal, not a replaced system binary.
  • A package present in packages.list and absent from packages.xml (or the reverse) points to an interrupted write or tampering on a rooted device.

See also