diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-01-07 23:09:09 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-01-07 23:09:09 +0000 |
commit | 774ec6735dcbe4e9413c4bc804060f3c8bd206df (patch) | |
tree | 6e80bf578f14795c6f18f72be4d41b3fb1c6b064 | |
parent | 314cb2efb7b1d8d9b584a6e0bd82727168cfd181 (diff) | |
parent | 4bd59a3568c6b9248cf99d79cb9e7df11d965497 (diff) | |
download | dexmaker-pie-b4s4-release.tar.gz |
Snap for 5214323 from 4bd59a3568c6b9248cf99d79cb9e7df11d965497 to pi-b4s4-releaseandroid-9.0.0_r39android-9.0.0_r38pie-b4s4-release
Change-Id: I81a609d38bbb305d52af0bdc61cb6928ba8545f9
-rw-r--r-- | README.version | 1 | ||||
-rw-r--r-- | dexmaker-tests/src/androidTest/java/com/android/dx/AppDataDirGuesserTest.java | 27 | ||||
-rw-r--r-- | dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java | 47 |
3 files changed, 73 insertions, 2 deletions
diff --git a/README.version b/README.version index 92d3d64..7f1bbd0 100644 --- a/README.version +++ b/README.version @@ -12,3 +12,4 @@ Local Modifications: Allow to share classloader via dexmaker.share_classloader system property (I8c2490c3ec8e8582dc41c486f8f7a406bd635ebb) Allow 'Q' until we can replace the version check with a number based check Mark mocks as trusted (needs upstreaming) + Minimal change to correctly guess data directory when running in secondary users
\ No newline at end of file diff --git a/dexmaker-tests/src/androidTest/java/com/android/dx/AppDataDirGuesserTest.java b/dexmaker-tests/src/androidTest/java/com/android/dx/AppDataDirGuesserTest.java index b1ff25f..a4a3407 100644 --- a/dexmaker-tests/src/androidTest/java/com/android/dx/AppDataDirGuesserTest.java +++ b/dexmaker-tests/src/androidTest/java/com/android/dx/AppDataDirGuesserTest.java @@ -17,6 +17,7 @@ package com.android.dx; import android.os.Build; +import android.os.Process; import org.junit.Test; import java.io.File; @@ -49,6 +50,14 @@ public final class AppDataDirGuesserTest { } @Test + public void testGuessCacheDir_ForSecondaryUser() { + guessCacheDirFor("/data/app/a.b.c.apk:/data/app/d.e.f.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"); } @@ -121,14 +130,22 @@ public final class AppDataDirGuesserTest { } } + @Test + public void testGetProcessUid() { + AppDataDirGuesser guesser = new AppDataDirGuesser(); + assertTrue(guesser.getProcessUid() == Process.myUid()); + } + private interface TestCondition { TestCondition withNonWriteable(String... files); + TestCondition withProcessUid(Integer uid); void shouldGive(String... files); } private TestCondition guessCacheDirFor(final String path) { final Set<String> notWriteable = new HashSet<>(); return new TestCondition() { + private Integer processUid; public void shouldGive(String... files) { AppDataDirGuesser guesser = new AppDataDirGuesser() { @Override @@ -139,6 +156,10 @@ public final class AppDataDirGuesserTest { boolean fileOrDirExists(File file) { return true; } + @Override + Integer getProcessUid() { + return processUid; + } }; File[] results = guesser.guessPath(path); assertNotNull("Null results for " + path, results); @@ -152,6 +173,12 @@ public final class AppDataDirGuesserTest { notWriteable.addAll(Arrays.asList(files)); return this; } + + @Override + public TestCondition withProcessUid(Integer uid) { + processUid = uid; + return this; + } }; } } diff --git a/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java b/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java index fa0ef69..cc1d803 100644 --- a/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java +++ b/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java @@ -18,6 +18,7 @@ package com.android.dx; import java.io.File; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -25,6 +26,9 @@ import java.util.List; * Uses heuristics to guess the application's private data directory. */ class AppDataDirGuesser { + // Copied from UserHandle, indicates range of uids allocated for a user. + public static final int PER_USER_RANGE = 100000; + public File guess() { try { ClassLoader classLoader = guessSuitableClassLoader(); @@ -146,8 +150,14 @@ class AppDataDirGuesser { end = dash; } String packageName = potential.substring(start, end); - File dataDir = new File("/data/data/" + packageName); - if (isWriteableDirectory(dataDir)) { + File dataDir = getWriteableDirectory("/data/data/" + packageName); + + if (dataDir == null) { + // If we can't access "/data/data", try to guess user specific data directory. + dataDir = guessUserDataDirectory(packageName); + } + + if (dataDir != null) { File cacheDir = new File(dataDir, "cache"); // The cache directory might not exist -- create if necessary if (fileOrDirExists(cacheDir) || cacheDir.mkdir()) { @@ -179,4 +189,37 @@ class AppDataDirGuesser { boolean isWriteableDirectory(File file) { return file.isDirectory() && file.canWrite(); } + + Integer getProcessUid() { + /* Uses reflection to try to fetch process UID. It will only work when executing on + * Android device. Otherwise, returns null. + */ + try { + Method myUid = Class.forName("android.os.Process").getMethod("myUid"); + + // Invoke the method on a null instance, since it's a static method. + return (Integer) myUid.invoke(/* instance= */ null); + } catch (Exception e) { + // Catch any exceptions thrown and default to returning a null. + return null; + } + } + + File guessUserDataDirectory(String packageName) { + Integer uid = getProcessUid(); + if (uid == null) { + // If we couldn't retrieve process uid, return null. + return null; + } + + // We're trying to get the ID of the Android user that's running the process. It can be + // inferred from the UID of the current process. + int userId = uid / PER_USER_RANGE; + return getWriteableDirectory(String.format("/data/user/%d/%s", userId, packageName)); + } + + private File getWriteableDirectory(String pathName) { + File dir = new File(pathName); + return isWriteableDirectory(dir) ? dir : null; + } } |