Add more module service interfaces
This commit is contained in:
parent
acaf40ca44
commit
ffc20e2e72
|
|
@ -84,15 +84,6 @@ public class ApplicationServiceClient implements ILSPApplicationService, IBinder
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle requestRemotePreferences(String packageName, int userId, String group, IBinder callback) {
|
||||
try {
|
||||
return service.requestRemotePreferences(packageName, userId, group, callback);
|
||||
} catch (RemoteException | NullPointerException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor requestInjectedManagerBinder(List<IBinder> binder) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.lsposed.lspd.models.Module;
|
||||
import org.lsposed.lspd.service.ILSPInjectedModuleService;
|
||||
import org.lsposed.lspd.util.LspModuleClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -70,12 +71,14 @@ public class LSPosedContext extends XposedContext {
|
|||
private final Context mBase;
|
||||
private final String mPackageName;
|
||||
private final String mApkPath;
|
||||
private final ILSPInjectedModuleService service;
|
||||
private final Map<String, SharedPreferences> mRemotePrefs = new ConcurrentHashMap<>();
|
||||
|
||||
LSPosedContext(Context base, String packageName, String apkPath) {
|
||||
LSPosedContext(Context base, String packageName, String apkPath, ILSPInjectedModuleService service) {
|
||||
this.mBase = base;
|
||||
this.mPackageName = packageName;
|
||||
this.mApkPath = apkPath;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public static void callOnPackageLoaded(XposedModuleInterface.PackageLoadedParam param) {
|
||||
|
|
@ -143,7 +146,7 @@ public class LSPosedContext extends XposedContext {
|
|||
}
|
||||
args[i] = null;
|
||||
}
|
||||
var ctx = new LSPosedContext((Context) ctor.newInstance(args), module.packageName, module.apkPath);
|
||||
var ctx = new LSPosedContext((Context) ctor.newInstance(args), module.packageName, module.apkPath, module.service);
|
||||
for (var entry : module.file.moduleClassNames) {
|
||||
var moduleClass = ctx.getClassLoader().loadClass(entry);
|
||||
Log.d(TAG, " Loading class " + moduleClass);
|
||||
|
|
@ -267,7 +270,7 @@ public class LSPosedContext extends XposedContext {
|
|||
@Override
|
||||
public SharedPreferences getSharedPreferences(String name, int mode) {
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
return mRemotePrefs.computeIfAbsent(name, __ -> new LSPosedRemotePreferences(mPackageName, Process.myPid() / PER_USER_RANGE, name));
|
||||
return mRemotePrefs.computeIfAbsent(name, __ -> new LSPosedRemotePreferences(service, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package org.lsposed.lspd.impl;
|
||||
|
||||
import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.lsposed.lspd.service.ILSPInjectedModuleService;
|
||||
import org.lsposed.lspd.service.IRemotePreferenceCallback;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
|
@ -29,6 +30,14 @@ public class LSPosedRemotePreferences implements SharedPreferences {
|
|||
synchronized public void onUpdate(Bundle bundle) {
|
||||
if (bundle.containsKey("map"))
|
||||
mMap.putAll((Map<String, ?>) bundle.getSerializable("map"));
|
||||
if (bundle.containsKey("delete")) {
|
||||
for (var key : bundle.getStringArrayList("delete")) {
|
||||
mMap.remove(key);
|
||||
synchronized (mListeners) {
|
||||
mListeners.forEach((listener, __) -> listener.onSharedPreferenceChanged(LSPosedRemotePreferences.this, key));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bundle.containsKey("diff")) {
|
||||
for (var key : bundle.getStringArrayList("diff")) {
|
||||
synchronized (mListeners) {
|
||||
|
|
@ -39,9 +48,9 @@ public class LSPosedRemotePreferences implements SharedPreferences {
|
|||
}
|
||||
};
|
||||
|
||||
public LSPosedRemotePreferences(String packageName, int userId, String group) {
|
||||
public LSPosedRemotePreferences(ILSPInjectedModuleService service, String group) {
|
||||
try {
|
||||
Bundle output = serviceClient.requestRemotePreferences(packageName, userId, group, callback.asBinder());
|
||||
Bundle output = service.requestRemotePreferences(group, callback);
|
||||
callback.onUpdate(output);
|
||||
} catch (RemoteException e) {
|
||||
XposedBridge.log(e);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ 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;
|
||||
|
|
@ -77,6 +78,7 @@ import hidden.HiddenApiBridge;
|
|||
|
||||
public class ConfigFileManager {
|
||||
static final Path basePath = Paths.get("/data/adb/lspd");
|
||||
static final Path modulePath = basePath.resolve("modules");
|
||||
static final Path daemonApkPath = Paths.get(System.getProperty("java.class.path", null));
|
||||
static final Path managerApkPath = basePath.resolve("manager.apk");
|
||||
static final File magiskDbPath = new File("/data/adb/magisk.db");
|
||||
|
|
@ -427,6 +429,19 @@ public class ConfigFileManager {
|
|||
return preloadDex;
|
||||
}
|
||||
|
||||
static Path resolveModulePath(String packageName, String path) throws IOException {
|
||||
var requestPath = Paths.get(path);
|
||||
if (requestPath.isAbsolute()) {
|
||||
throw new IOException("path must be relative");
|
||||
}
|
||||
var moduleDir = modulePath.resolve(packageName).normalize();
|
||||
var absolutePath = moduleDir.resolve(requestPath).normalize();
|
||||
if (!absolutePath.startsWith(moduleDir)) {
|
||||
throw new IOException("path must be in module dir");
|
||||
}
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
private static class FileLocker {
|
||||
private final FileChannel lockChannel;
|
||||
private final FileLock locker;
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ public class ConfigManager {
|
|||
} catch (PackageParser.PackageParserException e) {
|
||||
Log.w(TAG, "failed to parse parse " + module.apkPath, e);
|
||||
}
|
||||
module.service = new LSPInjectedModuleService(module);
|
||||
modules.add(module);
|
||||
}
|
||||
}
|
||||
|
|
@ -1003,9 +1004,9 @@ public class ConfigManager {
|
|||
}
|
||||
|
||||
// this is slow, avoid using it
|
||||
public String getModule(int uid) {
|
||||
public Module getModule(int uid) {
|
||||
for (var module : cachedModule.values()) {
|
||||
if (module.appId == uid % PER_USER_RANGE) return module.packageName;
|
||||
if (module.appId == uid % PER_USER_RANGE) return module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ package org.lsposed.lspd.service;
|
|||
|
||||
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
|
@ -142,15 +141,6 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
|||
return ConfigManager.getInstance().getPrefsPath(packageName, getCallingUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle requestRemotePreferences(String packageName, int userId, String group, IBinder callback) throws RemoteException {
|
||||
ensureRegistered();
|
||||
// TODO: Handle callback
|
||||
var bundle = new Bundle();
|
||||
bundle.putSerializable("map", ConfigManager.getInstance().getModulePrefs(packageName, userId, group));
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor requestInjectedManagerBinder(List<IBinder> binder) throws RemoteException {
|
||||
var processInfo = ensureRegistered();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package org.lsposed.lspd.service;
|
||||
|
||||
import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import org.lsposed.lspd.models.Module;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class LSPInjectedModuleService extends ILSPInjectedModuleService.Stub {
|
||||
private final Module loadedModule;
|
||||
private final LSPModuleService moduleService;
|
||||
|
||||
Map<String, Set<IRemotePreferenceCallback>> callbacks = new ConcurrentHashMap<>();
|
||||
|
||||
LSPInjectedModuleService(Module module) {
|
||||
loadedModule = module;
|
||||
moduleService = new LSPModuleService(module);
|
||||
}
|
||||
|
||||
LSPModuleService getModuleService() {
|
||||
return moduleService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle requestRemotePreferences(String group, IRemotePreferenceCallback callback) throws RemoteException {
|
||||
var bundle = new Bundle();
|
||||
var userId = Binder.getCallingUid() % PER_USER_RANGE;
|
||||
bundle.putSerializable("map", ConfigManager.getInstance().getModulePrefs(loadedModule.packageName, userId, group));
|
||||
if (callback != null) {
|
||||
var groupCallbacks = callbacks.computeIfAbsent(group, k -> ConcurrentHashMap.newKeySet());
|
||||
groupCallbacks.add(callback);
|
||||
callback.asBinder().unlinkToDeath(() -> groupCallbacks.remove(callback), 0);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
void onUpdateRemotePreferences(String group, Bundle diff) {
|
||||
var groupCallbacks = callbacks.get(group);
|
||||
if (groupCallbacks != null) {
|
||||
for (var callback : groupCallbacks) {
|
||||
try {
|
||||
callback.onUpdate(diff);
|
||||
} catch (RemoteException e) {
|
||||
groupCallbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,13 +19,19 @@
|
|||
|
||||
package org.lsposed.lspd.service;
|
||||
|
||||
import android.app.IUidObserver;
|
||||
import android.content.AttributionSource;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Map;
|
||||
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.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
|
@ -37,15 +43,16 @@ public class LSPModuleService extends IXposedService.Stub {
|
|||
|
||||
|
||||
private final static Set<Integer> uidSet = ConcurrentHashMap.newKeySet();
|
||||
private final static Map<Integer, LSPModuleService> serviceMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final int uid;
|
||||
private final String packageName;
|
||||
private final Module loadedModule;
|
||||
|
||||
static void uidStarts(int uid) {
|
||||
if (!uidSet.contains(uid)) {
|
||||
uidSet.add(uid);
|
||||
sendBinder(getService(uid));
|
||||
var module = ConfigManager.getInstance().getModule(uid);
|
||||
if (module != null) {
|
||||
((LSPInjectedModuleService) module.service).getModuleService().sendBinder(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -53,10 +60,8 @@ public class LSPModuleService extends IXposedService.Stub {
|
|||
uidSet.remove(uid);
|
||||
}
|
||||
|
||||
private static void sendBinder(LSPModuleService service) {
|
||||
if (service == null) return;
|
||||
var uid = service.uid;
|
||||
var name = service.packageName;
|
||||
private void sendBinder(int uid) {
|
||||
var name = loadedModule.packageName;
|
||||
try {
|
||||
int userId = uid / PackageService.PER_USER_RANGE;
|
||||
var authority = name + AUTHORITY_SUFFIX;
|
||||
|
|
@ -66,11 +71,10 @@ public class LSPModuleService extends IXposedService.Stub {
|
|||
return;
|
||||
}
|
||||
var extra = new Bundle();
|
||||
extra.putBinder("binder", service.asBinder());
|
||||
extra.putBinder("binder", asBinder());
|
||||
Bundle reply = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
reply = provider.call(new AttributionSource.Builder(1000).setPackageName("android").build(),
|
||||
authority, SEND_BINDER, null, extra);
|
||||
reply = provider.call(new AttributionSource.Builder(1000).setPackageName("android").build(), authority, SEND_BINDER, null, extra);
|
||||
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
|
||||
reply = provider.call("android", null, authority, SEND_BINDER, null, extra);
|
||||
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
|
||||
|
|
@ -86,23 +90,78 @@ public class LSPModuleService extends IXposedService.Stub {
|
|||
}
|
||||
}
|
||||
|
||||
public static LSPModuleService getService(int uid) {
|
||||
var module = ConfigManager.getInstance().getModule(uid);
|
||||
if (module == null) return null;
|
||||
return serviceMap.computeIfAbsent(uid, __ -> new LSPModuleService(module, uid));
|
||||
}
|
||||
|
||||
public static void removeService(int uid) {
|
||||
serviceMap.remove(uid);
|
||||
}
|
||||
|
||||
private LSPModuleService(String name, int uid) {
|
||||
this.uid = uid;
|
||||
this.packageName = name;
|
||||
LSPModuleService(Module module) {
|
||||
loadedModule = module;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAPIVersion() {
|
||||
return API;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String implementationName() {
|
||||
return "LSPosed";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String implementationVersion() throws RemoteException {
|
||||
return BuildConfig.VERSION_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long implementationVersionCode() throws RemoteException {
|
||||
return BuildConfig.VERSION_CODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getScope() {
|
||||
ArrayList<String> res = new ArrayList<>();
|
||||
var scope = ConfigManager.getInstance().getModuleScope(loadedModule.packageName);
|
||||
if (scope == null) return res;
|
||||
for (var s : scope) {
|
||||
res.add(s.packageName);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestScope(String packageName) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle requestRemotePreferences(String group) throws RemoteException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRemotePreferences(String group, Bundle diff) throws RemoteException {
|
||||
// TODO
|
||||
((LSPInjectedModuleService) loadedModule.service).onUpdateRemotePreferences(group, diff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openRemoteFile(String path, int mode) throws RemoteException {
|
||||
try {
|
||||
var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, path);
|
||||
if (!absolutePath.getParent().toFile().mkdirs()) {
|
||||
throw new IOException("failed to create parent dir");
|
||||
}
|
||||
return ParcelFileDescriptor.open(absolutePath.toFile(), mode);
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteRemoteFile(String path) throws RemoteException {
|
||||
try {
|
||||
var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, path);
|
||||
return absolutePath.toFile().delete();
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import static org.lsposed.lspd.service.PackageService.PER_USER_RANGE;
|
|||
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
||||
import static org.lsposed.lspd.service.ServiceManager.getExecutorService;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IUidObserver;
|
||||
import android.content.IIntentReceiver;
|
||||
|
|
@ -96,7 +95,7 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
var allUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false);
|
||||
if (userId == USER_NULL) userId = uid % PER_USER_RANGE;
|
||||
Uri uri = intent.getData();
|
||||
String moduleName = (uri != null) ? uri.getSchemeSpecificPart() : ConfigManager.getInstance().getModule(uid);
|
||||
String moduleName = (uri != null) ? uri.getSchemeSpecificPart() : ConfigManager.getInstance().getModule(uid).packageName;
|
||||
|
||||
ApplicationInfo applicationInfo = null;
|
||||
if (moduleName != null) {
|
||||
|
|
|
|||
|
|
@ -5,5 +5,21 @@ interface IXposedService {
|
|||
const String AUTHORITY_SUFFIX = ".XposedService";
|
||||
const String SEND_BINDER = "SendBinder";
|
||||
|
||||
// framework details
|
||||
long getAPIVersion() = 1;
|
||||
String implementationName() = 2;
|
||||
String implementationVersion() = 3;
|
||||
long implementationVersionCode() = 4;
|
||||
|
||||
// scope utilities
|
||||
List<String> getScope() = 10;
|
||||
oneway void requestScope(String packageName) = 11;
|
||||
|
||||
// remote preference utilities
|
||||
Bundle requestRemotePreferences(String group) = 20;
|
||||
void updateRemotePreferences(String group, in Bundle diff) = 21;
|
||||
|
||||
// remote file utilities
|
||||
ParcelFileDescriptor openRemoteFile(String path, int mode) = 30;
|
||||
boolean deleteRemoteFile(String path) = 31;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.lsposed.lspd.models;
|
||||
import org.lsposed.lspd.models.PreLoadedApk;
|
||||
import org.lsposed.lspd.service.ILSPInjectedModuleService;
|
||||
|
||||
parcelable Module {
|
||||
String packageName;
|
||||
|
|
@ -7,4 +8,5 @@ parcelable Module {
|
|||
String apkPath;
|
||||
PreLoadedApk file;
|
||||
ApplicationInfo applicationInfo;
|
||||
ILSPInjectedModuleService service;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,5 @@ interface ILSPApplicationService {
|
|||
|
||||
String getPrefsPath(String packageName);
|
||||
|
||||
Bundle requestRemotePreferences(String packageName, int userId, String group, IBinder callback);
|
||||
|
||||
ParcelFileDescriptor requestInjectedManagerBinder(out List<IBinder> binder);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package org.lsposed.lspd.service;
|
||||
|
||||
import org.lsposed.lspd.service.IRemotePreferenceCallback;
|
||||
|
||||
interface ILSPInjectedModuleService {
|
||||
Bundle requestRemotePreferences(String group, IRemotePreferenceCallback callback);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.lsposed.lspd.impl;
|
||||
package org.lsposed.lspd.service;
|
||||
|
||||
interface IRemotePreferenceCallback {
|
||||
oneway void onUpdate(in Bundle map);
|
||||
Loading…
Reference in New Issue