aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-01-07 23:09:09 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-01-07 23:09:09 +0000
commit774ec6735dcbe4e9413c4bc804060f3c8bd206df (patch)
tree6e80bf578f14795c6f18f72be4d41b3fb1c6b064
parent314cb2efb7b1d8d9b584a6e0bd82727168cfd181 (diff)
parent4bd59a3568c6b9248cf99d79cb9e7df11d965497 (diff)
downloaddexmaker-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.version1
-rw-r--r--dexmaker-tests/src/androidTest/java/com/android/dx/AppDataDirGuesserTest.java27
-rw-r--r--dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java47
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;
+ }
}