[core] Split daemon (#1503)
This commit is contained in:
parent
1451b546c1
commit
b9666c9d08
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<Jar>("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<BaseExtension>("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<Sync>("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<Exec>("killLspd") {
|
|||
commandLine(adb, "shell", "su", "-c", "killall", "lspd")
|
||||
isIgnoreExitValue = true
|
||||
}
|
||||
val pushLspd = task<Exec>("pushLspd") {
|
||||
dependsOn("mergeDexRiruDebug")
|
||||
workingDir("$buildDir/intermediates/dex/RiruDebug/mergeDexRiruDebug")
|
||||
commandLine(adb, "push", "classes.dex", "/data/local/tmp/lspd.dex")
|
||||
val pushDaemon = task<Exec>("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<Exec>("pushLspdNative") {
|
||||
val pushDaemonNative = task<Exec>("pushDaemonNative") {
|
||||
dependsOn("mergeRiruDebugNativeLibs")
|
||||
doFirst {
|
||||
val abi: String = ByteArrayOutputStream().use { outputStream ->
|
||||
|
|
@ -378,12 +317,12 @@ val pushLspdNative = task<Exec>("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<Exec>("reRunLspd") {
|
||||
dependsOn(pushLspd, pushLspdNative, killLspd)
|
||||
val reRunDaemon = task<Exec>("reRunDaemon") {
|
||||
dependsOn(pushDaemon, pushDaemonNative, killLspd)
|
||||
commandLine(adb, "shell", "su", "-c", "sh /data/adb/modules/*_lsposed/service.sh&")
|
||||
isIgnoreExitValue = true
|
||||
}
|
||||
|
|
@ -410,5 +349,5 @@ task<Exec>("reRunApp") {
|
|||
dependsOn(pushApk)
|
||||
commandLine(adb, "shell", "su", "-c", "mv -f $tmpApk /data/adb/lspd/manager.apk")
|
||||
isIgnoreExitValue = true
|
||||
finalizedBy(reRunLspd)
|
||||
finalizedBy(reRunDaemon)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 &"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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"))
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="org.lsposed.lspd.daemonservice" />
|
||||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<Jar>("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<BaseExtension>("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")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.lsposed.daemon">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true" />
|
||||
|
||||
</manifest>
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -266,7 +266,7 @@ public class PackageService {
|
|||
}
|
||||
}
|
||||
|
||||
public static ParceledListSlice<ResolveInfo> queryIntentActivities(android.content.Intent intent, java.lang.String resolvedType, int flags, int userId) throws RemoteException {
|
||||
public static ParceledListSlice<ResolveInfo> 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());
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">LSPosed</string>
|
||||
</resources>
|
||||
|
|
@ -14,7 +14,9 @@ include(
|
|||
":service",
|
||||
":interface",
|
||||
":hiddenapi-bridge",
|
||||
":manager-service"
|
||||
":manager-service",
|
||||
":daemon",
|
||||
":daemon-service"
|
||||
)
|
||||
|
||||
val serviceRoot = "service"
|
||||
|
|
|
|||
Loading…
Reference in New Issue