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;
import static org.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient;
import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.RemoteException;

View File

@ -20,7 +20,7 @@
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.content.Context;

View File

@ -20,7 +20,7 @@
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 de.robv.android.xposed.XposedBridge.hookAllMethods;
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
*/
package org.lsposed.lspd.config;
package org.lsposed.lspd.core;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import androidx.annotation.NonNull;
import org.lsposed.lspd.models.Module;
import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.util.Utils;
@ -31,32 +33,27 @@ import org.lsposed.lspd.util.Utils;
import java.util.Collections;
import java.util.List;
public class LSPApplicationServiceClient extends ApplicationServiceClient {
static ILSPApplicationService service = null;
static IBinder serviceBinder = null;
public class ApplicationServiceClient implements ILSPApplicationService, IBinder.DeathRecipient {
public static ApplicationServiceClient serviceClient = null;
static String processName = null;
final ILSPApplicationService service;
private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
serviceBinder.unlinkToDeath(this, 0);
serviceBinder = null;
service = null;
}
};
final String processName;
public static void Init(IBinder binder, String niceName) {
if (serviceClient == null && binder != null && serviceBinder == null && service == null) {
serviceBinder = binder;
processName = niceName;
private ApplicationServiceClient(@NonNull ILSPApplicationService service, @NonNull String processName) throws RemoteException {
this.service = service;
this.processName = processName;
this.service.asBinder().linkToDeath(this, 0);
}
synchronized static void Init(ILSPApplicationService service, String niceName) {
var binder = service.asBinder();
if (serviceClient == null && binder != null) {
try {
serviceBinder.linkToDeath(recipient, 0);
serviceClient = new ApplicationServiceClient(service, niceName);
} catch (RemoteException 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
public List<Module> getModulesList(String processName) {
public List<Module> getModulesList() {
try {
return service.getModulesList(processName);
return service.getModulesList();
} catch (RemoteException | NullPointerException ignored) {
}
return Collections.emptyList();
}
public List<Module> getModulesList() {
return getModulesList(processName);
}
@Override
public String getPrefsPath(String packageName) {
try {
@ -107,6 +100,12 @@ public class LSPApplicationServiceClient extends ApplicationServiceClient {
@Override
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.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.os.Process;
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.HandleSystemServerProcessHooker;
import org.lsposed.lspd.hooker.LoadedApkCstrHooker;
import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.util.Utils;
import de.robv.android.xposed.XposedBridge;
@ -58,19 +58,19 @@ public class Startup {
new LoadedApkCstrHooker());
}
public static void bootstrapXposed(String niceName) {
public static void bootstrapXposed() {
// Initialize the Xposed framework
try {
startBootstrapHook(XposedInit.startsSystemServer);
Utils.logI("Loading modules for " + niceName + "/" + Process.myUid());
XposedInit.loadModules();
} catch (Throwable 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
ApplicationServiceClient.Init(service, processName);
XposedBridge.initXResources();
XposedInit.startsSystemServer = isSystem;
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote

View File

@ -20,7 +20,7 @@
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.os.IBinder;

View File

@ -29,20 +29,54 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
import org.lsposed.lspd.models.Module;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class LSPApplicationService extends ILSPApplicationService.Stub {
final static int DEX_TRANSACTION_CODE = 1310096052;
// <uid, pid>
private final static Set<Pair<Integer, Integer>> cache = ConcurrentHashMap.newKeySet();
private final static Map<Integer, IBinder> handles = new ConcurrentHashMap<>();
private final static Set<IBinder.DeathRecipient> recipients = ConcurrentHashMap.newKeySet();
// key: <uid, pid>
private final static Map<Pair<Integer, Integer>, ProcessInfo> processes = new ConcurrentHashMap<>();
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
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);
}
public boolean registerHeartBeat(int uid, int pid, IBinder handle) {
public boolean registerHeartBeat(int uid, int pid, String processName, IBinder heartBeat) {
try {
var recipient = new DeathRecipient() {
@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));
new ProcessInfo(uid, pid, processName, heartBeat);
return true;
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
return false;
}
}
@Override
public List<Module> getModulesList(String processName) throws RemoteException {
ensureRegistered();
int pid = getCallingPid();
int uid = getCallingUid();
if (uid == 1000 && processName.equals("android")) {
public List<Module> getModulesList() throws RemoteException {
var processInfo = ensureRegistered();
if (processInfo.uid == 1000 && processInfo.processName.equals("android")) {
return ConfigManager.getInstance().getModulesForSystemServer();
}
if (ServiceManager.getManagerService().isRunningManager(pid, uid))
if (ServiceManager.getManagerService().isRunningManager(processInfo.pid, processInfo.uid))
return Collections.emptyList();
return ConfigManager.getInstance().getModulesForProcess(processName, uid);
return ConfigManager.getInstance().getModulesForProcess(processInfo.processName, processInfo.uid);
}
@Override
@ -107,35 +125,38 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
@Override
public IBinder requestModuleBinder(String name) throws RemoteException {
ensureRegistered();
if (ConfigManager.getInstance().isModule(getCallingUid(), name)) {
ConfigManager.getInstance().ensureModulePrefsPermission(getCallingUid(), name);
var processInfo = ensureRegistered();
if (ConfigManager.getInstance().isModule(processInfo.uid, name)) {
ConfigManager.getInstance().ensureModulePrefsPermission(processInfo.pid, name);
return ServiceManager.getModuleService(name);
} else return null;
}
@Override
public ParcelFileDescriptor requestInjectedManagerBinder(List<IBinder> binder) throws RemoteException {
ensureRegistered();
var pid = getCallingPid();
var uid = getCallingUid();
if (ServiceManager.getManagerService().postStartManager(pid, uid) ||
ConfigManager.getInstance().isManager(uid)) {
var heartbeat = handles.get(pid);
if (heartbeat != null) {
binder.add(ServiceManager.getManagerService().obtainManagerBinder(heartbeat, pid, uid));
}
var processInfo = ensureRegistered();
if (ServiceManager.getManagerService().postStartManager(processInfo.pid, processInfo.uid) ||
ConfigManager.getInstance().isManager(processInfo.uid)) {
binder.add(ServiceManager.getManagerService().obtainManagerBinder(processInfo.heartBeat, processInfo.pid, processInfo.uid));
}
return ConfigManager.getInstance().getManagerApk();
}
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 {
if (!hasRegister(getCallingUid(), getCallingPid()))
@NonNull
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");
}
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))
return null;
else
return ServiceManager.requestApplicationService(uid, pid, heartBeat);
return ServiceManager.requestApplicationService(uid, pid, processName, heartBeat);
}
@Override

View File

@ -63,7 +63,7 @@ public class LSPosedService extends ILSPosedService.Stub {
return null;
}
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;
}
public static LSPApplicationService requestApplicationService(int uid, int pid, IBinder heartBeat) {
if (applicationService.registerHeartBeat(uid, pid, heartBeat))
public static LSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) {
if (applicationService.registerHeartBeat(uid, pid, processName, heartBeat))
return applicationService;
else return null;
}

View File

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

View File

@ -2,7 +2,8 @@
dir=${0%/*}
tmpLspdApk="/data/local/tmp/daemon.apk"
debug="false"
debug=@DEBUG@
flavor=@FLAVOR@
if [ -r $tmpLspdApk ]; then
java_options="-Djava.class.path=$tmpLspdApk"
@ -27,12 +28,15 @@ fi
mount tmpfs -t tmpfs /data/resource-cache
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
$debug && log -p v -t "LSPosed" "zygote started"
touch /dev/socket&
exit
fi
done
fi
$debug && log -p d -t "LSPosed" "start $flavor daemon $*"
# shellcheck disable=SC2086
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;
import android.os.IBinder;
import android.os.Process;
import org.lsposed.lspd.BuildConfig;
import org.lsposed.lspd.config.LSPApplicationServiceClient;
import org.lsposed.lspd.service.ILSPApplicationService;
import org.lsposed.lspd.util.ParasiticManagerHooker;
import org.lsposed.lspd.util.Utils;
import org.lsposed.lspd.BuildConfig;
public class Main {
public static void forkCommon(boolean isSystem, String niceName, IBinder binder) {
LSPApplicationServiceClient.Init(binder, niceName);
Startup.initXposed(isSystem);
Startup.initXposed(isSystem, niceName, ILSPApplicationService.Stub.asInterface(binder));
if ((niceName.equals(BuildConfig.MANAGER_INJECTED_PKG_NAME) || niceName.equals(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME))
&& ParasiticManagerHooker.start()) {
Utils.logI("Loaded manager, skipping next steps");
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;
import static org.lsposed.lspd.config.ApplicationServiceClient.serviceClient;
import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient;
import android.app.ActivityThread;
import android.app.LoadedApk;
@ -24,8 +24,8 @@ import android.webkit.WebViewDelegate;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;
import org.lsposed.lspd.BuildConfig;
import org.lsposed.lspd.ILSPManagerService;
import org.lsposed.lspd.BuildConfig;
import java.io.FileInputStream;
import java.io.FileOutputStream;

View File

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