diff --git a/build.gradle.kts b/build.gradle.kts index 0a0495f8..48620a67 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,6 +37,9 @@ val repo = FileRepository(rootProject.file(".git")) val refId = repo.refDatabase.exactRef("refs/remotes/origin/master").objectId!! val commitCount = Git(repo).log().add(refId).call().count() +val injectedPackageName by extra("com.android.shell") +val injectedPackageUid by extra(2000) + val defaultManagerPackageName by extra("org.lsposed.manager") val apiCode by extra(93) val verCode by extra(commitCount + 4200) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 4e32dd87..c9a32e45 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -17,18 +17,12 @@ * Copyright (C) 2021 LSPosed Contributors */ -import com.android.build.gradle.BaseExtension -import com.android.ide.common.signing.KeystoreHelper 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.io.FileOutputStream -import java.io.PrintStream import java.security.MessageDigest import java.util.* -import java.util.jar.JarFile -import java.util.zip.ZipOutputStream plugins { id("com.android.application") @@ -43,10 +37,8 @@ val moduleMinRiruApiVersion = 25 val moduleMinRiruVersionName = "25.0.1" val moduleMaxRiruApiVersion = 25 -val injectedPackageName = "com.android.shell" -val injectedPackageUid = 2000 - -val agpVersion: String by rootProject.extra +val injectedPackageName: String by rootProject.extra +val injectedPackageUid: Int by rootProject.extra val defaultManagerPackageName: String by rootProject.extra val apiCode: Int by rootProject.extra @@ -169,18 +161,13 @@ dependencies { implementation("dev.rikka.ndk:riru:26.0.0") implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0") implementation("io.github.vvb2060.ndk:dobby:1.2") - implementation("com.android.tools.build:apksig:$agpVersion") implementation("org.apache.commons:commons-lang3:3.12.0") implementation("de.upb.cs.swt:axml:2.1.1") compileOnly("androidx.annotation:annotation:1.3.0") compileOnly(project(":hiddenapi-stubs")) implementation(project(":hiddenapi-bridge")) implementation(project(":manager-service")) - android.applicationVariants.all { - "${name}Implementation"(files(File(project.buildDir, "tmp/${name}R.jar")) { - builtBy("generateApp${name}RFile") - }) - } + implementation(project(":daemon-service")) } val zipAll = task("zipAll") { @@ -197,68 +184,15 @@ fun afterEval() = android.applicationVariants.forEach { variant -> val magiskDir = "$buildDir/magisk/$variantLowered" - task("generateApp${variantCapped}RFile") { - dependsOn(":app:process${buildTypeCapped}Resources") - doLast { - val rFile = JarFile( - File( - project(":app").buildDir, - "intermediates/compile_and_runtime_not_namespaced_r_class_jar/${buildTypeLowered}/R.jar" - ) - ) - ZipOutputStream( - FileOutputStream( - File( - project.buildDir, - "tmp/${variantCapped}R.jar" - ) - ) - ).use { - for (entry in rFile.entries()) { - if (entry.name.startsWith("org/lsposed/manager")) { - it.putNextEntry(entry) - rFile.getInputStream(entry).transferTo(it) - it.closeEntry() - } - } - } - } - } - - val app = rootProject.project(":app").extensions.getByName("android") - val outSrcDir = file("$buildDir/generated/source/signInfo/${variantLowered}") - val outSrc = file("$outSrcDir/org/lsposed/lspd/util/SignInfo.java") - val signInfoTask = tasks.register("generate${variantCapped}SignInfo") { - dependsOn(":app:validateSigning${buildTypeCapped}") - outputs.file(outSrc) - doLast { - val sign = app.buildTypes.named(buildTypeLowered).get().signingConfig - outSrc.parentFile.mkdirs() - val certificateInfo = KeystoreHelper.getCertificateInfo( - sign?.storeType, - sign?.storeFile, - sign?.storePassword, - sign?.keyPassword, - sign?.keyAlias - ) - PrintStream(outSrc).print( - """ - |package org.lsposed.lspd.util; - |public final class SignInfo { - | public static final byte[] CERTIFICATE = {${ - certificateInfo.certificate.encoded.joinToString(",") - }}; - |}""".trimMargin() - ) - } - } - variant.registerJavaGeneratingTask(signInfoTask, outSrcDir) - val moduleId = "${flavorLowered}_$moduleBaseId" val zipFileName = "$moduleName-v$verName-$verCode-${flavorLowered}-$buildTypeLowered.zip" val prepareMagiskFilesTask = task("prepareMagiskFiles$variantCapped") { - dependsOn("assemble$variantCapped", ":app:assemble$buildTypeCapped") + dependsOn( + "assemble$variantCapped", + ":app:assemble$buildTypeCapped", + ":daemon:assemble$buildTypeCapped" + ) into(magiskDir) from("${rootProject.projectDir}/README.md") from("$projectDir/magisk_module") { @@ -304,8 +238,13 @@ fun afterEval() = android.applicationVariants.forEach { variant -> include("*.apk") rename(".*\\.apk", "manager.apk") } + from("${project(":daemon").buildDir}/outputs/apk/${buildTypeLowered}") { + include("*.apk") + rename(".*\\.apk", "daemon.apk") + } into("lib") { from("${buildDir}/intermediates/stripped_native_libs/$variantCapped/out/lib") + from("${project(":daemon").buildDir}/intermediates/ndkBuild/$buildTypeLowered/obj/local") } val dexOutPath = if (buildTypeLowered == "release") "$buildDir/intermediates/dex/$variantCapped/minify${variantCapped}WithR8" else @@ -363,12 +302,12 @@ val killLspd = task("killLspd") { commandLine(adb, "shell", "su", "-c", "killall", "lspd") isIgnoreExitValue = true } -val pushLspd = task("pushLspd") { - dependsOn("mergeDexRiruDebug") - workingDir("$buildDir/intermediates/dex/RiruDebug/mergeDexRiruDebug") - commandLine(adb, "push", "classes.dex", "/data/local/tmp/lspd.dex") +val pushDaemon = task("pushDaemon") { + dependsOn(":daemon:assembleRiruDebug") + workingDir("${project(":daemon").buildDir}/outputs/apk/debug") + commandLine(adb, "push", "daemon-Zygisk-debug.apk", "/data/local/tmp/daemon.apk") } -val pushLspdNative = task("pushLspdNative") { +val pushDaemonNative = task("pushDaemonNative") { dependsOn("mergeRiruDebugNativeLibs") doFirst { val abi: String = ByteArrayOutputStream().use { outputStream -> @@ -378,12 +317,12 @@ val pushLspdNative = task("pushLspdNative") { } outputStream.toString().trim() } - workingDir("$buildDir/intermediates/merged_native_libs/RiruDebug/out/lib/$abi") + workingDir("${project(":daemon").buildDir}/intermediates/ndkBuild/debug/obj/local/$abi") } commandLine(adb, "push", "libdaemon.so", "/data/local/tmp/libdaemon.so") } -val reRunLspd = task("reRunLspd") { - dependsOn(pushLspd, pushLspdNative, killLspd) +val reRunDaemon = task("reRunDaemon") { + dependsOn(pushDaemon, pushDaemonNative, killLspd) commandLine(adb, "shell", "su", "-c", "sh /data/adb/modules/*_lsposed/service.sh&") isIgnoreExitValue = true } @@ -410,5 +349,5 @@ task("reRunApp") { dependsOn(pushApk) commandLine(adb, "shell", "su", "-c", "mv -f $tmpApk /data/adb/lspd/manager.apk") isIgnoreExitValue = true - finalizedBy(reRunLspd) + finalizedBy(reRunDaemon) } diff --git a/core/magisk_module/customize.sh b/core/magisk_module/customize.sh index 27d56fec..ed2c1230 100644 --- a/core/magisk_module/customize.sh +++ b/core/magisk_module/customize.sh @@ -84,6 +84,7 @@ extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH" extract "$ZIPFILE" 'service.sh' "$MODPATH" extract "$ZIPFILE" 'uninstall.sh' "$MODPATH" extract "$ZIPFILE" 'framework/lspd.dex' "$MODPATH" +extract "$ZIPFILE" 'daemon.apk' "$MODPATH" extract "$ZIPFILE" 'lspd' "$MODPATH" rm -f /data/adb/lspd/manager.apk extract "$ZIPFILE" 'manager.apk' '/data/adb/lspd' diff --git a/core/magisk_module/lspd b/core/magisk_module/lspd index 7d423516..020606ed 100644 --- a/core/magisk_module/lspd +++ b/core/magisk_module/lspd @@ -1,19 +1,19 @@ #!/system/bin/sh dir=${0%/*} -tmpLspdDex="/data/local/tmp/lspd.dex" +tmpLspdApk="/data/local/tmp/daemon.apk" debug="false" -if [ -r $tmpLspdDex ]; then - java_options="-Djava.class.path=$tmpLspdDex" +if [ -r $tmpLspdApk ]; then + java_options="-Djava.class.path=$tmpLspdApk" java_options="$java_options -Dlsp.library.path=/data/local/tmp" debug="true" elif [ -d "$dir/system" ]; then - java_options="-Djava.class.path=$dir/system/framework/lspd.dex" + java_options="-Djava.class.path=$dir/system/daemon.apk" java_options="$java_options -Dlsp.library.path=$dir" debug="true" else - java_options="-Djava.class.path=$dir/framework/lspd.dex" + java_options="-Djava.class.path=$dir/daemon.apk" java_options="$java_options -Dlsp.library.path=$dir" fi @@ -29,4 +29,4 @@ if [ $debug = "true" ]; then fi # shellcheck disable=SC2086 -exec /system/bin/app_process $java_options /system/bin --nice-name=lspd org.lsposed.lspd.core.Main "$@" >/dev/null 2>&1 +exec /system/bin/app_process $java_options /system/bin --nice-name=lspd org.lsposed.lspd.Main "$@" >/dev/null 2>&1 diff --git a/core/magisk_module/post-fs-data.sh b/core/magisk_module/post-fs-data.sh index b9ccb5c0..3e8d1856 100644 --- a/core/magisk_module/post-fs-data.sh +++ b/core/magisk_module/post-fs-data.sh @@ -25,5 +25,5 @@ if ! [ "$ZYGISK_ENABLED" = "$([ $FLAVOR = "zygisk" ] && echo 1)" ]; then log -t "LSPosed" "$FLAVOR does not match, skipping" exit fi -rm -f "/data/local/tmp/lspd.dex" +rm -f "/data/local/tmp/daemon.apk" unshare -m sh -c "$MODDIR/lspd &" diff --git a/core/src/main/cpp/Android.mk b/core/src/main/cpp/Android.mk index dc699f87..cba3d605 100644 --- a/core/src/main/cpp/Android.mk +++ b/core/src/main/cpp/Android.mk @@ -1,7 +1,6 @@ include src/main/cpp/external/DexBuilder/Android.mk include src/main/cpp/external/yahfa/Android.mk include src/main/cpp/main/Android.mk -include src/main/cpp/daemon/Android.mk $(call import-module,prefab/cxx) $(call import-module,prefab/riru) diff --git a/core/src/main/java/org/lsposed/lspd/core/Main.java b/core/src/main/java/org/lsposed/lspd/core/Main.java index 3d5995bb..655faa2d 100644 --- a/core/src/main/java/org/lsposed/lspd/core/Main.java +++ b/core/src/main/java/org/lsposed/lspd/core/Main.java @@ -35,7 +35,6 @@ import org.lsposed.lspd.hooker.CrashDumpHooker; import org.lsposed.lspd.hooker.HandleBindAppHooker; import org.lsposed.lspd.hooker.LoadedApkCstrHooker; import org.lsposed.lspd.hooker.SystemMainHooker; -import org.lsposed.lspd.service.ServiceManager; import org.lsposed.lspd.util.ParasiticManagerHooker; import org.lsposed.lspd.util.Utils; import org.lsposed.lspd.yahfa.hooker.YahfaHooker; @@ -100,8 +99,4 @@ public class Main { forkPostCommon(true, new File(Environment.getDataDirectory(), "android").toString(), "system_server"); } - - public static void main(String[] args) { - ServiceManager.start(args); - } } diff --git a/core/src/main/java/org/lsposed/lspd/service/ActivityController.java b/core/src/main/java/org/lsposed/lspd/service/ActivityController.java index 7ceb4b2f..c0ea186a 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ActivityController.java +++ b/core/src/main/java/org/lsposed/lspd/service/ActivityController.java @@ -1,6 +1,6 @@ package org.lsposed.lspd.service; -import static org.lsposed.lspd.service.ServiceManager.TAG; +import static org.lsposed.lspd.service.BridgeService.TAG; import android.annotation.SuppressLint; import android.app.ActivityThread; diff --git a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java b/core/src/main/java/org/lsposed/lspd/service/BridgeService.java index 141692a4..b6dfd109 100644 --- a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/core/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -19,7 +19,6 @@ package org.lsposed.lspd.service; -import static org.lsposed.lspd.service.ServiceManager.TAG; import static hidden.HiddenApiBridge.Binder_allowBlocking; import static hidden.HiddenApiBridge.Context_getActivityToken; @@ -27,15 +26,10 @@ import android.app.ActivityThread; import android.app.IApplicationThread; import android.content.Context; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.Parcel; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; -import android.system.ErrnoException; -import android.system.Os; import android.util.Log; import androidx.annotation.NonNull; @@ -43,14 +37,10 @@ import androidx.annotation.Nullable; import org.lsposed.lspd.BuildConfig; -import java.lang.reflect.Field; -import java.util.Map; - public class BridgeService { private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P'; private static final String DESCRIPTOR = "LSPosed"; - private static final String SERVICE_NAME = "activity"; - private static final String SHORTCUT_ID = "org.lsposed.manager.shortcut"; + protected static final String TAG = "LSPosed Bridge"; enum ACTION { ACTION_UNKNOWN, @@ -62,40 +52,6 @@ public class BridgeService { private static IBinder serviceBinder = null; private static ILSPosedService service = null; - // for service - private static IBinder bridgeService; - private static final IBinder.DeathRecipient bridgeRecipient = new IBinder.DeathRecipient() { - - @Override - public void binderDied() { - Log.i(TAG, "service " + SERVICE_NAME + " is dead. "); - - try { - //noinspection JavaReflectionMemberAccess DiscouragedPrivateApi - Field field = ServiceManager.class.getDeclaredField("sServiceManager"); - field.setAccessible(true); - field.set(null, null); - - //noinspection JavaReflectionMemberAccess DiscouragedPrivateApi - field = ServiceManager.class.getDeclaredField("sCache"); - field.setAccessible(true); - Object sCache = field.get(null); - if (sCache instanceof Map) { - //noinspection rawtypes - ((Map) sCache).clear(); - } - Log.i(TAG, "clear ServiceManager"); - } catch (Throwable e) { - Log.w(TAG, "clear ServiceManager: " + Log.getStackTraceString(e)); - } - - bridgeService.unlinkToDeath(this, 0); - bridgeService = null; - listener.onSystemServerDied(); - new Handler(Looper.getMainLooper()).post(() -> sendToBridge(serviceBinder, true)); - } - }; - // for client private static final IBinder.DeathRecipient serviceRecipient = new IBinder.DeathRecipient() { @Override @@ -107,100 +63,6 @@ public class BridgeService { } }; - public interface Listener { - void onSystemServerRestarted(); - - void onResponseFromBridgeService(boolean response); - - void onSystemServerDied(); - } - - private static Listener listener; - - // For service - // This MUST run in main thread - private static synchronized void sendToBridge(IBinder binder, boolean isRestart) { - assert Looper.myLooper() == Looper.getMainLooper(); - try { - Os.seteuid(0); - } catch (ErrnoException e) { - Log.e(TAG, "seteuid 0", e); - } - try { - do { - bridgeService = ServiceManager.getService(SERVICE_NAME); - if (bridgeService != null && bridgeService.pingBinder()) { - break; - } - - Log.i(TAG, "service " + SERVICE_NAME + " is not started, wait 1s."); - - try { - //noinspection BusyWait - Thread.sleep(1000); - } catch (Throwable e) { - Log.w(TAG, "sleep" + Log.getStackTraceString(e)); - } - } while (true); - - if (isRestart && listener != null) { - listener.onSystemServerRestarted(); - } - - try { - bridgeService.linkToDeath(bridgeRecipient, 0); - } catch (Throwable e) { - Log.w(TAG, "linkToDeath " + Log.getStackTraceString(e)); - var snapshot = bridgeService; - sendToBridge(binder, snapshot == null || !snapshot.isBinderAlive()); - return; - } - - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - boolean res = false; - // try at most three times - for (int i = 0; i < 3; i++) { - try { - data.writeInterfaceToken(DESCRIPTOR); - data.writeInt(ACTION.ACTION_SEND_BINDER.ordinal()); - Log.v(TAG, "binder " + binder.toString()); - data.writeStrongBinder(binder); - if (bridgeService == null) break; - res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0); - reply.readException(); - } catch (Throwable e) { - Log.e(TAG, "send binder " + Log.getStackTraceString(e)); - var snapshot = bridgeService; - sendToBridge(binder, snapshot == null || !snapshot.isBinderAlive()); - return; - } finally { - data.recycle(); - reply.recycle(); - } - - if (res) break; - - Log.w(TAG, "no response from bridge, retry in 1s"); - - try { - Thread.sleep(1000); - } catch (InterruptedException ignored) { - } - } - - if (listener != null) { - listener.onResponseFromBridgeService(res); - } - } finally { - try { - Os.seteuid(1000); - } catch (ErrnoException e) { - Log.e(TAG, "seteuid 1000", e); - } - } - } - // For client private static void receiveFromBridge(IBinder binder) { if (binder == null) { @@ -231,13 +93,6 @@ public class BridgeService { Log.i(TAG, "binder received"); } - public static void send(LSPosedService service, Listener listener) { - BridgeService.listener = listener; - BridgeService.service = service; - BridgeService.serviceBinder = service.asBinder(); - sendToBridge(serviceBinder, false); - } - public static ILSPosedService getService() { return service; } @@ -368,6 +223,7 @@ public class BridgeService { return res; } + @SuppressWarnings("unused") public static IBinder getApplicationServiceForSystemServer(IBinder binder, IBinder heartBeat) { if (binder == null || heartBeat == null) return null; try { diff --git a/core/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java b/core/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java index 64ed2a92..7dfb44c8 100644 --- a/core/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java +++ b/core/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java @@ -20,35 +20,11 @@ package org.lsposed.lspd.util; -import static org.lsposed.lspd.util.SignInfo.CERTIFICATE; - import android.os.IBinder; -import com.android.apksig.ApkVerifier; - -import java.io.File; -import java.util.Arrays; - import de.robv.android.xposed.XposedHelpers; public class InstallerVerifier { - public static boolean verifyInstallerSignature(String path) { - ApkVerifier verifier = new ApkVerifier.Builder(new File(path)) - .setMinCheckedPlatformVersion(27) - .build(); - try { - ApkVerifier.Result result = verifier.verify(); - if (!result.isVerified()) { - return false; - } - boolean ret = Arrays.equals(result.getSignerCertificates().get(0).getEncoded(), CERTIFICATE); - Utils.logI("verifyInstallerSignature: " + ret); - return ret; - } catch (Throwable t) { - Utils.logE("verifyInstallerSignature: ", t); - return false; - } - } public static boolean sendBinderToManager(final ClassLoader classLoader, IBinder binder) { Utils.logI("Found LSPosed Manager"); diff --git a/daemon-service/.gitignore b/daemon-service/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/daemon-service/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/daemon-service/build.gradle.kts b/daemon-service/build.gradle.kts new file mode 100644 index 00000000..fd29274f --- /dev/null +++ b/daemon-service/build.gradle.kts @@ -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) 2021 LSPosed Contributors + */ + +plugins { + id("com.android.library") +} + +val androidTargetSdkVersion: Int by rootProject.extra +val androidBuildToolsVersion: String by rootProject.extra +val androidMinSdkVersion: Int by rootProject.extra +val androidSourceCompatibility: JavaVersion by rootProject.extra +val androidTargetCompatibility: JavaVersion by rootProject.extra + +android { + compileSdk = androidTargetSdkVersion + buildToolsVersion = androidBuildToolsVersion + + defaultConfig { + minSdk = androidMinSdkVersion + targetSdk = androidTargetSdkVersion + consumerProguardFiles("proguard-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + } + } + + compileOptions { + sourceCompatibility = androidSourceCompatibility + targetCompatibility = androidTargetCompatibility + } + + aidlPackagedList += "org/lsposed/lspd/models/Module.aidl" + aidlPackagedList += "org/lsposed/lspd/models/PreloadedApk.aidl" +} + +dependencies { + + compileOnly(project(":hiddenapi-stubs")) +} diff --git a/daemon-service/proguard-rules.pro b/daemon-service/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/daemon-service/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/daemon-service/src/main/AndroidManifest.xml b/daemon-service/src/main/AndroidManifest.xml new file mode 100644 index 00000000..20b79d4b --- /dev/null +++ b/daemon-service/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/core/src/main/aidl/org/lsposed/lspd/models/Module.aidl b/daemon-service/src/main/aidl/org/lsposed/lspd/models/Module.aidl similarity index 100% rename from core/src/main/aidl/org/lsposed/lspd/models/Module.aidl rename to daemon-service/src/main/aidl/org/lsposed/lspd/models/Module.aidl diff --git a/core/src/main/aidl/org/lsposed/lspd/models/PreLoadedApk.aidl b/daemon-service/src/main/aidl/org/lsposed/lspd/models/PreLoadedApk.aidl similarity index 100% rename from core/src/main/aidl/org/lsposed/lspd/models/PreLoadedApk.aidl rename to daemon-service/src/main/aidl/org/lsposed/lspd/models/PreLoadedApk.aidl diff --git a/core/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl b/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl similarity index 100% rename from core/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl rename to daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl diff --git a/core/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl b/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl similarity index 100% rename from core/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl rename to daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl diff --git a/core/src/main/aidl/org/lsposed/lspd/service/ILSPosedService.aidl b/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPosedService.aidl similarity index 100% rename from core/src/main/aidl/org/lsposed/lspd/service/ILSPosedService.aidl rename to daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPosedService.aidl diff --git a/core/src/main/java/org/lsposed/lspd/util/Utils.java b/daemon-service/src/main/java/org/lsposed/lspd/util/Utils.java similarity index 97% rename from core/src/main/java/org/lsposed/lspd/util/Utils.java rename to daemon-service/src/main/java/org/lsposed/lspd/util/Utils.java index 7e72ff33..a22da5b7 100644 --- a/core/src/main/java/org/lsposed/lspd/util/Utils.java +++ b/daemon-service/src/main/java/org/lsposed/lspd/util/Utils.java @@ -24,7 +24,7 @@ import android.os.SystemProperties; import android.text.TextUtils; import android.util.Log; -import org.lsposed.lspd.BuildConfig; +import org.lsposed.lspd.daemonservice.BuildConfig; import java.time.ZoneId; import java.time.ZoneOffset; diff --git a/daemon/.gitignore b/daemon/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/daemon/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/daemon/build.gradle.kts b/daemon/build.gradle.kts new file mode 100644 index 00000000..5e58061e --- /dev/null +++ b/daemon/build.gradle.kts @@ -0,0 +1,203 @@ +/* + * 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 LSPosed Contributors + */ + +import com.android.build.gradle.BaseExtension +import com.android.ide.common.signing.KeystoreHelper +import java.io.PrintStream +import java.io.FileOutputStream +import java.util.Locale +import java.util.jar.JarFile +import java.util.zip.ZipOutputStream + +plugins { + id("com.android.application") +} + +val daemonName = "LSPosed" + +val injectedPackageName: String by rootProject.extra +val injectedPackageUid: Int by rootProject.extra + +val agpVersion: String 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 + +val androidTargetSdkVersion: Int by rootProject.extra +val androidMinSdkVersion: Int by rootProject.extra +val androidBuildToolsVersion: String by rootProject.extra +val androidCompileSdkVersion: Int by rootProject.extra +val androidCompileNdkVersion: String by rootProject.extra +val androidSourceCompatibility: JavaVersion by rootProject.extra +val androidTargetCompatibility: JavaVersion by rootProject.extra + +android { + compileSdk = androidCompileSdkVersion + ndkVersion = androidCompileNdkVersion + buildToolsVersion = androidBuildToolsVersion + + buildFeatures { + prefab = true + } + + defaultConfig { + applicationId = "org.lsposed.daemon" + minSdk = androidMinSdkVersion + targetSdk = androidTargetSdkVersion + versionCode = verCode + versionName = verName + multiDexEnabled = false + + externalNativeBuild { + ndkBuild { + arguments += "-j${Runtime.getRuntime().availableProcessors()}" + } + } + + 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""") + } + + lint { + isAbortOnError = true + isCheckReleaseBuilds = false + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles("proguard-rules.pro") + } + } + + externalNativeBuild { + ndkBuild { + path("src/main/cpp/Android.mk") + } + } + + compileOptions { + targetCompatibility(androidTargetCompatibility) + sourceCompatibility(androidSourceCompatibility) + } + + buildTypes { + all { + externalNativeBuild { + ndkBuild { + arguments += "NDK_OUT=${File(buildDir, ".cxx/$name").absolutePath}" + } + } + } + } +} + +fun afterEval() = android.applicationVariants.forEach { variant -> + val variantCapped = variant.name.capitalize(Locale.ROOT) + val variantLowered = variant.name.toLowerCase(Locale.ROOT) + + tasks["merge${variantCapped}JniLibFolders"].enabled = false + tasks["merge${variantCapped}NativeLibs"].enabled = false + + task("generateApp${variantLowered}RFile") { + dependsOn(":app:process${variantCapped}Resources") + doLast { + val rFile = JarFile( + File( + project(":app").buildDir, + "intermediates/compile_and_runtime_not_namespaced_r_class_jar/${variantLowered}/R.jar" + ) + ) + ZipOutputStream( + FileOutputStream( + File( + project.buildDir, + "tmp/${variantLowered}R.jar" + ) + ) + ).use { + for (entry in rFile.entries()) { + if (entry.name.startsWith("org/lsposed/manager")) { + it.putNextEntry(entry) + rFile.getInputStream(entry).transferTo(it) + it.closeEntry() + } + } + } + } + } + + val app = rootProject.project(":app").extensions.getByName("android") + val outSrcDir = file("$buildDir/generated/source/signInfo/${variantLowered}") + val outSrc = file("$outSrcDir/org/lsposed/lspd/util/SignInfo.java") + val signInfoTask = tasks.register("generate${variantCapped}SignInfo") { + dependsOn(":app:validateSigning${variantCapped}") + outputs.file(outSrc) + doLast { + val sign = app.buildTypes.named(variantLowered).get().signingConfig + outSrc.parentFile.mkdirs() + val certificateInfo = KeystoreHelper.getCertificateInfo( + sign?.storeType, + sign?.storeFile, + sign?.storePassword, + sign?.keyPassword, + sign?.keyAlias + ) + PrintStream(outSrc).print( + """ + |package org.lsposed.lspd.util; + |public final class SignInfo { + | public static final byte[] CERTIFICATE = {${ + certificateInfo.certificate.encoded.joinToString(",") + }}; + |}""".trimMargin() + ) + } + } + variant.registerJavaGeneratingTask(signInfoTask, outSrcDir) +} + +afterEvaluate { + afterEval() +} + +dependencies { + + implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0") + implementation("com.android.tools.build:apksig:$agpVersion") + implementation("org.apache.commons:commons-lang3:3.12.0") + compileOnly("androidx.annotation:annotation:1.3.0") + compileOnly(project(":hiddenapi-stubs")) + implementation(project(":hiddenapi-bridge")) + implementation(project(":daemon-service")) + implementation(project(":manager-service")) + android.applicationVariants.all { + "${name}Implementation"(files(File(project.buildDir, "tmp/${name}R.jar")) { + builtBy("generateApp${name}RFile") + }) + } +} diff --git a/daemon/proguard-rules.pro b/daemon/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/daemon/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/daemon/src/main/AndroidManifest.xml b/daemon/src/main/AndroidManifest.xml new file mode 100644 index 00000000..124ccb9d --- /dev/null +++ b/daemon/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/core/src/main/cpp/daemon/Android.mk b/daemon/src/main/cpp/Android.mk similarity index 89% rename from core/src/main/cpp/daemon/Android.mk rename to daemon/src/main/cpp/Android.mk index 8b614000..f60d3961 100644 --- a/core/src/main/cpp/daemon/Android.mk +++ b/daemon/src/main/cpp/Android.mk @@ -7,3 +7,5 @@ LOCAL_STATIC_LIBRARIES := cxx LOCAL_ALLOW_UNDEFINED_SYMBOLS := true LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) + +$(call import-module,prefab/cxx) \ No newline at end of file diff --git a/daemon/src/main/cpp/Application.mk b/daemon/src/main/cpp/Application.mk new file mode 100644 index 00000000..8787cc84 --- /dev/null +++ b/daemon/src/main/cpp/Application.mk @@ -0,0 +1,15 @@ +APP_CFLAGS := -Wall -Wextra +APP_CFLAGS += -fno-stack-protector -fomit-frame-pointer +APP_CFLAGS += -Wno-builtin-macro-redefined -D__FILE__=__FILE_NAME__ +APP_CPPFLAGS := -std=c++20 +APP_CONLYFLAGS := -std=c18 +APP_LDFLAGS := -Wl,--exclude-libs,ALL +APP_STL := none + +ifneq ($(NDK_DEBUG),1) +APP_CFLAGS += -Oz -flto +APP_CFLAGS += -Wno-unused -Wno-unused-parameter -Werror +APP_CFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden +APP_CFLAGS += -fno-unwind-tables -fno-asynchronous-unwind-tables +APP_LDFLAGS += -flto -Wl,--gc-sections -Wl,--strip-all +endif diff --git a/core/src/main/cpp/daemon/logcat.cpp b/daemon/src/main/cpp/logcat.cpp similarity index 100% rename from core/src/main/cpp/daemon/logcat.cpp rename to daemon/src/main/cpp/logcat.cpp diff --git a/core/src/main/cpp/daemon/logcat.h b/daemon/src/main/cpp/logcat.h similarity index 100% rename from core/src/main/cpp/daemon/logcat.h rename to daemon/src/main/cpp/logcat.h diff --git a/daemon/src/main/java/org/lsposed/lspd/Main.java b/daemon/src/main/java/org/lsposed/lspd/Main.java new file mode 100644 index 00000000..3263091f --- /dev/null +++ b/daemon/src/main/java/org/lsposed/lspd/Main.java @@ -0,0 +1,10 @@ +package org.lsposed.lspd; + +import org.lsposed.lspd.service.ServiceManager; + +public class Main { + + public static void main(String[] args) { + ServiceManager.start(args); + } +} diff --git a/core/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java b/daemon/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java rename to daemon/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java diff --git a/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java b/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java new file mode 100644 index 00000000..3249e8a2 --- /dev/null +++ b/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -0,0 +1,162 @@ +package org.lsposed.lspd.service; + +import static org.lsposed.lspd.service.ServiceManager.TAG; + +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Parcel; +import android.os.ServiceManager; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import java.lang.reflect.Field; +import java.util.Map; + +public class BridgeService { + + private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P'; + private static final String DESCRIPTOR = "LSPosed"; + private static final String SERVICE_NAME = "activity"; + + enum ACTION { + ACTION_UNKNOWN, + ACTION_SEND_BINDER, + ACTION_GET_BINDER, + } + + public interface Listener { + void onSystemServerRestarted(); + + void onResponseFromBridgeService(boolean response); + + void onSystemServerDied(); + } + + private static IBinder serviceBinder = null; + + private static Listener listener; + private static IBinder bridgeService; + private static final IBinder.DeathRecipient bridgeRecipient = new IBinder.DeathRecipient() { + + @Override + public void binderDied() { + Log.i(TAG, "service " + SERVICE_NAME + " is dead. "); + + try { + //noinspection JavaReflectionMemberAccess DiscouragedPrivateApi + Field field = ServiceManager.class.getDeclaredField("sServiceManager"); + field.setAccessible(true); + field.set(null, null); + + //noinspection JavaReflectionMemberAccess DiscouragedPrivateApi + field = ServiceManager.class.getDeclaredField("sCache"); + field.setAccessible(true); + Object sCache = field.get(null); + if (sCache instanceof Map) { + //noinspection rawtypes + ((Map) sCache).clear(); + } + Log.i(TAG, "clear ServiceManager"); + } catch (Throwable e) { + Log.w(TAG, "clear ServiceManager: " + Log.getStackTraceString(e)); + } + + bridgeService.unlinkToDeath(this, 0); + bridgeService = null; + listener.onSystemServerDied(); + new Handler(Looper.getMainLooper()).post(() -> sendToBridge(serviceBinder, true)); + } + }; + + // For service + // This MUST run in main thread + private static synchronized void sendToBridge(IBinder binder, boolean isRestart) { + assert Looper.myLooper() == Looper.getMainLooper(); + try { + Os.seteuid(0); + } catch (ErrnoException e) { + Log.e(TAG, "seteuid 0", e); + } + try { + do { + bridgeService = ServiceManager.getService(SERVICE_NAME); + if (bridgeService != null && bridgeService.pingBinder()) { + break; + } + + Log.i(TAG, "service " + SERVICE_NAME + " is not started, wait 1s."); + + try { + //noinspection BusyWait + Thread.sleep(1000); + } catch (Throwable e) { + Log.w(TAG, "sleep" + Log.getStackTraceString(e)); + } + } while (true); + + if (isRestart && listener != null) { + listener.onSystemServerRestarted(); + } + + try { + bridgeService.linkToDeath(bridgeRecipient, 0); + } catch (Throwable e) { + Log.w(TAG, "linkToDeath " + Log.getStackTraceString(e)); + var snapshot = bridgeService; + sendToBridge(binder, snapshot == null || !snapshot.isBinderAlive()); + return; + } + + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + boolean res = false; + // try at most three times + for (int i = 0; i < 3; i++) { + try { + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt(ACTION.ACTION_SEND_BINDER.ordinal()); + Log.v(TAG, "binder " + binder.toString()); + data.writeStrongBinder(binder); + if (bridgeService == null) break; + res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0); + reply.readException(); + } catch (Throwable e) { + Log.e(TAG, "send binder " + Log.getStackTraceString(e)); + var snapshot = bridgeService; + sendToBridge(binder, snapshot == null || !snapshot.isBinderAlive()); + return; + } finally { + data.recycle(); + reply.recycle(); + } + + if (res) break; + + Log.w(TAG, "no response from bridge, retry in 1s"); + + try { + Thread.sleep(1000); + } catch (InterruptedException ignored) { + } + } + + if (listener != null) { + listener.onResponseFromBridgeService(res); + } + } finally { + try { + Os.seteuid(1000); + } catch (ErrnoException e) { + Log.e(TAG, "seteuid 1000", e); + } + } + } + + public static void send(LSPosedService service, Listener listener) { + BridgeService.listener = listener; + BridgeService.serviceBinder = service.asBinder(); + sendToBridge(serviceBinder, false); + } +} diff --git a/core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java rename to daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java diff --git a/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java similarity index 99% rename from core/src/main/java/org/lsposed/lspd/service/ConfigManager.java rename to daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java index c56bcce1..5d4375a1 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -46,7 +46,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.apache.commons.lang3.SerializationUtils; -import org.lsposed.lspd.BuildConfig; +import org.lsposed.daemon.BuildConfig; import org.lsposed.lspd.models.Application; import org.lsposed.lspd.models.Module; diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java rename to daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPManagerService.java similarity index 99% rename from core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java rename to daemon/src/main/java/org/lsposed/lspd/service/LSPManagerService.java index e17ffbc4..3a25bade 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPManagerService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPManagerService.java @@ -60,7 +60,7 @@ import android.view.IWindowManager; import androidx.annotation.NonNull; -import org.lsposed.lspd.BuildConfig; +import org.lsposed.daemon.BuildConfig; import org.lsposed.lspd.ILSPManagerService; import org.lsposed.lspd.models.Application; import org.lsposed.lspd.models.UserInfo; @@ -79,7 +79,6 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.zip.ZipFile; -import de.robv.android.xposed.XposedBridge; import hidden.HiddenApiBridge; import io.github.xposed.xposedservice.utils.ParceledListSlice; @@ -502,7 +501,7 @@ public class LSPManagerService extends ILSPManagerService.Stub { @Override public int getXposedApiVersion() { - return XposedBridge.getXposedVersion(); + return BuildConfig.API_CODE; } @Override diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPModuleService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java similarity index 92% rename from core/src/main/java/org/lsposed/lspd/service/LSPModuleService.java rename to daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java index eff59bbc..1afe5f53 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java @@ -21,7 +21,8 @@ package org.lsposed.lspd.service; import android.os.IBinder; -import de.robv.android.xposed.XposedBridge; +import org.lsposed.daemon.BuildConfig; + import io.github.xposed.xposedservice.IXposedService; public class LSPModuleService extends IXposedService.Stub { @@ -39,6 +40,6 @@ public class LSPModuleService extends IXposedService.Stub { @Override public int getVersion() { - return XposedBridge.getXposedVersion(); + return BuildConfig.API_CODE; } } diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java rename to daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java similarity index 99% rename from core/src/main/java/org/lsposed/lspd/service/LSPosedService.java rename to daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java index fc043b28..aeb8b412 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPosedService.java @@ -35,7 +35,7 @@ import android.os.Bundle; import android.os.IBinder; import android.util.Log; -import org.lsposed.lspd.BuildConfig; +import org.lsposed.daemon.BuildConfig; import java.util.Arrays; diff --git a/core/src/main/java/org/lsposed/lspd/service/LogcatService.java b/daemon/src/main/java/org/lsposed/lspd/service/LogcatService.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/service/LogcatService.java rename to daemon/src/main/java/org/lsposed/lspd/service/LogcatService.java diff --git a/core/src/main/java/org/lsposed/lspd/service/PackageService.java b/daemon/src/main/java/org/lsposed/lspd/service/PackageService.java similarity index 99% rename from core/src/main/java/org/lsposed/lspd/service/PackageService.java rename to daemon/src/main/java/org/lsposed/lspd/service/PackageService.java index 4a88e7e4..63b1c87b 100644 --- a/core/src/main/java/org/lsposed/lspd/service/PackageService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/PackageService.java @@ -266,7 +266,7 @@ public class PackageService { } } - public static ParceledListSlice queryIntentActivities(android.content.Intent intent, java.lang.String resolvedType, int flags, int userId) throws RemoteException { + public static ParceledListSlice queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) throws RemoteException { IPackageManager pm = getPackageManager(); if (pm == null) return null; return new ParceledListSlice<>(pm.queryIntentActivities(intent, resolvedType, flags, userId).getList()); diff --git a/core/src/main/java/org/lsposed/lspd/service/ServiceManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java similarity index 98% rename from core/src/main/java/org/lsposed/lspd/service/ServiceManager.java rename to daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java index 64c07576..59c92c6e 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ServiceManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java @@ -29,11 +29,10 @@ import android.util.Log; import com.android.internal.os.BinderInternal; -import org.lsposed.lspd.BuildConfig; +import org.lsposed.daemon.BuildConfig; import java.io.File; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/core/src/main/java/org/lsposed/lspd/service/UserService.java b/daemon/src/main/java/org/lsposed/lspd/service/UserService.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/service/UserService.java rename to daemon/src/main/java/org/lsposed/lspd/service/UserService.java diff --git a/core/src/main/java/org/lsposed/lspd/util/FakeContext.java b/daemon/src/main/java/org/lsposed/lspd/util/FakeContext.java similarity index 100% rename from core/src/main/java/org/lsposed/lspd/util/FakeContext.java rename to daemon/src/main/java/org/lsposed/lspd/util/FakeContext.java diff --git a/daemon/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java b/daemon/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java new file mode 100644 index 00000000..e174e8f7 --- /dev/null +++ b/daemon/src/main/java/org/lsposed/lspd/util/InstallerVerifier.java @@ -0,0 +1,29 @@ +package org.lsposed.lspd.util; + +import com.android.apksig.ApkVerifier; + +import java.io.File; +import java.util.Arrays; + +import static org.lsposed.lspd.util.SignInfo.CERTIFICATE; + +public class InstallerVerifier { + + public static boolean verifyInstallerSignature(String path) { + ApkVerifier verifier = new ApkVerifier.Builder(new File(path)) + .setMinCheckedPlatformVersion(27) + .build(); + try { + ApkVerifier.Result result = verifier.verify(); + if (!result.isVerified()) { + return false; + } + boolean ret = Arrays.equals(result.getSignerCertificates().get(0).getEncoded(), CERTIFICATE); + Utils.logI("verifyInstallerSignature: " + ret); + return ret; + } catch (Throwable t) { + Utils.logE("verifyInstallerSignature: ", t); + return false; + } + } +} diff --git a/daemon/src/main/res/values/strings.xml b/daemon/src/main/res/values/strings.xml new file mode 100644 index 00000000..df33189d --- /dev/null +++ b/daemon/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + LSPosed + \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 2415878b..f0485ecb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,7 +14,9 @@ include( ":service", ":interface", ":hiddenapi-bridge", - ":manager-service" + ":manager-service", + ":daemon", + ":daemon-service" ) val serviceRoot = "service"