Use SharedMemory to load modules
This commit is contained in:
parent
258e10337d
commit
2d0a2bdd27
|
|
@ -16,7 +16,10 @@ import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.SharedMemory;
|
||||||
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
|
import android.system.OsConstants;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
|
@ -27,18 +30,21 @@ import org.lsposed.lspatch.share.Constants;
|
||||||
import org.lsposed.lspd.config.ApplicationServiceClient;
|
import org.lsposed.lspd.config.ApplicationServiceClient;
|
||||||
import org.lsposed.lspd.core.Main;
|
import org.lsposed.lspd.core.Main;
|
||||||
import org.lsposed.lspd.models.Module;
|
import org.lsposed.lspd.models.Module;
|
||||||
|
import org.lsposed.lspd.models.PreLoadedApk;
|
||||||
import org.lsposed.lspd.nativebridge.SigBypass;
|
import org.lsposed.lspd.nativebridge.SigBypass;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
@ -47,6 +53,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
import de.robv.android.xposed.XC_MethodHook;
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import de.robv.android.xposed.XposedBridge;
|
||||||
|
|
@ -191,8 +198,8 @@ public class LSPApplication extends ApplicationServiceClient {
|
||||||
if (target.lastModified() > lastInstalledTime) {
|
if (target.lastModified() > lastInstalledTime) {
|
||||||
embedded_modules.add(name);
|
embedded_modules.add(name);
|
||||||
var module = new Module();
|
var module = new Module();
|
||||||
module.apk = target.getAbsolutePath();
|
module.apkPath = target.getAbsolutePath();
|
||||||
module.name = target.getName();
|
module.packageName = target.getName();
|
||||||
LSPApplication.modules.add(module);
|
LSPApplication.modules.add(module);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -200,8 +207,8 @@ public class LSPApplication extends ApplicationServiceClient {
|
||||||
Files.copy(is, target.toPath());
|
Files.copy(is, target.toPath());
|
||||||
embedded_modules.add(name);
|
embedded_modules.add(name);
|
||||||
var module = new Module();
|
var module = new Module();
|
||||||
module.apk = target.getAbsolutePath();
|
module.apkPath = target.getAbsolutePath();
|
||||||
module.name = target.getName();
|
module.packageName = target.getName();
|
||||||
LSPApplication.modules.add(module);
|
LSPApplication.modules.add(module);
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
|
|
||||||
|
|
@ -227,19 +234,20 @@ public class LSPApplication extends ApplicationServiceClient {
|
||||||
}
|
}
|
||||||
if (app.metaData != null && app.metaData.containsKey("xposedminversion") && !embedded_modules.contains(app.packageName)) {
|
if (app.metaData != null && app.metaData.containsKey("xposedminversion") && !embedded_modules.contains(app.packageName)) {
|
||||||
var module = new Module();
|
var module = new Module();
|
||||||
module.apk = app.publicSourceDir;
|
module.apkPath = app.publicSourceDir;
|
||||||
module.name = app.packageName;
|
module.packageName = app.packageName;
|
||||||
LSPApplication.modules.add(module);
|
LSPApplication.modules.add(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final var new_modules = new JSONArray();
|
final var new_modules = new JSONArray();
|
||||||
LSPApplication.modules.forEach(m -> {
|
LSPApplication.modules.forEach(m -> {
|
||||||
try {
|
try {
|
||||||
|
m.file = loadModule(m.apkPath);
|
||||||
var module = new JSONObject();
|
var module = new JSONObject();
|
||||||
module.put("name", m.name);
|
module.put("name", m.packageName);
|
||||||
module.put("enabled", !disabled_modules.contains(m.name));
|
module.put("enabled", !disabled_modules.contains(m.packageName));
|
||||||
module.put("use_embed", embedded_modules.contains(m.name));
|
module.put("use_embed", embedded_modules.contains(m.packageName));
|
||||||
module.put("path", m.apk);
|
module.put("path", m.apkPath);
|
||||||
new_modules.put(module);
|
new_modules.put(module);
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
|
|
@ -257,6 +265,60 @@ public class LSPApplication extends ApplicationServiceClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void readDexes(ZipFile apkFile, List<SharedMemory> preLoadedDexes) {
|
||||||
|
int secondary = 2;
|
||||||
|
for (var dexFile = apkFile.getEntry("classes.dex"); dexFile != null;
|
||||||
|
dexFile = apkFile.getEntry("classes" + secondary + ".dex"), secondary++) {
|
||||||
|
try (var in = apkFile.getInputStream(dexFile)) {
|
||||||
|
var memory = SharedMemory.create(null, in.available());
|
||||||
|
var byteBuffer = memory.mapReadWrite();
|
||||||
|
Channels.newChannel(in).read(byteBuffer);
|
||||||
|
SharedMemory.unmap(byteBuffer);
|
||||||
|
memory.setProtect(OsConstants.PROT_READ);
|
||||||
|
preLoadedDexes.add(memory);
|
||||||
|
} catch (IOException | ErrnoException e) {
|
||||||
|
Log.w(TAG, "Can not load " + dexFile + " in " + apkFile, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readName(ZipFile apkFile, String initName, List<String> names) {
|
||||||
|
var initEntry = apkFile.getEntry(initName);
|
||||||
|
if (initEntry == null) return;
|
||||||
|
try (var in = apkFile.getInputStream(initEntry)) {
|
||||||
|
var reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
String name;
|
||||||
|
while ((name = reader.readLine()) != null) {
|
||||||
|
name = name.trim();
|
||||||
|
if (name.isEmpty() || name.startsWith("#")) continue;
|
||||||
|
names.add(name);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Can not open " + initEntry, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PreLoadedApk loadModule(String path) {
|
||||||
|
var file = new PreLoadedApk();
|
||||||
|
var preLoadedDexes = new ArrayList<SharedMemory>();
|
||||||
|
var moduleClassNames = new ArrayList<String>(1);
|
||||||
|
var moduleLibraryNames = new ArrayList<String>(1);
|
||||||
|
try (var apkFile = new ZipFile(path)) {
|
||||||
|
readDexes(apkFile, preLoadedDexes);
|
||||||
|
readName(apkFile, "assets/xposed_init", moduleClassNames);
|
||||||
|
readName(apkFile, "assets/native_init", moduleLibraryNames);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Can not open " + path, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (preLoadedDexes.isEmpty()) return null;
|
||||||
|
if (moduleClassNames.isEmpty()) return null;
|
||||||
|
file.preLoadedDexes = preLoadedDexes;
|
||||||
|
file.moduleClassNames = moduleClassNames;
|
||||||
|
file.moduleLibraryNames = moduleLibraryNames;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
public LSPApplication() {
|
public LSPApplication() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
core
2
core
|
|
@ -1 +1 @@
|
||||||
Subproject commit fe666de6eac0bac98cd0ea192d8cdcc7ea6b6d80
|
Subproject commit 89b6ddbb68c1256284153299036b0cfa8b887d9a
|
||||||
Loading…
Reference in New Issue