From 9abf3f2b161e71da5b0c00353bd5379c0ea8b6c8 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 3 Jan 2023 17:37:05 +0800 Subject: [PATCH] More implementation --- .../org/lsposed/lspd/impl/LSPosedContext.java | 11 ++- .../lsposed/lspd/service/ConfigManager.java | 91 +++++++++---------- .../service/LSPInjectedModuleService.java | 11 +++ .../lspd/service/LSPModuleService.java | 25 +++-- .../libxposed/service/IXposedService.aidl | 1 + .../service/ILSPInjectedModuleService.aidl | 2 + 6 files changed, 82 insertions(+), 59 deletions(-) diff --git a/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java b/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java index f9994443..432c7283 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java @@ -28,6 +28,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Process; +import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.view.Display; @@ -42,7 +43,9 @@ import org.lsposed.lspd.util.LspModuleClassLoader; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -285,8 +288,12 @@ public class LSPosedContext extends XposedContext { } @Override - public FileInputStream openFileInput(String name) { - throw new AbstractMethodError(); + public FileInputStream openFileInput(String name) throws FileNotFoundException { + try { + return new FileInputStream(service.openRemoteFile(name).getFileDescriptor()); + } catch (RemoteException e) { + throw new FileNotFoundException(e.getMessage()); + } } @Override diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java index 61be348d..11b68b98 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -34,6 +34,7 @@ import android.content.pm.PackageParser; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; @@ -44,7 +45,6 @@ import android.os.SystemClock; import android.permission.IPermissionManager; import android.system.ErrnoException; import android.system.Os; -import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -172,7 +172,7 @@ public class ConfigManager { private final Map cachedModule = new ConcurrentHashMap<>(); // packageName, userId, group, key, value - private final Map, Map>> cachedConfig = new ConcurrentHashMap<>(); + private final Map, Map>> cachedConfig = new ConcurrentHashMap<>(); private void updateCaches(boolean sync) { synchronized (cacheHandler) { @@ -423,8 +423,8 @@ public class ConfigManager { } private @NonNull - Map> fetchModuleConfig(String name, int user_id) { - var config = new ConcurrentHashMap>(); + Map> fetchModuleConfig(String name, int user_id) { + var config = new ConcurrentHashMap>(); try (Cursor cursor = db.query("configs", new String[]{"`group`", "`key`", "data"}, "module_pkg_name = ? and user_id = ?", new String[]{name, String.valueOf(user_id)}, null, null, null)) { @@ -441,7 +441,7 @@ public class ConfigManager { var data = cursor.getBlob(dataIdx); var object = SerializationUtils.deserialize(data); if (object == null) continue; - config.computeIfAbsent(group, g -> new ConcurrentHashMap<>()).put(key, object); + config.computeIfAbsent(group, g -> new HashMap<>()).put(key, object); } } return config; @@ -455,33 +455,49 @@ public class ConfigManager { public void updateModulePrefs(String moduleName, int userId, String group, Map values) { var config = cachedConfig.computeIfAbsent(new Pair<>(moduleName, userId), module -> fetchModuleConfig(module.first, module.second)); - var prefs = config.computeIfAbsent(group, g -> new ConcurrentHashMap<>()); - executeInTransaction(() -> { - var contents = new ContentValues(); - for (var entry : values.entrySet()) { - var key = entry.getKey(); - var value = entry.getValue(); - if (value instanceof Serializable) { - prefs.put(key, value); - contents.put("`group`", group); - contents.put("`key`", key); - contents.put("data", SerializationUtils.serialize((Serializable) value)); - contents.put("module_pkg_name", moduleName); - contents.put("user_id", String.valueOf(userId)); - } else { - prefs.remove(key); - db.delete("configs", "module_pkg_name=? and user_id=? and `group`=? and `key`=?", new String[]{moduleName, String.valueOf(userId), group, key}); + config.compute(group, (g, prefs) -> { + HashMap newPrefs = prefs == null ? new HashMap<>() : new HashMap<>(prefs); + executeInTransaction(() -> { + var contents = new ContentValues(); + for (var entry : values.entrySet()) { + var key = entry.getKey(); + var value = entry.getValue(); + if (value instanceof Serializable) { + newPrefs.put(key, value); + contents.put("`group`", group); + contents.put("`key`", key); + contents.put("data", SerializationUtils.serialize((Serializable) value)); + contents.put("module_pkg_name", moduleName); + contents.put("user_id", String.valueOf(userId)); + } else { + newPrefs.remove(key); + db.delete("configs", "module_pkg_name=? and user_id=? and `group`=? and `key`=?", new String[]{moduleName, String.valueOf(userId), group, key}); + } + if (contents.size() > 0) { + db.insertWithOnConflict("configs", null, contents, SQLiteDatabase.CONFLICT_REPLACE); + } } - if (contents.size() > 0) { - db.insertWithOnConflict("configs", null, contents, SQLiteDatabase.CONFLICT_REPLACE); + var bundle = new Bundle(); + bundle.putSerializable("config", (Serializable) config); + if (bundle.size() > 1024 * 1024) { + throw new IllegalArgumentException("Preference too large"); } - } + }); + return newPrefs; }); } - public ConcurrentHashMap getModulePrefs(String moduleName, int userId, String group) { + public void deleteModulePrefs(String moduleName, int userId, String group) { + db.delete("configs", "module_pkg_name=? and user_id=? and `group`=?", new String[]{moduleName, String.valueOf(userId), group}); + var config = cachedConfig.getOrDefault(new Pair<>(moduleName, userId), null); + if (config != null) { + config.remove(group); + } + } + + public HashMap getModulePrefs(String moduleName, int userId, String group) { var config = cachedConfig.computeIfAbsent(new Pair<>(moduleName, userId), module -> fetchModuleConfig(module.first, module.second)); - return config.getOrDefault(group, new ConcurrentHashMap<>()); + return config.getOrDefault(group, new HashMap<>()); } private synchronized void clearCache() { @@ -1026,11 +1042,6 @@ public class ConfigManager { return null; } - public boolean isModule(int uid, String name) { - var module = cachedModule.getOrDefault(name, null); - return module != null && module.appId == uid % PER_USER_RANGE; - } - private void walkFileTree(Path rootDir, Consumer action) throws IOException { if (Files.notExists(rootDir)) return; Files.walkFileTree(rootDir, new SimpleFileVisitor<>() { @@ -1048,24 +1059,6 @@ public class ConfigManager { }); } - public void ensureModulePrefsPermission(int uid, String packageName) { - if (packageName == null) return; - var path = Paths.get(getPrefsPath(packageName, uid)); - try { - var perms = PosixFilePermissions.fromString("rwx--x--x"); - Files.createDirectories(path, PosixFilePermissions.asFileAttribute(perms)); - walkFileTree(path, p -> { - try { - Os.chown(p.toString(), uid, uid); - } catch (ErrnoException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } - }); - } catch (IOException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } - } - private void removeModulePrefs(int uid, String packageName) throws IOException { if (packageName == null) return; var path = Paths.get(getPrefsPath(packageName, uid)); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java index 9a01150e..0c8bcb93 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java @@ -4,6 +4,7 @@ import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE; import android.os.Binder; import android.os.Bundle; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import org.lsposed.lspd.models.Module; @@ -40,6 +41,16 @@ public class LSPInjectedModuleService extends ILSPInjectedModuleService.Stub { return bundle; } + @Override + public ParcelFileDescriptor openRemoteFile(String path) throws RemoteException { + try { + var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, path); + return ParcelFileDescriptor.open(absolutePath.toFile(), ParcelFileDescriptor.MODE_READ_ONLY); + } catch (Throwable e) { + throw new RemoteException(e.getMessage()); + } + } + void onUpdateRemotePreferences(String group, Bundle diff) { var groupCallbacks = callbacks.get(group); if (groupCallbacks != null) { diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java index be9e25d8..eb2210c6 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java @@ -102,11 +102,12 @@ public class LSPModuleService extends IXposedService.Stub { loadedModule = module; } - private void ensureModule() throws RemoteException { - var appId = Binder.getCallingUid() % PackageService.PER_USER_RANGE; + private int ensureModule() throws RemoteException { + var appId = Binder.getCallingUid() % PER_USER_RANGE; if (loadedModule.appId != appId) { throw new RemoteException("Module " + loadedModule.packageName + " is not for uid " + Binder.getCallingUid()); } + return Binder.getCallingUid() / PER_USER_RANGE; } @Override @@ -153,17 +154,15 @@ public class LSPModuleService extends IXposedService.Stub { @Override public Bundle requestRemotePreferences(String group) throws RemoteException { - ensureModule(); + var userId = ensureModule(); var bundle = new Bundle(); - var userId = Binder.getCallingUid() % PER_USER_RANGE; bundle.putSerializable("map", ConfigManager.getInstance().getModulePrefs(loadedModule.packageName, userId, group)); return bundle; } @Override public void updateRemotePreferences(String group, Bundle diff) throws RemoteException { - ensureModule(); - var userId = Binder.getCallingUid() / PackageService.PER_USER_RANGE; + var userId = ensureModule(); Map values = new ArrayMap<>(); if (diff.containsKey("delete")) { var deletes = diff.getStringArrayList("delete"); @@ -181,8 +180,18 @@ public class LSPModuleService extends IXposedService.Stub { Log.e(TAG, "updateRemotePreferences: ", e); } } - ConfigManager.getInstance().updateModulePrefs(loadedModule.packageName, userId, group, values); - ((LSPInjectedModuleService) loadedModule.service).onUpdateRemotePreferences(group, diff); + try { + ConfigManager.getInstance().updateModulePrefs(loadedModule.packageName, userId, group, values); + ((LSPInjectedModuleService) loadedModule.service).onUpdateRemotePreferences(group, diff); + } catch (Throwable e) { + throw new RemoteException(e.getMessage()); + } + } + + @Override + public void deleteRemotePreferences(String group) throws RemoteException { + var userId = ensureModule(); + ConfigManager.getInstance().deleteModulePrefs(loadedModule.packageName, userId, group); } @Override diff --git a/libxposed/service/src/main/aidl/io/github/libxposed/service/IXposedService.aidl b/libxposed/service/src/main/aidl/io/github/libxposed/service/IXposedService.aidl index 47ea517b..eeac9d25 100644 --- a/libxposed/service/src/main/aidl/io/github/libxposed/service/IXposedService.aidl +++ b/libxposed/service/src/main/aidl/io/github/libxposed/service/IXposedService.aidl @@ -18,6 +18,7 @@ interface IXposedService { // remote preference utilities Bundle requestRemotePreferences(String group) = 20; void updateRemotePreferences(String group, in Bundle diff) = 21; + void deleteRemotePreferences(String group) = 22; // remote file utilities ParcelFileDescriptor openRemoteFile(String path, int mode) = 30; diff --git a/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPInjectedModuleService.aidl b/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPInjectedModuleService.aidl index fd441240..234f4756 100644 --- a/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPInjectedModuleService.aidl +++ b/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPInjectedModuleService.aidl @@ -4,4 +4,6 @@ import org.lsposed.lspd.service.IRemotePreferenceCallback; interface ILSPInjectedModuleService { Bundle requestRemotePreferences(String group, IRemotePreferenceCallback callback); + + ParcelFileDescriptor openRemoteFile(String path); }