[core] Move loadModule to ConfigFileManager (#1058)
This commit is contained in:
parent
f8688a561a
commit
6cb3eacea8
|
|
@ -1,15 +1,25 @@
|
||||||
package org.lsposed.lspd.service;
|
package org.lsposed.lspd.service;
|
||||||
|
|
||||||
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
import static org.lsposed.lspd.service.ServiceManager.toGlobalNamespace;
|
||||||
|
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.SELinux;
|
import android.os.SELinux;
|
||||||
|
import android.os.SharedMemory;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.OsConstants;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.lsposed.lspd.models.PreLoadedApk;
|
||||||
import org.lsposed.lspd.util.Utils;
|
import org.lsposed.lspd.util.Utils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.channels.FileLock;
|
import java.nio.channels.FileLock;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
|
|
@ -23,9 +33,12 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.nio.file.attribute.PosixFilePermissions;
|
import java.nio.file.attribute.PosixFilePermissions;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
class ConfigFileManager {
|
class ConfigFileManager {
|
||||||
static final Path basePath = Paths.get("/data/adb/lspd");
|
static final Path basePath = Paths.get("/data/adb/lspd");
|
||||||
|
|
@ -122,6 +135,62 @@ class ConfigFileManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
static PreLoadedApk loadModule(String path) {
|
||||||
|
if (path == null) return null;
|
||||||
|
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(toGlobalNamespace(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;
|
||||||
|
}
|
||||||
|
|
||||||
private static String readText(Path file) throws IOException {
|
private static String readText(Path file) throws IOException {
|
||||||
return new String(Files.readAllBytes(file)).trim();
|
return new String(Files.readAllBytes(file)).trim();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,9 @@ import android.os.HandlerThread;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.SELinux;
|
import android.os.SELinux;
|
||||||
import android.os.SharedMemory;
|
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.system.ErrnoException;
|
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 android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
|
@ -51,15 +49,11 @@ import org.apache.commons.lang3.SerializationUtils;
|
||||||
import org.lsposed.lspd.BuildConfig;
|
import org.lsposed.lspd.BuildConfig;
|
||||||
import org.lsposed.lspd.models.Application;
|
import org.lsposed.lspd.models.Application;
|
||||||
import org.lsposed.lspd.models.Module;
|
import org.lsposed.lspd.models.Module;
|
||||||
import org.lsposed.lspd.models.PreLoadedApk;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
@ -191,7 +185,7 @@ public class ConfigManager {
|
||||||
var packageName = cursor.getString(pkgNameIdx);
|
var packageName = cursor.getString(pkgNameIdx);
|
||||||
var m = cachedModule.computeIfAbsent(packageName, p -> {
|
var m = cachedModule.computeIfAbsent(packageName, p -> {
|
||||||
var module = new Module();
|
var module = new Module();
|
||||||
var file = loadModule(path);
|
var file = ConfigFileManager.loadModule(path);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
Log.w(TAG, "Can not load " + path + ", skip!");
|
Log.w(TAG, "Can not load " + path + ", skip!");
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -408,7 +402,7 @@ public class ConfigManager {
|
||||||
apkPath = getModuleApkPath(pkgInfo.applicationInfo);
|
apkPath = getModuleApkPath(pkgInfo.applicationInfo);
|
||||||
if (apkPath == null) obsoleteModules.add(packageName);
|
if (apkPath == null) obsoleteModules.add(packageName);
|
||||||
else obsoletePaths.put(packageName, apkPath);
|
else obsoletePaths.put(packageName, apkPath);
|
||||||
var file = loadModule(apkPath);
|
var file = ConfigFileManager.loadModule(apkPath);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
Log.w(TAG, "failed to load module " + packageName);
|
Log.w(TAG, "failed to load module " + packageName);
|
||||||
obsoleteModules.add(packageName);
|
obsoleteModules.add(packageName);
|
||||||
|
|
@ -525,62 +519,6 @@ public class ConfigManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private 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 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private PreLoadedApk loadModule(String path) {
|
|
||||||
if (path == null) return null;
|
|
||||||
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(toGlobalNamespace(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is called when a new process created, use the cached result
|
// This is called when a new process created, use the cached result
|
||||||
public List<Module> getModulesForProcess(String processName, int uid) {
|
public List<Module> getModulesForProcess(String processName, int uid) {
|
||||||
return isManager(uid) ? Collections.emptyList() : cachedScope.getOrDefault(new ProcessScope(processName, uid), Collections.emptyList());
|
return isManager(uid) ? Collections.emptyList() : cachedScope.getOrDefault(new ProcessScope(processName, uid), Collections.emptyList());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue