[core] Move loadModule to ConfigFileManager (#1058)

This commit is contained in:
vvb2060 2021-09-05 16:07:30 +08:00 committed by GitHub
parent f8688a561a
commit 6cb3eacea8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 64 deletions

View File

@ -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();
} }

View File

@ -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());