Skip to content

Commit 728fb69

Browse files
author
维术
committed
[Exposed] try inject the systemclassloader instead; (do not replace the app classloader)
1 parent d2c74d5 commit 728fb69

File tree

2 files changed

+51
-24
lines changed

2 files changed

+51
-24
lines changed

exposed-core/src/main/java/me/weishu/exposed/ExposedBridge.java

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public class ExposedBridge {
6565
? "/data/user_de/0/de.robv.android.xposed.installer/" : BASE_DIR_LEGACY;
6666

6767
private static final String VERSION_KEY = "version";
68+
private static boolean SYSTEM_CLASSLOADER_INJECT = true;
69+
70+
private static final String WECHAT_PACKAGE = "com.tencent.mm";
6871

6972
private static Pair<String, Set<String>> lastModuleList = Pair.create(null, null);
7073
private static Map<ClassLoader, ClassLoader> exposedClassLoaderMap = new HashMap<>();
@@ -76,7 +79,7 @@ public class ExposedBridge {
7679
private static ModuleLoadListener sModuleLoadListener = new ModuleLoadListener() {
7780
@Override
7881
public void onLoadingModule(String moduleClassName, ApplicationInfo applicationInfo, ClassLoader appClassLoader) {
79-
if ("com.tencent.mm".equalsIgnoreCase(applicationInfo.packageName)) {
82+
if (WECHAT_PACKAGE.equalsIgnoreCase(applicationInfo.packageName)) {
8083
isWeChat = true;
8184
}
8285
}
@@ -100,6 +103,8 @@ enum ModuleLoadResult {
100103
}
101104

102105
public static void initOnce(Context context, ApplicationInfo applicationInfo, ClassLoader appClassLoader) {
106+
SYSTEM_CLASSLOADER_INJECT = patchSystemClassLoader();
107+
103108
appContext = context;
104109
ReLinker.loadLibrary(context, "epic");
105110
ExposedHelper.initSeLinux(applicationInfo.processName);
@@ -109,15 +114,31 @@ public static void initOnce(Context context, ApplicationInfo applicationInfo, Cl
109114
initForXposedInstaller(context, applicationInfo, appClassLoader);
110115
}
111116

112-
public static void patchAppClassLoader(Context baseContext) {
113-
final ClassLoader originClassLoader = baseContext.getClassLoader();
114-
Object mPackageInfo = XposedHelpers.getObjectField(baseContext, "mPackageInfo");
115-
ClassLoader appClassLoaderWithXposed = getAppClassLoaderWithXposed(originClassLoader);
116-
XposedHelpers.setObjectField(mPackageInfo, "mClassLoader", appClassLoaderWithXposed);
117-
Thread.currentThread().setContextClassLoader(appClassLoaderWithXposed);
117+
private static boolean patchSystemClassLoader() {
118+
// 1. first create XposedClassLoader -> BootstrapClassLoader
119+
ClassLoader xposedClassLoader = new XposedClassLoader(ExposedBridge.class.getClassLoader());
120+
121+
// 2. replace the systemclassloader's parent.
122+
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
123+
124+
try {
125+
Field parent = ClassLoader.class.getDeclaredField("parent");
126+
parent.setAccessible(true);
127+
parent.set(systemClassLoader, xposedClassLoader);
128+
129+
// SystemClassLoader -> XposedClassLoader -> BootstrapClassLoader
130+
return systemClassLoader.getParent() == xposedClassLoader;
131+
} catch (NoSuchFieldException e) {
132+
// todo no such field ? use unsafe.
133+
log(e);
134+
return false;
135+
} catch (IllegalAccessException e) {
136+
log(e);
137+
return false;
138+
}
118139
}
119140

120-
public static synchronized ClassLoader getAppClassLoaderWithXposed(ClassLoader appClassLoader) {
141+
private static synchronized ClassLoader getAppClassLoaderWithXposed(ClassLoader appClassLoader) {
121142
if (exposedClassLoaderMap.containsKey(appClassLoader)) {
122143
return exposedClassLoaderMap.get(appClassLoader);
123144
} else {
@@ -151,18 +172,26 @@ public static ModuleLoadResult loadModule(final String moduleApkPath, String mod
151172
return ModuleLoadResult.DISABLED;
152173
}
153174

154-
log("Loading modules from " + moduleApkPath + " for process: " + currentApplicationInfo.processName);
175+
log("Loading modules from " + moduleApkPath + " for process: " + currentApplicationInfo.processName + " i s c: " + SYSTEM_CLASSLOADER_INJECT);
155176

156177
if (!new File(moduleApkPath).exists()) {
157178
log(moduleApkPath + " does not exist");
158179
return ModuleLoadResult.NOT_EXIST;
159180
}
160181

161-
ClassLoader hostClassLoader = ExposedBridge.class.getClassLoader();
162-
ClassLoader appClassLoaderWithXposed = getAppClassLoaderWithXposed(appClassLoader);
163-
164-
ClassLoader mcl = new DexClassLoader(moduleApkPath, moduleOdexDir, moduleLibPath, getXposedClassLoader(hostClassLoader));
165-
// ClassLoader mcl = new DexClassLoader(moduleApkPath, moduleOdexDir, moduleLibPath, hostClassLoader);
182+
ClassLoader appClassLoaderWithXposed;
183+
ClassLoader mcl;
184+
if (SYSTEM_CLASSLOADER_INJECT) {
185+
// we replace the systemclassloader's parent success, go with xposed's way
186+
appClassLoaderWithXposed = appClassLoader;
187+
mcl = new DexClassLoader(moduleApkPath, moduleOdexDir, moduleLibPath, XposedBridge.BOOTCLASSLOADER);
188+
} else {
189+
// replace failed, just wrap.
190+
ClassLoader hostClassLoader = ExposedBridge.class.getClassLoader();
191+
appClassLoaderWithXposed = getAppClassLoaderWithXposed(appClassLoader);
192+
mcl = new DexClassLoader(moduleApkPath, moduleOdexDir, moduleLibPath, getXposedClassLoader(hostClassLoader));
193+
// ClassLoader mcl = new DexClassLoader(moduleApkPath, moduleOdexDir, moduleLibPath, hostClassLoader);
194+
}
166195

167196
InputStream is = mcl.getResourceAsStream("assets/xposed_init");
168197
if (is == null) {
@@ -226,10 +255,7 @@ public static ModuleLoadResult loadModule(final String moduleApkPath, String mod
226255
} catch (IOException e) {
227256
log(e);
228257
} finally {
229-
try {
230-
is.close();
231-
} catch (IOException ignored) {
232-
}
258+
closeSliently(is);
233259
}
234260
return ModuleLoadResult.FAILED;
235261
}
@@ -284,8 +310,6 @@ private static void initForXposedInstaller(Context context, ApplicationInfo appl
284310
return;
285311
}
286312

287-
Log.i(TAG, "initForXposedInstaller");
288-
289313
// XposedInstaller
290314
final int fakeXposedVersion = 91;
291315
final String fakeVersionString = String.valueOf(fakeXposedVersion);

exposed-core/src/main/java/me/weishu/exposed/XposedClassLoader.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,22 @@
33
/**
44
* XposedClassLoader: use to only load xposed api classes.
55
*/
6-
public class XposedClassLoader extends ClassLoader {
6+
class XposedClassLoader extends ClassLoader {
77

88
private ClassLoader mHostClassLoader;
9-
public XposedClassLoader(ClassLoader hostClassLoader) {
10-
super(ClassLoader.getSystemClassLoader()); // parent is BootClassLoader
9+
10+
XposedClassLoader(ClassLoader hostClassLoader) {
11+
super(ClassLoader.getSystemClassLoader().getParent()); // BootstrapClassLoader
1112
mHostClassLoader = hostClassLoader;
1213
}
1314

1415
@Override
1516
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
1617
if (name.startsWith("de.robv.android.xposed")
1718
|| name.startsWith("android")
18-
|| name.startsWith("external")) {
19+
|| name.startsWith("external")
20+
|| name.startsWith("me.weishu.epic.art")
21+
|| name.startsWith("com.taobao.android.dexposed")) {
1922
return mHostClassLoader.loadClass(name);
2023
}
2124
return super.loadClass(name, resolve);

0 commit comments

Comments
 (0)