Add application service
This commit is contained in:
parent
3d2164b599
commit
c65af4c4b5
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
interface ILSPApplicationService {
|
||||||
|
void registerHeartBeat(IBinder handle) = 1;
|
||||||
|
|
||||||
|
IBinder requestModuleBinder() = 2;
|
||||||
|
|
||||||
|
IBinder requestManagerBinder() = 3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
import io.github.lsposed.lspd.service.ILSPApplicationService;
|
||||||
|
|
||||||
|
interface ILSPosedService {
|
||||||
|
ILSPApplicationService requestApplicationService(int uid, int pid) = 1;
|
||||||
|
}
|
||||||
|
|
@ -22,18 +22,16 @@ package io.github.lsposed.lspd.core;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.ServiceManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.ddm.DdmHandleAppName;
|
import android.ddm.DdmHandleAppName;
|
||||||
|
|
||||||
import io.github.lsposed.common.KeepAll;
|
import io.github.lsposed.common.KeepAll;
|
||||||
import io.github.lsposed.lspd.service.LSPosedService;
|
import io.github.lsposed.lspd.service.ServiceManager;
|
||||||
import io.github.lsposed.lspd.service.Service;
|
|
||||||
import io.github.lsposed.lspd.util.Utils;
|
import io.github.lsposed.lspd.util.Utils;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.Service.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
public class Main implements KeepAll {
|
public class Main implements KeepAll {
|
||||||
|
|
@ -115,7 +113,7 @@ public class Main implements KeepAll {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void waitSystemService(String name) {
|
private static void waitSystemService(String name) {
|
||||||
while (ServiceManager.getService(name) == null) {
|
while (android.os.ServiceManager.getService(name) == null) {
|
||||||
try {
|
try {
|
||||||
Log.i(TAG, "service " + name + " is not started, wait 1s.");
|
Log.i(TAG, "service " + name + " is not started, wait 1s.");
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
@ -136,6 +134,6 @@ public class Main implements KeepAll {
|
||||||
waitSystemService(Context.USER_SERVICE);
|
waitSystemService(Context.USER_SERVICE);
|
||||||
waitSystemService(Context.APP_OPS_SERVICE);
|
waitSystemService(Context.APP_OPS_SERVICE);
|
||||||
|
|
||||||
Service.start();
|
ServiceManager.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ public class XposedInstallerHooker {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Class<?> serviceClass = XposedHelpers.findClass("io.github.lsposed.manager.receivers.LSPosedManagerServiceClient", classLoader);
|
Class<?> serviceClass = XposedHelpers.findClass("io.github.lsposed.manager.receivers.LSPosedManagerServiceClient", classLoader);
|
||||||
XposedHelpers.setStaticObjectField(serviceClass, "binder", BridgeService.requireBinder());
|
// XposedHelpers.setStaticObjectField(serviceClass, "binder", BridgeService.requireBinder());
|
||||||
|
|
||||||
Utils.logI("Hooked LSPosed Manager");
|
Utils.logI("Hooked LSPosed Manager");
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,7 @@ import androidx.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.github.lsposed.lspd.ILSPManagerService;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
import io.github.xposed.xposedservice.IXposedService;
|
|
||||||
|
|
||||||
import static android.os.Binder.getCallingUid;
|
|
||||||
import static io.github.lsposed.lspd.service.Service.TAG;
|
|
||||||
|
|
||||||
public class BridgeService {
|
public class BridgeService {
|
||||||
private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P';
|
private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P';
|
||||||
|
|
@ -26,20 +22,19 @@ public class BridgeService {
|
||||||
|
|
||||||
enum ACTION {
|
enum ACTION {
|
||||||
ACTION_SEND_BINDER,
|
ACTION_SEND_BINDER,
|
||||||
ACTION_SEND_MANAGER_BINDER,
|
|
||||||
ACTION_GET_BINDER,
|
ACTION_GET_BINDER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for client
|
||||||
private static IBinder serviceBinder = null;
|
private static IBinder serviceBinder = null;
|
||||||
private static IXposedService service = null;
|
private static ILSPosedService service = null;
|
||||||
|
|
||||||
private static IBinder managerBinder = null;
|
|
||||||
private static ILSPManagerService manager = null;
|
|
||||||
|
|
||||||
|
// for service
|
||||||
private static final IBinder.DeathRecipient BRIDGE_SERVICE_DEATH_RECIPIENT = () -> {
|
private static final IBinder.DeathRecipient BRIDGE_SERVICE_DEATH_RECIPIENT = () -> {
|
||||||
Log.i(TAG, "service " + SERVICE_NAME + " is dead. ");
|
Log.i(TAG, "service " + SERVICE_NAME + " is dead. ");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@SuppressWarnings("JavaReflectionMemberAccess")
|
||||||
Field field = ServiceManager.class.getDeclaredField("sServiceManager");
|
Field field = ServiceManager.class.getDeclaredField("sServiceManager");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(null, null);
|
field.set(null, null);
|
||||||
|
|
@ -57,15 +52,13 @@ public class BridgeService {
|
||||||
Log.w(TAG, "clear ServiceManager: " + Log.getStackTraceString(e));
|
Log.w(TAG, "clear ServiceManager: " + Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToBridge(ACTION.ACTION_SEND_BINDER, serviceBinder, true);
|
sendToBridge(serviceBinder, true);
|
||||||
sendToBridge(ACTION.ACTION_SEND_MANAGER_BINDER, managerBinder, true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// for client
|
||||||
private static final IBinder.DeathRecipient LSPSERVICE_DEATH_RECIPIENT = () -> {
|
private static final IBinder.DeathRecipient LSPSERVICE_DEATH_RECIPIENT = () -> {
|
||||||
serviceBinder = null;
|
serviceBinder = null;
|
||||||
service = null;
|
service = null;
|
||||||
managerBinder = null;
|
|
||||||
manager = null;
|
|
||||||
Log.e(TAG, "service is dead");
|
Log.e(TAG, "service is dead");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -78,7 +71,8 @@ public class BridgeService {
|
||||||
|
|
||||||
private static Listener listener;
|
private static Listener listener;
|
||||||
|
|
||||||
private static void sendToBridge(ACTION action, IBinder binder, boolean isRestart) {
|
// For service
|
||||||
|
private static void sendToBridge(IBinder binder, boolean isRestart) {
|
||||||
IBinder bridgeService;
|
IBinder bridgeService;
|
||||||
do {
|
do {
|
||||||
bridgeService = ServiceManager.getService(SERVICE_NAME);
|
bridgeService = ServiceManager.getService(SERVICE_NAME);
|
||||||
|
|
@ -104,7 +98,7 @@ public class BridgeService {
|
||||||
bridgeService.linkToDeath(BRIDGE_SERVICE_DEATH_RECIPIENT, 0);
|
bridgeService.linkToDeath(BRIDGE_SERVICE_DEATH_RECIPIENT, 0);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.w(TAG, "linkToDeath " + Log.getStackTraceString(e));
|
Log.w(TAG, "linkToDeath " + Log.getStackTraceString(e));
|
||||||
sendToBridge(action, binder, false);
|
sendToBridge(binder, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +109,7 @@ public class BridgeService {
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
try {
|
try {
|
||||||
data.writeInterfaceToken(DESCRIPTOR);
|
data.writeInterfaceToken(DESCRIPTOR);
|
||||||
data.writeInt(action.ordinal());
|
data.writeInt(ACTION.ACTION_SEND_BINDER.ordinal());
|
||||||
Log.v(TAG, "binder " + binder.toString());
|
Log.v(TAG, "binder " + binder.toString());
|
||||||
data.writeStrongBinder(binder);
|
data.writeStrongBinder(binder);
|
||||||
res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0);
|
res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0);
|
||||||
|
|
@ -142,24 +136,13 @@ public class BridgeService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void receiveFromBridge(ACTION action, IBinder binder) {
|
// For client
|
||||||
|
private static void receiveFromBridge(IBinder binder) {
|
||||||
if (binder == null) {
|
if (binder == null) {
|
||||||
Log.e(TAG, "received empty binder");
|
Log.e(TAG, "received empty binder");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(action == ACTION.ACTION_SEND_MANAGER_BINDER) {
|
|
||||||
if (managerBinder != null) {
|
|
||||||
managerBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
managerBinder = binder;
|
|
||||||
manager = LSPManagerService.Stub.asInterface(managerBinder);
|
|
||||||
try {
|
|
||||||
managerBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
|
||||||
} catch (RemoteException ignored) {
|
|
||||||
}
|
|
||||||
} else if (action == ACTION.ACTION_SEND_BINDER) {
|
|
||||||
if (serviceBinder == null) {
|
if (serviceBinder == null) {
|
||||||
PackageReceiver.register();
|
PackageReceiver.register();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -167,12 +150,11 @@ public class BridgeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceBinder = binder;
|
serviceBinder = binder;
|
||||||
service = IXposedService.Stub.asInterface(serviceBinder);
|
service = ILSPosedService.Stub.asInterface(serviceBinder);
|
||||||
try {
|
try {
|
||||||
serviceBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
serviceBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
||||||
} catch (RemoteException ignored) {
|
} catch (RemoteException ignored) {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "binder received");
|
Log.i(TAG, "binder received");
|
||||||
}
|
}
|
||||||
|
|
@ -181,48 +163,13 @@ public class BridgeService {
|
||||||
BridgeService.listener = listener;
|
BridgeService.listener = listener;
|
||||||
BridgeService.service = service;
|
BridgeService.service = service;
|
||||||
BridgeService.serviceBinder = service.asBinder();
|
BridgeService.serviceBinder = service.asBinder();
|
||||||
sendToBridge(ACTION.ACTION_SEND_BINDER, serviceBinder, false);
|
sendToBridge(serviceBinder, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void send(LSPManagerService service, Listener listener) {
|
public static ILSPosedService getService() {
|
||||||
BridgeService.listener = listener;
|
|
||||||
BridgeService.manager = service;
|
|
||||||
BridgeService.managerBinder = service.asBinder();
|
|
||||||
sendToBridge(ACTION.ACTION_SEND_MANAGER_BINDER, managerBinder, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IXposedService getService() {
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ILSPManagerService getManager() {
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IBinder requireBinder() {
|
|
||||||
IBinder binder = ServiceManager.getService(SERVICE_NAME);
|
|
||||||
if (binder == null) return null;
|
|
||||||
|
|
||||||
Parcel data = Parcel.obtain();
|
|
||||||
Parcel reply = Parcel.obtain();
|
|
||||||
try {
|
|
||||||
data.writeInterfaceToken(DESCRIPTOR);
|
|
||||||
data.writeInt(ACTION.ACTION_GET_BINDER.ordinal());
|
|
||||||
binder.transact(TRANSACTION_CODE, data, reply, 0);
|
|
||||||
reply.readException();
|
|
||||||
IBinder received = reply.readStrongBinder();
|
|
||||||
if (received != null) {
|
|
||||||
return received;
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
data.recycle();
|
|
||||||
reply.recycle();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "RedundantSuppression"})
|
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||||
public static boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) {
|
public static boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) {
|
||||||
data.enforceInterface(DESCRIPTOR);
|
data.enforceInterface(DESCRIPTOR);
|
||||||
|
|
@ -231,10 +178,9 @@ public class BridgeService {
|
||||||
Log.d(TAG, "onTransact: action=" + action + ", callingUid=" + Binder.getCallingUid() + ", callingPid=" + Binder.getCallingPid());
|
Log.d(TAG, "onTransact: action=" + action + ", callingUid=" + Binder.getCallingUid() + ", callingPid=" + Binder.getCallingPid());
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ACTION_SEND_BINDER:
|
case ACTION_SEND_BINDER: {
|
||||||
case ACTION_SEND_MANAGER_BINDER: {
|
|
||||||
if (Binder.getCallingUid() == 0) {
|
if (Binder.getCallingUid() == 0) {
|
||||||
receiveFromBridge(action, data.readStrongBinder());
|
receiveFromBridge(data.readStrongBinder());
|
||||||
if (reply != null) {
|
if (reply != null) {
|
||||||
reply.writeNoException();
|
reply.writeNoException();
|
||||||
}
|
}
|
||||||
|
|
@ -243,22 +189,25 @@ public class BridgeService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ACTION_GET_BINDER: {
|
case ACTION_GET_BINDER: {
|
||||||
|
IBinder binder = null;
|
||||||
try {
|
try {
|
||||||
if (!PackageService.isInstaller(getCallingUid())) return false;
|
binder = service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid()).asBinder();
|
||||||
} catch (Throwable ignored) {
|
} catch (RemoteException e) {
|
||||||
return false;
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
if (reply != null) {
|
if (binder != null && reply != null) {
|
||||||
reply.writeNoException();
|
reply.writeNoException();
|
||||||
Log.d(TAG, "saved binder is " + managerBinder.toString());
|
Log.d(TAG, "got binder is " + binder);
|
||||||
reply.writeStrongBinder(managerBinder);
|
reply.writeStrongBinder(binder);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||||
public static boolean execTransact(int code, long dataObj, long replyObj, int flags) {
|
public static boolean execTransact(int code, long dataObj, long replyObj, int flags) {
|
||||||
Log.d(TAG, String.valueOf(code));
|
Log.d(TAG, String.valueOf(code));
|
||||||
if (code != TRANSACTION_CODE) return false;
|
if (code != TRANSACTION_CODE) return false;
|
||||||
|
|
@ -266,7 +215,7 @@ public class BridgeService {
|
||||||
Parcel data = ParcelUtils.fromNativePointer(dataObj);
|
Parcel data = ParcelUtils.fromNativePointer(dataObj);
|
||||||
Parcel reply = ParcelUtils.fromNativePointer(replyObj);
|
Parcel reply = ParcelUtils.fromNativePointer(replyObj);
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null || reply == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,8 +239,8 @@ public class BridgeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
if (data != null) data.recycle();
|
data.recycle();
|
||||||
if (reply != null) reply.recycle();
|
reply.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
|
|
@ -20,12 +22,16 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.Service.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
||||||
|
// This config manager assume uid won't change when our service is off.
|
||||||
|
// Otherwise, user should maintain it manually.
|
||||||
|
// TODO: manager package name supports
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
static ConfigManager instance = null;
|
static ConfigManager instance = null;
|
||||||
|
|
||||||
final private File configPath = new File("/data/adb/lspd/config");
|
final private File basePath = new File("/data/adb/lspd");
|
||||||
|
final private File configPath = new File(basePath, "config");
|
||||||
final private SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File(configPath, "modules_config.db"), null);
|
final private SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File(configPath, "modules_config.db"), null);
|
||||||
|
|
||||||
final private File resourceHookSwitch = new File(configPath, "enable_resources");
|
final private File resourceHookSwitch = new File(configPath, "enable_resources");
|
||||||
|
|
@ -41,6 +47,10 @@ public class ConfigManager {
|
||||||
// only check on boot
|
// only check on boot
|
||||||
final private boolean isPermissive;
|
final private boolean isPermissive;
|
||||||
|
|
||||||
|
final private File logPath = new File(basePath, "log");
|
||||||
|
final private File modulesLogPath = new File(logPath, "modules.log");
|
||||||
|
final private File verboseLogPath = new File(logPath, "verbose.log");
|
||||||
|
|
||||||
final FileObserver configObserver = new FileObserver(configPath) {
|
final FileObserver configObserver = new FileObserver(configPath) {
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(int event, @Nullable String path) {
|
public void onEvent(int event, @Nullable String path) {
|
||||||
|
|
@ -154,7 +164,7 @@ public class ConfigManager {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("apk_path", apkPath);
|
values.put("apk_path", apkPath);
|
||||||
int count = db.updateWithOnConflict("enabled_modules", values, "package_name = ?", new String[]{packageName}, SQLiteDatabase.CONFLICT_REPLACE);
|
int count = db.updateWithOnConflict("enabled_modules", values, "package_name = ?", new String[]{packageName}, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
if (count > 1) {
|
if (count >= 1) {
|
||||||
cacheScopes();
|
cacheScopes();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -214,9 +224,9 @@ public class ConfigManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeApps(int uid) {
|
public boolean removeApp(int uid) {
|
||||||
int count = db.delete("scope", "uid = ?", new String[]{String.valueOf(uid)});
|
int count = db.delete("scope", "uid = ?", new String[]{String.valueOf(uid)});
|
||||||
if (count > 1) {
|
if (count >= 1) {
|
||||||
cacheScopes();
|
cacheScopes();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -250,4 +260,22 @@ public class ConfigManager {
|
||||||
public int variant() {
|
public int variant() {
|
||||||
return variant;
|
return variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ParcelFileDescriptor getModulesLog() {
|
||||||
|
try {
|
||||||
|
return ParcelFileDescriptor.open(modulesLogPath, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParcelFileDescriptor getVerboseLog() {
|
||||||
|
try {
|
||||||
|
return ParcelFileDescriptor.open(verboseLogPath, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
||||||
|
public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
|
// <uid, pid>
|
||||||
|
private final static Set<Pair<Integer, Integer>> cache = ConcurrentHashMap.newKeySet();
|
||||||
|
private final static Set<IBinder> handles = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerHeartBeat(IBinder handle) throws RemoteException {
|
||||||
|
handles.add(handle);
|
||||||
|
int uid = Binder.getCallingUid();
|
||||||
|
int pid = Binder.getCallingPid();
|
||||||
|
cache.add(new Pair<>(uid, pid));
|
||||||
|
handle.linkToDeath(() -> {
|
||||||
|
Log.d(TAG, "pid=" + pid + " uid=" + uid + " is dead.");
|
||||||
|
cache.remove(new Pair<>(uid, pid));
|
||||||
|
handles.remove(handle);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if module
|
||||||
|
@Override
|
||||||
|
public IBinder requestModuleBinder() {
|
||||||
|
if (!hasRegister(Binder.getCallingUid(), Binder.getCallingPid()))
|
||||||
|
return null;
|
||||||
|
return ServiceManager.getModuleService();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if manager
|
||||||
|
@Override
|
||||||
|
public IBinder requestManagerBinder() {
|
||||||
|
if (!hasRegister(Binder.getCallingUid(), Binder.getCallingPid()))
|
||||||
|
return null;
|
||||||
|
return ServiceManager.getManagerService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRegister(int uid, int pid) {
|
||||||
|
return cache.contains(new Pair<>(uid, pid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,33 +3,16 @@ package io.github.lsposed.lspd.service;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import de.robv.android.xposed.XposedBridge;
|
||||||
import io.github.lsposed.lspd.ILSPManagerService;
|
import io.github.lsposed.lspd.ILSPManagerService;
|
||||||
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.Service.TAG;
|
|
||||||
|
|
||||||
public class LSPManagerService extends ILSPManagerService.Stub {
|
public class LSPManagerService extends ILSPManagerService.Stub {
|
||||||
|
|
||||||
public LSPManagerService() {
|
LSPManagerService() {
|
||||||
BridgeService.send(this, new BridgeService.Listener() {
|
|
||||||
@Override
|
|
||||||
public void onSystemServerRestarted() {
|
|
||||||
Log.w(TAG, "system restarted...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResponseFromBridgeService(boolean response) {
|
|
||||||
if (response) {
|
|
||||||
Log.i(TAG, "sent service to bridge");
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "no response from bridge");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder asBinder() {
|
public IBinder asBinder() {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import de.robv.android.xposed.XposedBridge;
|
||||||
|
import io.github.xposed.xposedservice.IXposedService;
|
||||||
|
|
||||||
|
public class LSPModuleService extends IXposedService.Stub {
|
||||||
|
|
||||||
|
public LSPModuleService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder asBinder() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVersion() {
|
||||||
|
return XposedBridge.getXposedVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
package io.github.lsposed.lspd.service;
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
import io.github.xposed.xposedservice.IXposedService;
|
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.Service.TAG;
|
public class LSPosedService extends ILSPosedService.Stub {
|
||||||
|
LSPosedService() {
|
||||||
public class LSPosedService extends IXposedService.Stub {
|
|
||||||
|
|
||||||
public LSPosedService() {
|
|
||||||
BridgeService.send(this, new BridgeService.Listener() {
|
BridgeService.send(this, new BridgeService.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSystemServerRestarted() {
|
public void onSystemServerRestarted() {
|
||||||
|
|
@ -29,12 +26,17 @@ public class LSPosedService extends IXposedService.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder asBinder() {
|
public ILSPApplicationService requestApplicationService(int uid, int pid) {
|
||||||
return this;
|
if (Binder.getCallingUid() != 1000) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ConfigManager.getInstance().shouldSkipUid(uid)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ServiceManager.getApplicationService().hasRegister(uid, pid)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ServiceManager.getApplicationService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getVersion() {
|
|
||||||
return XposedBridge.getXposedVersion();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package io.github.lsposed.lspd.service;
|
|
||||||
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class Service {
|
|
||||||
public static final String TAG = "LSPosedService";
|
|
||||||
// call by ourselves
|
|
||||||
public static void start() {
|
|
||||||
Log.i(TAG, "starting server...");
|
|
||||||
|
|
||||||
Looper.prepare();
|
|
||||||
new LSPosedService();
|
|
||||||
new LSPManagerService();
|
|
||||||
Looper.loop();
|
|
||||||
|
|
||||||
Log.i(TAG, "server exited");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class ServiceManager {
|
||||||
|
private static LSPosedService mainService = null;
|
||||||
|
private static LSPModuleService moduleService = null;
|
||||||
|
private static LSPApplicationService applicationService = null;
|
||||||
|
private static LSPManagerService managerService = null;
|
||||||
|
public static final String TAG = "LSPosedService";
|
||||||
|
// call by ourselves
|
||||||
|
public static void start() {
|
||||||
|
Log.i(TAG, "starting server...");
|
||||||
|
|
||||||
|
Looper.prepare();
|
||||||
|
mainService = new LSPosedService();
|
||||||
|
moduleService = new LSPModuleService();
|
||||||
|
applicationService = new LSPApplicationService();
|
||||||
|
managerService = new LSPManagerService();
|
||||||
|
Looper.loop();
|
||||||
|
|
||||||
|
Log.i(TAG, "server exited");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LSPModuleService getModuleService() {
|
||||||
|
return moduleService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LSPApplicationService getApplicationService() {
|
||||||
|
return applicationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LSPManagerService getManagerService() {
|
||||||
|
return managerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue