Load module together with package name

This commit is contained in:
LoveSy 2021-05-21 05:10:09 +08:00 committed by LoveSy
parent 2eefe094d9
commit 9d417fa6cf
5 changed files with 46 additions and 40 deletions

View File

@ -7,7 +7,7 @@ interface ILSPApplicationService {
boolean isResourcesHookEnabled() = 5;
String[] getModulesList(String processName) = 6;
Map getModulesList(String processName) = 6;
String getPrefsPath(String packageName) = 7;

View File

@ -219,25 +219,25 @@ public final class XposedInit {
return false;
}
synchronized (moduleLoadLock) {
// TODO: process name
String[] moduleList = serviceClient.getModulesList();
var moduleList = serviceClient.getModulesList();
ArraySet<String> newLoadedApk = new ArraySet<>();
for (String apk : moduleList)
moduleList.forEach((name, apk) -> {
if (loadedModules.contains(apk)) {
newLoadedApk.add(apk);
} else {
loadedModules.add(apk); // temporarily add it for XSharedPreference
boolean loadSuccess = loadModule(apk);
boolean loadSuccess = loadModule(name, apk);
if (loadSuccess) {
newLoadedApk.add(apk);
}
}
loadedModules.clear();
loadedModules.addAll(newLoadedApk);
loadedModules.clear();
loadedModules.addAll(newLoadedApk);
// refresh callback according to current loaded module list
pruneCallbacks(loadedModules);
// refresh callback according to current loaded module list
pruneCallbacks(loadedModules);
});
}
return true;
}
@ -276,7 +276,7 @@ public final class XposedInit {
* Load all so from an APK by reading <code>assets/native_init</code>.
* It will only store the so names but not doing anything.
*/
private static boolean initNativeModule(ClassLoader mcl, String apk) {
private static boolean initNativeModule(ClassLoader mcl, String name) {
InputStream is = mcl.getResourceAsStream("assets/native_init");
if (is == null) return true;
BufferedReader moduleLibraryReader = new BufferedReader(new InputStreamReader(is));
@ -288,7 +288,7 @@ public final class XposedInit {
}
}
} catch (IOException e) {
Log.e(TAG, " Failed to load native library list from " + apk, e);
Log.e(TAG, " Failed to load native library list from " + name, e);
return false;
} finally {
closeSilently(is);
@ -297,7 +297,7 @@ public final class XposedInit {
}
private static boolean initModule(ClassLoader mcl, String apk) {
private static boolean initModule(ClassLoader mcl, String name, String apk) {
InputStream is = mcl.getResourceAsStream("assets/xposed_init");
if (is == null) {
return true;
@ -346,7 +346,7 @@ public final class XposedInit {
}
}
} catch (IOException e) {
Log.e(TAG, " Failed to load module from " + apk, e);
Log.e(TAG, " Failed to load module " + name + " from " + apk, e);
return false;
} finally {
closeSilently(is);
@ -359,8 +359,8 @@ public final class XposedInit {
* in <code>assets/xposed_init</code>.
*/
@SuppressLint("PrivateApi")
private static boolean loadModule(String apk) {
Log.i(TAG, "Loading modules from " + apk);
private static boolean loadModule(String name, String apk) {
Log.i(TAG, "Loading module " + name + " from " + apk);
if (!new File(apk).exists()) {
Log.e(TAG, " File does not exist");
@ -378,7 +378,7 @@ public final class XposedInit {
try {
if (mcl.loadClass(XposedBridge.class.getName()).getClassLoader() != initLoader) {
Log.e(TAG, " Cannot load module:");
Log.e(TAG, " Cannot load module: " + name);
Log.e(TAG, " The Xposed API classes are compiled into the module's APK.");
Log.e(TAG, " This may cause strange issues and must be fixed by the module developer.");
Log.e(TAG, " For details, see: http://api.xposed.info/using.html");
@ -387,7 +387,7 @@ public final class XposedInit {
} catch (ClassNotFoundException ignored) {
}
return initNativeModule(mcl, apk) && initModule(mcl, apk);
return initNativeModule(mcl, apk) && initModule(mcl, name, apk);
}
public final static HashSet<String> loadedPackagesInProcess = new HashSet<>(1);

View File

@ -24,6 +24,8 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import java.io.File;
import java.util.Collections;
import java.util.Map;
import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.util.Utils;
@ -86,15 +88,16 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
}
@Override
public String[] getModulesList(String processName) {
public Map<String, String> getModulesList(String processName) {
try {
//noinspection unchecked
return service.getModulesList(processName);
} catch (RemoteException | NullPointerException ignored) {
}
return new String[0];
return Collections.emptyMap();
}
public String[] getModulesList() {
public Map<String, String> getModulesList() {
return getModulesList(processName);
}

View File

@ -113,7 +113,7 @@ public class ConfigManager {
private final Handler cacheHandler;
private final ConcurrentHashMap<String, SharedMemory> moduleDexes = new ConcurrentHashMap<>();
private final Map<String, SharedMemory> moduleDexes = new ConcurrentHashMap<>();
private long lastModuleCacheTime = 0;
private long requestModuleCacheTime = 0;
@ -161,9 +161,9 @@ public class ConfigManager {
"PRIMARY KEY (mid, app_pkg_name, user_id)" +
");");
private final ConcurrentHashMap<ProcessScope, Set<String>> cachedScope = new ConcurrentHashMap<>();
private final Map<ProcessScope, Map<String, String>> cachedScope = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, String> cachedModule = new ConcurrentHashMap<>();
private final Map<Integer, String> cachedModule = new ConcurrentHashMap<>();
private void updateCaches(boolean sync) {
synchronized (this) {
@ -206,15 +206,16 @@ public class ConfigManager {
}
}
public String[] getModulesPathForSystemServer() {
HashSet<String> modules = new HashSet<>();
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"apk_path"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) {
public Map<String, String> getModulesForSystemServer() {
HashMap<String, String> modules = new HashMap<>();
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"module_pkg_name", "apk_path"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) {
int apkPathIdx = cursor.getColumnIndex("apk_path");
int pkgNameIdx = cursor.getColumnIndex("module_pkg_name");
while (cursor.moveToNext()) {
modules.add(cursor.getString(apkPathIdx));
modules.put(cursor.getString(pkgNameIdx), cursor.getString(apkPathIdx));
}
}
return modules.toArray(new String[0]);
return modules;
}
private static String readText(@NonNull File file) throws IOException {
@ -388,13 +389,14 @@ public class ConfigManager {
if (lastScopeCacheTime >= requestScopeCacheTime) return;
else lastScopeCacheTime = SystemClock.elapsedRealtime();
cachedScope.clear();
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"app_pkg_name", "user_id", "apk_path"},
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"app_pkg_name", "module_pkg_name", "user_id", "apk_path"},
"enabled = 1", null, null, null, null)) {
if (cursor == null) {
Log.e(TAG, "db cache failed");
return;
}
int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name");
int modulePkgNameIdx = cursor.getColumnIndex("module_pkg_name");
int userIdIdx = cursor.getColumnIndex("user_id");
int apkPathIdx = cursor.getColumnIndex("apk_path");
HashSet<Application> obsoletePackages = new HashSet<>();
@ -405,6 +407,7 @@ public class ConfigManager {
// system server always loads database
if (app.packageName.equals("android")) continue;
String apk_path = cursor.getString(apkPathIdx);
String module_pkg = cursor.getString(modulePkgNameIdx);
try {
List<ProcessScope> processesScope = getAssociatedProcesses(app);
if (processesScope.isEmpty()) {
@ -412,7 +415,7 @@ public class ConfigManager {
continue;
}
for (ProcessScope processScope : processesScope)
cachedScope.computeIfAbsent(processScope, ignored -> new HashSet<>()).add(apk_path);
cachedScope.computeIfAbsent(processScope, ignored -> new HashMap<>()).put(module_pkg, apk_path);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
@ -423,17 +426,17 @@ public class ConfigManager {
}
}
Log.d(TAG, "cached Scope");
for (ProcessScope ps : cachedScope.keySet()) {
cachedScope.forEach((ps, module) -> {
Log.d(TAG, ps.processName + "/" + ps.uid);
for (String apk : cachedScope.get(ps)) {
Log.d(TAG, "\t" + apk);
}
}
module.forEach((pkg_name, apk_path) -> {
Log.d(TAG, "\t" + pkg_name);
});
});
}
// This is called when a new process created, use the cached result
public String[] getModulesPathForProcess(String processName, int uid) {
return isManager(uid) ? new String[0] : cachedScope.getOrDefault(new ProcessScope(processName, uid), Collections.emptySet()).toArray(new String[0]);
public Map<String, String> getModulesForProcess(String processName, int uid) {
return isManager(uid) ? Collections.emptyMap() : cachedScope.getOrDefault(new ProcessScope(processName, uid), Collections.emptyMap());
}
// This is called when a new process created, use the cached result

View File

@ -67,13 +67,13 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
}
@Override
public String[] getModulesList(String processName) throws RemoteException {
public Map<String, String> getModulesList(String processName) throws RemoteException {
ensureRegistered();
int callingUid = getCallingUid();
if (callingUid == 1000 && processName.equals("android")) {
return ConfigManager.getInstance().getModulesPathForSystemServer();
return ConfigManager.getInstance().getModulesForSystemServer();
}
return ConfigManager.getInstance().getModulesPathForProcess(processName, callingUid);
return ConfigManager.getInstance().getModulesForProcess(processName, callingUid);
}
@Override