Refactor ApplicationService (#1775)

This commit is contained in:
LoveSy 2022-03-20 08:44:17 +08:00 committed by GitHub
parent 3049dbb29b
commit 416167a226
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 125 additions and 122 deletions

View File

@ -1,6 +1,6 @@
package de.robv.android.xposed; package de.robv.android.xposed;
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient; import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;

View File

@ -20,7 +20,7 @@
package de.robv.android.xposed; package de.robv.android.xposed;
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient; import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;

View File

@ -20,7 +20,7 @@
package de.robv.android.xposed; package de.robv.android.xposed;
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient; import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import static org.lsposed.lspd.deopt.PrebuiltMethodsDeopter.deoptResourceMethods; import static org.lsposed.lspd.deopt.PrebuiltMethodsDeopter.deoptResourceMethods;
import static de.robv.android.xposed.XposedBridge.hookAllMethods; import static de.robv.android.xposed.XposedBridge.hookAllMethods;
import static de.robv.android.xposed.XposedHelpers.callMethod; import static de.robv.android.xposed.XposedHelpers.callMethod;

View File

@ -1,24 +0,0 @@
package org.lsposed.lspd.config;
import android.os.IBinder;
import org.lsposed.lspd.models.Module;
import org.lsposed.lspd.service.ILSPApplicationService;
import java.util.List;
abstract public class ApplicationServiceClient implements ILSPApplicationService {
public static ApplicationServiceClient serviceClient = null;
@Override
abstract public IBinder requestModuleBinder(String name);
@Override
abstract public List<Module> getModulesList(String processName);
abstract public List<Module> getModulesList();
@Override
abstract public String getPrefsPath(String packageName);
}

View File

@ -17,13 +17,15 @@
* Copyright (C) 2021 LSPosed Contributors * Copyright (C) 2021 LSPosed Contributors
*/ */
package org.lsposed.lspd.config; package org.lsposed.lspd.core;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import androidx.annotation.NonNull;
import org.lsposed.lspd.models.Module; import org.lsposed.lspd.models.Module;
import org.lsposed.lspd.service.ILSPApplicationService; import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.util.Utils; import org.lsposed.lspd.util.Utils;
@ -31,32 +33,27 @@ import org.lsposed.lspd.util.Utils;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class LSPApplicationServiceClient extends ApplicationServiceClient { public class ApplicationServiceClient implements ILSPApplicationService, IBinder.DeathRecipient {
static ILSPApplicationService service = null; public static ApplicationServiceClient serviceClient = null;
static IBinder serviceBinder = null;
static String processName = null; final ILSPApplicationService service;
private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() { final String processName;
@Override
public void binderDied() {
serviceBinder.unlinkToDeath(this, 0);
serviceBinder = null;
service = null;
}
};
public static void Init(IBinder binder, String niceName) { private ApplicationServiceClient(@NonNull ILSPApplicationService service, @NonNull String processName) throws RemoteException {
if (serviceClient == null && binder != null && serviceBinder == null && service == null) { this.service = service;
serviceBinder = binder; this.processName = processName;
processName = niceName; this.service.asBinder().linkToDeath(this, 0);
}
synchronized static void Init(ILSPApplicationService service, String niceName) {
var binder = service.asBinder();
if (serviceClient == null && binder != null) {
try { try {
serviceBinder.linkToDeath(recipient, 0); serviceClient = new ApplicationServiceClient(service, niceName);
} catch (RemoteException e) { } catch (RemoteException e) {
Utils.logE("link to death error: ", e); Utils.logE("link to death error: ", e);
} }
service = ILSPApplicationService.Stub.asInterface(binder);
serviceClient = new LSPApplicationServiceClient();
} }
} }
@ -70,18 +67,14 @@ public class LSPApplicationServiceClient extends ApplicationServiceClient {
} }
@Override @Override
public List<Module> getModulesList(String processName) { public List<Module> getModulesList() {
try { try {
return service.getModulesList(processName); return service.getModulesList();
} catch (RemoteException | NullPointerException ignored) { } catch (RemoteException | NullPointerException ignored) {
} }
return Collections.emptyList(); return Collections.emptyList();
} }
public List<Module> getModulesList() {
return getModulesList(processName);
}
@Override @Override
public String getPrefsPath(String packageName) { public String getPrefsPath(String packageName) {
try { try {
@ -107,6 +100,12 @@ public class LSPApplicationServiceClient extends ApplicationServiceClient {
@Override @Override
public IBinder asBinder() { public IBinder asBinder() {
return serviceBinder; return service.asBinder();
}
@Override
public void binderDied() {
service.asBinder().unlinkToDeath(this, 0);
serviceClient = null;
} }
} }

View File

@ -24,7 +24,6 @@ import android.app.ActivityThread;
import android.app.LoadedApk; import android.app.LoadedApk;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo; import android.content.res.CompatibilityInfo;
import android.os.Process;
import com.android.internal.os.ZygoteInit; import com.android.internal.os.ZygoteInit;
@ -33,6 +32,7 @@ import org.lsposed.lspd.hooker.CrashDumpHooker;
import org.lsposed.lspd.hooker.HandleBindAppHooker; import org.lsposed.lspd.hooker.HandleBindAppHooker;
import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker; import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker;
import org.lsposed.lspd.hooker.LoadedApkCstrHooker; import org.lsposed.lspd.hooker.LoadedApkCstrHooker;
import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.util.Utils; import org.lsposed.lspd.util.Utils;
import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedBridge;
@ -58,19 +58,19 @@ public class Startup {
new LoadedApkCstrHooker()); new LoadedApkCstrHooker());
} }
public static void bootstrapXposed(String niceName) { public static void bootstrapXposed() {
// Initialize the Xposed framework // Initialize the Xposed framework
try { try {
startBootstrapHook(XposedInit.startsSystemServer); startBootstrapHook(XposedInit.startsSystemServer);
Utils.logI("Loading modules for " + niceName + "/" + Process.myUid());
XposedInit.loadModules(); XposedInit.loadModules();
} catch (Throwable t) { } catch (Throwable t) {
Utils.logE("error during Xposed initialization", t); Utils.logE("error during Xposed initialization", t);
} }
} }
public static void initXposed(boolean isSystem) { public static void initXposed(boolean isSystem, String processName, ILSPApplicationService service) {
// init logger // init logger
ApplicationServiceClient.Init(service, processName);
XposedBridge.initXResources(); XposedBridge.initXResources();
XposedInit.startsSystemServer = isSystem; XposedInit.startsSystemServer = isSystem;
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote

View File

@ -20,7 +20,7 @@
package org.lsposed.lspd.hooker; package org.lsposed.lspd.hooker;
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient; import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.app.LoadedApk; import android.app.LoadedApk;
import android.os.IBinder; import android.os.IBinder;

View File

@ -29,20 +29,54 @@ import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull;
import org.lsposed.lspd.models.Module; import org.lsposed.lspd.models.Module;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class LSPApplicationService extends ILSPApplicationService.Stub { public class LSPApplicationService extends ILSPApplicationService.Stub {
final static int DEX_TRANSACTION_CODE = 1310096052; final static int DEX_TRANSACTION_CODE = 1310096052;
// <uid, pid> // key: <uid, pid>
private final static Set<Pair<Integer, Integer>> cache = ConcurrentHashMap.newKeySet(); private final static Map<Pair<Integer, Integer>, ProcessInfo> processes = new ConcurrentHashMap<>();
private final static Map<Integer, IBinder> handles = new ConcurrentHashMap<>();
private final static Set<IBinder.DeathRecipient> recipients = ConcurrentHashMap.newKeySet(); static class ProcessInfo implements DeathRecipient {
int uid;
int pid;
String processName;
IBinder heartBeat;
ProcessInfo(int uid, int pid, String processName, IBinder heartBeat) throws RemoteException {
this.uid = uid;
this.pid = pid;
this.processName = processName;
this.heartBeat = heartBeat;
heartBeat.linkToDeath(this, 0);
Log.d(TAG, "register " + this);
processes.put(new Pair<>(uid, pid), this);
}
@Override
public void binderDied() {
Log.d(TAG, this + " is dead");
heartBeat.unlinkToDeath(this, 0);
processes.remove(new Pair<>(uid, pid), this);
}
@NonNull
@Override
public String toString() {
return "ProcessInfo{" +
"uid=" + uid +
", pid=" + pid +
", processName='" + processName + '\'' +
", heartBeat=" + heartBeat +
'}';
}
}
@Override @Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
@ -57,40 +91,24 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
return super.onTransact(code, data, reply, flags); return super.onTransact(code, data, reply, flags);
} }
public boolean registerHeartBeat(int uid, int pid, IBinder handle) { public boolean registerHeartBeat(int uid, int pid, String processName, IBinder heartBeat) {
try { try {
var recipient = new DeathRecipient() { new ProcessInfo(uid, pid, processName, heartBeat);
@Override
public void binderDied() {
Log.d(TAG, "pid=" + pid + " uid=" + uid + " is dead.");
cache.remove(new Pair<>(uid, pid));
handles.remove(pid, handle);
handle.unlinkToDeath(this, 0);
recipients.remove(this);
}
};
recipients.add(recipient);
handle.linkToDeath(recipient, 0);
handles.put(pid, handle);
cache.add(new Pair<>(uid, pid));
return true; return true;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
return false; return false;
} }
} }
@Override @Override
public List<Module> getModulesList(String processName) throws RemoteException { public List<Module> getModulesList() throws RemoteException {
ensureRegistered(); var processInfo = ensureRegistered();
int pid = getCallingPid(); if (processInfo.uid == 1000 && processInfo.processName.equals("android")) {
int uid = getCallingUid();
if (uid == 1000 && processName.equals("android")) {
return ConfigManager.getInstance().getModulesForSystemServer(); return ConfigManager.getInstance().getModulesForSystemServer();
} }
if (ServiceManager.getManagerService().isRunningManager(pid, uid)) if (ServiceManager.getManagerService().isRunningManager(processInfo.pid, processInfo.uid))
return Collections.emptyList(); return Collections.emptyList();
return ConfigManager.getInstance().getModulesForProcess(processName, uid); return ConfigManager.getInstance().getModulesForProcess(processInfo.processName, processInfo.uid);
} }
@Override @Override
@ -107,35 +125,38 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
@Override @Override
public IBinder requestModuleBinder(String name) throws RemoteException { public IBinder requestModuleBinder(String name) throws RemoteException {
ensureRegistered(); var processInfo = ensureRegistered();
if (ConfigManager.getInstance().isModule(getCallingUid(), name)) { if (ConfigManager.getInstance().isModule(processInfo.uid, name)) {
ConfigManager.getInstance().ensureModulePrefsPermission(getCallingUid(), name); ConfigManager.getInstance().ensureModulePrefsPermission(processInfo.pid, name);
return ServiceManager.getModuleService(name); return ServiceManager.getModuleService(name);
} else return null; } else return null;
} }
@Override @Override
public ParcelFileDescriptor requestInjectedManagerBinder(List<IBinder> binder) throws RemoteException { public ParcelFileDescriptor requestInjectedManagerBinder(List<IBinder> binder) throws RemoteException {
ensureRegistered(); var processInfo = ensureRegistered();
var pid = getCallingPid(); if (ServiceManager.getManagerService().postStartManager(processInfo.pid, processInfo.uid) ||
var uid = getCallingUid(); ConfigManager.getInstance().isManager(processInfo.uid)) {
if (ServiceManager.getManagerService().postStartManager(pid, uid) || binder.add(ServiceManager.getManagerService().obtainManagerBinder(processInfo.heartBeat, processInfo.pid, processInfo.uid));
ConfigManager.getInstance().isManager(uid)) {
var heartbeat = handles.get(pid);
if (heartbeat != null) {
binder.add(ServiceManager.getManagerService().obtainManagerBinder(heartbeat, pid, uid));
}
} }
return ConfigManager.getInstance().getManagerApk(); return ConfigManager.getInstance().getManagerApk();
} }
public boolean hasRegister(int uid, int pid) { public boolean hasRegister(int uid, int pid) {
return cache.contains(new Pair<>(uid, pid)); return processes.containsKey(new Pair<>(uid, pid));
} }
private void ensureRegistered() throws RemoteException { @NonNull
if (!hasRegister(getCallingUid(), getCallingPid())) private ProcessInfo ensureRegistered() throws RemoteException {
var uid = getCallingUid();
var pid = getCallingPid();
var key = new Pair<>(uid, pid);
ProcessInfo processInfo = processes.getOrDefault(key, null);
if (processInfo == null || uid != processInfo.uid || pid != processInfo.pid) {
processes.remove(key, processInfo);
Log.w(TAG, "non-authorized: info=" + processInfo + " uid=" + uid + " pid=" + pid);
throw new RemoteException("Not registered"); throw new RemoteException("Not registered");
}
return processInfo;
} }
} }

View File

@ -83,7 +83,7 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme
if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName)) if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName))
return null; return null;
else else
return ServiceManager.requestApplicationService(uid, pid, heartBeat); return ServiceManager.requestApplicationService(uid, pid, processName, heartBeat);
} }
@Override @Override

