Skip to content

Commit

Permalink
guessPath not to depend on the first level of app directory
Browse files Browse the repository at this point in the history
We are updating apps' apk path to have a two-level structure.

Default apk path of an installed app:
Before: /data/app/[packageName]-[randomString]/base.apk
After: /data/app/[randomStringA]/[packageName]-[randomStringB]/base.apk

This CL fixes the path guessing assumption the apk dir is only one level
below the /data/app dir.

Fixes #155.
  • Loading branch information
schfan-1 authored and ttanxu committed Jan 28, 2020
1 parent 4d0ce55 commit 0cb9108
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,45 @@
public final class AppDataDirGuesserTest {
@Test
public void testGuessCacheDir_SimpleExample() {
guessCacheDirFor("/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor("/data/app/a.b.c.tests.apk").shouldGive("/data/data/a.b.c.tests/cache");
guessCacheDirFor("/data/app/a.b.c-xxx/base.apk")
.shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor("/data/app/a.b.c.tests-xxx/base.apk")
.shouldGive("/data/data/a.b.c.tests/cache");
}

@Test
public void testGuessCacheDir_MultipleResultsSeparatedByColon() {
guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk")
guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:/data/app/d.e.f-xxx/base.apk")
.shouldGive("/data/data/a.b.c/cache", "/data/data/d.e.f/cache");
}

@Test
public void testGuessCacheDir_NotWriteableSkipped() {
guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk")
guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:/data/app/d.e.f-xxx/base.apk")
.withNonWriteable("/data/data/a.b.c/cache")
.shouldGive("/data/data/d.e.f/cache");
}

@Test
public void testGuessCacheDir_ForSecondaryUser() {
guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.apk")
guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:/data/app/d.e.f-xxx/base.apk")
.withNonWriteable("/data/data/a.b.c", "/data/data/d.e.f")
.withProcessUid(1110009)
.shouldGive("/data/user/11/a.b.c/cache", "/data/user/11/d.e.f/cache");
}

@Test
public void testGuessCacheDir_StripHyphenatedSuffixes() {
guessCacheDirFor("/data/app/a.b.c-2.apk").shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor("/data/app/a.b.c-2/base.apk")
.shouldGive("/data/data/a.b.c/cache");
}

@Test
public void testGuessCacheDir_LeadingAndTrailingColonsIgnored() {
guessCacheDirFor("/data/app/a.b.c.apk:asdf:").shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor(":asdf:/data/app/a.b.c.apk").shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor("/data/app/a.b.c-xxx/base.apk:asdf:")
.shouldGive("/data/data/a.b.c/cache");
guessCacheDirFor(":asdf:/data/app/a.b.c-xxx/base.apk")
.shouldGive("/data/data/a.b.c/cache");
}

@Test
Expand All @@ -82,8 +87,38 @@ public void testGuessCacheDir_JarsIgnored() {
@Test
public void testGuessCacheDir_RealWorldExample() {
String realPath = "/system/framework/android.test.runner.jar:" +
"/data/app/com.google.android.voicesearch.tests-2.apk:" +
"/data/app/com.google.android.voicesearch-1.apk";
"/data/app/com.google.android.voicesearch.tests-2/base.apk:" +
"/data/app/com.google.android.voicesearch-1/base.apk";
guessCacheDirFor(realPath)
.withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
.shouldGive("/data/data/com.google.android.voicesearch/cache");
}

@Test
public void testGuessCacheDir_RealWorldExampleWithOneLevelSubDirectories() {
String realPath = "/system/framework/android.test.runner.jar:" +
"/data/app/com.google.android.voicesearch.tests-abcde/base.apk:" +
"/data/app/com.google.android.voicesearch-fghij/base.apk";
guessCacheDirFor(realPath)
.withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
.shouldGive("/data/data/com.google.android.voicesearch/cache");
}

@Test
public void testGuessCacheDir_RealWorldExampleWithTwoLevelSubDirectories() {
String realPath = "/system/framework/android.test.runner.jar:" +
"/data/app/abcde/com.google.android.voicesearch.tests-fghij/base.apk:" +
"/data/app/klmno/com.google.android.voicesearch-pqrst/base.apk";
guessCacheDirFor(realPath)
.withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
.shouldGive("/data/data/com.google.android.voicesearch/cache");
}

@Test
public void testGuessCacheDir_RealWorldExampleWithHyphensInPath() {
String realPath = "/system/framework/android.test.runner.jar:" +
"/data/app/a-b-c/com.google.android.voicesearch.tests-e-f-g/base.apk:" +
"/data/app/com.google.android.voicesearch-k-l-n/base.apk";
guessCacheDirFor(realPath)
.withNonWriteable("/data/data/com.google.android.voicesearch.tests/cache")
.shouldGive("/data/data/com.google.android.voicesearch/cache");
Expand Down
23 changes: 17 additions & 6 deletions dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,20 +136,31 @@ private static String processClassLoaderString43OrLater(String input) {

File[] guessPath(String input) {
List<File> results = new ArrayList<>();
String apkPathRoot = "/data/app/";
for (String potential : splitPathList(input)) {
if (!potential.startsWith("/data/app/")) {
if (!potential.startsWith(apkPathRoot)) {
continue;
}
int start = "/data/app/".length();
int end = potential.lastIndexOf(".apk");
if (end != potential.length() - 4) {
continue;
}
int dash = potential.indexOf("-");
if (dash != -1) {
end = dash;
int endSlash = potential.lastIndexOf("/", end);
if (endSlash == apkPathRoot.length() - 1) {
// Apks cannot be directly under /data/app
continue;
}
int startSlash = potential.lastIndexOf("/", endSlash - 1);
if (startSlash == -1) {
continue;
}
// Look for the first dash after the package name
int dash = potential.indexOf("-", startSlash);
if (dash == -1) {
continue;
}
String packageName = potential.substring(start, end);
end = dash;
String packageName = potential.substring(startSlash + 1, end);
File dataDir = getWriteableDirectory("/data/data/" + packageName);

if (dataDir == null) {
Expand Down

0 comments on commit 0cb9108

Please sign in to comment.