Load module together with package name
This commit is contained in:
parent
2eefe094d9
commit
9d417fa6cf
|
|
@ -7,7 +7,7 @@ interface ILSPApplicationService {
|
|||
|
||||
boolean isResourcesHookEnabled() = 5;
|
||||
|
||||
String[] getModulesList(String processName) = 6;
|
||||
Map getModulesList(String processName) = 6;
|
||||
|
||||
String getPrefsPath(String packageName) = 7;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue