[core] Store pkg name & user id, judge process name & uid

This commit is contained in:
LoveSy 2021-02-19 22:29:45 +08:00 committed by tehcneko
parent aa50e65cf1
commit 6e115426e4
22 changed files with 362 additions and 100 deletions

View File

@ -11,7 +11,7 @@ interface ILSPApplicationService {
boolean isResourcesHookEnabled() = 5;
String[] getModulesList() = 6;
String[] getModulesList(String processName) = 6;
String getPrefsPath(String packageName) = 7;

View File

@ -3,7 +3,7 @@ package io.github.lsposed.lspd.service;
import io.github.lsposed.lspd.service.ILSPApplicationService;
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;
}

View File

@ -234,7 +234,7 @@ namespace lspd {
void
Context::OnNativeForkAndSpecializePost(JNIEnv *env) {
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) {
LoadDex(env);
InstallInlineHooks();

View File

@ -73,8 +73,8 @@ namespace lspd {
write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken",
"(Ljava/lang/String;)V");
write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V");
// writeStringMethod_ = env->GetMethodID(parcel_class_, "writeString",
// "(Ljava/lang/String;)V");
write_string_method_ = env->GetMethodID(parcel_class_, "writeString",
"(Ljava/lang/String;)V");
read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V");
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder",
"()Landroid/os/IBinder;");
@ -126,7 +126,7 @@ namespace lspd {
LOGD("Done InitService");
}
jobject Service::RequestBinder(JNIEnv *env) {
jobject Service::RequestBinder(JNIEnv *env, jstring nice_name) {
if (UNLIKELY(!initialized_)) {
LOGE("Service not initialized");
return nullptr;
@ -146,6 +146,7 @@ namespace lspd {
auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data());
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_string_method_, nice_name);
auto res = JNI_CallBooleanMethod(env, bridgeService, transact_method_,
BRIDGE_TRANSACTION_CODE,

View File

@ -31,7 +31,7 @@ namespace lspd {
void HookBridge(const Context& context, JNIEnv *env);
jobject RequestBinder(JNIEnv *env);
jobject RequestBinder(JNIEnv *env, jstring nice_name);
jobject RequestBinderForSystemServer(JNIEnv *env);
@ -65,6 +65,7 @@ namespace lspd {
jmethodID recycleMethod_ = nullptr;
jmethodID write_interface_token_method_ = nullptr;
jmethodID write_int_method_ = nullptr;
jmethodID write_string_method_ = nullptr;
jmethodID read_exception_method_ = nullptr;
jmethodID read_strong_binder_method_ = nullptr;

View File

@ -353,6 +353,7 @@ public final class XposedInit {
topClassLoader = parent;
}
// TODO: process name
String[] moduleList = serviceClient.getModulesList();
ArraySet<String> newLoadedApk = new ArraySet<>();
for (String apk : moduleList)

View File

@ -16,12 +16,14 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
static String baseCachePath = null;
static String basePrefsPath = null;
static String processName = 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) {
serviceBinder = binder;
processName = niceName;
try {
serviceBinder.linkToDeath(
new IBinder.DeathRecipient() {
@ -89,14 +91,18 @@ public class LSPApplicationServiceClient implements ILSPApplicationService {
}
@Override
public String[] getModulesList() {
public String[] getModulesList(String processName) {
try {
return service.getModulesList();
return service.getModulesList(processName);
} catch (RemoteException | NullPointerException ignored) {
}
return new String[0];
}
public String[] getModulesList(){
return getModulesList(processName);
}
@Override
public String getPrefsPath(String packageName) {
try {

View File

@ -40,7 +40,7 @@ public class Main implements KeepAll {
private static final Binder heartBeatBinder = new Binder();
public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
LSPApplicationServiceClient.Init(binder);
LSPApplicationServiceClient.Init(binder, niceName);
serviceClient.registerHeartBeat(heartBeatBinder);
final int variant = serviceClient.getVariant();
Impl lspd = getImpl(variant);
@ -52,7 +52,7 @@ public class Main implements KeepAll {
}
public static void forkSystemServerPost(IBinder binder) {
LSPApplicationServiceClient.Init(binder);
LSPApplicationServiceClient.Init(binder, "android");
serviceClient.registerHeartBeat(heartBeatBinder);
final int variant = serviceClient.getVariant();
Impl lspd = getImpl(variant);

View File

@ -8,6 +8,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.os.Process;
@ -15,7 +16,15 @@ import androidx.annotation.Keep;
import androidx.annotation.NonNull;
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.Method;
import java.util.ArrayList;
import java.util.Map;
import static hidden.HiddenApiBridge.Binder_allowBlocking;
@ -44,6 +53,7 @@ public class BridgeService {
this.bridgeService = bridgeService;
bridgeService.linkToDeath(this, 0);
}
@Override
public void binderDied() {
Log.i(TAG, "service " + SERVICE_NAME + " is dead. ");
@ -222,7 +232,8 @@ public class BridgeService {
case ACTION_GET_BINDER: {
IBinder binder = null;
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) {
Log.e(TAG, Log.getStackTraceString(e));
}
@ -282,11 +293,67 @@ public class BridgeService {
if (binder == null) return null;
try {
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();
} catch (Throwable e) {
Log.e(TAG, Log.getStackTraceString(e));
}
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));
}
}
}

View File

@ -21,9 +21,14 @@ import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.github.lsposed.lspd.Application;
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
// 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 {
static ConfigManager instance = null;
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);
static final private File basePath = new File("/data/adb/lspd");
static final private File configPath = new File(basePath, "config");
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;
final private File variantSwitch = new File(configPath, "variant");
static final private File variantSwitch = new File(configPath, "variant");
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;
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 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;
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
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, "all.log");
static final private File logPath = new File(basePath, "log");
static final private File modulesLogPath = new File(logPath, "modules.log");
static final private File verboseLogPath = new File(logPath, "all.log");
final FileObserver configObserver = new FileObserver(configPath) {
@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();
}
private String readText(@NonNull File file, String defaultValue) {
static private String readText(@NonNull File file, String defaultValue) {
try {
if (!file.exists()) return defaultValue;
return readText(file);
@ -83,7 +140,7 @@ public class ConfigManager {
return defaultValue;
}
private void writeText(@NonNull File file, String value) {
static private void writeText(@NonNull File file, String value) {
try {
Files.write(file.toPath(), value.getBytes(), StandardOpenOption.CREATE);
} 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 {
if (!file.exists()) return defaultValue;
return Integer.parseInt(readText(file));
@ -101,7 +158,7 @@ public class ConfigManager {
return defaultValue;
}
private void writeInt(@NonNull File file, int value) {
static private void writeInt(@NonNull File file, int value) {
writeText(file, String.valueOf(value));
}
@ -130,21 +187,6 @@ public class ConfigManager {
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() {
if (instance == null)
instance = new ConfigManager();
@ -164,51 +206,81 @@ public class ConfigManager {
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() {
modulesForUid.clear();
try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"uid", "apk_path"},
cachedScope.clear();
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)) {
if (cursor == null) {
Log.e(TAG, "db cache failed");
return;
}
int uid_idx = cursor.getColumnIndex("uid");
int apk_path_idx = cursor.getColumnIndex("apk_path");
int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name");
int userIdIdx = cursor.getColumnIndex("user_id");
int apkPathIdx = cursor.getColumnIndex("apk_path");
HashSet<Application> obsoletePackages = new HashSet<>();
while (cursor.moveToNext()) {
int uid = cursor.getInt(uid_idx);
String apk_path = cursor.getString(apk_path_idx);
modulesForUid.computeIfAbsent(uid, ignored -> new ArrayList<>()).add(apk_path);
Application app = new Application();
app.packageName = cursor.getString(appPkgNameIdx);
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
public String[] getModulesPathForUid(int uid) {
return isManager(uid) ? new String[0] : modulesForUid.getOrDefault(uid, new ArrayList<>()).toArray(new String[0]);
public String[] getModulesPathForProcess(String processName, int uid) {
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
// The signature matches Riru's
public boolean shouldSkipUid(int uid) {
return !modulesForUid.containsKey(uid) && !isManager(uid);
public boolean shouldSkipProcess(ProcessScope scope) {
return !cachedScope.containsKey(scope) && !isManager(scope.uid);
}
// 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);
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)) {
if (cursor == null) {
return null;
}
int uid_idx = cursor.getColumnIndex("uid");
HashSet<Integer> result = new HashSet<>();
int userIdIdx = cursor.getColumnIndex("user_id");
int appPkgNameIdx = cursor.getColumnIndex("app_pkg_name");
ArrayList<Application> result = new ArrayList<>();
while (cursor.moveToNext()) {
int uid = cursor.getInt(uid_idx);
result.add(uid);
Application scope = new Application();
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;
}
ContentValues values = new ContentValues();
values.put("package_name", packageName);
values.put("module_pkg_name", packageName);
values.put("apk_path", apkPath);
int count = (int) db.insertWithOnConflict("modules", null, values, SQLiteDatabase.CONFLICT_IGNORE);
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) {
cacheScopes();
@ -236,7 +308,7 @@ public class ConfigManager {
Log.w(TAG, "get module id should not be called inside transaction");
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.getCount() != 1) return -1;
cursor.moveToFirst();
@ -244,17 +316,18 @@ public class ConfigManager {
}
}
public boolean setModuleScope(String packageName, int[] uid) {
if (uid == null || uid.length == 0) return false;
public boolean setModuleScope(String packageName, List<Application> scopes) {
if (scopes.isEmpty()) return false;
int mid = getModuleId(packageName);
if (mid == -1) return false;
try {
db.beginTransaction();
db.delete("scope", "mid = ?", new String[]{String.valueOf(mid)});
for (int id : uid) {
for (Application app : scopes) {
ContentValues values = new ContentValues();
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);
}
} finally {
@ -266,15 +339,15 @@ public class ConfigManager {
}
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) {
Log.e(TAG, "query enabled modules failed");
return null;
}
int pkg_idx = cursor.getColumnIndex("package_name");
int modulePkgNameIdx = cursor.getColumnIndex("module_pkg_name");
HashSet<String> result = new HashSet<>();
while (cursor.moveToNext()) {
result.add(cursor.getString(pkg_idx));
result.add(cursor.getString(modulePkgNameIdx));
}
return result.toArray(new String[0]);
}
@ -328,9 +401,13 @@ public class ConfigManager {
return true;
}
public boolean removeApp(int uid) {
int count = db.delete("scope", "uid = ?", new String[]{String.valueOf(uid)});
if (count >= 1) {
public boolean removeAppWithoutCache(Application app) {
int count = db.delete("scope", "app_pkg_name = ? AND user_id=?", new String[]{app.packageName, String.valueOf(app.userId)});
return count >= 1;
}
public boolean removeApp(Application scope) {
if (removeAppWithoutCache(scope)) {
cacheScopes();
return true;
}
@ -397,8 +474,8 @@ public class ConfigManager {
}
}
public boolean isManager(String package_name) {
return package_name.equals(manager);
public boolean isManager(String module_pkg_name) {
return module_pkg_name.equals(manager);
}
public boolean isManager(int uid) {

View File

@ -48,9 +48,13 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
}
@Override
public String[] getModulesList() throws RemoteException {
public String[] getModulesList(String processName) throws RemoteException {
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

View File

@ -5,11 +5,10 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import java.util.List;
import de.robv.android.xposed.XposedBridge;
import io.github.lsposed.lspd.BuildConfig;
import io.github.lsposed.lspd.ILSPManagerService;
import io.github.lsposed.lspd.Application;
import io.github.lsposed.lspd.utils.ParceledListSlice;
public class LSPManagerService extends ILSPManagerService.Stub {
@ -55,13 +54,13 @@ public class LSPManagerService extends ILSPManagerService.Stub {
}
@Override
public boolean setModuleScope(String packageName, int[] uid) {
return ConfigManager.getInstance().setModuleScope(packageName, uid);
public boolean setModuleScope(String packageName, ParceledListSlice<Application> scope) {
return ConfigManager.getInstance().setModuleScope(packageName, scope.getList());
}
@Override
public int[] getModuleScope(String packageName) {
return ConfigManager.getInstance().getModuleScope(packageName);
public ParceledListSlice<Application> getModuleScope(String packageName) {
return new ParceledListSlice<Application>(ConfigManager.getInstance().getModuleScope(packageName));
}
@Override

View File

@ -8,17 +8,25 @@ import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;
import io.github.lsposed.lspd.Application;
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
public class LSPosedService extends ILSPosedService.Stub {
@Override
public ILSPApplicationService requestApplicationService(int uid, int pid) {
public ILSPApplicationService requestApplicationService(int uid, int pid, String processName) {
if (Binder.getCallingUid() != 1000) {
Log.w(TAG, "Someone else got my binder!?");
return null;
}
if (ConfigManager.getInstance().shouldSkipUid(uid)) {
Log.d(TAG, "Skipped uid " + uid);
if (uid == 1000 && processName.equals("android")) {
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;
}
if (ServiceManager.getApplicationService().hasRegister(uid, pid)) {
@ -40,10 +48,14 @@ public class LSPosedService extends ILSPosedService.Stub {
return;
}
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
int userId = intent.getIntExtra(Intent.EXTRA_USER, -1);
boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) && uid > 0 && !replacing) {
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);
boolean isXposedModule = pkgInfo != null && pkgInfo.applicationInfo != null &&

View File

@ -1,16 +1,25 @@
package io.github.lsposed.lspd.service;
import android.content.pm.ComponentInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import io.github.lsposed.lspd.utils.ParceledListSlice;
import static android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS;
public class PackageService {
public static final int PER_USER_RANGE = 100000;
private static IPackageManager pm = null;
private static IBinder binder = null;
@ -34,6 +43,14 @@ public class PackageService {
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 {
ArrayList<PackageInfo> res = new ArrayList<>();
IPackageManager pm = getPackageManager();
@ -46,6 +63,31 @@ public class PackageService {
public static void grantRuntimePermission(String packageName, String permissionName, int userId) throws RemoteException {
IPackageManager pm = getPackageManager();
if (pm == null) return;
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);
}
}

View File

@ -1,6 +1,7 @@
package io.github.lsposed.lspd.service;
import android.content.Context;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
@ -32,7 +33,7 @@ public class ServiceManager {
applicationService = new LSPApplicationService();
managerService = new LSPManagerService();
android.os.ServiceManager.addService("serial", mainService);
android.os.ServiceManager.addService("serial", (IBinder) mainService);
waitSystemService("package");
waitSystemService("activity");
@ -61,10 +62,15 @@ public class ServiceManager {
Log.e(TAG, Log.getStackTraceString(e));
}
Looper.loop();
Log.i(TAG, "server exited");
System.exit(0);
//noinspection InfiniteLoopStatement
while (true) {
try {
Looper.loop();
} catch (Throwable e) {
Log.i(TAG, "server exited with " + Log.getStackTraceString(e));
Log.i(TAG, "restarting");
}
}
}
public static LSPModuleService getModuleService() {

View File

@ -0,0 +1,8 @@
package com.android.server;
public class LocalServices {
public static <T> T getService(Class<T> type) {
throw new UnsupportedOperationException("STUB");
}
}

View File

@ -0,0 +1,4 @@
package com.android.server;
public abstract class SystemService {
}

View File

@ -0,0 +1,7 @@
package com.android.server;
import java.util.ArrayList;
public class SystemServiceManager {
private final ArrayList<SystemService> mServices = new ArrayList<>();
}

View File

@ -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");
}
}
}

View File

@ -0,0 +1,5 @@
package com.android.server.am;
public class ProcessRecord {
String processName = null;
}

View File

@ -0,0 +1,6 @@
package io.github.lsposed.lspd;
parcelable Application {
String packageName;
int userId;
}

View File

@ -1,6 +1,8 @@
package io.github.lsposed.lspd;
import io.github.lsposed.lspd.utils.ParceledListSlice;
import io.github.lsposed.lspd.Application;
interface ILSPManagerService {
ParceledListSlice<PackageInfo> getInstalledPackagesFromAllUsers(int flags) = 2;
@ -11,9 +13,9 @@ interface ILSPManagerService {
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;