[core] Store pkg name & user id, judge process name & uid
This commit is contained in:
parent
aa50e65cf1
commit
6e115426e4
|
|
@ -11,7 +11,7 @@ interface ILSPApplicationService {
|
||||||
|
|
||||||
boolean isResourcesHookEnabled() = 5;
|
boolean isResourcesHookEnabled() = 5;
|
||||||
|
|
||||||
String[] getModulesList() = 6;
|
String[] getModulesList(String processName) = 6;
|
||||||
|
|
||||||
String getPrefsPath(String packageName) = 7;
|
String getPrefsPath(String packageName) = 7;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package io.github.lsposed.lspd.service;
|
||||||
import io.github.lsposed.lspd.service.ILSPApplicationService;
|
import io.github.lsposed.lspd.service.ILSPApplicationService;
|
||||||
|
|
||||||
interface ILSPosedService {
|
interface ILSPosedService {
|
||||||
ILSPApplicationService requestApplicationService(int uid, int pid) = 1;
|
ILSPApplicationService requestApplicationService(int uid, int pid, String processName) = 1;
|
||||||
|
|
||||||
oneway void dispatchPackageChanged(in Intent intent) = 2;
|
oneway void dispatchPackageChanged(in Intent intent) = 2;
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +234,7 @@ namespace lspd {
|
||||||
void
|
void
|
||||||
Context::OnNativeForkAndSpecializePost(JNIEnv *env) {
|
Context::OnNativeForkAndSpecializePost(JNIEnv *env) {
|
||||||
const JUTFString process_name(env, nice_name_);
|
const JUTFString process_name(env, nice_name_);
|
||||||
auto binder = skip_? nullptr : Service::instance()->RequestBinder(env);
|
auto binder = skip_? nullptr : Service::instance()->RequestBinder(env, nice_name_);
|
||||||
if (binder) {
|
if (binder) {
|
||||||
LoadDex(env);
|
LoadDex(env);
|
||||||
InstallInlineHooks();
|
InstallInlineHooks();
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ namespace lspd {
|
||||||
write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken",
|
write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken",
|
||||||
"(Ljava/lang/String;)V");
|
"(Ljava/lang/String;)V");
|
||||||
write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V");
|
write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V");
|
||||||
// writeStringMethod_ = env->GetMethodID(parcel_class_, "writeString",
|
write_string_method_ = env->GetMethodID(parcel_class_, "writeString",
|
||||||
// "(Ljava/lang/String;)V");
|
"(Ljava/lang/String;)V");
|
||||||
read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V");
|
read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V");
|
||||||
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder",
|
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder",
|
||||||
"()Landroid/os/IBinder;");
|
"()Landroid/os/IBinder;");
|
||||||
|
|
@ -126,7 +126,7 @@ namespace lspd {
|
||||||
LOGD("Done InitService");
|
LOGD("Done InitService");
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject Service::RequestBinder(JNIEnv *env) {
|
jobject Service::RequestBinder(JNIEnv *env, jstring nice_name) {
|
||||||
if (UNLIKELY(!initialized_)) {
|
if (UNLIKELY(!initialized_)) {
|
||||||
LOGE("Service not initialized");
|
LOGE("Service not initialized");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -146,6 +146,7 @@ namespace lspd {
|
||||||
auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data());
|
auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data());
|
||||||
JNI_CallVoidMethod(env, data, write_interface_token_method_, descriptor);
|
JNI_CallVoidMethod(env, data, write_interface_token_method_, descriptor);
|
||||||
JNI_CallVoidMethod(env, data, write_int_method_, BRIDGE_ACTION_GET_BINDER);
|
JNI_CallVoidMethod(env, data, write_int_method_, BRIDGE_ACTION_GET_BINDER);
|
||||||
|
JNI_CallVoidMethod(env, data, write_string_method_, nice_name);
|
||||||
|
|
||||||
auto res = JNI_CallBooleanMethod(env, bridgeService, transact_method_,
|
auto res = JNI_CallBooleanMethod(env, bridgeService, transact_method_,
|
||||||
BRIDGE_TRANSACTION_CODE,
|
BRIDGE_TRANSACTION_CODE,
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace lspd {
|
||||||
|
|
||||||
void HookBridge(const Context& context, JNIEnv *env);
|
void HookBridge(const Context& context, JNIEnv *env);
|
||||||
|
|
||||||
jobject RequestBinder(JNIEnv *env);
|
jobject RequestBinder(JNIEnv *env, jstring nice_name);
|
||||||
|
|
||||||
jobject RequestBinderForSystemServer(JNIEnv *env);
|
jobject RequestBinderForSystemServer(JNIEnv *env);
|
||||||
|
|
||||||
|
|
@ -65,6 +65,7 @@ namespace lspd {
|
||||||
jmethodID recycleMethod_ = nullptr;
|
jmethodID recycleMethod_ = nullptr;
|
||||||
jmethodID write_interface_token_method_ = nullptr;
|
jmethodID write_interface_token_method_ = nullptr;
|
||||||
jmethodID write_int_method_ = nullptr;
|
jmethodID write_int_method_ = nullptr;
|
||||||
|
jmethodID write_string_method_ = nullptr;
|
||||||
jmethodID read_exception_method_ = nullptr;
|
jmethodID read_exception_method_ = nullptr;
|
||||||
jmethodID read_strong_binder_method_ = nullptr;
|
jmethodID read_strong_binder_method_ = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -353,6 +353,7 @@ public final class XposedInit {
|
||||||
topClassLoader = parent;
|
topClassLoader = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: process name
|
||||||
String[] moduleList = serviceClient.getModulesList();
|
String[] moduleList = serviceClient.getModulesList();
|
||||||
ArraySet<String> newLoadedApk = new ArraySet<>();
|
ArraySet<String> newLoadedApk = new ArraySet<>();
|
||||||
for (String apk : moduleList)
|
for (String apk : moduleList)
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
|
||||||
|
|
||||||
static String baseCachePath = null;
|
static String baseCachePath = null;
|
||||||
static String basePrefsPath = null;
|
static String basePrefsPath = null;
|
||||||
|
static String processName = null;
|
||||||
|
|
||||||
public static LSPApplicationServiceClient serviceClient = null;
|
public static LSPApplicationServiceClient serviceClient = null;
|
||||||
|
|
||||||
public static void Init(IBinder binder) {
|
public static void Init(IBinder binder, String niceName) {
|
||||||
if (serviceClient == null && binder != null && serviceBinder == null && service == null) {
|
if (serviceClient == null && binder != null && serviceBinder == null && service == null) {
|
||||||
serviceBinder = binder;
|
serviceBinder = binder;
|
||||||
|
processName = niceName;
|
||||||
try {
|
try {
|
||||||
serviceBinder.linkToDeath(
|
serviceBinder.linkToDeath(
|
||||||
new IBinder.DeathRecipient() {
|
new IBinder.DeathRecipient() {
|
||||||
|
|
@ -89,14 +91,18 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getModulesList() {
|
public String[] getModulesList(String processName) {
|
||||||
try {
|
try {
|
||||||
return service.getModulesList();
|
return service.getModulesList(processName);
|
||||||
} catch (RemoteException | NullPointerException ignored) {
|
} catch (RemoteException | NullPointerException ignored) {
|
||||||
}
|
}
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getModulesList(){
|
||||||
|
return getModulesList(processName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPrefsPath(String packageName) {
|
public String getPrefsPath(String packageName) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public class Main implements KeepAll {
|
||||||
private static final Binder heartBeatBinder = new Binder();
|
private static final Binder heartBeatBinder = new Binder();
|
||||||
|
|
||||||
public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
|
public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
|
||||||
LSPApplicationServiceClient.Init(binder);
|
LSPApplicationServiceClient.Init(binder, niceName);
|
||||||
serviceClient.registerHeartBeat(heartBeatBinder);
|
serviceClient.registerHeartBeat(heartBeatBinder);
|
||||||
final int variant = serviceClient.getVariant();
|
final int variant = serviceClient.getVariant();
|
||||||
Impl lspd = getImpl(variant);
|
Impl lspd = getImpl(variant);
|
||||||
|
|
@ -52,7 +52,7 @@ public class Main implements KeepAll {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void forkSystemServerPost(IBinder binder) {
|
public static void forkSystemServerPost(IBinder binder) {
|
||||||
LSPApplicationServiceClient.Init(binder);
|
LSPApplicationServiceClient.Init(binder, "android");
|
||||||
serviceClient.registerHeartBeat(heartBeatBinder);
|
serviceClient.registerHeartBeat(heartBeatBinder);
|
||||||
final int variant = serviceClient.getVariant();
|
final int variant = serviceClient.getVariant();
|
||||||
Impl lspd = getImpl(variant);
|
Impl lspd = getImpl(variant);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
|
||||||
|
|
@ -15,7 +16,15 @@ import androidx.annotation.Keep;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.SystemService;
|
||||||
|
import com.android.server.SystemServiceManager;
|
||||||
|
import com.android.server.am.ActivityManagerService;
|
||||||
|
import com.android.server.am.ProcessRecord;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static hidden.HiddenApiBridge.Binder_allowBlocking;
|
import static hidden.HiddenApiBridge.Binder_allowBlocking;
|
||||||
|
|
@ -44,6 +53,7 @@ public class BridgeService {
|
||||||
this.bridgeService = bridgeService;
|
this.bridgeService = bridgeService;
|
||||||
bridgeService.linkToDeath(this, 0);
|
bridgeService.linkToDeath(this, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
Log.i(TAG, "service " + SERVICE_NAME + " is dead. ");
|
Log.i(TAG, "service " + SERVICE_NAME + " is dead. ");
|
||||||
|
|
@ -222,7 +232,8 @@ public class BridgeService {
|
||||||
case ACTION_GET_BINDER: {
|
case ACTION_GET_BINDER: {
|
||||||
IBinder binder = null;
|
IBinder binder = null;
|
||||||
try {
|
try {
|
||||||
binder = service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid()).asBinder();
|
String processName = data.readString();
|
||||||
|
binder = service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid(), processName).asBinder();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, Log.getStackTraceString(e));
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
|
|
@ -282,11 +293,67 @@ public class BridgeService {
|
||||||
if (binder == null) return null;
|
if (binder == null) return null;
|
||||||
try {
|
try {
|
||||||
ILSPosedService service = ILSPosedService.Stub.asInterface(binder);
|
ILSPosedService service = ILSPosedService.Stub.asInterface(binder);
|
||||||
ILSPApplicationService applicationService = service.requestApplicationService(Process.myUid(), Process.myPid());
|
ILSPApplicationService applicationService = service.requestApplicationService(Process.myUid(), Process.myPid(), "android");
|
||||||
if (applicationService != null) return applicationService.asBinder();
|
if (applicationService != null) return applicationService.asBinder();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e(TAG, Log.getStackTraceString(e));
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
private static void tryGetActivityManagerServiceInstance() {
|
||||||
|
try {
|
||||||
|
Log.e(TAG, "Trying to get the ams");
|
||||||
|
Field localServiceField = LocalServices.class.getDeclaredField("sLocalServiceObjects");
|
||||||
|
localServiceField.setAccessible(true);
|
||||||
|
ArrayMap<Class<?>, Object> localServiceMap = (ArrayMap<Class<?>, Object>) localServiceField.get(null);
|
||||||
|
Class<?> systemServiceManagerClass = null;
|
||||||
|
for (Class<?> clazz : localServiceMap.keySet()) {
|
||||||
|
if (clazz.getName().equals("com.android.server.SystemServiceManager")) {
|
||||||
|
systemServiceManagerClass = clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Field parentField = ClassLoader.class.getDeclaredField("parent");
|
||||||
|
parentField.setAccessible(true);
|
||||||
|
parentField.set(BridgeService.class.getClassLoader(), systemServiceManagerClass.getClassLoader());
|
||||||
|
SystemServiceManager systemServiceManager = LocalServices.getService(SystemServiceManager.class);
|
||||||
|
ArrayList<SystemService> services;
|
||||||
|
try {
|
||||||
|
Field servicesField = systemServiceManagerClass.getDeclaredField("mServices");
|
||||||
|
servicesField.setAccessible(true);
|
||||||
|
services = (ArrayList<SystemService>) servicesField.get(systemServiceManager);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityManagerService.Lifecycle lifecycle = null;
|
||||||
|
|
||||||
|
for (SystemService service : services) {
|
||||||
|
if (service instanceof ActivityManagerService.Lifecycle) {
|
||||||
|
lifecycle = (ActivityManagerService.Lifecycle) service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lifecycle == null) {
|
||||||
|
Log.e(TAG, "I cannot get the lifecycle...");
|
||||||
|
}
|
||||||
|
ActivityManagerService activityManagerService = lifecycle.getService();
|
||||||
|
if (activityManagerService != null) {
|
||||||
|
Log.e(TAG, "I got the ams!!!: " + activityManagerService);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "I cannot get the ams");
|
||||||
|
}
|
||||||
|
Method findProcessLockedMethod = ActivityManagerService.class.getDeclaredMethod("findProcessLocked", String.class, int.class, String.class);
|
||||||
|
findProcessLockedMethod.setAccessible(true);
|
||||||
|
ProcessRecord record = (ProcessRecord) findProcessLockedMethod.invoke(activityManagerService, String.valueOf(Binder.getCallingPid()), 0, "LSPosed");
|
||||||
|
Field processNameField = ProcessRecord.class.getDeclaredField("processName");
|
||||||
|
processNameField.setAccessible(true);
|
||||||
|
if (record != null) {
|
||||||
|
Log.e(TAG, "I got the record!!!: " + record);
|
||||||
|
Log.e(TAG, "I got the process name: " + processNameField.get(record));
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,14 @@ import java.io.OutputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import io.github.lsposed.lspd.Application;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
||||||
// This config manager assume uid won't change when our service is off.
|
// This config manager assume uid won't change when our service is off.
|
||||||
|
|
@ -31,35 +36,35 @@ import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
public class ConfigManager {
|
public class ConfigManager {
|
||||||
static ConfigManager instance = null;
|
static ConfigManager instance = null;
|
||||||
|
|
||||||
final private File basePath = new File("/data/adb/lspd");
|
static final private File basePath = new File("/data/adb/lspd");
|
||||||
final private File configPath = new File(basePath, "config");
|
static final private File configPath = new File(basePath, "config");
|
||||||
final private SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File(configPath, "modules_config.db"), null);
|
static final private SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File(configPath, "modules_config.db"), null);
|
||||||
|
|
||||||
final private File resourceHookSwitch = new File(configPath, "enable_resources");
|
static final private File resourceHookSwitch = new File(configPath, "enable_resources");
|
||||||
private boolean resourceHook = false;
|
private boolean resourceHook = false;
|
||||||
|
|
||||||
final private File variantSwitch = new File(configPath, "variant");
|
static final private File variantSwitch = new File(configPath, "variant");
|
||||||
private int variant = -1;
|
private int variant = -1;
|
||||||
|
|
||||||
final private File verboseLogSwitch = new File(configPath, "verbose_log");
|
static final private File verboseLogSwitch = new File(configPath, "verbose_log");
|
||||||
private boolean verboseLog = false;
|
private boolean verboseLog = false;
|
||||||
|
|
||||||
final private String DEFAULT_MANAGER_PACKAGE_NAME = "io.github.lsposed.manager";
|
static final private String DEFAULT_MANAGER_PACKAGE_NAME = "io.github.lsposed.manager";
|
||||||
|
|
||||||
final private File managerPath = new File(configPath, "manager");
|
static final private File managerPath = new File(configPath, "manager");
|
||||||
private String manager = null;
|
private String manager = null;
|
||||||
private int managerUid = -1;
|
private int managerUid = -1;
|
||||||
|
|
||||||
final private File miscFile = new File(basePath, "misc_path");
|
static final private File miscFile = new File(basePath, "misc_path");
|
||||||
private String miscPath = null;
|
private String miscPath = null;
|
||||||
|
|
||||||
final private File selinuxPath = new File("/sys/fs/selinux/enforce");
|
static final private File selinuxPath = new File("/sys/fs/selinux/enforce");
|
||||||
// only check on boot
|
// only check on boot
|
||||||
final private boolean isPermissive;
|
final private boolean isPermissive;
|
||||||
|
|
||||||
final private File logPath = new File(basePath, "log");
|
static final private File logPath = new File(basePath, "log");
|
||||||
final private File modulesLogPath = new File(logPath, "modules.log");
|
static final private File modulesLogPath = new File(logPath, "modules.log");
|
||||||
final private File verboseLogPath = new File(logPath, "all.log");
|
static final private File verboseLogPath = new File(logPath, "all.log");
|
||||||
|
|
||||||
final FileObserver configObserver = new FileObserver(configPath) {
|
final FileObserver configObserver = new FileObserver(configPath) {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -69,11 +74,63 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private String readText(@NonNull File file) throws IOException {
|
static class ProcessScope {
|
||||||
|
String processName;
|
||||||
|
int uid;
|
||||||
|
|
||||||
|
ProcessScope(@NonNull String processName, int uid) {
|
||||||
|
this.processName = processName;
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object o) {
|
||||||
|
if(o instanceof ProcessScope) {
|
||||||
|
ProcessScope p = (ProcessScope) o;
|
||||||
|
return p.processName.equals(processName) && p.uid == uid;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static private final SQLiteStatement createModulesTable = db.compileStatement("CREATE TABLE IF NOT EXISTS modules (" +
|
||||||
|
"mid integer PRIMARY KEY AUTOINCREMENT," +
|
||||||
|
"module_pkg_name text NOT NULL UNIQUE," +
|
||||||
|
"apk_path text NOT NULL, " +
|
||||||
|
"enabled BOOLEAN DEFAULT 0 " +
|
||||||
|
"CHECK (enabled IN (0, 1))" +
|
||||||
|
");");
|
||||||
|
static private final SQLiteStatement createScopeTable = db.compileStatement("CREATE TABLE IF NOT EXISTS scope (" +
|
||||||
|
"mid integer," +
|
||||||
|
"app_pkg_name text NOT NULL," +
|
||||||
|
"user_id integer NOT NULL," +
|
||||||
|
"PRIMARY KEY (mid, app_pkg_name, user_id)" +
|
||||||
|
");");
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<ProcessScope, Set<String>> cachedScope = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static boolean shouldSkipSystemServer() {
|
||||||
|
try(Cursor cursor = db.query("scope", new String[]{"mid"}, "app_pkg_name=?", new String[]{"android"}, null, null, null)){
|
||||||
|
return cursor == null || !cursor.moveToNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getModulesPathForSystemServer() {
|
||||||
|
HashSet<String> modules = new HashSet<>();
|
||||||
|
try(Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"apk_path"}, "app_pkg_name=?", new String[]{"android"}, null, null, null)){
|
||||||
|
int apkPathIdx = cursor.getColumnIndex("apk_path");
|
||||||
|
while(cursor.moveToNext()) {
|
||||||
|
modules.add(cursor.getString(apkPathIdx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modules.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static private String readText(@NonNull File file) throws IOException {
|
||||||
return new String(Files.readAllBytes(file.toPath())).trim();
|
return new String(Files.readAllBytes(file.toPath())).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readText(@NonNull File file, String defaultValue) {
|
static private String readText(@NonNull File file, String defaultValue) {
|
||||||
try {
|
try {
|
||||||
if (!file.exists()) return defaultValue;
|
if (!file.exists()) return defaultValue;
|
||||||
return readText(file);
|
return readText(file);
|
||||||
|
|
@ -83,7 +140,7 @@ public class ConfigManager {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeText(@NonNull File file, String value) {
|
static private void writeText(@NonNull File file, String value) {
|
||||||
try {
|
try {
|
||||||
Files.write(file.toPath(), value.getBytes(), StandardOpenOption.CREATE);
|
Files.write(file.toPath(), value.getBytes(), StandardOpenOption.CREATE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -91,7 +148,7 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readInt(@NonNull File file, int defaultValue) {
|
static private int readInt(@NonNull File file, int defaultValue) {
|
||||||
try {
|
try {
|
||||||
if (!file.exists()) return defaultValue;
|
if (!file.exists()) return defaultValue;
|
||||||
return Integer.parseInt(readText(file));
|
return Integer.parseInt(readText(file));
|
||||||
|
|
@ -101,7 +158,7 @@ public class ConfigManager {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeInt(@NonNull File file, int value) {
|
static private void writeInt(@NonNull File file, int value) {
|
||||||
writeText(file, String.valueOf(value));
|
writeText(file, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,21 +187,6 @@ public class ConfigManager {
|
||||||
updateManager();
|
updateManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SQLiteStatement createModulesTable = db.compileStatement("CREATE TABLE IF NOT EXISTS modules (" +
|
|
||||||
"mid integer PRIMARY KEY AUTOINCREMENT," +
|
|
||||||
"package_name text NOT NULL UNIQUE," +
|
|
||||||
"apk_path text NOT NULL, " +
|
|
||||||
"enabled BOOLEAN DEFAULT 0 " +
|
|
||||||
"CHECK (enabled IN (0, 1))" +
|
|
||||||
");");
|
|
||||||
private final SQLiteStatement createScopeTable = db.compileStatement("CREATE TABLE IF NOT EXISTS scope (" +
|
|
||||||
"mid integer," +
|
|
||||||
"uid integer," +
|
|
||||||
"PRIMARY KEY (mid, uid)" +
|
|
||||||
");");
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<Integer, ArrayList<String>> modulesForUid = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
static ConfigManager getInstance() {
|
static ConfigManager getInstance() {
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
instance = new ConfigManager();
|
instance = new ConfigManager();
|
||||||
|
|
@ -164,51 +206,81 @@ public class ConfigManager {
|
||||||
createScopeTable.execute();
|
createScopeTable.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ProcessScope> getAssociatedProcesses(Application app) throws RemoteException {
|
||||||
|
PackageInfo pkgInfo = PackageService.getPackageInfo(app.packageName, 0, app.userId);
|
||||||
|
List<ProcessScope> processes = new ArrayList<>();
|
||||||
|
if (pkgInfo != null && pkgInfo.applicationInfo != null) {
|
||||||
|
for(String process: PackageService.getProcessesForUid(pkgInfo.applicationInfo.uid)){
|
||||||
|
processes.add(new ProcessScope(process, pkgInfo.applicationInfo.uid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return processes;
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized void cacheScopes() {
|
private synchronized void cacheScopes() {
|
||||||
modulesForUid.clear();
|
cachedScope.clear();
|
||||||
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"uid", "apk_path"},
|
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"app_pkg_name", "user_id", "apk_path"},
|
||||||
"enabled = ?", new String[]{"1"}, null, null, null)) {
|
"enabled = ?", new String[]{"1"}, null, null, null)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
Log.e(TAG, "db cache failed");
|
Log.e(TAG, "db cache failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int uid_idx = cursor.getColumnIndex("uid");
|
int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name");
|
||||||
int apk_path_idx = cursor.getColumnIndex("apk_path");
|
int userIdIdx = cursor.getColumnIndex("user_id");
|
||||||
|
int apkPathIdx = cursor.getColumnIndex("apk_path");
|
||||||
|
HashSet<Application> obsoletePackages = new HashSet<>();
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
int uid = cursor.getInt(uid_idx);
|
Application app = new Application();
|
||||||
String apk_path = cursor.getString(apk_path_idx);
|
app.packageName = cursor.getString(appPkgNameIdx);
|
||||||
modulesForUid.computeIfAbsent(uid, ignored -> new ArrayList<>()).add(apk_path);
|
app.userId = cursor.getInt(userIdIdx);
|
||||||
|
String apk_path = cursor.getString(apkPathIdx);
|
||||||
|
try {
|
||||||
|
List<ProcessScope> processesScope = getAssociatedProcesses(app);
|
||||||
|
if (processesScope.isEmpty()) {
|
||||||
|
obsoletePackages.add(app);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (ProcessScope processScope : processesScope)
|
||||||
|
cachedScope.computeIfAbsent(processScope, ignored -> new HashSet<>()).add(apk_path);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Application obsoletePackage : obsoletePackages) {
|
||||||
|
removeAppWithoutCache(obsoletePackage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called when a new process created, use the cached result
|
// This is called when a new process created, use the cached result
|
||||||
public String[] getModulesPathForUid(int uid) {
|
public String[] getModulesPathForProcess(String processName, int uid) {
|
||||||
return isManager(uid) ? new String[0] : modulesForUid.getOrDefault(uid, new ArrayList<>()).toArray(new String[0]);
|
return isManager(uid) ? new String[0] : cachedScope.getOrDefault(new ProcessScope(processName, uid), Collections.emptySet()).toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called when a new process created, use the cached result
|
// This is called when a new process created, use the cached result
|
||||||
// The signature matches Riru's
|
public boolean shouldSkipProcess(ProcessScope scope) {
|
||||||
public boolean shouldSkipUid(int uid) {
|
return !cachedScope.containsKey(scope) && !isManager(scope.uid);
|
||||||
return !modulesForUid.containsKey(uid) && !isManager(uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should only be called by manager, so we don't need to cache it
|
// This should only be called by manager, so we don't need to cache it
|
||||||
public int[] getModuleScope(String packageName) {
|
public List<Application> getModuleScope(String packageName) {
|
||||||
int mid = getModuleId(packageName);
|
int mid = getModuleId(packageName);
|
||||||
if (mid == -1) return null;
|
if (mid == -1) return null;
|
||||||
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"uid"},
|
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"app_pkg_name", "user_id"},
|
||||||
"scope.mid = ?", new String[]{String.valueOf(mid)}, null, null, null)) {
|
"scope.mid = ?", new String[]{String.valueOf(mid)}, null, null, null)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int uid_idx = cursor.getColumnIndex("uid");
|
int userIdIdx = cursor.getColumnIndex("user_id");
|
||||||
HashSet<Integer> result = new HashSet<>();
|
int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name");
|
||||||
|
ArrayList<Application> result = new ArrayList<>();
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
int uid = cursor.getInt(uid_idx);
|
Application scope = new Application();
|
||||||
result.add(uid);
|
scope.packageName = cursor.getString(appPkgNameIdx);
|
||||||
|
scope.userId = cursor.getInt(userIdIdx);
|
||||||
|
result.add(scope);
|
||||||
}
|
}
|
||||||
return result.stream().mapToInt(i -> i).toArray();
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,11 +290,11 @@ public class ConfigManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("package_name", packageName);
|
values.put("module_pkg_name", packageName);
|
||||||
values.put("apk_path", apkPath);
|
values.put("apk_path", apkPath);
|
||||||
int count = (int) db.insertWithOnConflict("modules", null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
int count = (int) db.insertWithOnConflict("modules", null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
count = db.updateWithOnConflict("modules", values, "package_name=?", new String[]{packageName}, SQLiteDatabase.CONFLICT_IGNORE);
|
count = db.updateWithOnConflict("modules", values, "module_pkg_name=?", new String[]{packageName}, SQLiteDatabase.CONFLICT_IGNORE);
|
||||||
}
|
}
|
||||||
if (count >= 1) {
|
if (count >= 1) {
|
||||||
cacheScopes();
|
cacheScopes();
|
||||||
|
|
@ -236,7 +308,7 @@ public class ConfigManager {
|
||||||
Log.w(TAG, "get module id should not be called inside transaction");
|
Log.w(TAG, "get module id should not be called inside transaction");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
try (Cursor cursor = db.query("modules", new String[]{"mid"}, "package_name=?", new String[]{packageName}, null, null, null)) {
|
try (Cursor cursor = db.query("modules", new String[]{"mid"}, "module_pkg_name=?", new String[]{packageName}, null, null, null)) {
|
||||||
if (cursor == null) return -1;
|
if (cursor == null) return -1;
|
||||||
if (cursor.getCount() != 1) return -1;
|
if (cursor.getCount() != 1) return -1;
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
|
|
@ -244,17 +316,18 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setModuleScope(String packageName, int[] uid) {
|
public boolean setModuleScope(String packageName, List<Application> scopes) {
|
||||||
if (uid == null || uid.length == 0) return false;
|
if (scopes.isEmpty()) return false;
|
||||||
int mid = getModuleId(packageName);
|
int mid = getModuleId(packageName);
|
||||||
if (mid == -1) return false;
|
if (mid == -1) return false;
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
db.delete("scope", "mid = ?", new String[]{String.valueOf(mid)});
|
db.delete("scope", "mid = ?", new String[]{String.valueOf(mid)});
|
||||||
for (int id : uid) {
|
for (Application app : scopes) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("mid", mid);
|
values.put("mid", mid);
|
||||||
values.put("uid", id);
|
values.put("app_pkg_name", app.packageName);
|
||||||
|
values.put("user_id", app.userId);
|
||||||
db.insertWithOnConflict("scope", null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
db.insertWithOnConflict("scope", null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -266,15 +339,15 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] enabledModules() {
|
public String[] enabledModules() {
|
||||||
try (Cursor cursor = db.query("modules", new String[]{"package_name"}, "enabled = ?", new String[]{"1"}, null, null, null)) {
|
try (Cursor cursor = db.query("modules", new String[]{"module_pkg_name"}, "enabled = ?", new String[]{"1"}, null, null, null)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
Log.e(TAG, "query enabled modules failed");
|
Log.e(TAG, "query enabled modules failed");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int pkg_idx = cursor.getColumnIndex("package_name");
|
int modulePkgNameIdx = cursor.getColumnIndex("module_pkg_name");
|
||||||
HashSet<String> result = new HashSet<>();
|
HashSet<String> result = new HashSet<>();
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
result.add(cursor.getString(pkg_idx));
|
result.add(cursor.getString(modulePkgNameIdx));
|
||||||
}
|
}
|
||||||
return result.toArray(new String[0]);
|
return result.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
@ -328,9 +401,13 @@ public class ConfigManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeApp(int uid) {
|
public boolean removeAppWithoutCache(Application app) {
|
||||||
int count = db.delete("scope", "uid = ?", new String[]{String.valueOf(uid)});
|
int count = db.delete("scope", "app_pkg_name = ? AND user_id=?", new String[]{app.packageName, String.valueOf(app.userId)});
|
||||||
if (count >= 1) {
|
return count >= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeApp(Application scope) {
|
||||||
|
if (removeAppWithoutCache(scope)) {
|
||||||
cacheScopes();
|
cacheScopes();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -397,8 +474,8 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isManager(String package_name) {
|
public boolean isManager(String module_pkg_name) {
|
||||||
return package_name.equals(manager);
|
return module_pkg_name.equals(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isManager(int uid) {
|
public boolean isManager(int uid) {
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,13 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getModulesList() throws RemoteException {
|
public String[] getModulesList(String processName) throws RemoteException {
|
||||||
ensureRegistered();
|
ensureRegistered();
|
||||||
return ConfigManager.getInstance().getModulesPathForUid(Binder.getCallingUid());
|
int callingUid = Binder.getCallingUid();
|
||||||
|
if (callingUid == 1000 && processName.equals("android")) {
|
||||||
|
ConfigManager.getModulesPathForSystemServer();
|
||||||
|
}
|
||||||
|
return ConfigManager.getInstance().getModulesPathForProcess(processName, callingUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@ import android.os.IBinder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.robv.android.xposed.XposedBridge;
|
import de.robv.android.xposed.XposedBridge;
|
||||||
import io.github.lsposed.lspd.BuildConfig;
|
import io.github.lsposed.lspd.BuildConfig;
|
||||||
import io.github.lsposed.lspd.ILSPManagerService;
|
import io.github.lsposed.lspd.ILSPManagerService;
|
||||||
|
import io.github.lsposed.lspd.Application;
|
||||||
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
||||||
|
|
||||||
public class LSPManagerService extends ILSPManagerService.Stub {
|
public class LSPManagerService extends ILSPManagerService.Stub {
|
||||||
|
|
@ -55,13 +54,13 @@ public class LSPManagerService extends ILSPManagerService.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setModuleScope(String packageName, int[] uid) {
|
public boolean setModuleScope(String packageName, ParceledListSlice<Application> scope) {
|
||||||
return ConfigManager.getInstance().setModuleScope(packageName, uid);
|
return ConfigManager.getInstance().setModuleScope(packageName, scope.getList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getModuleScope(String packageName) {
|
public ParceledListSlice<Application> getModuleScope(String packageName) {
|
||||||
return ConfigManager.getInstance().getModuleScope(packageName);
|
return new ParceledListSlice<Application>(ConfigManager.getInstance().getModuleScope(packageName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,25 @@ import android.os.Binder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import io.github.lsposed.lspd.Application;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
||||||
public class LSPosedService extends ILSPosedService.Stub {
|
public class LSPosedService extends ILSPosedService.Stub {
|
||||||
@Override
|
@Override
|
||||||
public ILSPApplicationService requestApplicationService(int uid, int pid) {
|
public ILSPApplicationService requestApplicationService(int uid, int pid, String processName) {
|
||||||
if (Binder.getCallingUid() != 1000) {
|
if (Binder.getCallingUid() != 1000) {
|
||||||
Log.w(TAG, "Someone else got my binder!?");
|
Log.w(TAG, "Someone else got my binder!?");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (ConfigManager.getInstance().shouldSkipUid(uid)) {
|
if (uid == 1000 && processName.equals("android")) {
|
||||||
Log.d(TAG, "Skipped uid " + uid);
|
if (ConfigManager.shouldSkipSystemServer())
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return ServiceManager.getApplicationService();
|
||||||
|
}
|
||||||
|
if (ConfigManager.getInstance().shouldSkipProcess(new ConfigManager.ProcessScope(processName, uid))) {
|
||||||
|
Log.d(TAG, "Skipped " + processName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (ServiceManager.getApplicationService().hasRegister(uid, pid)) {
|
if (ServiceManager.getApplicationService().hasRegister(uid, pid)) {
|
||||||
|
|
@ -40,10 +48,14 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
||||||
|
int userId = intent.getIntExtra(Intent.EXTRA_USER, -1);
|
||||||
boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||||
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) && uid > 0 && !replacing) {
|
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) && uid > 0 && !replacing) {
|
||||||
ConfigManager.getInstance().removeModule(packageName);
|
ConfigManager.getInstance().removeModule(packageName);
|
||||||
ConfigManager.getInstance().removeApp(uid);
|
Application app = new Application();
|
||||||
|
app.packageName = packageName;
|
||||||
|
app.userId = userId;
|
||||||
|
ConfigManager.getInstance().removeApp(app);
|
||||||
}
|
}
|
||||||
PackageInfo pkgInfo = PackageService.getPackageInfo(packageName, PackageManager.GET_META_DATA, 0);
|
PackageInfo pkgInfo = PackageService.getPackageInfo(packageName, PackageManager.GET_META_DATA, 0);
|
||||||
boolean isXposedModule = pkgInfo != null && pkgInfo.applicationInfo != null &&
|
boolean isXposedModule = pkgInfo != null && pkgInfo.applicationInfo != null &&
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,25 @@
|
||||||
package io.github.lsposed.lspd.service;
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
|
import android.content.pm.ComponentInfo;
|
||||||
import android.content.pm.IPackageManager;
|
import android.content.pm.IPackageManager;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ServiceInfo;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
||||||
|
|
||||||
|
import static android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS;
|
||||||
|
|
||||||
public class PackageService {
|
public class PackageService {
|
||||||
|
public static final int PER_USER_RANGE = 100000;
|
||||||
|
|
||||||
private static IPackageManager pm = null;
|
private static IPackageManager pm = null;
|
||||||
private static IBinder binder = null;
|
private static IBinder binder = null;
|
||||||
|
|
||||||
|
|
@ -34,6 +43,14 @@ public class PackageService {
|
||||||
return pm.getPackagesForUid(uid);
|
return pm.getPackagesForUid(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<String> getProcessesForUid(int uid) throws RemoteException {
|
||||||
|
HashSet<String> processNames = new HashSet<>();
|
||||||
|
for (String packageName : getPackagesForUid(uid)) {
|
||||||
|
processNames.addAll(fetchProcesses(packageName, uid / PER_USER_RANGE));
|
||||||
|
}
|
||||||
|
return processNames;
|
||||||
|
}
|
||||||
|
|
||||||
public static ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) throws RemoteException {
|
public static ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) throws RemoteException {
|
||||||
ArrayList<PackageInfo> res = new ArrayList<>();
|
ArrayList<PackageInfo> res = new ArrayList<>();
|
||||||
IPackageManager pm = getPackageManager();
|
IPackageManager pm = getPackageManager();
|
||||||
|
|
@ -46,6 +63,31 @@ public class PackageService {
|
||||||
|
|
||||||
public static void grantRuntimePermission(String packageName, String permissionName, int userId) throws RemoteException {
|
public static void grantRuntimePermission(String packageName, String permissionName, int userId) throws RemoteException {
|
||||||
IPackageManager pm = getPackageManager();
|
IPackageManager pm = getPackageManager();
|
||||||
|
if (pm == null) return;
|
||||||
pm.grantRuntimePermission(packageName, permissionName, userId);
|
pm.grantRuntimePermission(packageName, permissionName, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<String> fetchProcesses(PackageInfo pkgInfo) {
|
||||||
|
HashSet<String> processNames = new HashSet<>();
|
||||||
|
for (ComponentInfo[] componentInfos : new ComponentInfo[][]{pkgInfo.activities, pkgInfo.receivers, pkgInfo.providers}) {
|
||||||
|
for (ComponentInfo componentInfo : componentInfos) {
|
||||||
|
processNames.add(componentInfo.processName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ServiceInfo service : pkgInfo.services) {
|
||||||
|
if ((service.flags & FLAG_ISOLATED_PROCESS) == 0) {
|
||||||
|
processNames.add(service.processName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return processNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<String> fetchProcesses(String packageName, int userId) throws RemoteException {
|
||||||
|
IPackageManager pm = getPackageManager();
|
||||||
|
if (pm == null) return new HashSet<>();
|
||||||
|
PackageInfo pkgInfo = pm.getPackageInfo(packageName, PackageManager.MATCH_DISABLED_COMPONENTS |
|
||||||
|
PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES |
|
||||||
|
PackageManager.GET_SERVICES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS, userId);
|
||||||
|
return fetchProcesses(pkgInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package io.github.lsposed.lspd.service;
|
package io.github.lsposed.lspd.service;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
@ -32,7 +33,7 @@ public class ServiceManager {
|
||||||
applicationService = new LSPApplicationService();
|
applicationService = new LSPApplicationService();
|
||||||
managerService = new LSPManagerService();
|
managerService = new LSPManagerService();
|
||||||
|
|
||||||
android.os.ServiceManager.addService("serial", mainService);
|
android.os.ServiceManager.addService("serial", (IBinder) mainService);
|
||||||
|
|
||||||
waitSystemService("package");
|
waitSystemService("package");
|
||||||
waitSystemService("activity");
|
waitSystemService("activity");
|
||||||
|
|
@ -61,10 +62,15 @@ public class ServiceManager {
|
||||||
Log.e(TAG, Log.getStackTraceString(e));
|
Log.e(TAG, Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection InfiniteLoopStatement
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
Looper.loop();
|
Looper.loop();
|
||||||
|
} catch (Throwable e) {
|
||||||
Log.i(TAG, "server exited");
|
Log.i(TAG, "server exited with " + Log.getStackTraceString(e));
|
||||||
System.exit(0);
|
Log.i(TAG, "restarting");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LSPModuleService getModuleService() {
|
public static LSPModuleService getModuleService() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.android.server;
|
||||||
|
|
||||||
|
public class LocalServices {
|
||||||
|
|
||||||
|
public static <T> T getService(Class<T> type) {
|
||||||
|
throw new UnsupportedOperationException("STUB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.android.server;
|
||||||
|
|
||||||
|
public abstract class SystemService {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.android.server;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class SystemServiceManager {
|
||||||
|
private final ArrayList<SystemService> mServices = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.android.server.am;
|
||||||
|
|
||||||
|
import com.android.server.SystemService;
|
||||||
|
|
||||||
|
public class ActivityManagerService {
|
||||||
|
public static final class Lifecycle extends SystemService {
|
||||||
|
public ActivityManagerService getService() {
|
||||||
|
throw new UnsupportedOperationException("STUB");
|
||||||
|
}
|
||||||
|
private ProcessRecord findProcessLocked(String process, int userId, String callName) {
|
||||||
|
throw new UnsupportedOperationException("STUB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.android.server.am;
|
||||||
|
|
||||||
|
public class ProcessRecord {
|
||||||
|
String processName = null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.github.lsposed.lspd;
|
||||||
|
|
||||||
|
parcelable Application {
|
||||||
|
String packageName;
|
||||||
|
int userId;
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package io.github.lsposed.lspd;
|
package io.github.lsposed.lspd;
|
||||||
|
|
||||||
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
import io.github.lsposed.lspd.utils.ParceledListSlice;
|
||||||
|
import io.github.lsposed.lspd.Application;
|
||||||
|
|
||||||
|
|
||||||
interface ILSPManagerService {
|
interface ILSPManagerService {
|
||||||
ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) = 2;
|
ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) = 2;
|
||||||
|
|
@ -11,9 +13,9 @@ interface ILSPManagerService {
|
||||||
|
|
||||||
boolean disableModule(String packageName) = 5;
|
boolean disableModule(String packageName) = 5;
|
||||||
|
|
||||||
boolean setModuleScope(String packageName, in int[] uid) = 6;
|
boolean setModuleScope(String packageName, in ParceledListSlice<Application> scope) = 6;
|
||||||
|
|
||||||
int[] getModuleScope(String packageName) = 7;
|
ParceledListSlice<Application> getModuleScope(String packageName) = 7;
|
||||||
|
|
||||||
boolean isResourceHook() = 9;
|
boolean isResourceHook() = 9;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue