Parallize module cache and preload (#1681)
This commit is contained in:
parent
26f414ff03
commit
36d1f8dba7
|
|
@ -35,8 +35,23 @@
|
|||
#include "slicer/writer.h"
|
||||
#include "obfuscation.h"
|
||||
|
||||
namespace {
|
||||
std::mutex init_lock{};
|
||||
std::string obfuscated_signature;
|
||||
const std::string old_signature = "Lde/robv/android/xposed";
|
||||
|
||||
jclass class_file_descriptor;
|
||||
jmethodID method_file_descriptor_ctor;
|
||||
|
||||
jclass class_shared_memory;
|
||||
jmethodID method_shared_memory_ctor;
|
||||
|
||||
bool inited = false;
|
||||
}
|
||||
|
||||
void maybeInit(JNIEnv *env) {
|
||||
if (inited.test_and_set(std::memory_order_acq_rel)) [[likely]] return;
|
||||
if (inited) [[likely]] return;
|
||||
std::lock_guard l(init_lock);
|
||||
LOGD("ObfuscationManager.init");
|
||||
if (auto file_descriptor = JNI_FindClass(env, "java/io/FileDescriptor")) {
|
||||
class_file_descriptor = JNI_NewGlobalRef(env, file_descriptor);
|
||||
|
|
@ -96,6 +111,7 @@ void maybeInit(JNIEnv *env) {
|
|||
|
||||
LOGD("ObfuscationManager.getObfuscatedSignature: %s", obfuscated_signature.c_str());
|
||||
LOGD("ObfuscationManager init successfully");
|
||||
inited = true;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
|
|
|||
|
|
@ -21,17 +21,6 @@
|
|||
#include <string>
|
||||
#include "jni_helper.h"
|
||||
|
||||
static std::string obfuscated_signature;
|
||||
static const std::string old_signature = "Lde/robv/android/xposed";
|
||||
|
||||
static std::atomic_flag inited;
|
||||
|
||||
static jclass class_file_descriptor;
|
||||
static jmethodID method_file_descriptor_ctor;
|
||||
|
||||
static jclass class_shared_memory;
|
||||
static jmethodID method_shared_memory_ctor;
|
||||
|
||||
class WA: public dex::Writer::Allocator {
|
||||
// addr: {size, fd}
|
||||
std::unordered_map<void*, std::pair<size_t, int>> allocated_;
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ import java.util.UUID;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
|
@ -196,25 +197,23 @@ public class ConfigManager {
|
|||
int apkPathIdx = cursor.getColumnIndex("apk_path");
|
||||
int pkgNameIdx = cursor.getColumnIndex("module_pkg_name");
|
||||
while (cursor.moveToNext()) {
|
||||
var path = cursor.getString(apkPathIdx);
|
||||
var packageName = cursor.getString(pkgNameIdx);
|
||||
var m = cachedModule.computeIfAbsent(packageName, p -> {
|
||||
var module = new Module();
|
||||
var file = ConfigFileManager.loadModule(path, dexObfuscate);
|
||||
if (file == null) {
|
||||
Log.w(TAG, "Can not load " + path + ", skip!");
|
||||
return null;
|
||||
}
|
||||
module.packageName = cursor.getString(pkgNameIdx);
|
||||
module.apkPath = path;
|
||||
module.file = file;
|
||||
module.appId = -1;
|
||||
return module;
|
||||
});
|
||||
if (m != null) modules.add(m);
|
||||
var module = new Module();
|
||||
module.apkPath = cursor.getString(apkPathIdx);
|
||||
module.packageName = cursor.getString(pkgNameIdx);
|
||||
module.appId = -1;
|
||||
modules.add(module);
|
||||
}
|
||||
}
|
||||
return modules;
|
||||
return modules.parallelStream().filter(m -> {
|
||||
var file = ConfigFileManager.loadModule(m.apkPath, dexObfuscate);
|
||||
if (file == null) {
|
||||
Log.w(TAG, "Can not load " + m.apkPath + ", skip!");
|
||||
return false;
|
||||
}
|
||||
m.file = file;
|
||||
cachedModule.put(m.packageName, m);
|
||||
return true;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private synchronized void updateConfig() {
|
||||
|
|
@ -455,9 +454,9 @@ public class ConfigManager {
|
|||
}
|
||||
int pkgNameIdx = cursor.getColumnIndex("module_pkg_name");
|
||||
int apkPathIdx = cursor.getColumnIndex("apk_path");
|
||||
Set<String> obsoleteModules = new HashSet<>();
|
||||
Set<String> obsoleteModules = ConcurrentHashMap.newKeySet();
|
||||
// packageName, apkPath
|
||||
Map<String, String> obsoletePaths = new HashMap<>();
|
||||
Map<String, String> obsoletePaths = new ConcurrentHashMap<>();
|
||||
cachedModule.values().removeIf(m -> {
|
||||
if (m.apkPath == null || !existsInGlobalNamespace(m.apkPath)) {
|
||||
toClose.addAll(m.file.preLoadedDexes);
|
||||
|
|
@ -465,52 +464,60 @@ public class ConfigManager {
|
|||
}
|
||||
return false;
|
||||
});
|
||||
List<Module> modules = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
String packageName = cursor.getString(pkgNameIdx);
|
||||
String apkPath = cursor.getString(apkPathIdx);
|
||||
if (packageName.equals("lspd")) continue;
|
||||
// if still present after removeIf, this package did not change.
|
||||
var oldModule = cachedModule.get(packageName);
|
||||
var module = new Module();
|
||||
module.packageName = packageName;
|
||||
module.apkPath = apkPath;
|
||||
modules.add(module);
|
||||
}
|
||||
|
||||
modules.stream().parallel().filter(m -> {
|
||||
var oldModule = cachedModule.get(m.packageName);
|
||||
PackageInfo pkgInfo = null;
|
||||
try {
|
||||
pkgInfo = PackageService.getPackageInfoFromAllUsers(packageName, MATCH_ALL_FLAGS).values().stream().findFirst().orElse(null);
|
||||
pkgInfo = PackageService.getPackageInfoFromAllUsers(m.packageName, MATCH_ALL_FLAGS).values().stream().findFirst().orElse(null);
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, "get package info of " + packageName, e);
|
||||
Log.w(TAG, "get package info of " + m.packageName, e);
|
||||
}
|
||||
if (pkgInfo == null || pkgInfo.applicationInfo == null) {
|
||||
obsoleteModules.add(packageName);
|
||||
continue;
|
||||
obsoleteModules.add(m.packageName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (oldModule != null &&
|
||||
pkgInfo.applicationInfo.sourceDir != null &&
|
||||
apkPath != null && oldModule.apkPath != null &&
|
||||
existsInGlobalNamespace(apkPath) &&
|
||||
Objects.equals(apkPath, oldModule.apkPath) &&
|
||||
Objects.equals(new File(pkgInfo.applicationInfo.sourceDir).getParent(), new File(apkPath).getParent())) {
|
||||
m.apkPath != null && oldModule.apkPath != null &&
|
||||
existsInGlobalNamespace(m.apkPath) &&
|
||||
Objects.equals(m.apkPath, oldModule.apkPath) &&
|
||||
Objects.equals(new File(pkgInfo.applicationInfo.sourceDir).getParent(), new File(m.apkPath).getParent())) {
|
||||
if (oldModule.appId != -1) {
|
||||
Log.d(TAG, packageName + " did not change, skip caching it");
|
||||
Log.d(TAG, m.packageName + " did not change, skip caching it");
|
||||
} else {
|
||||
// cache from system server, keep it and set only the appId
|
||||
oldModule.appId = pkgInfo.applicationInfo.uid;
|
||||
}
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
apkPath = getModuleApkPath(pkgInfo.applicationInfo);
|
||||
if (apkPath == null) obsoleteModules.add(packageName);
|
||||
else obsoletePaths.put(packageName, apkPath);
|
||||
var file = ConfigFileManager.loadModule(apkPath, dexObfuscate);
|
||||
m.apkPath = getModuleApkPath(pkgInfo.applicationInfo);
|
||||
if (m.apkPath == null) obsoleteModules.add(m.packageName);
|
||||
else obsoletePaths.put(m.packageName, m.apkPath);
|
||||
m.appId = pkgInfo.applicationInfo.uid;
|
||||
return true;
|
||||
}).forEach(m -> {
|
||||
var file = ConfigFileManager.loadModule(m.apkPath, dexObfuscate);
|
||||
if (file == null) {
|
||||
Log.w(TAG, "failed to load module " + packageName);
|
||||
obsoleteModules.add(packageName);
|
||||
continue;
|
||||
Log.w(TAG, "failed to load module " + m.packageName);
|
||||
obsoleteModules.add(m.packageName);
|
||||
return;
|
||||
}
|
||||
var module = new Module();
|
||||
module.apkPath = apkPath;
|
||||
module.packageName = packageName;
|
||||
module.file = file;
|
||||
module.appId = pkgInfo.applicationInfo.uid;
|
||||
cachedModule.put(packageName, module);
|
||||
}
|
||||
m.file = file;
|
||||
cachedModule.put(m.packageName, m);
|
||||
});
|
||||
|
||||
if (PackageService.isAlive()) {
|
||||
obsoleteModules.forEach(this::removeModuleWithoutCache);
|
||||
obsoletePaths.forEach((packageName, path) -> updateModuleApkPath(packageName, path, true));
|
||||
|
|
|
|||
Loading…
Reference in New Issue