The changes of APK install location since Android Oreo

Zhang quaful
3 min readJun 17, 2018

--

In Google’s official document of “Android 8.0 Behavior Changes”, it mentioned:

  • You can no longer assume that APKs reside in directories whose names end in -1 or -2. Apps should usesourceDir to get the directory, and not rely on the directory format directly.

But what actually happened in the end of the APK install location?

In Android 7.0 and before, after an APK is installed, it will be located in /data/app path. More specifically, in Android 7.0, the APK file will be installed into /data/app/<package name>-<num>/ folder, where the <package name> is the package name of the APK, and the num may be 1 or 2. We can install a real APK of an Android app for example:

Get a rooted Android 7.0 phone (or using an Android 7.0 emulator), install an app named “APUS Launcher” from https://play.google.com/store/apps/details?id=com.apusapps.launcher, and use adb shell to log in to the phone:

We can see that there is a folder named “com.apusapps.launcher-1” in /data/app path, and the APK file is located in that folder, named “base.apk”.

If we have already installed “APUS Launcher” before, and upgrading it to its new version (which means the existing APK file will be overwritten by the new version), the “com.apusapps.launcher-1” folder will be renamed to “com.apusapps.launcher-2” after the upgrading:

The secret is in the code of PackageManagerService.java (ref: https://android.googlesource.com/platform/frameworks/base/+/android-7.1.2_r36/services/core/java/com/android/server/pm/PackageManagerService.java):

private File getNextCodePath(File targetDir, String packageName) {
int suffix = 1;
File result;
do {
result = new File(targetDir, packageName + "-" + suffix);
suffix++;
} while (result.exists());
return result;
}

When PackageManagerService is installing an APK, it firstly install it into a temporary path (for example, /data/app/vmdl439623483.tmp/base.apk), and in the final steps, it will rename the temporary path to a final name (ref to installPackageLI method). To make sure the final name does not conflict with some existing path, it will increase the number of suffix repeatedly.

Since Android Oreo, the code has been changed (ref: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r36/services/core/java/com/android/server/pm/PackageManagerService.java):

private File getNextCodePath(File targetDir, String packageName) {
File result;
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[16];
do {
random.nextBytes(bytes);
String suffix = Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP);
result = new File(targetDir, packageName + "-" + suffix);
} while (result.exists());
return result;
}

Every time when renaming, it just take a random base64 string as the suffix. And also the base64 string will be changed when upgrading the APK to a new version.

Since the install location of the APK file has been changed into a random path, we can no longer guess the actual path of an installed app. UsingsourceDir to get the directory will be the only way. Now we can understand the statement of Google’s document.

--

--

Zhang quaful

Senior mobile developer, entrepreneur and open-source-enthusiasts.