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.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<String, Object>) output.getSerializable("map"));
}
} catch (Throwable e) {
XposedBridge.log(e);
}
}

View File

@ -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;

View File

@ -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<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 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<String, Object> getModulePrefs(String moduleName, int userId, String group) {

View File

@ -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<Integer> 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<String> getScope() {
public List<String> getScope() throws RemoteException {
ensureModule();
ArrayList<String> 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<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);
}