View File

@ -63,7 +63,7 @@ public class LSPosedService extends ILSPosedService.Stub {
return null; return null;
} }
Log.d(TAG, "returned service"); Log.d(TAG, "returned service");
return ServiceManager.requestApplicationService(uid, pid, heartBeat); return ServiceManager.requestApplicationService(uid, pid, processName, heartBeat);
} }
/** /**

View File

@ -166,8 +166,8 @@ public class ServiceManager {
return applicationService; return applicationService;
} }
public static LSPApplicationService requestApplicationService(int uid, int pid, IBinder heartBeat) { public static LSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) {
if (applicationService.registerHeartBeat(uid, pid, heartBeat)) if (applicationService.registerHeartBeat(uid, pid, processName, heartBeat))
return applicationService; return applicationService;
else return null; else return null;
} }

View File

@ -148,7 +148,7 @@ fun afterEval() = android.applicationVariants.forEach { variant ->
into(magiskDir) into(magiskDir)
from("${rootProject.projectDir}/README.md") from("${rootProject.projectDir}/README.md")
from("$projectDir/magisk_module") { from("$projectDir/magisk_module") {
exclude("riru.sh", "module.prop", "customize.sh", "sepolicy.rule", "post-fs-data.sh") exclude("riru.sh", "module.prop", "customize.sh", "sepolicy.rule", "daemon")
} }
from("$projectDir/magisk_module") { from("$projectDir/magisk_module") {
include("module.prop") include("module.prop")
@ -163,13 +163,16 @@ fun afterEval() = android.applicationVariants.forEach { variant ->
"zygisk" -> "Requires Magisk 24.0+ and Zygisk enabled" "zygisk" -> "Requires Magisk 24.0+ and Zygisk enabled"
else -> "No further requirements" else -> "No further requirements"
}, },
"api" to flavorCapped "api" to flavorCapped,
) )
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf")) filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
} }
from("$projectDir/magisk_module") { from("$projectDir/magisk_module") {
include("customize.sh", "post-fs-data.sh") include("customize.sh", "daemon")
val tokens = mapOf("FLAVOR" to flavorLowered) val tokens = mapOf(
"FLAVOR" to flavorLowered,
"DEBUG" to if (buildTypeLowered == "debug") "true" else "false"
)
filter<ReplaceTokens>("tokens" to tokens) filter<ReplaceTokens>("tokens" to tokens)
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf")) filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
} }
@ -181,7 +184,6 @@ fun afterEval() = android.applicationVariants.forEach { variant ->
"RIRU_MODULE_API_VERSION" to moduleMaxRiruApiVersion.toString(), "RIRU_MODULE_API_VERSION" to moduleMaxRiruApiVersion.toString(),
"RIRU_MODULE_MIN_API_VERSION" to moduleMinRiruApiVersion.toString(), "RIRU_MODULE_MIN_API_VERSION" to moduleMinRiruApiVersion.toString(),
"RIRU_MODULE_MIN_RIRU_VERSION_NAME" to moduleMinRiruVersionName, "RIRU_MODULE_MIN_RIRU_VERSION_NAME" to moduleMinRiruVersionName,
"RIRU_MODULE_DEBUG" to if (buildTypeLowered == "debug") "true" else "false",
) )
filter<ReplaceTokens>("tokens" to tokens) filter<ReplaceTokens>("tokens" to tokens)
filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf")) filter<FixCrLfFilter>("eol" to FixCrLfFilter.CrLf.newInstance("lf"))

View File

@ -2,7 +2,8 @@
dir=${0%/*} dir=${0%/*}
tmpLspdApk="/data/local/tmp/daemon.apk" tmpLspdApk="/data/local/tmp/daemon.apk"
debug="false" debug=@DEBUG@
flavor=@FLAVOR@
if [ -r $tmpLspdApk ]; then if [ -r $tmpLspdApk ]; then
java_options="-Djava.class.path=$tmpLspdApk" java_options="-Djava.class.path=$tmpLspdApk"
@ -27,12 +28,15 @@ fi
mount tmpfs -t tmpfs /data/resource-cache mount tmpfs -t tmpfs /data/resource-cache
if [ ! -S "/dev/socket/zygote" ]; then if [ ! -S "/dev/socket/zygote" ]; then
timeout 1 inotifyd - /dev/socket:near | while read -r; do timeout 0.5 inotifyd - /dev/socket:near | while read -r line; do
$debug && log -p v -t "LSPosed" "inotify: $line"
if [ -S "/dev/socket/zygote" ]; then if [ -S "/dev/socket/zygote" ]; then
$debug && log -p v -t "LSPosed" "zygote started"
touch /dev/socket& touch /dev/socket&
exit exit
fi fi
done done
fi fi
$debug && log -p d -t "LSPosed" "start $flavor daemon $*"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
exec /system/bin/app_process $java_options /system/bin --nice-name=lspd org.lsposed.lspd.Main "$@" >/dev/null 2>&1 exec /system/bin/app_process $java_options /system/bin --nice-name=lspd org.lsposed.lspd.Main "$@" >/dev/null 2>&1

View File

@ -20,22 +20,23 @@
package org.lsposed.lspd.core; package org.lsposed.lspd.core;
import android.os.IBinder; import android.os.IBinder;
import android.os.Process;
import org.lsposed.lspd.BuildConfig; import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.config.LSPApplicationServiceClient;
import org.lsposed.lspd.util.ParasiticManagerHooker; import org.lsposed.lspd.util.ParasiticManagerHooker;
import org.lsposed.lspd.util.Utils; import org.lsposed.lspd.util.Utils;
import org.lsposed.lspd.BuildConfig;
public class Main { public class Main {
public static void forkCommon(boolean isSystem, String niceName, IBinder binder) { public static void forkCommon(boolean isSystem, String niceName, IBinder binder) {
LSPApplicationServiceClient.Init(binder, niceName); Startup.initXposed(isSystem, niceName, ILSPApplicationService.Stub.asInterface(binder));
Startup.initXposed(isSystem);
if ((niceName.equals(BuildConfig.MANAGER_INJECTED_PKG_NAME) || niceName.equals(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME)) if ((niceName.equals(BuildConfig.MANAGER_INJECTED_PKG_NAME) || niceName.equals(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME))
&& ParasiticManagerHooker.start()) { && ParasiticManagerHooker.start()) {
Utils.logI("Loaded manager, skipping next steps"); Utils.logI("Loaded manager, skipping next steps");
return; return;
} }
Startup.bootstrapXposed(niceName); Utils.logI("Loading xposed for " + niceName + "/" + Process.myUid());
Startup.bootstrapXposed();
} }
} }

View File

@ -1,6 +1,6 @@
package org.lsposed.lspd.util; package org.lsposed.lspd.util;
import static org.lsposed.lspd.config.ApplicationServiceClient.serviceClient; import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.app.LoadedApk; import android.app.LoadedApk;
@ -24,8 +24,8 @@ import android.webkit.WebViewDelegate;
import android.webkit.WebViewFactory; import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider; import android.webkit.WebViewFactoryProvider;
import org.lsposed.lspd.BuildConfig;
import org.lsposed.lspd.ILSPManagerService; import org.lsposed.lspd.ILSPManagerService;
import org.lsposed.lspd.BuildConfig;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;

View File

@ -5,7 +5,7 @@ import org.lsposed.lspd.models.Module;
interface ILSPApplicationService { interface ILSPApplicationService {
IBinder requestModuleBinder(String name); IBinder requestModuleBinder(String name);
List<Module> getModulesList(String processName); List<Module> getModulesList();
String getPrefsPath(String packageName); String getPrefsPath(String packageName);