Implement RemotePreferences edit

This commit is contained in:
LoveSy 2023-01-03 16:43:48 +08:00 committed by LoveSy
parent cfe15100c0
commit 87db036fdf
4 changed files with 88 additions and 30 deletions

View File

@ -2,7 +2,6 @@ package org.lsposed.lspd.impl;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException;
import android.util.ArraySet; import android.util.ArraySet;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -53,8 +52,10 @@ public class LSPosedRemotePreferences implements SharedPreferences {
public LSPosedRemotePreferences(ILSPInjectedModuleService service, String group) { public LSPosedRemotePreferences(ILSPInjectedModuleService service, String group) {
try { try {
Bundle output = service.requestRemotePreferences(group, callback); Bundle output = service.requestRemotePreferences(group, callback);
callback.onUpdate(output); if (output.containsKey("map")) {
} catch (RemoteException e) { mMap.putAll((Map<String, Object>) output.getSerializable("map"));
}
} catch (Throwable e) {
XposedBridge.log(e); XposedBridge.log(e);
} }
} }

View File

@ -26,7 +26,6 @@ import android.content.res.AssetManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.Process; import android.os.Process;
import android.os.RemoteException;
import android.os.SELinux; import android.os.SELinux;
import android.os.SharedMemory; import android.os.SharedMemory;
import android.system.ErrnoException; import android.system.ErrnoException;

View File

@ -44,6 +44,7 @@ import android.os.SystemClock;
import android.permission.IPermissionManager; import android.permission.IPermissionManager;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.system.Os; import android.system.Os;
import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -447,21 +448,35 @@ public class ConfigManager {
} }
public void updateModulePrefs(String moduleName, int userId, String group, String key, Object value) { public void updateModulePrefs(String moduleName, int userId, String group, String key, Object value) {
Map<String, Object> values = new HashMap<>();
values.put(key, value);
updateModulePrefs(moduleName, userId, group, values);
}
public void updateModulePrefs(String moduleName, int userId, String group, Map<String, Object> values) {
var config = cachedConfig.computeIfAbsent(new Pair<>(moduleName, userId), module -> fetchModuleConfig(module.first, module.second)); var config = cachedConfig.computeIfAbsent(new Pair<>(moduleName, userId), module -> fetchModuleConfig(module.first, module.second));
var prefs = config.computeIfAbsent(group, g -> new ConcurrentHashMap<>()); var prefs = config.computeIfAbsent(group, g -> new ConcurrentHashMap<>());
if (value instanceof Serializable) { executeInTransaction(() -> {
prefs.put(key, value); var contents = new ContentValues();
var values = new ContentValues(); for (var entry : values.entrySet()) {
values.put("`group`", group); var key = entry.getKey();
values.put("`key`", key); var value = entry.getValue();
values.put("data", SerializationUtils.serialize((Serializable) value)); if (value instanceof Serializable) {
values.put("module_pkg_name", moduleName); prefs.put(key, value);
values.put("user_id", String.valueOf(userId)); contents.put("`group`", group);
db.insertWithOnConflict("configs", null, values, SQLiteDatabase.CONFLICT_REPLACE); contents.put("`key`", key);
} else { contents.put("data", SerializationUtils.serialize((Serializable) value));
prefs.remove(key); contents.put("module_pkg_name", moduleName);
db.delete("configs", "module_pkg_name=? and user_id=? and `group`=? and `key`=?", new String[]{moduleName, String.valueOf(userId), group, key}); 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<String, Object> getModulePrefs(String moduleName, int userId, String group) { public ConcurrentHashMap<String, Object> getModulePrefs(String moduleName, int userId, String group) {

View File

@ -19,19 +19,26 @@
package org.lsposed.lspd.service; package org.lsposed.lspd.service;
import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE;
import android.content.AttributionSource; import android.content.AttributionSource;
import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import org.lsposed.daemon.BuildConfig; import org.lsposed.daemon.BuildConfig;
import org.lsposed.lspd.models.Module; import org.lsposed.lspd.models.Module;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -44,7 +51,8 @@ public class LSPModuleService extends IXposedService.Stub {
private final static Set<Integer> uidSet = ConcurrentHashMap.newKeySet(); private final static Set<Integer> uidSet = ConcurrentHashMap.newKeySet();
private final Module loadedModule; private final @NonNull
Module loadedModule;
static void uidStarts(int uid) { static void uidStarts(int uid) {
if (!uidSet.contains(uid)) { if (!uidSet.contains(uid)) {
@ -90,32 +98,44 @@ public class LSPModuleService extends IXposedService.Stub {
} }
} }
LSPModuleService(Module module) { LSPModuleService(@NonNull Module module) {
loadedModule = 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 @Override
public int getAPIVersion() { public int getAPIVersion() throws RemoteException {
ensureModule();
return API; return API;
} }
@Override @Override
public String getFrameworkName() { public String getFrameworkName() throws RemoteException {
ensureModule();
return "LSPosed"; return "LSPosed";
} }
@Override @Override
public String getFrameworkVersion() { public String getFrameworkVersion() throws RemoteException {
ensureModule();
return BuildConfig.VERSION_NAME; return BuildConfig.VERSION_NAME;
} }
@Override @Override
public long getFrameworkVersionCode() { public long getFrameworkVersionCode() throws RemoteException {
ensureModule();
return BuildConfig.VERSION_CODE; return BuildConfig.VERSION_CODE;
} }
@Override @Override
public List<String> getScope() { public List<String> getScope() throws RemoteException {
ensureModule();
ArrayList<String> res = new ArrayList<>(); ArrayList<String> res = new ArrayList<>();
var scope = ConfigManager.getInstance().getModuleScope(loadedModule.packageName); var scope = ConfigManager.getInstance().getModuleScope(loadedModule.packageName);
if (scope == null) return res; if (scope == null) return res;
@ -126,19 +146,42 @@ public class LSPModuleService extends IXposedService.Stub {
} }
@Override @Override
public void requestScope(String packageName) { public void requestScope(String packageName) throws RemoteException {
ensureModule();
// TODO // TODO
} }
@Override @Override
public Bundle requestRemotePreferences(String group) { public Bundle requestRemotePreferences(String group) throws RemoteException {
// TODO ensureModule();
return null; var bundle = new Bundle();
var userId = Binder.getCallingUid() % PER_USER_RANGE;
bundle.putSerializable("map", ConfigManager.getInstance().getModulePrefs(loadedModule.packageName, userId, group));
return bundle;
} }
@Override @Override
public void updateRemotePreferences(String group, Bundle diff) { public void updateRemotePreferences(String group, Bundle diff) throws RemoteException {
// TODO ensureModule();
var userId = Binder.getCallingUid() / PackageService.PER_USER_RANGE;
Map<String, Object> 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); ((LSPInjectedModuleService) loadedModule.service).onUpdateRemotePreferences(group, diff);
} }