From 6f6c4b67d736e96a61f89b5db22c2e9bbde19461 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Mon, 3 Jul 2023 13:40:12 +0800 Subject: [PATCH] Use correct pkg name for system_server (#2580) Allow hooking processes of android package besides system_server system_server: uid=1000 pkg=system proc=system ChooserActivity,ResolverActivity: uid=1000 pkg=android proc=android:ui,system:ui Co-authored-by: 5ec1cff Co-authored-by: vvb2060 --- .../lsposed/manager/adapters/AppHelper.java | 15 ++++++ .../manager/adapters/ScopeAdapter.java | 37 +++++++-------- .../org/lsposed/manager/util/ModuleUtil.java | 47 ++++++++++++------- build.gradle.kts | 6 +-- .../lspd/hooker/LoadedApkCtorHooker.java | 9 ---- .../lspd/hooker/LoadedApkGetCLHooker.java | 3 +- .../java/org/lsposed/lspd/util/Hookers.java | 10 ++-- .../lsposed/lspd/service/ConfigManager.java | 32 +++++++++---- .../lspd/service/LSPApplicationService.java | 3 +- .../lspd/service/LSPSystemServerService.java | 2 +- .../lsposed/lspd/service/LSPosedService.java | 2 +- .../src/main/jni/src/magisk_loader.cpp | 2 +- magisk-loader/src/main/jni/src/service.cpp | 2 +- 13 files changed, 102 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/org/lsposed/manager/adapters/AppHelper.java b/app/src/main/java/org/lsposed/manager/adapters/AppHelper.java index 42142351..91928738 100644 --- a/app/src/main/java/org/lsposed/manager/adapters/AppHelper.java +++ b/app/src/main/java/org/lsposed/manager/adapters/AppHelper.java @@ -27,6 +27,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Parcel; import android.view.MenuItem; import org.lsposed.manager.ConfigManager; @@ -140,6 +141,20 @@ public class AppHelper { synchronized public static List getAppList(boolean force) { if (appList == null || force) { appList = ConfigManager.getInstalledPackagesFromAllUsers(PackageManager.GET_META_DATA | PackageManager.MATCH_UNINSTALLED_PACKAGES, true); + PackageInfo system = null; + for (var app : appList) { + if ("android".equals(app.packageName)) { + var p = Parcel.obtain(); + app.writeToParcel(p, 0); + p.setDataPosition(0); + system = PackageInfo.CREATOR.createFromParcel(p); + system.packageName = "system"; + break; + } + } + if (system != null) { + appList.add(system); + } } return appList; } diff --git a/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java b/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java index d3b739cd..2a3a2f83 100644 --- a/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java +++ b/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java @@ -90,7 +90,6 @@ import rikka.material.app.LocaleDelegate; import rikka.widget.mainswitchbar.MainSwitchBar; import rikka.widget.mainswitchbar.OnMainSwitchChangeListener; -@SuppressLint("NotifyDataSetChanged") public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter implements Filterable { private final Activity activity; @@ -165,7 +164,7 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter tmpChkList) { - if (info.packageName.equals("android")) { + if (info.packageName.equals("system")) { return false; } if (tmpChkList.contains(app)) { @@ -190,18 +189,15 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter comparator = AppHelper.getAppListComparator(preferences.getInt("list_sort", 0), pm); Comparator frameworkComparator = (a, b) -> { - if (a.packageName.equals("android") == b.packageName.equals("android")) { + if (a.packageName.equals("system") == b.packageName.equals("system")) { return comparator.compare(a.packageInfo, b.packageInfo); - } else if (a.packageName.equals("android")) { + } else if (a.packageName.equals("system")) { return -1; } else { return 1; @@ -303,7 +299,6 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter() { @Override @@ -416,16 +411,18 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter { int userId = info.applicationInfo.uid / App.PER_USER_RANGE; String packageName = info.packageName; - if (packageName.equals("android") && userId != 0 || + if (packageName.equals("system") && userId != 0 || packageName.equals(module.packageName) || packageName.equals(BuildConfig.APPLICATION_ID)) { return; @@ -587,7 +586,7 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter ConfigManager.reboot()); } else if (denyList.contains(appInfo.packageName)) { fragment.showHint(activity.getString(R.string.deny_list, appInfo.label), true); diff --git a/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java b/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java index 35968a8a..e6298630 100644 --- a/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java +++ b/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java @@ -43,6 +43,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -257,9 +258,9 @@ public final class ModuleUtil { public final long updateTime; public final ApplicationInfo app; public final PackageInfo pkg; - private String appName; // loaded lazyily - private String description; // loaded lazyily - private List scopeList; // loaded lazyily + private String appName; // loaded lazily + private String description; // loaded lazily + private List scopeList; // loaded lazily private InstalledModule(PackageInfo pkg, ZipFile modernModuleApk) { app = pkg.applicationInfo; @@ -305,6 +306,8 @@ public final class ModuleUtil { try (var reader = new BufferedReader(new InputStreamReader(modernModuleApk.getInputStream(scopeEntry)))) { scopeList = reader.lines().collect(Collectors.toList()); } + } else { + scopeList = Collections.emptyList(); } } catch (IOException | OutOfMemoryError e) { Log.e(App.TAG, "Error while closing modern module APK", e); @@ -350,25 +353,37 @@ public final class ModuleUtil { public List getScopeList() { if (scopeList != null) return scopeList; - if (legacy) { - try { - int scopeListResourceId = app.metaData.getInt("xposedscope"); - if (scopeListResourceId != 0) { - scopeList = Arrays.asList(pm.getResourcesForApplication(app).getStringArray(scopeListResourceId)); - } else { - String scopeListString = app.metaData.getString("xposedscope"); - if (scopeListString != null) - scopeList = Arrays.asList(scopeListString.split(";")); - } - } catch (Exception ignored) { + List list = null; + try { + int scopeListResourceId = app.metaData.getInt("xposedscope"); + if (scopeListResourceId != 0) { + scopeList = Arrays.asList(pm.getResourcesForApplication(app).getStringArray(scopeListResourceId)); + } else { + String scopeListString = app.metaData.getString("xposedscope"); + if (scopeListString != null) + list = Arrays.asList(scopeListString.split(";")); } + } catch (Exception ignored) { } - if (scopeList == null) { + if (list == null) { OnlineModule module = RepoLoader.getInstance().getOnlineModule(packageName); if (module != null && module.getScope() != null) { - scopeList = module.getScope(); + list = module.getScope(); } } + if (list != null) { + list.replaceAll(s -> + switch (s) { + case "android": + yield "system"; + case "system": + yield "android"; + default: + yield s; + } + ); + scopeList = list; + } return scopeList; } diff --git a/build.gradle.kts b/build.gradle.kts index db13ac6c..9ea9a544 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,11 +66,11 @@ val verCode by extra(commitCount) val verName by extra(latestTag) val androidTargetSdkVersion by extra(33) val androidMinSdkVersion by extra(27) -val androidBuildToolsVersion by extra("33.0.1") +val androidBuildToolsVersion by extra("33.0.2") val androidCompileSdkVersion by extra(33) val androidCompileNdkVersion by extra("25.2.9519653") -val androidSourceCompatibility by extra(JavaVersion.VERSION_11) -val androidTargetCompatibility by extra(JavaVersion.VERSION_11) +val androidSourceCompatibility by extra(JavaVersion.VERSION_17) +val androidTargetCompatibility by extra(JavaVersion.VERSION_17) tasks.register("Delete", Delete::class) { delete(rootProject.buildDir) diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java index 3bde9d23..ab93fa48 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java @@ -20,15 +20,12 @@ package org.lsposed.lspd.hooker; -import android.app.ActivityThread; import android.app.LoadedApk; import android.content.res.XResources; import android.util.Log; import org.lsposed.lspd.util.Hookers; -import java.util.Optional; - import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedInit; @@ -59,12 +56,6 @@ public class LoadedApkCtorHooker extends XC_MethodHook { } } - // mIncludeCode checking should go ahead of loadedPackagesInProcess added checking - if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) { - Hookers.logD("LoadedApk# mIncludeCode == false: " + mAppDir); - return; - } - if (!XposedInit.loadedPackagesInProcess.add(packageName)) { Hookers.logD("LoadedApk# has been loaded before, skip: " + mAppDir); return; diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java index 27933e21..560287e8 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java @@ -24,7 +24,6 @@ import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient; import android.annotation.SuppressLint; import android.app.ActivityThread; -import android.app.AndroidAppHelper; import android.app.LoadedApk; import android.content.pm.ApplicationInfo; import android.os.Build; @@ -90,7 +89,7 @@ public class LoadedApkGetCLHooker extends XC_MethodHook { boolean isFirstPackage = packageName != null && processName != null && packageName.equals(loadedApk.getPackageName()); if (!isFirstPackage) { packageName = loadedApk.getPackageName(); - processName = AndroidAppHelper.currentProcessName(); + processName = ActivityThread.currentPackageName(); } else if (packageName.equals("android")) { packageName = "system"; } diff --git a/core/src/main/java/org/lsposed/lspd/util/Hookers.java b/core/src/main/java/org/lsposed/lspd/util/Hookers.java index c878c7a5..6805e8e9 100644 --- a/core/src/main/java/org/lsposed/lspd/util/Hookers.java +++ b/core/src/main/java/org/lsposed/lspd/util/Hookers.java @@ -20,18 +20,18 @@ package org.lsposed.lspd.util; -import android.app.AndroidAppHelper; +import android.app.ActivityThread; public class Hookers { public static void logD(String prefix) { - Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(), - AndroidAppHelper.currentProcessName())); + Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, ActivityThread.currentPackageName(), + ActivityThread.currentProcessName())); } public static void logE(String prefix, Throwable throwable) { - Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(), - AndroidAppHelper.currentProcessName()), throwable); + Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, ActivityThread.currentPackageName(), + ActivityThread.currentProcessName()), throwable); } } diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java index a35bf8ec..053c5f3a 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -39,6 +39,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.SELinux; import android.os.SharedMemory; @@ -202,7 +203,7 @@ public class ConfigManager { Log.e(TAG, "skip injecting into android because sepolicy was not loaded properly"); return true; // skip } - try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"modules.mid"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) { + try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"modules.mid"}, "app_pkg_name=? AND enabled=1", new String[]{"system"}, null, null, null)) { return cursor == null || !cursor.moveToNext(); } } @@ -220,7 +221,7 @@ public class ConfigManager { } List modules = new LinkedList<>(); - try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"module_pkg_name", "apk_path"}, "app_pkg_name=? AND enabled=1", new String[]{"android"}, null, null, null)) { + try (Cursor cursor = db.query("scope INNER JOIN modules ON scope.mid = modules.mid", new String[]{"module_pkg_name", "apk_path"}, "app_pkg_name=? AND enabled=1", new String[]{"system"}, null, null, null)) { int apkPathIdx = cursor.getColumnIndex("apk_path"); int pkgNameIdx = cursor.getColumnIndex("module_pkg_name"); while (cursor.moveToNext()) { @@ -416,11 +417,15 @@ public class ConfigManager { db.compileStatement("DROP TABLE old_configs;").execute(); db.setVersion(2); }); + case 2: + executeInTransaction(() -> { + db.compileStatement("UPDATE scope SET app_pkg_name = 'system' WHERE app_pkg_name = 'android';").execute(); + db.setVersion(3); + }); default: break; } - } catch ( - Throwable e) { + } catch (Throwable e) { Log.e(TAG, "init db", e); } @@ -429,8 +434,17 @@ public class ConfigManager { private List getAssociatedProcesses(Application app) throws RemoteException { Pair, Integer> result = PackageService.fetchProcessesWithUid(app); List processes = new ArrayList<>(); + if (app.packageName.equals("android")) { + // this is hardcoded for ResolverActivity + processes.add(new ProcessScope("system:ui", Process.SYSTEM_UID)); + } for (String processName : result.first) { - processes.add(new ProcessScope(processName, result.second)); + var uid = result.second; + if (uid == Process.SYSTEM_UID && processName.equals("system")) { + // code run in system_server + continue; + } + processes.add(new ProcessScope(processName, uid)); } return processes; } @@ -669,7 +683,7 @@ public class ConfigManager { })) continue; // system server always loads database - if (app.packageName.equals("android")) continue; + if (app.packageName.equals("system")) continue; try { List processesScope = cachedProcessScope.computeIfAbsent(new Pair<>(app.packageName, app.userId), (k) -> { @@ -841,7 +855,7 @@ public class ConfigManager { executeInTransaction(() -> { db.delete("scope", "mid = ?", new String[]{String.valueOf(mid)}); for (Application app : scopes) { - if (app.packageName.equals("android") && app.userId != 0) continue; + if (app.packageName.equals("system") && app.userId != 0) continue; ContentValues values = new ContentValues(); values.put("mid", mid); values.put("app_pkg_name", app.packageName); @@ -858,7 +872,7 @@ public class ConfigManager { if (scopePackageName == null) return false; int mid = getModuleId(packageName); if (mid == -1) return false; - if (scopePackageName.equals("android") && userId != 0) return false; + if (scopePackageName.equals("system") && userId != 0) return false; executeInTransaction(() -> { ContentValues values = new ContentValues(); values.put("mid", mid); @@ -875,7 +889,7 @@ public class ConfigManager { if (scopePackageName == null) return false; int mid = getModuleId(packageName); if (mid == -1) return false; - if (scopePackageName.equals("android") && userId != 0) return false; + if (scopePackageName.equals("system") && userId != 0) return false; executeInTransaction(() -> { db.delete("scope", "mid = ? AND app_pkg_name = ? AND user_id = ?", new String[]{String.valueOf(mid), scopePackageName, String.valueOf(userId)}); }); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java index 4cb1bc7a..40cf3316 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java @@ -24,6 +24,7 @@ import static org.lsposed.lspd.service.ServiceManager.TAG; import android.os.IBinder; import android.os.Parcel; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.util.Pair; @@ -117,7 +118,7 @@ public class LSPApplicationService extends ILSPApplicationService.Stub { private List getAllModulesList() throws RemoteException { var processInfo = ensureRegistered(); - if (processInfo.uid == 1000 && processInfo.processName.equals("android")) { + if (processInfo.uid == Process.SYSTEM_UID && processInfo.processName.equals("system")) { return ConfigManager.getInstance().getModulesForSystemServer(); } if (ServiceManager.getManagerService().isRunningManager(processInfo.pid, processInfo.uid)) diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java index 4ad3166e..9dffa55a 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java @@ -80,7 +80,7 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme public ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) { Log.d(TAG, "ILSPApplicationService.requestApplicationService: " + uid + " " + pid + " " + processName + " " + heartBeat); requested = 1; - if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName)) + if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"system".equals(processName)) return null; else return ServiceManager.requestApplicationService(uid, pid, processName, heartBeat); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java index 10d5638d..da6b62a0 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java @@ -206,7 +206,7 @@ public class LSPosedService extends ILSPosedService.Stub { if (isXposedModule) { var enabledModules = ConfigManager.getInstance().enabledModules(); var scope = ConfigManager.getInstance().getModuleScope(packageName); - boolean systemModule = scope != null && scope.parallelStream().anyMatch(app -> app.packageName.equals("android")); + boolean systemModule = scope != null && scope.parallelStream().anyMatch(app -> app.packageName.equals("system")); boolean enabled = Arrays.asList(enabledModules).contains(packageName); if (!(Intent.ACTION_UID_REMOVED.equals(action) || Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action) || allUsers)) LSPNotificationManager.notifyModuleUpdated(packageName, userId, enabled, systemModule); diff --git a/magisk-loader/src/main/jni/src/magisk_loader.cpp b/magisk-loader/src/main/jni/src/magisk_loader.cpp index 00835a17..d4f4a4d1 100644 --- a/magisk-loader/src/main/jni/src/magisk_loader.cpp +++ b/magisk-loader/src/main/jni/src/magisk_loader.cpp @@ -139,7 +139,7 @@ namespace lspd { SetupEntryClass(env); FindAndCall(env, "forkCommon", "(ZLjava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V", - JNI_TRUE, JNI_NewStringUTF(env, "android"), nullptr, application_binder); + JNI_TRUE, JNI_NewStringUTF(env, "system"), nullptr, application_binder); GetArt(true); } else { LOGI("skipped system server"); diff --git a/magisk-loader/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp index 35b62f75..538b07a6 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -297,7 +297,7 @@ namespace lspd { JNI_CallVoidMethod(env, wrapper.data, write_int_method_, getuid()); JNI_CallVoidMethod(env, wrapper.data, write_int_method_, getpid()); - JNI_CallVoidMethod(env, wrapper.data, write_string_method_, JNI_NewStringUTF(env, "android")); + JNI_CallVoidMethod(env, wrapper.data, write_string_method_, JNI_NewStringUTF(env, "system")); JNI_CallVoidMethod(env, wrapper.data, write_strong_binder_method_, heart_beat_binder); auto res = wrapper.transact(system_server_binder, BRIDGE_TRANSACTION_CODE);