From 2e927133e0a0a84191a1087f246d1cecf897250a Mon Sep 17 00:00:00 2001 From: Lev Rumyantsev Date: Wed, 17 Jun 2026 12:12:27 -0700 Subject: [PATCH] Support BaseDexClassLoader in AppDataDirGuesser AppDataDirGuesser was strictly casting the ClassLoader to PathClassLoader. This fails if the test is run under a different ClassLoader (like DexClassLoader or InMemoryDexClassLoader), which can happen in automated test runs or guest execution environments. By casting to BaseDexClassLoader instead, we support all standard Android class loaders since they all inherit from BaseDexClassLoader and use DexPathList internally. Also added a fallback to ActivityThread.currentApplication().getCacheDir() if the class loader guessing still fails. --- .../com/android/dx/AppDataDirGuesser.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java b/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java index 4a591bf..f6aca1c 100644 --- a/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java +++ b/dexmaker/src/main/java/com/android/dx/AppDataDirGuesser.java @@ -34,7 +34,7 @@ public File guess() { try { ClassLoader classLoader = guessSuitableClassLoader(); // Check that we have an instance of the PathClassLoader. - Class clazz = Class.forName("dalvik.system.PathClassLoader"); + Class clazz = Class.forName("dalvik.system.BaseDexClassLoader"); clazz.cast(classLoader); // Use the toString() method to calculate the data directory. String pathFromThisClassLoader = getPathFromThisClassLoader(classLoader, clazz); @@ -44,7 +44,16 @@ public File guess() { } } catch (ClassCastException ignored) { } catch (ClassNotFoundException ignored) { + } catch (Throwable ignored) { } + + // Fallback + File fallback = guessContextCacheDir(); + if (fallback != null) { + System.out.println("DexMaker: Guessed dexcache directory via ActivityThread: " + fallback.getAbsolutePath()); + return fallback; + } + return null; } @@ -217,6 +226,25 @@ Integer getProcessUid() { } } + private File guessContextCacheDir() { + try { + Class activityThreadClass = Class.forName("android.app.ActivityThread"); + Method currentApplicationMethod = activityThreadClass.getMethod("currentApplication"); + Object app = currentApplicationMethod.invoke(null); + if (app != null) { + Method getCacheDirMethod = app.getClass().getMethod("getCacheDir"); + File cacheDir = (File) getCacheDirMethod.invoke(app); + if (cacheDir != null) { + if (isWriteableDirectory(cacheDir)) { + return cacheDir; + } + } + } + } catch (Throwable ignored) { + } + return null; + } + File guessUserDataDirectory(String packageName) { Integer uid = getProcessUid(); if (uid == null) {