diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml
index ae19985d..3e50c673 100644
--- a/.github/workflows/core.yml
+++ b/.github/workflows/core.yml
@@ -55,7 +55,7 @@ jobs:
with:
path: |
~/.ccache
- core/build/.lto-cache
+ magisk-loader/build/.lto-cache
daemon/build/.lto-cache
key: native-cache-${{ github.sha }}
restore-keys: native-cache-
@@ -83,14 +83,14 @@ jobs:
if: success()
id: prepareArtifact
run: |
- riruReleaseName=`ls core/release/LSPosed-v*-riru-release.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=riruReleaseName::$riruReleaseName"
- riruDebugName=`ls core/release/LSPosed-v*-riru-debug.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=riruDebugName::$riruDebugName"
- zygiskReleaseName=`ls core/release/LSPosed-v*-zygisk-release.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=zygiskReleaseName::$zygiskReleaseName"
- zygiskDebugName=`ls core/release/LSPosed-v*-zygisk-debug.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=zygiskDebugName::$zygiskDebugName"
- unzip core/release/LSPosed-v*-riru-release.zip -d LSPosed-riru-release
- unzip core/release/LSPosed-v*-riru-debug.zip -d LSPosed-riru-debug
- unzip core/release/LSPosed-v*-zygisk-release.zip -d LSPosed-zygisk-release
- unzip core/release/LSPosed-v*-zygisk-debug.zip -d LSPosed-zygisk-debug
+ riruReleaseName=`ls magisk-loader/release/LSPosed-v*-riru-release.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=riruReleaseName::$riruReleaseName"
+ riruDebugName=`ls magisk-loader/release/LSPosed-v*-riru-debug.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=riruDebugName::$riruDebugName"
+ zygiskReleaseName=`ls magisk-loader/release/LSPosed-v*-zygisk-release.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=zygiskReleaseName::$zygiskReleaseName"
+ zygiskDebugName=`ls magisk-loader/release/LSPosed-v*-zygisk-debug.zip | awk -F '(/|.zip)' '{print $3}'` && echo "::set-output name=zygiskDebugName::$zygiskDebugName"
+ unzip magisk-loader/release/LSPosed-v*-riru-release.zip -d LSPosed-riru-release
+ unzip magisk-loader/release/LSPosed-v*-riru-debug.zip -d LSPosed-riru-debug
+ unzip magisk-loader/release/LSPosed-v*-zygisk-release.zip -d LSPosed-zygisk-release
+ unzip magisk-loader/release/LSPosed-v*-zygisk-debug.zip -d LSPosed-zygisk-debug
- name: Upload riru release
uses: actions/upload-artifact@v2
with:
@@ -116,14 +116,14 @@ jobs:
with:
name: mappings
path: |
- core/build/outputs/mapping
+ magisk-loader/build/outputs/mapping
app/build/outputs/mapping
- name: Upload symbols
uses: actions/upload-artifact@v2
with:
name: symbols
path: |
- core/build/symbols
+ magisk-loader/build/symbols
daemon/build/symbols
- name: Post to channel
if: ${{ github.event_name != 'pull_request' && success() && github.ref == 'refs/heads/master' }}
@@ -134,7 +134,7 @@ jobs:
COMMIT_URL: ${{ github.event.head_commit.url }}
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
- OUTPUT="core/release/"
+ OUTPUT="magisk-loader/release/"
export riruRelease=$(find $OUTPUT -name "LSPosed-v*-riru-release.zip")
export riruDebug=$(find $OUTPUT -name "LSPosed-v*-riru-debug.zip")
export zygiskRelease=$(find $OUTPUT -name "LSPosed-v*-zygisk-release.zip")
diff --git a/build.gradle.kts b/build.gradle.kts
index bf2fcde0..6d157aff 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -14,8 +14,9 @@
* You should have received a copy of the GNU General Public License
* along with LSPosed. If not, see .
*
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
+
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.gradle.BaseExtension
@@ -77,6 +78,7 @@ fun Project.configureBaseExtension() {
externalNativeBuild {
cmake {
arguments += "-DEXTERNAL_ROOT=${File(rootDir.absolutePath, "external")}"
+ arguments += "-DCORE_ROOT=${File(rootDir.absolutePath, "core/src/main/jni")}"
abiFilters("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
val flags = arrayOf(
"-Wall",
diff --git a/core/.gitignore b/core/.gitignore
index 99ef122d..9ff2a377 100644
--- a/core/.gitignore
+++ b/core/.gitignore
@@ -1,4 +1,2 @@
/build
-/release
-/src/main/cpp/api/config.cpp
/.cxx
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index e454798d..d488f2d9 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -14,56 +14,26 @@
* You should have received a copy of the GNU General Public License
* along with LSPosed. If not, see .
*
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
-import org.apache.commons.codec.binary.Hex
-import org.apache.tools.ant.filters.FixCrLfFilter
-import org.apache.tools.ant.filters.ReplaceTokens
-import java.io.ByteArrayOutputStream
-import java.security.MessageDigest
-import java.util.*
+val apiCode: Int by rootProject.extra
plugins {
- id("com.android.application")
+ id("com.android.library")
}
-val moduleName = "LSPosed"
-val moduleBaseId = "lsposed"
-val authors = "LSPosed Developers"
-
-val riruModuleId = "lsposed"
-val moduleMinRiruApiVersion = 25
-val moduleMinRiruVersionName = "25.0.1"
-val moduleMaxRiruApiVersion = 25
-
-val injectedPackageName: String by rootProject.extra
-val injectedPackageUid: Int by rootProject.extra
-
-val defaultManagerPackageName: String by rootProject.extra
-val apiCode: Int by rootProject.extra
-val verCode: Int by rootProject.extra
-val verName: String by rootProject.extra
-
android {
- flavorDimensions += "api"
+ namespace = "org.lsposed.lspd.core"
buildFeatures {
- prefab = true
+ androidResources = false
}
defaultConfig {
- applicationId = "org.lsposed.lspd"
- multiDexEnabled = false
+ consumerProguardFiles("proguard-rules.pro")
buildConfigField("int", "API_CODE", "$apiCode")
- buildConfigField(
- "String",
- "DEFAULT_MANAGER_PACKAGE_NAME",
- """"$defaultManagerPackageName""""
- )
- buildConfigField("String", "MANAGER_INJECTED_PKG_NAME", """"$injectedPackageName"""")
- buildConfigField("int", "MANAGER_INJECTED_UID", """$injectedPackageUid""")
}
buildTypes {
@@ -72,253 +42,14 @@ android {
proguardFiles("proguard-rules.pro")
}
}
-
- externalNativeBuild {
- cmake {
- path("src/main/jni/CMakeLists.txt")
- }
- }
-
- productFlavors {
- all {
- externalNativeBuild {
- cmake {
- arguments += "-DMODULE_NAME=${name.toLowerCase()}_$moduleBaseId"
- arguments += "-DAPI=${name.toLowerCase()}"
- }
- }
- buildConfigField("String", "API", """"$name"""")
- }
-
- create("Riru") {
- dimension = "api"
- externalNativeBuild {
- cmake {
- arguments += "-DAPI_VERSION=$moduleMaxRiruApiVersion"
- }
- }
- }
-
- create("Zygisk") {
- dimension = "api"
- externalNativeBuild {
- cmake {
- arguments += "-DAPI_VERSION=1"
- }
- }
- }
- }
-
}
-
dependencies {
implementation("org.apache.commons:commons-lang3:3.12.0")
implementation("de.upb.cs.swt:axml:2.1.2")
compileOnly("androidx.annotation:annotation:1.3.0")
compileOnly(projects.hiddenapi.stubs)
implementation(projects.hiddenapi.bridge)
- implementation(projects.services.managerService)
implementation(projects.services.daemonService)
+ implementation(projects.services.managerService)
}
-
-val zipAll = task("zipAll") {
-
-}
-
-val apkDir: String
- get() = if (rootProject.extra.properties["android.injected.invoked.from.ide"] == "true") "intermediates" else "outputs"
-
-fun afterEval() = android.applicationVariants.forEach { variant ->
- val variantCapped = variant.name.capitalize(Locale.ROOT)
- val variantLowered = variant.name.toLowerCase(Locale.ROOT)
- val buildTypeCapped = variant.buildType.name.capitalize(Locale.ROOT)
- val buildTypeLowered = variant.buildType.name.toLowerCase(Locale.ROOT)
- val flavorCapped = variant.flavorName!!.capitalize(Locale.ROOT)
- val flavorLowered = variant.flavorName!!.toLowerCase(Locale.ROOT)
-
- val magiskDir = "$buildDir/magisk/$variantLowered"
-
- val moduleId = "${flavorLowered}_$moduleBaseId"
- val zipFileName = "$moduleName-v$verName-$verCode-${flavorLowered}-$buildTypeLowered.zip"
-
- val prepareMagiskFilesTask = task("prepareMagiskFiles$variantCapped") {
- dependsOn(
- "assemble$variantCapped",
- ":app:package$buildTypeCapped",
- ":daemon:package$buildTypeCapped"
- )
- into(magiskDir)
- from("${rootProject.projectDir}/README.md")
- from("$projectDir/magisk_module") {
- exclude("riru.sh", "module.prop", "customize.sh", "sepolicy.rule", "post-fs-data.sh")
- }
- from("$projectDir/magisk_module") {
- include("module.prop")
- expand(
- "moduleId" to moduleId,
- "versionName" to "v$verName",
- "versionCode" to verCode,
- "authorList" to authors,
- "updateJson" to "https://lsposed.github.io/LSPosed/release/${flavorLowered}.json",
- "requirement" to when (flavorLowered) {
- "riru" -> "Requires Riru $moduleMinRiruVersionName or above installed"
- "zygisk" -> "Requires Magisk 24.0+ and Zygisk enabled"
- else -> "No further requirements"
- },
- "api" to flavorCapped
- )
- filter("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
- }
- from("$projectDir/magisk_module") {
- include("customize.sh", "post-fs-data.sh")
- val tokens = mapOf("FLAVOR" to flavorLowered)
- filter("tokens" to tokens)
- filter("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
- }
- if (flavorLowered == "riru") {
- from("${projectDir}/magisk_module") {
- include("riru.sh", "sepolicy.rule")
- val tokens = mapOf(
- "RIRU_MODULE_LIB_NAME" to "lspd",
- "RIRU_MODULE_API_VERSION" to moduleMaxRiruApiVersion.toString(),
- "RIRU_MODULE_MIN_API_VERSION" to moduleMinRiruApiVersion.toString(),
- "RIRU_MODULE_MIN_RIRU_VERSION_NAME" to moduleMinRiruVersionName,
- "RIRU_MODULE_DEBUG" to if (buildTypeLowered == "debug") "true" else "false",
- )
- filter("tokens" to tokens)
- filter("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
- }
- }
- from(project(":app").tasks.getByName("package$buildTypeCapped").outputs) {
- include("*.apk")
- rename(".*\\.apk", "manager.apk")
- }
- from(project(":daemon").tasks.getByName("package$buildTypeCapped").outputs) {
- include("*.apk")
- rename(".*\\.apk", "daemon.apk")
- }
- into("lib") {
- from("${buildDir}/intermediates/cmake/$variantCapped/obj") {
- include("**/liblspd.so")
- }
- from("${project(":daemon").buildDir}/intermediates/cmake/$buildTypeLowered/obj") {
- include("**/libdaemon.so")
- }
- }
- val dexOutPath = if (buildTypeLowered == "release")
- "$buildDir/intermediates/dex/$variantCapped/minify${variantCapped}WithR8" else
- "$buildDir/intermediates/dex/$variantCapped/mergeDex$variantCapped"
- into("framework") {
- from(dexOutPath)
- rename("classes.dex", "lspd.dex")
- }
- doLast {
- fileTree(magiskDir).visit {
- if (isDirectory) return@visit
- val md = MessageDigest.getInstance("SHA-256")
- file.forEachBlock(4096) { bytes, size ->
- md.update(bytes, 0, size)
- }
- file(file.path + ".sha256").writeText(Hex.encodeHexString(md.digest()))
- }
- }
- }
-
- val zipTask = task("zip${variantCapped}") {
- dependsOn(prepareMagiskFilesTask)
- archiveFileName.set(zipFileName)
- destinationDirectory.set(file("$projectDir/release"))
- from(magiskDir)
- }
-
- zipAll.dependsOn(zipTask)
-
- val adb: String = androidComponents.sdkComponents.adb.get().asFile.absolutePath
- val pushTask = task("push${variantCapped}") {
- dependsOn(zipTask)
- workingDir("${projectDir}/release")
- commandLine(adb, "push", zipFileName, "/data/local/tmp/")
- }
- val flashTask = task("flash${variantCapped}") {
- dependsOn(pushTask)
- commandLine(
- adb, "shell", "su", "-c",
- "magisk --install-module /data/local/tmp/${zipFileName}"
- )
- }
- task("flashAndReboot${variantCapped}") {
- dependsOn(flashTask)
- commandLine(adb, "shell", "reboot")
- }
-}
-
-afterEvaluate {
- afterEval()
-}
-
-val adb: String = androidComponents.sdkComponents.adb.get().asFile.absolutePath
-val killLspd = task("killLspd") {
- commandLine(adb, "shell", "su", "-c", "killall", "lspd")
- isIgnoreExitValue = true
-}
-val pushDaemon = task("pushDaemon") {
- dependsOn(":daemon:assembleDebug")
- workingDir("${project(":daemon").buildDir}/$apkDir/apk/debug")
- commandLine(adb, "push", "daemon-debug.apk", "/data/local/tmp/daemon.apk")
-}
-val pushDaemonNative = task("pushDaemonNative") {
- dependsOn(":daemon:assembleDebug")
- doFirst {
- val abi: String = ByteArrayOutputStream().use { outputStream ->
- exec {
- commandLine(adb, "shell", "getprop", "ro.product.cpu.abi")
- standardOutput = outputStream
- }
- outputStream.toString().trim()
- }
- workingDir("${project(":daemon").buildDir}/intermediates/ndkBuild/debug/obj/local/$abi")
- }
- commandLine(adb, "push", "libdaemon.so", "/data/local/tmp/libdaemon.so")
-}
-val reRunDaemon = task("reRunDaemon") {
- dependsOn(pushDaemon, pushDaemonNative, killLspd)
- // tricky to pass a minus number to avoid the injection warning
- commandLine(
- adb,
- "shell",
- "ASH_STANDALONE=1",
- "su",
- "-pc",
- "/data/adb/magisk/busybox sh /data/adb/modules/*_lsposed/service.sh --system-server-max-retry=-1&"
- )
- isIgnoreExitValue = true
-}
-val tmpApk = "/data/local/tmp/lsp.apk"
-val pushApk = task("pushApk") {
- dependsOn(":app:assembleDebug")
- workingDir("${project(":app").buildDir}/$apkDir/apk/debug")
- commandLine(adb, "push", "app-debug.apk", tmpApk)
-}
-val openApp = task("openApp") {
- commandLine(
- adb,
- "shell",
- "am",
- "start",
- "-a",
- "android.intent.action.MAIN",
- "-c",
- "org.lsposed.manager.LAUNCH_MANAGER",
- "com.android.shell/.BugreportWarningActivity"
- )
-}
-task("reRunApp") {
- dependsOn(pushApk)
- commandLine(adb, "shell", "su", "-c", "mv -f $tmpApk /data/adb/lspd/manager.apk")
- isIgnoreExitValue = true
- finalizedBy(reRunDaemon)
-}
-
-evaluationDependsOn(":app")
-evaluationDependsOn(":daemon")
diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro
index f92b4bc8..5e7ede50 100644
--- a/core/proguard-rules.pro
+++ b/core/proguard-rules.pro
@@ -1,15 +1,8 @@
-keep class de.robv.android.xposed.** {*;}
-keep class android.** { *; }
--keepclasseswithmembers class org.lsposed.lspd.core.Main {
- public static void forkSystemServerPost(android.os.IBinder);
- public static void forkAndSpecializePost(java.lang.String, java.lang.String, android.os.IBinder);
-}
-keepclasseswithmembers,includedescriptorclasses class * {
native ;
}
--keepclasseswithmembers class org.lsposed.lspd.service.BridgeService {
- public static boolean *(android.os.IBinder, int, long, long, int);
-}
-assumenosideeffects class android.util.Log {
public static *** v(...);
diff --git a/core/src/main/java/de/robv/android/xposed/XSharedPreferences.java b/core/src/main/java/de/robv/android/xposed/XSharedPreferences.java
index fe7ab025..7a77f9e8 100644
--- a/core/src/main/java/de/robv/android/xposed/XSharedPreferences.java
+++ b/core/src/main/java/de/robv/android/xposed/XSharedPreferences.java
@@ -15,7 +15,7 @@
* along with LSPosed. If not, see .
*
* Copyright (C) 2020 EdXposed Contributors
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
package de.robv.android.xposed;
@@ -31,7 +31,7 @@ import android.util.Log;
import com.android.internal.util.XmlUtils;
-import org.lsposed.lspd.BuildConfig;
+import org.lsposed.lspd.core.BuildConfig;
import org.lsposed.lspd.util.MetaDataReader;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/src/main/java/de/robv/android/xposed/XposedBridge.java b/core/src/main/java/de/robv/android/xposed/XposedBridge.java
index 723000af..3b813c8e 100644
--- a/core/src/main/java/de/robv/android/xposed/XposedBridge.java
+++ b/core/src/main/java/de/robv/android/xposed/XposedBridge.java
@@ -15,7 +15,7 @@
* along with LSPosed. If not, see .
*
* Copyright (C) 2020 EdXposed Contributors
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
package de.robv.android.xposed;
@@ -27,7 +27,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.Log;
-import org.lsposed.lspd.BuildConfig;
+import org.lsposed.lspd.core.BuildConfig;
import org.lsposed.lspd.nativebridge.HookBridge;
import org.lsposed.lspd.nativebridge.ResourcesHook;
diff --git a/core/src/main/java/org/lsposed/lspd/core/Main.java b/core/src/main/java/org/lsposed/lspd/core/Startup.java
similarity index 62%
rename from core/src/main/java/org/lsposed/lspd/core/Main.java
rename to core/src/main/java/org/lsposed/lspd/core/Startup.java
index 4fcc3c05..5702f770 100644
--- a/core/src/main/java/org/lsposed/lspd/core/Main.java
+++ b/core/src/main/java/org/lsposed/lspd/core/Startup.java
@@ -15,7 +15,7 @@
* along with LSPosed. If not, see .
*
* Copyright (C) 2020 EdXposed Contributors
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
package org.lsposed.lspd.core;
@@ -24,30 +24,23 @@ import android.app.ActivityThread;
import android.app.LoadedApk;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
-import android.os.Environment;
-import android.os.IBinder;
import android.os.Process;
import com.android.internal.os.ZygoteInit;
-import org.lsposed.lspd.BuildConfig;
-import org.lsposed.lspd.config.LSPApplicationServiceClient;
import org.lsposed.lspd.deopt.PrebuiltMethodsDeopter;
import org.lsposed.lspd.hooker.CrashDumpHooker;
import org.lsposed.lspd.hooker.HandleBindAppHooker;
-import org.lsposed.lspd.hooker.LoadedApkCstrHooker;
import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker;
-import org.lsposed.lspd.util.ParasiticManagerHooker;
+import org.lsposed.lspd.hooker.LoadedApkCstrHooker;
import org.lsposed.lspd.util.Utils;
-import java.io.File;
-
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.XposedInit;
-public class Main {
- public static void startBootstrapHook(boolean isSystem, String appDataDir) {
+public class Startup {
+ private static void startBootstrapHook(boolean isSystem) {
Utils.logD("startBootstrapHook starts: isSystem = " + isSystem);
XposedHelpers.findAndHookMethod(Thread.class, "dispatchUncaughtException",
Throwable.class, new CrashDumpHooker());
@@ -58,45 +51,28 @@ public class Main {
XposedHelpers.findAndHookMethod(ActivityThread.class,
"handleBindApplication",
"android.app.ActivityThread$AppBindData",
- new HandleBindAppHooker(appDataDir));
+ new HandleBindAppHooker());
XposedHelpers.findAndHookConstructor(LoadedApk.class,
ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class,
ClassLoader.class, boolean.class, boolean.class, boolean.class,
new LoadedApkCstrHooker());
}
- private static void installBootstrapHooks(boolean isSystem, String appDataDir) {
+ public static void bootstrapXposed(String niceName) {
// Initialize the Xposed framework
try {
- startBootstrapHook(isSystem, appDataDir);
+ startBootstrapHook(XposedInit.startsSystemServer);
+ Utils.logI("Loading modules for " + niceName + "/" + Process.myUid());
+ XposedInit.loadModules();
} catch (Throwable t) {
Utils.logE("error during Xposed initialization", t);
}
}
- public static void forkPostCommon(boolean isSystem, String appDataDir, String niceName) {
+ public static void initXposed(boolean isSystem) {
// init logger
XposedBridge.initXResources();
XposedInit.startsSystemServer = isSystem;
PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote
- if ((niceName.equals(BuildConfig.MANAGER_INJECTED_PKG_NAME) || niceName.equals(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME))
- && ParasiticManagerHooker.start()) {
- Utils.logI("Loaded manager, skipping next steps");
- return;
- }
- installBootstrapHooks(isSystem, appDataDir);
- Utils.logI("Loading modules for " + niceName + "/" + Process.myUid());
- XposedInit.loadModules();
- }
-
- public static void forkAndSpecializePost(String appDataDir, String niceName, IBinder binder) {
- LSPApplicationServiceClient.Init(binder, niceName);
- forkPostCommon(false, appDataDir, niceName);
- }
-
- public static void forkSystemServerPost(IBinder binder) {
- LSPApplicationServiceClient.Init(binder, "android");
- forkPostCommon(true,
- new File(Environment.getDataDirectory(), "android").toString(), "system_server");
}
}
diff --git a/core/src/main/java/org/lsposed/lspd/hooker/HandleBindAppHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/HandleBindAppHooker.java
index 00f17763..686ce0e6 100644
--- a/core/src/main/java/org/lsposed/lspd/hooker/HandleBindAppHooker.java
+++ b/core/src/main/java/org/lsposed/lspd/hooker/HandleBindAppHooker.java
@@ -15,7 +15,7 @@
* along with LSPosed. If not, see .
*
* Copyright (C) 2020 EdXposed Contributors
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
package org.lsposed.lspd.hooker;
@@ -35,11 +35,6 @@ import de.robv.android.xposed.XposedInit;
// normal process initialization (for new Activity, Service, BroadcastReceiver etc.)
public class HandleBindAppHooker extends XC_MethodHook {
- String appDataDir;
-
- public HandleBindAppHooker(String appDataDir) {
- this.appDataDir = appDataDir;
- }
@Override
protected void beforeHookedMethod(MethodHookParam param) {
@@ -54,8 +49,7 @@ public class HandleBindAppHooker extends XC_MethodHook {
// Note: packageName="android" -> system_server process, ams pms etc;
// packageName="system" -> android pkg, system dialogues.
- Utils.logD("processName=" + appProcessName +
- ", packageName=" + reportedPackageName + ", appDataDir=" + appDataDir);
+ Utils.logD("processName=" + appProcessName + ", packageName=" + reportedPackageName);
CompatibilityInfo compatInfo = (CompatibilityInfo) XposedHelpers.getObjectField(bindData, "compatInfo");
if (appInfo.sourceDir == null) {
diff --git a/core/src/main/jni/CMakeLists.txt b/core/src/main/jni/CMakeLists.txt
index 30c2202a..8dfa79b8 100644
--- a/core/src/main/jni/CMakeLists.txt
+++ b/core/src/main/jni/CMakeLists.txt
@@ -1,4 +1,4 @@
-project(lspd)
+project(core)
cmake_minimum_required(VERSION 3.4.1)
add_subdirectory(${EXTERNAL_ROOT} external)
@@ -7,27 +7,11 @@ configure_file(template/config.cpp src/config.cpp)
aux_source_directory(src SRC_LIST)
aux_source_directory(src/jni SRC_LIST)
-if (${API} STREQUAL "riru")
- set(SRC_LIST ${SRC_LIST} api/riru_main.cpp)
-elseif (${API} STREQUAL "zygisk")
- set(SRC_LIST ${SRC_LIST} api/zygisk_main.cpp)
-endif()
-add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/src/config.cpp)
+add_library(${PROJECT_NAME} STATIC ${SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/src/config.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC include)
target_include_directories(${PROJECT_NAME} PRIVATE src)
-target_link_libraries(${PROJECT_NAME} dobby dex_builder_static log lsplant_static)
-
-if (DEFINED DEBUG_SYMBOLS_PATH)
- set(DEBUG_SYMBOLS_PATH ${DEBUG_SYMBOLS_PATH}/${API})
- message(STATUS "Debug symbols will be placed at ${DEBUG_SYMBOLS_PATH}")
- add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory ${DEBUG_SYMBOLS_PATH}/${ANDROID_ABI}
- COMMAND ${CMAKE_OBJCOPY} --only-keep-debug $
- ${DEBUG_SYMBOLS_PATH}/${ANDROID_ABI}/${PROJECT_NAME}.debug
- COMMAND ${CMAKE_STRIP} --strip-all $
- COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink ${DEBUG_SYMBOLS_PATH}/${ANDROID_ABI}/${PROJECT_NAME}.debug
- $)
-endif()
+target_link_libraries(${PROJECT_NAME} PUBLIC dobby lsplant_static log)
+target_link_libraries(${PROJECT_NAME} PRIVATE dex_builder_static)
diff --git a/core/src/main/jni/include/config.h b/core/src/main/jni/include/config.h
index 5ab07278..4c5eff54 100644
--- a/core/src/main/jni/include/config.h
+++ b/core/src/main/jni/include/config.h
@@ -15,7 +15,7 @@
* along with LSPosed. If not, see .
*
* Copyright (C) 2020 EdXposed Contributors
- * Copyright (C) 2021 LSPosed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
*/
#pragma once
@@ -59,9 +59,6 @@ namespace lspd {
# define LP_SELECT(lp32, lp64) lp32
#endif
- inline static constexpr auto kEntryClassName = "org.lsposed.lspd.core.Main"_tstr;
- inline static constexpr auto kBridgeServiceClassName = "org.lsposed.lspd.service.BridgeService"_tstr;
-
inline static constexpr auto kLibArtName = "libart.so"_tstr;
inline static constexpr auto kLibFwName = "libandroidfw.so"_tstr;
@@ -70,7 +67,5 @@ namespace lspd {
}
extern const int versionCode;
- extern const int apiVersion;
extern const char* const versionName;
- extern const char* const moduleName;
}
diff --git a/core/src/main/jni/src/context.h b/core/src/main/jni/include/context.h
similarity index 71%
rename from core/src/main/jni/src/context.h
rename to core/src/main/jni/include/context.h
index 2e66db3c..030ddf2a 100644
--- a/core/src/main/jni/src/context.h
+++ b/core/src/main/jni/include/context.h
@@ -49,22 +49,12 @@ namespace lspd {
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
};
- void OnNativeForkAndSpecializePre(JNIEnv *env, jint uid, jintArray &gids, jstring nice_name,
- jboolean is_child_zygote, jstring app_data_dir);
+ virtual ~Context() = default;
- void OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name, jstring app_data_dir);
-
- void OnNativeForkSystemServerPost(JNIEnv *env);
-
- void OnNativeForkSystemServerPre(JNIEnv *env);
-
- void Init();
-
- private:
- inline static std::unique_ptr instance_ = std::make_unique();
+ protected:
+ inline static std::unique_ptr instance_;
jobject inject_class_loader_ = nullptr;
jclass entry_class_ = nullptr;
- bool skip_ = false;
struct PreloadedDex {
@@ -90,7 +80,7 @@ namespace lspd {
};
// Use with caution!
- PreloadedDex(void* addr, size_t size) : addr_(addr), size_(size) {};
+ PreloadedDex(void *addr, size_t size) : addr_(addr), size_(size) {};
operator bool() const { return addr_ && size_; }
@@ -107,19 +97,31 @@ namespace lspd {
Context() {}
- void LoadDex(JNIEnv *env, int fd, size_t size);
-
- void Init(JNIEnv *env, const lsplant::InitInfo& initInfo);
-
static lsplant::ScopedLocalRef FindClassFromLoader(JNIEnv *env, jobject class_loader,
- std::string_view class_name);
-
- static void setAllowUnload(bool unload);
+ std::string_view class_name);
template
- void FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig,
- Args &&... args) const;
+ inline void FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig,
+ Args &&... args) const {
+ if (!entry_class_) [[unlikely]] {
+ LOGE("cannot call method %s, entry class is null", method_name.data());
+ return;
+ }
+ jmethodID mid = lsplant::JNI_GetStaticMethodID(env, entry_class_, method_name, method_sig);
+ if (mid) [[likely]] {
+ lsplant::JNI_CallStaticVoidMethod(env, entry_class_, mid, std::forward(args)...);
+ } else {
+ LOGE("method %s id is null", method_name.data());
+ }
+ }
+ virtual void InitHooks(JNIEnv *env, const lsplant::InitInfo &initInfo);
+
+ virtual void LoadDex(JNIEnv *env, PreloadedDex &&dex) = 0;
+
+ virtual void SetupEntryClass(JNIEnv *env) = 0;
+
+ private:
friend std::unique_ptr std::make_unique();
};
diff --git a/core/src/main/jni/src/elf_util.h b/core/src/main/jni/include/elf_util.h
similarity index 100%
rename from core/src/main/jni/src/elf_util.h
rename to core/src/main/jni/include/elf_util.h
diff --git a/core/src/main/jni/src/native_hook.h b/core/src/main/jni/include/native_hook.h
similarity index 100%
rename from core/src/main/jni/src/native_hook.h
rename to core/src/main/jni/include/native_hook.h
diff --git a/core/src/main/jni/src/symbol_cache.h b/core/src/main/jni/include/symbol_cache.h
similarity index 100%
rename from core/src/main/jni/src/symbol_cache.h
rename to core/src/main/jni/include/symbol_cache.h
diff --git a/core/src/main/jni/src/context.cpp b/core/src/main/jni/src/context.cpp
index 1c4b47c5..c19e937c 100644
--- a/core/src/main/jni/src/context.cpp
+++ b/core/src/main/jni/src/context.cpp
@@ -19,39 +19,19 @@
*/
#include
+
#include "config.h"
-#include "utils/jni_helper.hpp"
-#include "jni/resources_hook.h"
#include "context.h"
#include "native_hook.h"
-#include "elf_util.h"
+#include "native_util.h"
#include "jni/hook_bridge.h"
#include "jni/native_api.h"
-#include "service.h"
-#include
+#include "jni/resources_hook.h"
#include "symbol_cache.h"
-#include
-#include
-#include
-
using namespace lsplant;
-static_assert(FS_IOC_SETFLAGS == LP_SELECT(0x40046602, 0x40086602));
-
namespace lspd {
- extern int *allowUnload;
-
- constexpr int FIRST_ISOLATED_UID = 99000;
- constexpr int LAST_ISOLATED_UID = 99999;
- constexpr int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
- constexpr int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
- constexpr int SHARED_RELRO_UID = 1037;
- constexpr int PER_USER_RANGE = 100000;
-
- static constexpr uid_t kAidInjected = INJECTED_AID;
- static constexpr uid_t kAidInet = 3003;
-
Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) {
LOGD("Context::PreloadedDex::PreloadedDex: fd=%d, size=%zu", fd, size);
auto *addr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
@@ -68,46 +48,10 @@ namespace lspd {
if (*this) munmap(addr_, size_);
}
- void Context::LoadDex(JNIEnv *env, int fd, size_t size) {
- LOGD("Context::LoadDex: %d", fd);
- // map fd to memory. fd should be created with ASharedMemory_create.
- auto dex = PreloadedDex(fd, size); // for RAII...
-
- auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
- auto getsyscl_mid = JNI_GetStaticMethodID(
- env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
- auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
- if (!sys_classloader) [[unlikely]] {
- LOGE("getSystemClassLoader failed!!!");
- return;
- }
- auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
- auto initMid = JNI_GetMethodID(env, in_memory_classloader, "",
- "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
- auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
- auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size());
- if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
- dex_buffer, sys_classloader)) {
- inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
- } else {
- LOGE("InMemoryDexClassLoader creation failed!!!");
- return;
- }
-
- env->DeleteLocalRef(dex_buffer);
- }
-
- void Context::Init() {
- }
-
- void Context::Init(JNIEnv *env, const lsplant::InitInfo& initInfo) {
+ void Context::InitHooks(JNIEnv *env, const lsplant::InitInfo& initInfo) {
if (!lsplant::Init(env, initInfo)) {
return;
}
- if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(),
- kEntryClassName)) {
- entry_class_ = JNI_NewGlobalRef(env, entry_class);
- }
RegisterResourcesHook(env);
RegisterHookBridge(env);
@@ -138,160 +82,4 @@ namespace lspd {
LOGE("Class %s not found", class_name.data());
return {env, nullptr};
}
-
- template
- void
- Context::FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig,
- Args &&... args) const {
- if (!entry_class_) [[unlikely]] {
- LOGE("cannot call method %s, entry class is null", method_name.data());
- return;
- }
- jmethodID mid = JNI_GetStaticMethodID(env, entry_class_, method_name, method_sig);
- if (mid) [[likely]] {
- JNI_CallStaticVoidMethod(env, entry_class_, mid, std::forward(args)...);
- } else {
- LOGE("method %s id is null", method_name.data());
- }
- }
-
- void
- Context::OnNativeForkSystemServerPre(JNIEnv *env) {
- Service::instance()->InitService(env);
- skip_ = !symbol_cache->initialized.test(std::memory_order_acquire);
- if (skip_) [[unlikely]] {
- LOGW("skip system server due to symbol cache");
- }
- setAllowUnload(skip_);
- }
-
- void
- Context::OnNativeForkSystemServerPost(JNIEnv *env) {
- if (!skip_) {
- auto *instance = Service::instance();
- auto system_server_binder = instance->RequestSystemServerBinder(env);
- if (!system_server_binder) {
- LOGF("Failed to get system server binder, system server initialization failed. ");
- return;
- }
-
- auto application_binder = instance->RequestApplicationBinderFromSystemServer(env, system_server_binder);
-
- // Call application_binder directly if application binder is available,
- // or we proxy the request from system server binder
- auto [dex_fd, size]= instance->RequestLSPDex(env, application_binder ? application_binder : system_server_binder);
- LoadDex(env, dex_fd, size);
- close(dex_fd);
- instance->HookBridge(*this, env);
-
- if (application_binder) {
- lsplant::InitInfo initInfo{
- .inline_hooker = [](auto t, auto r) {
- void* bk = nullptr;
- return HookFunction(t, r, &bk) == RS_SUCCESS ? bk : nullptr;
- },
- .inline_unhooker = [](auto t) {
- return UnhookFunction(t) == RT_SUCCESS ;
- },
- .art_symbol_resolver = [](auto symbol) {
- return GetArt()->getSymbAddress(symbol);
- },
- };
- InstallInlineHooks(initInfo);
- Init(env, initInfo);
- FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", application_binder);
- GetArt(true);
- } else {
- LOGI("skipped system server");
- GetArt(true);
- }
- }
- }
-
- void Context::OnNativeForkAndSpecializePre(JNIEnv *env,
- jint uid,
- jintArray &gids,
- jstring nice_name,
- jboolean is_child_zygote,
- jstring app_data_dir) {
- if (uid == kAidInjected) {
- int array_size = gids ? env->GetArrayLength(gids) : 0;
- auto region = std::make_unique(array_size + 1);
- auto *new_gids = env->NewIntArray(array_size + 1);
- if (gids) env->GetIntArrayRegion(gids, 0, array_size, region.get());
- region.get()[array_size] = kAidInet;
- env->SetIntArrayRegion(new_gids, 0, array_size + 1, region.get());
- if (gids) env->SetIntArrayRegion(gids, 0, 1, region.get() + array_size);
- gids = new_gids;
- }
- Service::instance()->InitService(env);
- const auto app_id = uid % PER_USER_RANGE;
- JUTFString process_name(env, nice_name);
- skip_ = !symbol_cache->initialized.test(std::memory_order_acquire);
- if (!skip_ && !app_data_dir) {
- LOGD("skip injecting into %s because it has no data dir", process_name.get());
- skip_ = true;
- }
- if (!skip_ && is_child_zygote) {
- skip_ = true;
- LOGD("skip injecting into %s because it's a child zygote", process_name.get());
- }
-
- if (!skip_ && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
- (app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
- app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
- app_id == SHARED_RELRO_UID)) {
- skip_ = true;
- LOGI("skip injecting into %s because it's isolated", process_name.get());
- }
- setAllowUnload(skip_);
- }
-
- void
- Context::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name,
- jstring app_data_dir) {
- const JUTFString process_name(env, nice_name);
- auto *instance = Service::instance();
- auto binder = skip_ ? ScopedLocalRef{env, nullptr}
- : instance->RequestBinder(env, nice_name);
- if (binder) {
- lsplant::InitInfo initInfo{
- .inline_hooker = [](auto t, auto r) {
- void* bk = nullptr;
- return HookFunction(t, r, &bk) == RS_SUCCESS ? bk : nullptr;
- },
- .inline_unhooker = [](auto t) {
- return UnhookFunction(t) == RT_SUCCESS;
- },
- .art_symbol_resolver = [](auto symbol){
- return GetArt()->getSymbAddress(symbol);
- },
- };
- InstallInlineHooks(initInfo);
- auto [dex_fd, size] = instance->RequestLSPDex(env, binder);
- LoadDex(env, dex_fd, size);
- close(dex_fd);
- Init(env, initInfo);
- LOGD("Done prepare");
- FindAndCall(env, "forkAndSpecializePost",
- "(Ljava/lang/String;Ljava/lang/String;Landroid/os/IBinder;)V",
- app_data_dir, nice_name,
- binder);
- LOGD("injected xposed into %s", process_name.get());
- setAllowUnload(false);
- GetArt(true);
- } else {
- auto context = Context::ReleaseInstance();
- auto service = Service::ReleaseInstance();
- GetArt(true);
- LOGD("skipped %s", process_name.get());
- setAllowUnload(true);
- }
- }
-
- void Context::setAllowUnload(bool unload) {
- if (allowUnload) {
- *allowUnload = unload ? 1 : 0;
- }
- }
} // namespace lspd
diff --git a/core/src/main/jni/template/config.cpp b/core/src/main/jni/template/config.cpp
index d2fcef6d..3f6e9568 100644
--- a/core/src/main/jni/template/config.cpp
+++ b/core/src/main/jni/template/config.cpp
@@ -2,7 +2,5 @@
namespace lspd {
const int versionCode = ${VERSION_CODE};
-const int apiVersion = ${API_VERSION};
const char* const versionName = "${VERSION_NAME}";
-const char* const moduleName = "${MODULE_NAME}";
}
diff --git a/magisk-loader/.gitignore b/magisk-loader/.gitignore
new file mode 100644
index 00000000..b5e4b9f3
--- /dev/null
+++ b/magisk-loader/.gitignore
@@ -0,0 +1,3 @@
+/build
+/release
+/.cxx
diff --git a/magisk-loader/build.gradle.kts b/magisk-loader/build.gradle.kts
new file mode 100644
index 00000000..7ec0fa55
--- /dev/null
+++ b/magisk-loader/build.gradle.kts
@@ -0,0 +1,321 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
+ */
+
+import org.apache.commons.codec.binary.Hex
+import org.apache.tools.ant.filters.FixCrLfFilter
+import org.apache.tools.ant.filters.ReplaceTokens
+import java.io.ByteArrayOutputStream
+import java.security.MessageDigest
+import java.util.*
+
+plugins {
+ id("com.android.application")
+}
+
+val moduleName = "LSPosed"
+val moduleBaseId = "lsposed"
+val authors = "LSPosed Developers"
+
+val riruModuleId = "lsposed"
+val moduleMinRiruApiVersion = 25
+val moduleMinRiruVersionName = "25.0.1"
+val moduleMaxRiruApiVersion = 25
+
+val injectedPackageName: String by rootProject.extra
+val injectedPackageUid: Int by rootProject.extra
+
+val defaultManagerPackageName: String by rootProject.extra
+val apiCode: Int by rootProject.extra
+val verCode: Int by rootProject.extra
+val verName: String by rootProject.extra
+
+android {
+ flavorDimensions += "api"
+
+ buildFeatures {
+ prefab = true
+ }
+
+ defaultConfig {
+ applicationId = "org.lsposed.lspd"
+ multiDexEnabled = false
+
+ buildConfigField("int", "API_CODE", "$apiCode")
+ buildConfigField(
+ "String",
+ "DEFAULT_MANAGER_PACKAGE_NAME",
+ """"$defaultManagerPackageName""""
+ )
+ buildConfigField("String", "MANAGER_INJECTED_PKG_NAME", """"$injectedPackageName"""")
+ buildConfigField("int", "MANAGER_INJECTED_UID", """$injectedPackageUid""")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ proguardFiles("proguard-rules.pro")
+ }
+ }
+
+ externalNativeBuild {
+ cmake {
+ path("src/main/jni/CMakeLists.txt")
+ }
+ }
+
+ productFlavors {
+ all {
+ externalNativeBuild {
+ cmake {
+ arguments += "-DMODULE_NAME=${name.toLowerCase()}_$moduleBaseId"
+ arguments += "-DAPI=${name.toLowerCase()}"
+ }
+ }
+ buildConfigField("String", "API", """"$name"""")
+ }
+
+ create("Riru") {
+ dimension = "api"
+ externalNativeBuild {
+ cmake {
+ arguments += "-DAPI_VERSION=$moduleMaxRiruApiVersion"
+ }
+ }
+ }
+
+ create("Zygisk") {
+ dimension = "api"
+ externalNativeBuild {
+ cmake {
+ arguments += "-DAPI_VERSION=1"
+ }
+ }
+ }
+ }
+}
+
+dependencies {
+ compileOnly("androidx.annotation:annotation:1.3.0")
+ compileOnly(projects.hiddenapi.stubs)
+ implementation(projects.core)
+ implementation(projects.hiddenapi.bridge)
+ implementation(projects.services.managerService)
+ implementation(projects.services.daemonService)
+}
+
+val zipAll = task("zipAll") {
+
+}
+
+val apkDir: String
+ get() = if (rootProject.extra.properties["android.injected.invoked.from.ide"] == "true") "intermediates" else "outputs"
+
+fun afterEval() = android.applicationVariants.forEach { variant ->
+ val variantCapped = variant.name.capitalize(Locale.ROOT)
+ val variantLowered = variant.name.toLowerCase(Locale.ROOT)
+ val buildTypeCapped = variant.buildType.name.capitalize(Locale.ROOT)
+ val buildTypeLowered = variant.buildType.name.toLowerCase(Locale.ROOT)
+ val flavorCapped = variant.flavorName!!.capitalize(Locale.ROOT)
+ val flavorLowered = variant.flavorName!!.toLowerCase(Locale.ROOT)
+
+ val magiskDir = "$buildDir/magisk/$variantLowered"
+
+ val moduleId = "${flavorLowered}_$moduleBaseId"
+ val zipFileName = "$moduleName-v$verName-$verCode-${flavorLowered}-$buildTypeLowered.zip"
+
+ val prepareMagiskFilesTask = task("prepareMagiskFiles$variantCapped") {
+ dependsOn(
+ "assemble$variantCapped",
+ ":app:package$buildTypeCapped",
+ ":daemon:package$buildTypeCapped"
+ )
+ into(magiskDir)
+ from("${rootProject.projectDir}/README.md")
+ from("$projectDir/magisk_module") {
+ exclude("riru.sh", "module.prop", "customize.sh", "sepolicy.rule", "post-fs-data.sh")
+ }
+ from("$projectDir/magisk_module") {
+ include("module.prop")
+ expand(
+ "moduleId" to moduleId,
+ "versionName" to "v$verName",
+ "versionCode" to verCode,
+ "authorList" to authors,
+ "updateJson" to "https://lsposed.github.io/LSPosed/release/${flavorLowered}.json",
+ "requirement" to when (flavorLowered) {
+ "riru" -> "Requires Riru $moduleMinRiruVersionName or above installed"
+ "zygisk" -> "Requires Magisk 24.0+ and Zygisk enabled"
+ else -> "No further requirements"
+ },
+ "api" to flavorCapped
+ )
+ filter("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
+ }
+ from("$projectDir/magisk_module") {
+ include("customize.sh", "post-fs-data.sh")
+ val tokens = mapOf("FLAVOR" to flavorLowered)
+ filter("tokens" to tokens)
+ filter("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
+ }
+ if (flavorLowered == "riru") {
+ from("${projectDir}/magisk_module") {
+ include("riru.sh", "sepolicy.rule")
+ val tokens = mapOf(
+ "RIRU_MODULE_LIB_NAME" to "lspd",
+ "RIRU_MODULE_API_VERSION" to moduleMaxRiruApiVersion.toString(),
+ "RIRU_MODULE_MIN_API_VERSION" to moduleMinRiruApiVersion.toString(),
+ "RIRU_MODULE_MIN_RIRU_VERSION_NAME" to moduleMinRiruVersionName,
+ "RIRU_MODULE_DEBUG" to if (buildTypeLowered == "debug") "true" else "false",
+ )
+ filter("tokens" to tokens)
+ filter("eol" to FixCrLfFilter.CrLf.newInstance("lf"))
+ }
+ }
+ from(project(":app").tasks.getByName("package$buildTypeCapped").outputs) {
+ include("*.apk")
+ rename(".*\\.apk", "manager.apk")
+ }
+ from(project(":daemon").tasks.getByName("package$buildTypeCapped").outputs) {
+ include("*.apk")
+ rename(".*\\.apk", "daemon.apk")
+ }
+ into("lib") {
+ from("${buildDir}/intermediates/cmake/$variantCapped/obj") {
+ include("**/liblspd.so")
+ }
+ from("${project(":daemon").buildDir}/intermediates/cmake/$buildTypeLowered/obj") {
+ include("**/libdaemon.so")
+ }
+ }
+ val dexOutPath = if (buildTypeLowered == "release")
+ "$buildDir/intermediates/dex/$variantCapped/minify${variantCapped}WithR8" else
+ "$buildDir/intermediates/dex/$variantCapped/mergeDex$variantCapped"
+ into("framework") {
+ from(dexOutPath)
+ rename("classes.dex", "lspd.dex")
+ }
+ doLast {
+ fileTree(magiskDir).visit {
+ if (isDirectory) return@visit
+ val md = MessageDigest.getInstance("SHA-256")
+ file.forEachBlock(4096) { bytes, size ->
+ md.update(bytes, 0, size)
+ }
+ file(file.path + ".sha256").writeText(Hex.encodeHexString(md.digest()))
+ }
+ }
+ }
+
+ val zipTask = task("zip${variantCapped}") {
+ dependsOn(prepareMagiskFilesTask)
+ archiveFileName.set(zipFileName)
+ destinationDirectory.set(file("$projectDir/release"))
+ from(magiskDir)
+ }
+
+ zipAll.dependsOn(zipTask)
+
+ val adb: String = androidComponents.sdkComponents.adb.get().asFile.absolutePath
+ val pushTask = task("push${variantCapped}") {
+ dependsOn(zipTask)
+ workingDir("${projectDir}/release")
+ commandLine(adb, "push", zipFileName, "/data/local/tmp/")
+ }
+ val flashTask = task("flash${variantCapped}") {
+ dependsOn(pushTask)
+ commandLine(
+ adb, "shell", "su", "-c",
+ "magisk --install-module /data/local/tmp/${zipFileName}"
+ )
+ }
+ task("flashAndReboot${variantCapped}") {
+ dependsOn(flashTask)
+ commandLine(adb, "shell", "reboot")
+ }
+}
+
+afterEvaluate {
+ afterEval()
+}
+
+val adb: String = androidComponents.sdkComponents.adb.get().asFile.absolutePath
+val killLspd = task("killLspd") {
+ commandLine(adb, "shell", "su", "-c", "killall", "lspd")
+ isIgnoreExitValue = true
+}
+val pushDaemon = task("pushDaemon") {
+ dependsOn(":daemon:assembleDebug")
+ workingDir("${project(":daemon").buildDir}/$apkDir/apk/debug")
+ commandLine(adb, "push", "daemon-debug.apk", "/data/local/tmp/daemon.apk")
+}
+val pushDaemonNative = task("pushDaemonNative") {
+ dependsOn(":daemon:assembleDebug")
+ doFirst {
+ val abi: String = ByteArrayOutputStream().use { outputStream ->
+ exec {
+ commandLine(adb, "shell", "getprop", "ro.product.cpu.abi")
+ standardOutput = outputStream
+ }
+ outputStream.toString().trim()
+ }
+ workingDir("${project(":daemon").buildDir}/intermediates/ndkBuild/debug/obj/local/$abi")
+ }
+ commandLine(adb, "push", "libdaemon.so", "/data/local/tmp/libdaemon.so")
+}
+val reRunDaemon = task("reRunDaemon") {
+ dependsOn(pushDaemon, pushDaemonNative, killLspd)
+ // tricky to pass a minus number to avoid the injection warning
+ commandLine(
+ adb,
+ "shell",
+ "ASH_STANDALONE=1",
+ "su",
+ "-pc",
+ "/data/adb/magisk/busybox sh /data/adb/modules/*_lsposed/service.sh --system-server-max-retry=-1&"
+ )
+ isIgnoreExitValue = true
+}
+val tmpApk = "/data/local/tmp/lsp.apk"
+val pushApk = task("pushApk") {
+ dependsOn(":app:assembleDebug")
+ workingDir("${project(":app").buildDir}/$apkDir/apk/debug")
+ commandLine(adb, "push", "app-debug.apk", tmpApk)
+}
+val openApp = task("openApp") {
+ commandLine(
+ adb,
+ "shell",
+ "am",
+ "start",
+ "-a",
+ "android.intent.action.MAIN",
+ "-c",
+ "org.lsposed.manager.LAUNCH_MANAGER",
+ "com.android.shell/.BugreportWarningActivity"
+ )
+}
+task("reRunApp") {
+ dependsOn(pushApk)
+ commandLine(adb, "shell", "su", "-c", "mv -f $tmpApk /data/adb/lspd/manager.apk")
+ isIgnoreExitValue = true
+ finalizedBy(reRunDaemon)
+}
+
+evaluationDependsOn(":app")
+evaluationDependsOn(":daemon")
diff --git a/core/magisk_module/META-INF/com/google/android/update-binary b/magisk-loader/magisk_module/META-INF/com/google/android/update-binary
similarity index 100%
rename from core/magisk_module/META-INF/com/google/android/update-binary
rename to magisk-loader/magisk_module/META-INF/com/google/android/update-binary
diff --git a/core/magisk_module/META-INF/com/google/android/updater-script b/magisk-loader/magisk_module/META-INF/com/google/android/updater-script
similarity index 100%
rename from core/magisk_module/META-INF/com/google/android/updater-script
rename to magisk-loader/magisk_module/META-INF/com/google/android/updater-script
diff --git a/core/magisk_module/customize.sh b/magisk-loader/magisk_module/customize.sh
similarity index 100%
rename from core/magisk_module/customize.sh
rename to magisk-loader/magisk_module/customize.sh
diff --git a/core/magisk_module/daemon b/magisk-loader/magisk_module/daemon
similarity index 100%
rename from core/magisk_module/daemon
rename to magisk-loader/magisk_module/daemon
diff --git a/core/magisk_module/module.prop b/magisk-loader/magisk_module/module.prop
similarity index 100%
rename from core/magisk_module/module.prop
rename to magisk-loader/magisk_module/module.prop
diff --git a/core/magisk_module/post-fs-data.sh b/magisk-loader/magisk_module/post-fs-data.sh
similarity index 100%
rename from core/magisk_module/post-fs-data.sh
rename to magisk-loader/magisk_module/post-fs-data.sh
diff --git a/core/magisk_module/riru.sh b/magisk-loader/magisk_module/riru.sh
similarity index 100%
rename from core/magisk_module/riru.sh
rename to magisk-loader/magisk_module/riru.sh
diff --git a/core/magisk_module/sepolicy.rule b/magisk-loader/magisk_module/sepolicy.rule
similarity index 100%
rename from core/magisk_module/sepolicy.rule
rename to magisk-loader/magisk_module/sepolicy.rule
diff --git a/core/magisk_module/service.sh b/magisk-loader/magisk_module/service.sh
similarity index 100%
rename from core/magisk_module/service.sh
rename to magisk-loader/magisk_module/service.sh
diff --git a/core/magisk_module/system.prop b/magisk-loader/magisk_module/system.prop
similarity index 100%
rename from core/magisk_module/system.prop
rename to magisk-loader/magisk_module/system.prop
diff --git a/core/magisk_module/uninstall.sh b/magisk-loader/magisk_module/uninstall.sh
similarity index 100%
rename from core/magisk_module/uninstall.sh
rename to magisk-loader/magisk_module/uninstall.sh
diff --git a/core/magisk_module/util_functions.sh b/magisk-loader/magisk_module/util_functions.sh
similarity index 100%
rename from core/magisk_module/util_functions.sh
rename to magisk-loader/magisk_module/util_functions.sh
diff --git a/core/magisk_module/verify.sh b/magisk-loader/magisk_module/verify.sh
similarity index 100%
rename from core/magisk_module/verify.sh
rename to magisk-loader/magisk_module/verify.sh
diff --git a/magisk-loader/proguard-rules.pro b/magisk-loader/proguard-rules.pro
new file mode 100644
index 00000000..bb5a17a5
--- /dev/null
+++ b/magisk-loader/proguard-rules.pro
@@ -0,0 +1,17 @@
+-keepclasseswithmembers class org.lsposed.lspd.core.Main {
+ public static void forkCommon(boolean, java.lang.String, android.os.IBinder);
+}
+-keepclasseswithmembers,includedescriptorclasses class * {
+ native ;
+}
+-keepclasseswithmembers class org.lsposed.lspd.service.BridgeService {
+ public static boolean *(android.os.IBinder, int, long, long, int);
+}
+
+-assumenosideeffects class android.util.Log {
+ public static *** v(...);
+ public static *** d(...);
+}
+-repackageclasses
+-allowaccessmodification
+-dontwarn org.slf4j.impl.StaticLoggerBinder
diff --git a/core/src/main/AndroidManifest.xml b/magisk-loader/src/main/AndroidManifest.xml
similarity index 89%
rename from core/src/main/AndroidManifest.xml
rename to magisk-loader/src/main/AndroidManifest.xml
index 1f659bee..c04c0dc9 100644
--- a/core/src/main/AndroidManifest.xml
+++ b/magisk-loader/src/main/AndroidManifest.xml
@@ -14,8 +14,7 @@
~ You should have received a copy of the GNU General Public License
~ along with LSPosed. If not, see .
~
- ~ Copyright (C) 2020 EdXposed Contributors
- ~ Copyright (C) 2021 LSPosed Contributors
+ ~ Copyright (C) 2022 LSPosed Contributors
-->
diff --git a/magisk-loader/src/main/java/org/lsposed/lspd/core/Main.java b/magisk-loader/src/main/java/org/lsposed/lspd/core/Main.java
new file mode 100644
index 00000000..1ba77634
--- /dev/null
+++ b/magisk-loader/src/main/java/org/lsposed/lspd/core/Main.java
@@ -0,0 +1,41 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2022 LSPosed Contributors
+ */
+
+package org.lsposed.lspd.core;
+
+import android.os.IBinder;
+
+import org.lsposed.lspd.BuildConfig;
+import org.lsposed.lspd.config.LSPApplicationServiceClient;
+import org.lsposed.lspd.util.ParasiticManagerHooker;
+import org.lsposed.lspd.util.Utils;
+
+public class Main {
+
+ public static void forkCommon(boolean isSystem, String niceName, IBinder binder) {
+ LSPApplicationServiceClient.Init(binder, niceName);
+ Startup.initXposed(isSystem);
+ if ((niceName.equals(BuildConfig.MANAGER_INJECTED_PKG_NAME) || niceName.equals(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME))
+ && ParasiticManagerHooker.start()) {
+ Utils.logI("Loaded manager, skipping next steps");
+ return;
+ }
+ Startup.bootstrapXposed(niceName);
+ }
+}
diff --git a/core/src/main/java/org/lsposed/lspd/service/ActivityController.java b/magisk-loader/src/main/java/org/lsposed/lspd/service/ActivityController.java
similarity index 100%
rename from core/src/main/java/org/lsposed/lspd/service/ActivityController.java
rename to magisk-loader/src/main/java/org/lsposed/lspd/service/ActivityController.java
diff --git a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java b/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java
similarity index 99%
rename from core/src/main/java/org/lsposed/lspd/service/BridgeService.java
rename to magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java
index 10ccbb40..71fcd4e1 100644
--- a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java
+++ b/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java
@@ -28,7 +28,6 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
-import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
diff --git a/core/src/main/java/org/lsposed/lspd/service/ParcelUtils.java b/magisk-loader/src/main/java/org/lsposed/lspd/service/ParcelUtils.java
similarity index 100%
rename from core/src/main/java/org/lsposed/lspd/service/ParcelUtils.java
rename to magisk-loader/src/main/java/org/lsposed/lspd/service/ParcelUtils.java
diff --git a/core/src/main/java/org/lsposed/lspd/util/ParasiticManagerHooker.java b/magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerHooker.java
similarity index 100%
rename from core/src/main/java/org/lsposed/lspd/util/ParasiticManagerHooker.java
rename to magisk-loader/src/main/java/org/lsposed/lspd/util/ParasiticManagerHooker.java
diff --git a/magisk-loader/src/main/jni/CMakeLists.txt b/magisk-loader/src/main/jni/CMakeLists.txt
new file mode 100644
index 00000000..4dfc3f69
--- /dev/null
+++ b/magisk-loader/src/main/jni/CMakeLists.txt
@@ -0,0 +1,32 @@
+project(lspd)
+cmake_minimum_required(VERSION 3.4.1)
+
+add_subdirectory(${CORE_ROOT} core)
+
+configure_file(template/loader.cpp src/loader.cpp)
+
+aux_source_directory(src SRC_LIST)
+if (${API} STREQUAL "riru")
+ set(SRC_LIST ${SRC_LIST} api/riru_main.cpp)
+elseif (${API} STREQUAL "zygisk")
+ set(SRC_LIST ${SRC_LIST} api/zygisk_main.cpp)
+endif()
+
+add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/src/loader.cpp)
+
+target_include_directories(${PROJECT_NAME} PUBLIC include)
+target_include_directories(${PROJECT_NAME} PRIVATE src)
+
+target_link_libraries(${PROJECT_NAME} core log)
+
+if (DEFINED DEBUG_SYMBOLS_PATH)
+ set(DEBUG_SYMBOLS_PATH ${DEBUG_SYMBOLS_PATH}/${API})
+ message(STATUS "Debug symbols will be placed at ${DEBUG_SYMBOLS_PATH}")
+ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${DEBUG_SYMBOLS_PATH}/${ANDROID_ABI}
+ COMMAND ${CMAKE_OBJCOPY} --only-keep-debug $
+ ${DEBUG_SYMBOLS_PATH}/${ANDROID_ABI}/${PROJECT_NAME}.debug
+ COMMAND ${CMAKE_STRIP} --strip-all $
+ COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink ${DEBUG_SYMBOLS_PATH}/${ANDROID_ABI}/${PROJECT_NAME}.debug
+ $)
+endif()
diff --git a/core/src/main/jni/api/riru.h b/magisk-loader/src/main/jni/api/riru.h
similarity index 100%
rename from core/src/main/jni/api/riru.h
rename to magisk-loader/src/main/jni/api/riru.h
diff --git a/core/src/main/jni/api/riru_main.cpp b/magisk-loader/src/main/jni/api/riru_main.cpp
similarity index 86%
rename from core/src/main/jni/api/riru_main.cpp
rename to magisk-loader/src/main/jni/api/riru_main.cpp
index 22c36708..80bb0b17 100644
--- a/core/src/main/jni/api/riru_main.cpp
+++ b/magisk-loader/src/main/jni/api/riru_main.cpp
@@ -23,8 +23,8 @@
#include
#include
#include "logging.h"
-#include "config.h"
-#include "context.h"
+#include "loader.h"
+#include "magisk_loader.h"
#include "symbol_cache.h"
#define RIRU_MODULE
@@ -36,13 +36,12 @@ namespace lspd {
std::string magiskPath;
jstring nice_name = nullptr;
- jstring app_data_dir = nullptr;
void onModuleLoaded() {
LOGI("onModuleLoaded: welcome to LSPosed!");
LOGI("onModuleLoaded: version v%s (%d)", versionName, versionCode);
InitSymbolCache(nullptr);
- Context::GetInstance()->Init();
+ MagiskLoader::Init();
}
void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *,
@@ -57,28 +56,27 @@ namespace lspd {
jboolean *,
jboolean *) {
nice_name = *_nice_name;
- app_data_dir = *_app_data_dir;
- Context::GetInstance()->OnNativeForkAndSpecializePre(env, *_uid, *gids,
+ MagiskLoader::GetInstance()->OnNativeForkAndSpecializePre(env, *_uid, *gids,
nice_name,
*start_child_zygote,
- app_data_dir);
+ *_app_data_dir);
}
void nativeForkAndSpecializePost(JNIEnv *env, jclass, jint res) {
if (res == 0)
- Context::GetInstance()->OnNativeForkAndSpecializePost(env, nice_name, app_data_dir);
+ MagiskLoader::GetInstance()->OnNativeForkAndSpecializePost(env, nice_name);
}
void nativeForkSystemServerPre(JNIEnv *env, jclass, uid_t *, gid_t *,
jintArray *, jint *,
jobjectArray *, jlong *,
jlong *) {
- Context::GetInstance()->OnNativeForkSystemServerPre(env);
+ MagiskLoader::GetInstance()->OnNativeForkSystemServerPre(env);
}
void nativeForkSystemServerPost(JNIEnv *env, jclass, jint res) {
if (res == 0)
- Context::GetInstance()->OnNativeForkSystemServerPost(env);
+ MagiskLoader::GetInstance()->OnNativeForkSystemServerPost(env);
}
/* method added in Android Q */
@@ -93,15 +91,14 @@ namespace lspd {
jboolean *,
jboolean *) {
nice_name = *_nice_name;
- app_data_dir = *_app_data_dir;
- Context::GetInstance()->OnNativeForkAndSpecializePre(env, *_uid, *gids,
+ MagiskLoader::GetInstance()->OnNativeForkAndSpecializePre(env, *_uid, *gids,
nice_name,
*start_child_zygote,
- app_data_dir);
+ *_app_data_dir);
}
void specializeAppProcessPost(JNIEnv *env, jclass) {
- Context::GetInstance()->OnNativeForkAndSpecializePost(env, nice_name, app_data_dir);
+ MagiskLoader::GetInstance()->OnNativeForkAndSpecializePost(env, nice_name);
}
}
diff --git a/core/src/main/jni/api/zygisk.h b/magisk-loader/src/main/jni/api/zygisk.h
similarity index 100%
rename from core/src/main/jni/api/zygisk.h
rename to magisk-loader/src/main/jni/api/zygisk.h
diff --git a/core/src/main/jni/api/zygisk_main.cpp b/magisk-loader/src/main/jni/api/zygisk_main.cpp
similarity index 96%
rename from core/src/main/jni/api/zygisk_main.cpp
rename to magisk-loader/src/main/jni/api/zygisk_main.cpp
index 3914d2ce..05b3537e 100644
--- a/core/src/main/jni/api/zygisk_main.cpp
+++ b/magisk-loader/src/main/jni/api/zygisk_main.cpp
@@ -24,8 +24,8 @@
#include "zygisk.h"
#include "logging.h"
-#include "context.h"
-#include "config.h"
+#include "loader.h"
+#include "magisk_loader.h"
#include "symbol_cache.h"
namespace lspd {
@@ -281,7 +281,7 @@ namespace lspd {
void onLoad(zygisk::Api *api, JNIEnv *env) override {
env_ = env;
api_ = api;
- Context::GetInstance()->Init();
+ MagiskLoader::Init();
auto companion = api->connectCompanion();
if (companion == -1) {
@@ -308,19 +308,18 @@ namespace lspd {
}
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
- Context::GetInstance()->OnNativeForkAndSpecializePre(
+ MagiskLoader::GetInstance()->OnNativeForkAndSpecializePre(
env_, args->uid, args->gids, args->nice_name,
args->is_child_zygote ? *args->is_child_zygote : false, args->app_data_dir);
}
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
- Context::GetInstance()->OnNativeForkAndSpecializePost(env_, args->nice_name,
- args->app_data_dir);
+ MagiskLoader::GetInstance()->OnNativeForkAndSpecializePost(env_, args->nice_name);
if (*allowUnload) api_->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
}
void preServerSpecialize([[maybe_unused]] zygisk::ServerSpecializeArgs *args) override {
- Context::GetInstance()->OnNativeForkSystemServerPre(env_);
+ MagiskLoader::GetInstance()->OnNativeForkSystemServerPre(env_);
}
void postServerSpecialize([[maybe_unused]] const zygisk::ServerSpecializeArgs *args) override {
@@ -333,7 +332,7 @@ namespace lspd {
env_->DeleteLocalRef(name);
env_->DeleteLocalRef(process);
}
- Context::GetInstance()->OnNativeForkSystemServerPost(env_);
+ MagiskLoader::GetInstance()->OnNativeForkSystemServerPost(env_);
if (*allowUnload) api_->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
}
};
diff --git a/magisk-loader/src/main/jni/include/loader.h b/magisk-loader/src/main/jni/include/loader.h
new file mode 100644
index 00000000..90838ee3
--- /dev/null
+++ b/magisk-loader/src/main/jni/include/loader.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2022 LSPosed Contributors
+ */
+
+//
+// Created by Nullptr on 2022/3/16.
+//
+
+#pragma once
+
+#include "config.h"
+
+namespace lspd {
+ inline static constexpr auto kEntryClassName = "org.lsposed.lspd.core.Main"_tstr;
+ inline static constexpr auto kBridgeServiceClassName = "org.lsposed.lspd.service.BridgeService"_tstr;
+
+ extern const int apiVersion;
+ extern const char* const moduleName;
+}
diff --git a/magisk-loader/src/main/jni/src/magisk_loader.cpp b/magisk-loader/src/main/jni/src/magisk_loader.cpp
new file mode 100644
index 00000000..8801a32f
--- /dev/null
+++ b/magisk-loader/src/main/jni/src/magisk_loader.cpp
@@ -0,0 +1,224 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2020 EdXposed Contributors
+ * Copyright (C) 2021 - 2022 LSPosed Contributors
+ */
+
+#include
+#include
+#include
+
+#include "elf_util.h"
+#include "loader.h"
+#include "magisk_loader.h"
+#include "native_hook.h"
+#include "native_util.h"
+#include "service.h"
+#include "symbol_cache.h"
+#include "utils/jni_helper.hpp"
+
+using namespace lsplant;
+
+static_assert(FS_IOC_SETFLAGS == LP_SELECT(0x40046602, 0x40086602));
+
+namespace lspd {
+ extern int *allowUnload;
+
+ constexpr int FIRST_ISOLATED_UID = 99000;
+ constexpr int LAST_ISOLATED_UID = 99999;
+ constexpr int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
+ constexpr int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
+ constexpr int SHARED_RELRO_UID = 1037;
+ constexpr int PER_USER_RANGE = 100000;
+
+ static constexpr uid_t kAidInjected = INJECTED_AID;
+ static constexpr uid_t kAidInet = 3003;
+
+ void MagiskLoader::LoadDex(JNIEnv *env, PreloadedDex &&dex) {
+ auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
+ auto getsyscl_mid = JNI_GetStaticMethodID(
+ env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
+ auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
+ if (!sys_classloader) [[unlikely]] {
+ LOGE("getSystemClassLoader failed!!!");
+ return;
+ }
+ auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
+ auto initMid = JNI_GetMethodID(env, in_memory_classloader, "",
+ "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
+ auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
+ auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size());
+ if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
+ dex_buffer, sys_classloader)) {
+ inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
+ } else {
+ LOGE("InMemoryDexClassLoader creation failed!!!");
+ return;
+ }
+
+ env->DeleteLocalRef(dex_buffer);
+ }
+
+ void MagiskLoader::SetupEntryClass(JNIEnv *env) {
+ if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(),
+ kEntryClassName)) {
+ entry_class_ = JNI_NewGlobalRef(env, entry_class);
+ }
+ }
+
+ void
+ MagiskLoader::OnNativeForkSystemServerPre(JNIEnv *env) {
+ Service::instance()->InitService(env);
+ skip_ = !symbol_cache->initialized.test(std::memory_order_acquire);
+ if (skip_) [[unlikely]] {
+ LOGW("skip system server due to symbol cache");
+ }
+ setAllowUnload(skip_);
+ }
+
+ void
+ MagiskLoader::OnNativeForkSystemServerPost(JNIEnv *env) {
+ if (!skip_) {
+ auto *instance = Service::instance();
+ auto system_server_binder = instance->RequestSystemServerBinder(env);
+ if (!system_server_binder) {
+ LOGF("Failed to get system server binder, system server initialization failed. ");
+ return;
+ }
+
+ auto application_binder = instance->RequestApplicationBinderFromSystemServer(env, system_server_binder);
+
+ // Call application_binder directly if application binder is available,
+ // or we proxy the request from system server binder
+ auto [dex_fd, size]= instance->RequestLSPDex(env, application_binder ? application_binder : system_server_binder);
+ LoadDex(env, PreloadedDex(dex_fd, size));
+ close(dex_fd);
+ instance->HookBridge(*this, env);
+
+ if (application_binder) {
+ lsplant::InitInfo initInfo{
+ .inline_hooker = [](auto t, auto r) {
+ void* bk = nullptr;
+ return HookFunction(t, r, &bk) == RS_SUCCESS ? bk : nullptr;
+ },
+ .inline_unhooker = [](auto t) {
+ return UnhookFunction(t) == RT_SUCCESS ;
+ },
+ .art_symbol_resolver = [](auto symbol) {
+ return GetArt()->getSymbAddress(symbol);
+ },
+ };
+ InstallInlineHooks(initInfo);
+ InitHooks(env, initInfo);
+ SetupEntryClass(env);
+ FindAndCall(env, "forkCommon",
+ "(ZLjava/lang/String;Landroid/os/IBinder;)V",
+ JNI_TRUE, JNI_NewStringUTF(env, "android"), application_binder);
+ GetArt(true);
+ } else {
+ LOGI("skipped system server");
+ GetArt(true);
+ }
+ }
+ }
+
+ void MagiskLoader::OnNativeForkAndSpecializePre(JNIEnv *env,
+ jint uid,
+ jintArray &gids,
+ jstring nice_name,
+ jboolean is_child_zygote,
+ jstring app_data_dir) {
+ if (uid == kAidInjected) {
+ int array_size = gids ? env->GetArrayLength(gids) : 0;
+ auto region = std::make_unique(array_size + 1);
+ auto *new_gids = env->NewIntArray(array_size + 1);
+ if (gids) env->GetIntArrayRegion(gids, 0, array_size, region.get());
+ region.get()[array_size] = kAidInet;
+ env->SetIntArrayRegion(new_gids, 0, array_size + 1, region.get());
+ if (gids) env->SetIntArrayRegion(gids, 0, 1, region.get() + array_size);
+ gids = new_gids;
+ }
+ Service::instance()->InitService(env);
+ const auto app_id = uid % PER_USER_RANGE;
+ JUTFString process_name(env, nice_name);
+ skip_ = !symbol_cache->initialized.test(std::memory_order_acquire);
+ if (!skip_ && !app_data_dir) {
+ LOGD("skip injecting into %s because it has no data dir", process_name.get());
+ skip_ = true;
+ }
+ if (!skip_ && is_child_zygote) {
+ skip_ = true;
+ LOGD("skip injecting into %s because it's a child zygote", process_name.get());
+ }
+
+ if (!skip_ && ((app_id >= FIRST_ISOLATED_UID && app_id <= LAST_ISOLATED_UID) ||
+ (app_id >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
+ app_id <= LAST_APP_ZYGOTE_ISOLATED_UID) ||
+ app_id == SHARED_RELRO_UID)) {
+ skip_ = true;
+ LOGI("skip injecting into %s because it's isolated", process_name.get());
+ }
+ setAllowUnload(skip_);
+ }
+
+ void
+ MagiskLoader::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name) {
+ const JUTFString process_name(env, nice_name);
+ auto *instance = Service::instance();
+ auto binder = skip_ ? ScopedLocalRef{env, nullptr}
+ : instance->RequestBinder(env, nice_name);
+ if (binder) {
+ lsplant::InitInfo initInfo{
+ .inline_hooker = [](auto t, auto r) {
+ void* bk = nullptr;
+ return HookFunction(t, r, &bk) == RS_SUCCESS ? bk : nullptr;
+ },
+ .inline_unhooker = [](auto t) {
+ return UnhookFunction(t) == RT_SUCCESS;
+ },
+ .art_symbol_resolver = [](auto symbol){
+ return GetArt()->getSymbAddress(symbol);
+ },
+ };
+ InstallInlineHooks(initInfo);
+ auto [dex_fd, size] = instance->RequestLSPDex(env, binder);
+ LoadDex(env, PreloadedDex(dex_fd, size));
+ close(dex_fd);
+ InitHooks(env, initInfo);
+ SetupEntryClass(env);
+ LOGD("Done prepare");
+ FindAndCall(env, "forkCommon",
+ "(ZLjava/lang/String;Landroid/os/IBinder;)V",
+ JNI_FALSE, nice_name, binder);
+ LOGD("injected xposed into %s", process_name.get());
+ setAllowUnload(false);
+ GetArt(true);
+ } else {
+ auto context = Context::ReleaseInstance();
+ auto service = Service::ReleaseInstance();
+ GetArt(true);
+ LOGD("skipped %s", process_name.get());
+ setAllowUnload(true);
+ }
+ }
+
+ void MagiskLoader::setAllowUnload(bool unload) {
+ if (allowUnload) {
+ *allowUnload = unload ? 1 : 0;
+ }
+ }
+} // namespace lspd
diff --git a/magisk-loader/src/main/jni/src/magisk_loader.h b/magisk-loader/src/main/jni/src/magisk_loader.h
new file mode 100644
index 00000000..f418ebcf
--- /dev/null
+++ b/magisk-loader/src/main/jni/src/magisk_loader.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2022 LSPosed Contributors
+ */
+
+//
+// Created by Nullptr on 2022/3/16.
+//
+
+#pragma once
+
+#include "context.h"
+
+namespace lspd {
+ class MagiskLoader : public Context {
+ public:
+ inline static void Init() {
+ instance_ = std::make_unique();
+ }
+
+ inline static MagiskLoader *GetInstance() {
+ return static_cast(instance_.get());
+ }
+
+ void OnNativeForkAndSpecializePre(JNIEnv *env, jint uid, jintArray &gids, jstring nice_name,
+ jboolean is_child_zygote, jstring app_data_dir);
+
+ void OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name);
+
+ void OnNativeForkSystemServerPost(JNIEnv *env);
+
+ void OnNativeForkSystemServerPre(JNIEnv *env);
+
+ protected:
+ void LoadDex(JNIEnv *env, PreloadedDex &&dex) override;
+
+ void SetupEntryClass(JNIEnv *env) override;
+
+ private:
+ bool skip_ = false;
+
+ static void setAllowUnload(bool unload);
+ };
+} // namespace lspd
diff --git a/core/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp
similarity index 99%
rename from core/src/main/jni/src/service.cpp
rename to magisk-loader/src/main/jni/src/service.cpp
index 6e0c2ca8..d828b2b8 100644
--- a/core/src/main/jni/src/service.cpp
+++ b/magisk-loader/src/main/jni/src/service.cpp
@@ -23,7 +23,7 @@
#include
#include
-#include "config.h"
+#include "loader.h"
#include "service.h"
#include "context.h"
#include "utils/jni_helper.hpp"
diff --git a/core/src/main/jni/src/service.h b/magisk-loader/src/main/jni/src/service.h
similarity index 100%
rename from core/src/main/jni/src/service.h
rename to magisk-loader/src/main/jni/src/service.h
diff --git a/magisk-loader/src/main/jni/template/loader.cpp b/magisk-loader/src/main/jni/template/loader.cpp
new file mode 100644
index 00000000..f4394c43
--- /dev/null
+++ b/magisk-loader/src/main/jni/template/loader.cpp
@@ -0,0 +1,6 @@
+#include "loader.h"
+
+namespace lspd {
+const int apiVersion = ${API_VERSION};
+const char* const moduleName = "${MODULE_NAME}";
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 5711dd1f..ad8ab6d4 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -31,6 +31,7 @@ include(
":daemon",
":hiddenapi:stubs",
":hiddenapi:bridge",
+ ":magisk-loader",
":services:manager-service",
":services:daemon-service",
":services:xposed-service:interface",