From 87db036fdf17cb670554db984d926a7b9b7fbb2e Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 3 Jan 2023 16:43:48 +0800 Subject: [PATCH] Implement RemotePreferences edit --- .../lspd/impl/LSPosedRemotePreferences.java | 7 +- .../lspd/service/ConfigFileManager.java | 1 - .../lsposed/lspd/service/ConfigManager.java | 41 +++++++---- .../lspd/service/LSPModuleService.java | 69 +++++++++++++++---- 4 files changed, 88 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java b/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java index 4e9c843e..6d4eb277 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java @@ -2,7 +2,6 @@ package org.lsposed.lspd.impl; import android.content.SharedPreferences; import android.os.Bundle; -import android.os.RemoteException; import android.util.ArraySet; import androidx.annotation.Nullable; @@ -53,8 +52,10 @@ public class LSPosedRemotePreferences implements SharedPreferences { public LSPosedRemotePreferences(ILSPInjectedModuleService service, String group) { try { Bundle output = service.requestRemotePreferences(group, callback); - callback.onUpdate(output); - } catch (RemoteException e) { + if (output.containsKey("map")) { + mMap.putAll((Map) output.getSerializable("map")); + } + } catch (Throwable e) { XposedBridge.log(e); } } diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java index cb222926..7f8cab01 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -26,7 +26,6 @@ import android.content.res.AssetManager; import android.content.res.Resources; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.RemoteException; import android.os.SELinux; import android.os.SharedMemory; import android.system.ErrnoException; 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 7ddccc3a..61be348d 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -44,6 +44,7 @@ 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; @@ -447,21 +448,35 @@ public class ConfigManager { } public void updateModulePrefs(String moduleName, int userId, String group, String key, Object value) { + Map values = new HashMap<>(); + values.put(key, value); + updateModulePrefs(moduleName, userId, group, values); + } + + 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<>()); - if (value instanceof Serializable) { - prefs.put(key, value); - var values = new ContentValues(); - values.put("`group`", group); - values.put("`key`", key); - values.put("data", SerializationUtils.serialize((Serializable) value)); - values.put("module_pkg_name", moduleName); - values.put("user_id", String.valueOf(userId)); - db.insertWithOnConflict("configs", null, values, SQLiteDatabase.CONFLICT_REPLACE); - } 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}); - } + 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}); + } + if (contents.size() > 0) { + db.insertWithOnConflict("configs", null, contents, SQLiteDatabase.CONFLICT_REPLACE); + } + } + }); } public ConcurrentHashMap getModulePrefs(String moduleName, int userId, String group) { 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 40d6114a..be9e25d8 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java @@ -19,19 +19,26 @@ package org.lsposed.lspd.service; +import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE; + import android.content.AttributionSource; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.Log; +import androidx.annotation.NonNull; + import org.lsposed.daemon.BuildConfig; import org.lsposed.lspd.models.Module; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -44,7 +51,8 @@ public class LSPModuleService extends IXposedService.Stub { private final static Set uidSet = ConcurrentHashMap.newKeySet(); - private final Module loadedModule; + private final @NonNull + Module loadedModule; static void uidStarts(int uid) { if (!uidSet.contains(uid)) { @@ -90,32 +98,44 @@ public class LSPModuleService extends IXposedService.Stub { } } - LSPModuleService(Module module) { + LSPModuleService(@NonNull Module module) { loadedModule = module; } + private void ensureModule() throws RemoteException { + var appId = Binder.getCallingUid() % PackageService.PER_USER_RANGE; + if (loadedModule.appId != appId) { + throw new RemoteException("Module " + loadedModule.packageName + " is not for uid " + Binder.getCallingUid()); + } + } + @Override - public int getAPIVersion() { + public int getAPIVersion() throws RemoteException { + ensureModule(); return API; } @Override - public String getFrameworkName() { + public String getFrameworkName() throws RemoteException { + ensureModule(); return "LSPosed"; } @Override - public String getFrameworkVersion() { + public String getFrameworkVersion() throws RemoteException { + ensureModule(); return BuildConfig.VERSION_NAME; } @Override - public long getFrameworkVersionCode() { + public long getFrameworkVersionCode() throws RemoteException { + ensureModule(); return BuildConfig.VERSION_CODE; } @Override - public List getScope() { + public List getScope() throws RemoteException { + ensureModule(); ArrayList res = new ArrayList<>(); var scope = ConfigManager.getInstance().getModuleScope(loadedModule.packageName); if (scope == null) return res; @@ -126,19 +146,42 @@ public class LSPModuleService extends IXposedService.Stub { } @Override - public void requestScope(String packageName) { + public void requestScope(String packageName) throws RemoteException { + ensureModule(); // TODO } @Override - public Bundle requestRemotePreferences(String group) { - // TODO - return null; + public Bundle requestRemotePreferences(String group) throws RemoteException { + 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) { - // TODO + public void updateRemotePreferences(String group, Bundle diff) throws RemoteException { + ensureModule(); + var userId = Binder.getCallingUid() / PackageService.PER_USER_RANGE; + Map values = new ArrayMap<>(); + if (diff.containsKey("delete")) { + var deletes = diff.getStringArrayList("delete"); + for (var key : deletes) { + values.put(key, null); + } + } + if (diff.containsKey("put")) { + try { + var puts = (Map) diff.getSerializable("put"); + for (var entry : puts.entrySet()) { + values.put((String) entry.getKey(), entry.getValue()); + } + } catch (Throwable e) { + Log.e(TAG, "updateRemotePreferences: ", e); + } + } + ConfigManager.getInstance().updateModulePrefs(loadedModule.packageName, userId, group, values); ((LSPInjectedModuleService) loadedModule.service).onUpdateRemotePreferences(group, diff); }