From 3f94f49568a7f89dcd7ef7b7f66dfe19543f3b7b Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 13 Feb 2021 23:51:21 +0800 Subject: [PATCH] [core] Say hello to binder --- app/build.gradle | 3 +- .../java/io/github/lsposed/manager/App.java | 3 + .../receivers/LSPosedServiceClient.java | 53 ++++ core/build.gradle | 1 + core/src/main/cpp/main/include/config.h | 1 + core/src/main/cpp/main/include/native_util.h | 2 +- core/src/main/cpp/main/src/context.cpp | 135 ++------ core/src/main/cpp/main/src/context.h | 35 +-- core/src/main/cpp/main/src/resource_hook.cpp | 2 +- core/src/main/cpp/main/src/service.cpp | 90 ++++++ core/src/main/cpp/main/src/service.h | 16 + .../de/robv/android/xposed/XposedBridge.java | 22 -- .../io/github/lsposed/lspd/core/Main.java | 32 ++ .../lspd/hooker/XposedInstallerHooker.java | 8 + .../lsposed/lspd/service/BridgeService.java | 291 ++++++++++++++++++ .../lsposed/lspd/service/LSPosedService.java | 53 ++++ .../lsposed/lspd/service/PackageReceiver.java | 17 +- .../lsposed/lspd/service/ParcelUtils.java | 42 +++ .../lsposed/lspd/service/ServiceProxy.java | 105 ------- core/template_override/customize.sh | 1 + core/template_override/post-fs-data.sh | 1 + core/template_override/service.sh | 7 +- .../java/android/ddm/DdmHandleAppName.java | 7 + service/.gitignore | 1 + service/build.gradle | 21 ++ service/proguard-rules.pro | 21 ++ service/src/main/AndroidManifest.xml | 5 + .../lsposed/lspd/service/ILSPosedService.aidl | 5 + settings.gradle | 1 + 29 files changed, 715 insertions(+), 266 deletions(-) create mode 100644 app/src/main/java/io/github/lsposed/manager/receivers/LSPosedServiceClient.java create mode 100644 core/src/main/cpp/main/src/service.cpp create mode 100644 core/src/main/cpp/main/src/service.h create mode 100644 core/src/main/java/io/github/lsposed/lspd/service/BridgeService.java create mode 100644 core/src/main/java/io/github/lsposed/lspd/service/LSPosedService.java create mode 100644 core/src/main/java/io/github/lsposed/lspd/service/ParcelUtils.java delete mode 100644 core/src/main/java/io/github/lsposed/lspd/service/ServiceProxy.java create mode 100644 hiddenapi-stubs/src/main/java/android/ddm/DdmHandleAppName.java create mode 100644 service/.gitignore create mode 100644 service/build.gradle create mode 100644 service/proguard-rules.pro create mode 100644 service/src/main/AndroidManifest.xml create mode 100644 service/src/main/aidl/io/github/lsposed/lspd/service/ILSPosedService.aidl diff --git a/app/build.gradle b/app/build.gradle index f7362f2b..acb280cd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,7 +143,8 @@ dependencies { implementation 'me.zhanghai.android.appiconloader:appiconloader-glide:1.2.0' implementation 'me.zhanghai.android.fastscroll:library:1.1.5' implementation files('libs/WeatherView-2.0.3.aar') - compileOnly project(':hiddenapi-stubs') + compileOnly project(":hiddenapi-stubs") + implementation project(path: ':service') } configurations { diff --git a/app/src/main/java/io/github/lsposed/manager/App.java b/app/src/main/java/io/github/lsposed/manager/App.java index 3c0b1f36..70ee141e 100644 --- a/app/src/main/java/io/github/lsposed/manager/App.java +++ b/app/src/main/java/io/github/lsposed/manager/App.java @@ -42,6 +42,8 @@ import okhttp3.Cache; import okhttp3.OkHttpClient; import rikka.material.app.DayNightDelegate; +import static io.github.lsposed.manager.receivers.LSPosedServiceClient.testBinder; + public class App extends Application { public static final String TAG = "LSPosedManager"; @SuppressLint("StaticFieldLeak") @@ -61,6 +63,7 @@ public class App extends Application { public void onCreate() { super.onCreate(); + testBinder(); if (!BuildConfig.DEBUG) { try { Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { diff --git a/app/src/main/java/io/github/lsposed/manager/receivers/LSPosedServiceClient.java b/app/src/main/java/io/github/lsposed/manager/receivers/LSPosedServiceClient.java new file mode 100644 index 00000000..3023bd8f --- /dev/null +++ b/app/src/main/java/io/github/lsposed/manager/receivers/LSPosedServiceClient.java @@ -0,0 +1,53 @@ +package io.github.lsposed.manager.receivers; + +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import io.github.lsposed.manager.App; +import io.github.lsposed.lspd.service.ILSPosedService; + +public class LSPosedServiceClient { + public static IBinder binder = null; + public static ILSPosedService service = null; + + private static final IBinder.DeathRecipient DEATH_RECIPIENT = () -> { + binder = null; + service = null; + }; + + public static IBinder getBinder() { + try { + Log.e(App.TAG, "Cannot get binder"); + } catch (Throwable ignored) { + } + return null; + } + + public static void testBinder() { + if (binder == null && service == null) { + binder = getBinder(); + } + if (binder == null) { + return; + } + + try { + binder.linkToDeath(DEATH_RECIPIENT, 0); + } catch (Throwable e) { + e.printStackTrace(); + } + + service = ILSPosedService.Stub.asInterface(binder); + if (service == null) { + return; + } + int ver = -1; + try { + ver = service.getVersion(); + } catch (RemoteException e) { + e.printStackTrace(); + } + Log.i(App.TAG, "Got version " + ver); + } +} diff --git a/core/build.gradle b/core/build.gradle index f17d45a5..16e1b4d5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -58,6 +58,7 @@ dependencies { implementation 'rikka.ndk:riru:10' implementation 'com.android.tools.build:apksig:4.1.2' implementation project(path: ':sandhook-hooklib') + implementation project(path: ':service') compileOnly project(':hiddenapi-stubs') compileOnly project(':key-selector') compileOnly 'androidx.annotation:annotation:1.1.0' diff --git a/core/src/main/cpp/main/include/config.h b/core/src/main/cpp/main/include/config.h index 8464bf15..1078ef39 100644 --- a/core/src/main/cpp/main/include/config.h +++ b/core/src/main/cpp/main/include/config.h @@ -50,6 +50,7 @@ inline constexpr bool is64 = Is64(); static const auto kEntryClassName = "io.github.lsposed.lspd.core.Main"s; static const auto kClassLinkerClassName = "io.github.lsposed.lspd.nativebridge.ClassLinker"s; + static const auto kBridgeServiceClassName = "io.github.lsposed.lspd.service.BridgeService"s; static const auto kSandHookClassName = "com.swift.sandhook.SandHook"s; static const auto kSandHookNeverCallClassName = "com.swift.sandhook.ClassNeverCall"s; diff --git a/core/src/main/cpp/main/include/native_util.h b/core/src/main/cpp/main/include/native_util.h index cb15bdfb..b14e5a93 100644 --- a/core/src/main/cpp/main/include/native_util.h +++ b/core/src/main/cpp/main/include/native_util.h @@ -36,7 +36,7 @@ namespace lspd { jint method_count) { ScopedLocalRef clazz(env, - Context::GetInstance()->FindClassFromLoader(env, class_name)); + Context::GetInstance()->FindClassFromCurrentLoader(env, class_name)); if (clazz.get() == nullptr) { LOG(FATAL) << "Couldn't find class: " << class_name; return; diff --git a/core/src/main/cpp/main/src/context.cpp b/core/src/main/cpp/main/src/context.cpp index f02c7104..10795b91 100644 --- a/core/src/main/cpp/main/src/context.cpp +++ b/core/src/main/cpp/main/src/context.cpp @@ -37,6 +37,7 @@ #include "native_hook.h" #include "jni/logger.h" #include "jni/native_api.h" +#include "service.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-value" @@ -66,23 +67,19 @@ namespace lspd { } void Context::PreLoadDex(const fs::path &dex_path) { - if (LIKELY(!dexes.empty())) return; + if (LIKELY(!dex.empty())) return; std::ifstream is(dex_path, std::ios::binary); if (!is.good()) { LOGE("Cannot load path %s", dex_path.c_str()); return; } - dexes.emplace_back(std::istreambuf_iterator(is), - std::istreambuf_iterator()); - LOGI("Loaded %s with size %zu", dex_path.c_str(), dexes.back().size()); + dex.assign(std::istreambuf_iterator(is), + std::istreambuf_iterator()); + LOGI("Loaded %s with size %zu", dex_path.c_str(), dex.size()); } - void Context::InjectDexAndInit(JNIEnv *env) { - if (LIKELY(initialized_)) { - return; - } - + void Context::LoadDex(JNIEnv *env) { jclass classloader = JNI_FindClass(env, "java/lang/ClassLoader"); jmethodID getsyscl_mid = JNI_GetStaticMethodID( env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); @@ -93,17 +90,12 @@ namespace lspd { } jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "", - "([Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); + "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); jclass byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer"); - auto buffer_array = env->NewObjectArray(dexes.size(), byte_buffer_class, nullptr); - for (size_t i = 0; i != dexes.size(); ++i) { - auto &dex = dexes.at(i); - auto buffer = env->NewDirectByteBuffer(reinterpret_cast(dex.data()), + auto dex_buffer = env->NewDirectByteBuffer(reinterpret_cast(dex.data()), dex.size()); - env->SetObjectArrayElement(buffer_array, i, buffer); - } jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, - buffer_array, sys_classloader); + dex_buffer, sys_classloader); env->DeleteLocalRef(classloader); env->DeleteLocalRef(sys_classloader); env->DeleteLocalRef(in_memory_classloader); @@ -118,10 +110,15 @@ namespace lspd { env->DeleteLocalRef(my_cl); - // initialize pending methods related env->GetJavaVM(&vm_); + + // Make sure config manager is always working + RegisterConfigManagerMethods(env); + } + + void Context::Init(JNIEnv *env) { class_linker_class_ = (jclass) env->NewGlobalRef( - FindClassFromLoader(env, kClassLinkerClassName)); + FindClassFromCurrentLoader(env, kClassLinkerClassName)); post_fixup_static_mid_ = JNI_GetStaticMethodID(env, class_linker_class_, "onPostFixupStaticTrampolines", "(Ljava/lang/Class;)V"); @@ -131,7 +128,6 @@ namespace lspd { RegisterLogger(env); RegisterEdxpResourcesHook(env); - RegisterConfigManagerMethods(env); RegisterArtClassLinker(env); RegisterEdxpYahfa(env); RegisterPendingHooks(env); @@ -140,13 +136,12 @@ namespace lspd { variant_ = Variant(ConfigManager::GetInstance()->GetVariant()); LOGI("LSP Variant: %d", variant_); - initialized_ = true; - if (variant_ == SANDHOOK) { //for SandHook variant - ScopedLocalRef sandhook_class(env, FindClassFromLoader(env, kSandHookClassName)); + ScopedLocalRef sandhook_class(env, FindClassFromCurrentLoader(env, kSandHookClassName)); ScopedLocalRef nevercall_class(env, - FindClassFromLoader(env, kSandHookNeverCallClassName)); + FindClassFromCurrentLoader(env, + kSandHookNeverCallClassName)); if (sandhook_class == nullptr || nevercall_class == nullptr) { // fail-fast return; } @@ -158,9 +153,10 @@ namespace lspd { } jclass - Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name) { - jclass clz = JNI_GetObjectClass(env, class_loader); - jmethodID mid = JNI_GetMethodID(env, clz, "loadClass", + Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, std::string_view class_name) { + if (class_loader == nullptr) return nullptr; + static jclass clz = JNI_FindClass(env, "dalvik/system/DexClassLoader"); + static jmethodID mid = JNI_GetMethodID(env, clz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); jclass ret = nullptr; if (!mid) { @@ -168,22 +164,17 @@ namespace lspd { } if (LIKELY(mid)) { jobject target = JNI_CallObjectMethod(env, class_loader, mid, - env->NewStringUTF(class_name)); + env->NewStringUTF(class_name.data())); if (target) { return (jclass) target; } } else { LOGE("No loadClass/findClass method found"); } - LOGE("Class %s not found", class_name); + LOGE("Class %s not found", class_name.data()); return ret; } - - inline void Context::PrepareJavaEnv(JNIEnv *env) { - InjectDexAndInit(env); - } - inline void Context::FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const { if (UNLIKELY(!entry_class_)) { @@ -222,75 +213,10 @@ namespace lspd { skip_ = true; LOGD("skip injecting into android because no module hooks it"); } - if (!skip_) { - PreLoadDex(ConfigManager::GetInjectDexPath()); - } + PreLoadDex(ConfigManager::GetInjectDexPath()); ConfigManager::GetInstance()->EnsurePermission("android", 1000); } - void Context::RegisterEdxpService(JNIEnv *env) { - auto path = ConfigManager::GetFrameworkPath("lspd.dex"); - std::ifstream is(path, std::ios::binary); - if (!is.good()) { - LOGE("Cannot load path %s", path.c_str()); - return; - } - std::vector dex{std::istreambuf_iterator(is), - std::istreambuf_iterator()}; - LOGI("Loaded %s with size %zu", path.c_str(), dex.size()); - - jclass classloader = JNI_FindClass(env, "java/lang/ClassLoader"); - jmethodID getsyscl_mid = JNI_GetStaticMethodID( - env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); - jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid); - - if (UNLIKELY(!sys_classloader)) { - LOGE("getSystemClassLoader failed!!!"); - return; - } - // load dex - jobject bufferDex = env->NewDirectByteBuffer(reinterpret_cast(dex.data()), - dex.size()); - - jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader"); - jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "", - "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); - jobject my_cl = JNI_NewObject(env, in_memory_classloader, - initMid, - bufferDex, - sys_classloader); - - env->DeleteLocalRef(classloader); - env->DeleteLocalRef(sys_classloader); - env->DeleteLocalRef(in_memory_classloader); - - if (UNLIKELY(my_cl == nullptr)) { - LOGE("InMemoryDexClassLoader creation failed!!!"); - return; - } - - auto service_class = (jclass) env->NewGlobalRef( - FindClassFromLoader(env, my_cl, "io.github.lsposed.lspd.service.ServiceProxy")); - if (LIKELY(service_class)) { - jfieldID path_fid = JNI_GetStaticFieldID(env, service_class, "CONFIG_PATH", - "Ljava/lang/String;"); - jfieldID pn_fid = JNI_GetStaticFieldID(env, service_class, "INSTALLER_PACKAGE_NAME", - "Ljava/lang/String;"); - if (LIKELY(path_fid) && LIKELY(pn_fid)) { - env->SetStaticObjectField(service_class, path_fid, env->NewStringUTF( - ConfigManager::GetMiscPath().c_str())); - env->SetStaticObjectField(service_class, pn_fid, env->NewStringUTF( - ConfigManager::GetInstance()->GetInstallerPackageName().c_str())); - jmethodID install_mid = JNI_GetStaticMethodID(env, service_class, - "install", "()V"); - if (LIKELY(install_mid)) { - JNI_CallStaticVoidMethod(env, service_class, install_mid); - LOGW("Installed LSPosed Service"); - } - } - } - } - int Context::OnNativeForkSystemServerPost(JNIEnv *env, [[maybe_unused]] jclass clazz, jint res) { if (res == 0) { @@ -305,14 +231,15 @@ namespace lspd { munmap(buf, 1); } } + LoadDex(env); if (!skip_) { InstallInlineHooks(); - PrepareJavaEnv(env); + Init(env); // only do work in child since FindAndCall would print log FindAndCall(env, "forkSystemServerPost", "(II)V", res, variant_); } - RegisterEdxpService(env); + InitService(*this, env); } else { // in zygote process, res is child zygote pid // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 @@ -414,8 +341,9 @@ namespace lspd { if (res == 0) { const JUTFString process_name(env, nice_name_); if (!skip_) { + LoadDex(env); InstallInlineHooks(); - PrepareJavaEnv(env); + Init(env); LOGD("Done prepare"); FindAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;Ljava/lang/String;I)V", @@ -434,6 +362,7 @@ namespace lspd { return 0; } + } #pragma clang diagnostic pop \ No newline at end of file diff --git a/core/src/main/cpp/main/src/context.h b/core/src/main/cpp/main/src/context.h index c14f5635..5f603525 100644 --- a/core/src/main/cpp/main/src/context.h +++ b/core/src/main/cpp/main/src/context.h @@ -53,8 +53,6 @@ namespace lspd { void CallOnPostFixupStaticTrampolines(void *class_ptr); - void PrepareJavaEnv(JNIEnv *env); - void FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const; inline auto *GetJavaVM() const { return vm_; } @@ -69,13 +67,9 @@ namespace lspd { inline auto GetAppModulesList() const { return app_modules_list_; } - inline jclass FindClassFromLoader(JNIEnv *env, const std::string &className) const { - return FindClassFromLoader(env, className.c_str()); - }; - - inline jclass FindClassFromLoader(JNIEnv *env, const char *className) const { + inline jclass FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const { return FindClassFromLoader(env, GetCurrentClassLoader(), className); - } + }; void OnNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, @@ -93,13 +87,10 @@ namespace lspd { jlong permitted_capabilities, jlong effective_capabilities); - inline auto IsInitialized() const { return initialized_; } - inline auto GetVariant() const { return variant_; }; private: inline static std::unique_ptr instance_; - bool initialized_ = false; Variant variant_ = NONE; jobject inject_class_loader_ = nullptr; jclass entry_class_ = nullptr; @@ -109,33 +100,29 @@ namespace lspd { jclass class_linker_class_ = nullptr; jmethodID post_fixup_static_mid_ = nullptr; bool skip_ = false; - std::vector> dexes; - std::vector app_modules_list_; + std::vector dex{}; + std::vector app_modules_list_{}; Context() {} void PreLoadDex(const std::filesystem::path &dex_paths); - void InjectDexAndInit(JNIEnv *env); + void LoadDex(JNIEnv *env); - inline jclass FindClassFromLoader(JNIEnv *env, jobject class_loader, - const std::string &class_name) const { - return FindClassFromLoader(env, class_loader, class_name.c_str()); - } + void Init(JNIEnv *env); - static jclass - FindClassFromLoader(JNIEnv *env, jobject class_loader, const char *class_name); + static jclass FindClassFromLoader(JNIEnv *env, jobject class_loader, + std::string_view class_name); static bool ShouldSkipInject(const std::string &package_name, uid_t user, uid_t uid, bool res, - const std::function& empty_list, + const std::function &empty_list, bool is_child_zygote); - static std::tuple GetAppInfoFromDir(JNIEnv *env, jstring dir, jstring nice_name); + static std::tuple + GetAppInfoFromDir(JNIEnv *env, jstring dir, jstring nice_name); friend std::unique_ptr std::make_unique(); - - static void RegisterEdxpService(JNIEnv *env); }; } diff --git a/core/src/main/cpp/main/src/resource_hook.cpp b/core/src/main/cpp/main/src/resource_hook.cpp index f7771e68..8e6b5e85 100644 --- a/core/src/main/cpp/main/src/resource_hook.cpp +++ b/core/src/main/cpp/main/src/resource_hook.cpp @@ -88,7 +88,7 @@ namespace lspd { } jboolean XposedBridge_initXResourcesNative(JNIEnv *env, jclass) { - classXResources = Context::GetInstance()->FindClassFromLoader(env, kXResourcesClassName); + classXResources = Context::GetInstance()->FindClassFromCurrentLoader(env, kXResourcesClassName); if (!classXResources) { LOGE("Error while loading XResources class '%s':", kXResourcesClassName); return JNI_FALSE; diff --git a/core/src/main/cpp/main/src/service.cpp b/core/src/main/cpp/main/src/service.cpp new file mode 100644 index 00000000..d093613c --- /dev/null +++ b/core/src/main/cpp/main/src/service.cpp @@ -0,0 +1,90 @@ +// +// Created by loves on 2/7/2021. +// + +#include +#include +#include +#include "service.h" +#include "context.h" + +namespace lspd { + + namespace { + constexpr uint32_t BRIDGE_TRANSACTION_CODE = 1598837584; + + JNINativeInterface native_interface_replace{}; + jmethodID exec_transact_backup_methodID = nullptr; + + jboolean (*call_boolean_method_va_backup)(JNIEnv *env, jobject obj, jmethodID methodId, + va_list args) = nullptr; + + jclass bridge_service_class = nullptr; + jmethodID exec_transact_replace_methodID = nullptr; + } + + static bool exec_transact_replace(jboolean *res, JNIEnv *env, jobject obj, va_list args) { + jint code; + + va_list copy; + va_copy(copy, args); + code = va_arg(copy, jint); + va_end(copy); + + if (UNLIKELY(code == BRIDGE_TRANSACTION_CODE)) { + *res = env->CallStaticBooleanMethodV(bridge_service_class, + exec_transact_replace_methodID, + args); + return true; + } + + return false; + } + + static jboolean + call_boolean_method_va_replace(JNIEnv *env, jobject obj, jmethodID methodId, va_list args) { + if (UNLIKELY(methodId == exec_transact_backup_methodID)) { + jboolean res = false; + if (LIKELY(exec_transact_replace(&res, env, obj, args))) return res; + // else fallback to backup + } + return call_boolean_method_va_backup(env, obj, methodId, args); + } + + void InitService(const Context &context, JNIEnv *env) { + bridge_service_class = context.FindClassFromCurrentLoader(env, kBridgeServiceClassName); + if (!bridge_service_class) { + LOGE("server class not found"); + return; + } + bridge_service_class = (jclass) env->NewGlobalRef(bridge_service_class); + exec_transact_replace_methodID = env->GetStaticMethodID(bridge_service_class, + "execTransact", + "(IJJI)Z"); + if (!exec_transact_replace_methodID) { + LOGE("execTransact class not found"); + return; + } + + ScopedLocalRef binderClass(env, env->FindClass("android/os/Binder")); + exec_transact_backup_methodID = env->GetMethodID(binderClass.get(), "execTransact", + "(IJJI)Z"); + auto set_table_override = reinterpret_cast(DobbySymbolResolver(nullptr, + "_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface")); + if (!set_table_override) { + LOGE("set table override not found"); + } + memcpy(&native_interface_replace, env->functions, sizeof(JNINativeInterface)); + + call_boolean_method_va_backup = env->functions->CallBooleanMethodV; + native_interface_replace.CallBooleanMethodV = &call_boolean_method_va_replace; + + if (set_table_override != nullptr) { + set_table_override(&native_interface_replace); + } + + LOGD("Done InitService"); + } + +} \ No newline at end of file diff --git a/core/src/main/cpp/main/src/service.h b/core/src/main/cpp/main/src/service.h new file mode 100644 index 00000000..2c731ead --- /dev/null +++ b/core/src/main/cpp/main/src/service.h @@ -0,0 +1,16 @@ +// +// Created by loves on 2/7/2021. +// + +#ifndef LSPOSED_SERVICE_H +#define LSPOSED_SERVICE_H + +#include +#include "context.h" + +namespace lspd { + void InitService(const Context & context, JNIEnv *env); +} + + +#endif //LSPOSED_SERVICE_H 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 1a9bfd87..35a01f9d 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/core/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -544,28 +544,6 @@ public final class XposedBridge { return invokeOriginalMethodNative(method, methodId, parameterTypes, returnType, thisObject, args); } - /*package*/ static void setObjectClass(Object obj, Class clazz) { - if (clazz.isAssignableFrom(obj.getClass())) { - throw new IllegalArgumentException("Cannot transfer object from " + obj.getClass() + " to " + clazz); - } - setObjectClassNative(obj, clazz); - } - - private static native void setObjectClassNative(Object obj, Class clazz); - /*package*/ static native void dumpObjectNative(Object obj); - - /*package*/ static Object cloneToSubclass(Object obj, Class targetClazz) { - if (obj == null) - return null; - - if (!obj.getClass().isAssignableFrom(targetClazz)) - throw new ClassCastException(targetClazz + " doesn't extend " + obj.getClass()); - - return cloneToSubclassNative(obj, targetClazz); - } - - private static native Object cloneToSubclassNative(Object obj, Class targetClazz); - private static void removeFinalFlagNative(Class clazz) { LSPdConfigGlobal.getHookProvider().removeFinalFlagNative(clazz); } diff --git a/core/src/main/java/io/github/lsposed/lspd/core/Main.java b/core/src/main/java/io/github/lsposed/lspd/core/Main.java index 2be21c5e..679ee0e9 100644 --- a/core/src/main/java/io/github/lsposed/lspd/core/Main.java +++ b/core/src/main/java/io/github/lsposed/lspd/core/Main.java @@ -21,12 +21,19 @@ package io.github.lsposed.lspd.core; import android.annotation.SuppressLint; +import android.content.Context; +import android.os.ServiceManager; +import android.util.Log; +import android.ddm.DdmHandleAppName; import io.github.lsposed.common.KeepAll; +import io.github.lsposed.lspd.service.LSPosedService; import io.github.lsposed.lspd.util.Utils; import java.util.concurrent.atomic.AtomicReference; +import static io.github.lsposed.lspd.service.LSPosedService.TAG; + @SuppressLint("DefaultLocale") public class Main implements KeepAll { private static final AtomicReference lspdImplRef = new AtomicReference<>(null); @@ -105,4 +112,29 @@ public class Main implements KeepAll { public static synchronized int getEdxpVariant() { return getEdxpImpl().getVariant(); } + + private static void waitSystemService(String name) { + while (ServiceManager.getService(name) == null) { + try { + Log.i(TAG, "service " + name + " is not started, wait 1s."); + Thread.sleep(1000); + } catch (InterruptedException e) { + Log.i(TAG, Log.getStackTraceString(e)); + } + } + } + + public static void main(String[] args) { + for (String arg : args) { + if (arg.equals("--debug")) { + DdmHandleAppName.setAppName("lspd", 0); + } + } + waitSystemService("package"); + waitSystemService("activity"); + waitSystemService(Context.USER_SERVICE); + waitSystemService(Context.APP_OPS_SERVICE); + + LSPosedService.start(); + } } diff --git a/core/src/main/java/io/github/lsposed/lspd/hooker/XposedInstallerHooker.java b/core/src/main/java/io/github/lsposed/lspd/hooker/XposedInstallerHooker.java index 85f756ab..cd65744c 100644 --- a/core/src/main/java/io/github/lsposed/lspd/hooker/XposedInstallerHooker.java +++ b/core/src/main/java/io/github/lsposed/lspd/hooker/XposedInstallerHooker.java @@ -27,6 +27,7 @@ import io.github.lsposed.lspd.BuildConfig; import io.github.lsposed.lspd.nativebridge.ConfigManager; import io.github.lsposed.lspd.core.EdxpImpl; import io.github.lsposed.lspd.core.Main; +import io.github.lsposed.lspd.service.BridgeService; import io.github.lsposed.lspd.util.Utils; public class XposedInstallerHooker { @@ -114,6 +115,13 @@ public class XposedInstallerHooker { return ConfigManager.getMiscPath(); } }); + XposedHelpers.findAndHookMethod("io.github.lsposed.manager.receivers.LSPosedServiceClient", classLoader, "getBinder", new XC_MethodReplacement(){ + @Override + protected Object replaceHookedMethod(MethodHookParam param) { + return BridgeService.requireBinder(); + } + }); + Utils.logI("Hooked LSPosed Manager"); } catch (Throwable t) { Utils.logW("Could not hook LSPosed Manager", t); diff --git a/core/src/main/java/io/github/lsposed/lspd/service/BridgeService.java b/core/src/main/java/io/github/lsposed/lspd/service/BridgeService.java new file mode 100644 index 00000000..01ef3597 --- /dev/null +++ b/core/src/main/java/io/github/lsposed/lspd/service/BridgeService.java @@ -0,0 +1,291 @@ +package io.github.lsposed.lspd.service; + +import android.app.ActivityThread; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.lang.reflect.Field; +import java.util.Map; + +import io.github.lsposed.lspd.nativebridge.ConfigManager; +import io.github.lsposed.lspd.util.Utils; + +import static io.github.lsposed.lspd.service.LSPosedService.TAG; + +public class BridgeService { + private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P'; + private static final String DESCRIPTOR = "android.app.IActivityManager"; + private static final String SERVICE_NAME = "activity"; + + private static final int ACTION_SEND_BINDER = 1; + private static final int ACTION_GET_BINDER = ACTION_SEND_BINDER + 1; + + private static IBinder serviceBinder = null; + private static ILSPosedService service = null; + + private static final IBinder.DeathRecipient BRIDGE_SERVICE_DEATH_RECIPIENT = () -> { + Log.i(TAG, "service " + SERVICE_NAME + " is dead. "); + + try { + Field field = ServiceManager.class.getDeclaredField("sServiceManager"); + field.setAccessible(true); + field.set(null, null); + + //noinspection JavaReflectionMemberAccess + 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)); + } + + sendToBridge(true); + }; + + private static final IBinder.DeathRecipient LSPSERVICE_DEATH_RECIPIENT = () -> { + serviceBinder = null; + service = null; + Log.e(TAG, "service is dead"); + }; + + public interface Listener { + + void onSystemServerRestarted(); + + void onResponseFromBridgeService(boolean response); + } + + private static Listener listener; + + private static PackageManager pm = null; + + private static void sendToBridge(boolean isRestart) { + IBinder bridgeService; + 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(BRIDGE_SERVICE_DEATH_RECIPIENT, 0); + } catch (Throwable e) { + Log.w(TAG, "linkToDeath " + Log.getStackTraceString(e)); + sendToBridge(false); + 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_SEND_BINDER); + Log.v(TAG, "binder " + serviceBinder.toString()); + data.writeStrongBinder(serviceBinder); + res = bridgeService.transact(TRANSACTION_CODE, data, reply, 0); + reply.readException(); + } catch (Throwable e) { + Log.e(TAG, "send binder " + Log.getStackTraceString(e)); + } 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); + } + } + + private static void receiveFromBridge(IBinder binder) { + if (binder == null) { + Log.e(TAG, "received empty binder"); + return; + } + + if (serviceBinder == null) { + PackageReceiver.register(); + } else { + serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0); + } + + serviceBinder = binder; + service = ILSPosedService.Stub.asInterface(serviceBinder); + try { + serviceBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0); + } catch (RemoteException ignored) { + } + + Log.i(TAG, "binder received"); + } + + public static void send(LSPosedService service, Listener listener) { + BridgeService.listener = listener; + BridgeService.service = service; + BridgeService.serviceBinder = service.asBinder(); + sendToBridge(false); + } + + public static ILSPosedService getService() { + return service; + } + + private static PackageManager getPackageManager() { + if (pm != null) return pm; + ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + Utils.logW("ActivityThread is null"); + return null; + } + Context context = activityThread.getSystemContext(); + if (context == null) { + Utils.logW("context is null"); + return null; + } + pm = context.getPackageManager(); + return pm; + } + + public static IBinder requireBinder() { + IBinder binder = ServiceManager.getService(SERVICE_NAME); + if (binder == null) return null; + + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(DESCRIPTOR); + data.writeInt(ACTION_GET_BINDER); + binder.transact(TRANSACTION_CODE, data, reply, 0); + reply.readException(); + IBinder received = reply.readStrongBinder(); + if (received != null) { + return received; + } + } catch (Throwable e) { + e.printStackTrace(); + } finally { + data.recycle(); + reply.recycle(); + } + return null; + } + + @SuppressWarnings({"unused", "RedundantSuppression"}) + public static boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) { + data.enforceInterface(DESCRIPTOR); + + int action = data.readInt(); + Log.d(TAG, "onTransact: action=" + action + ", callingUid=" + Binder.getCallingUid() + ", callingPid=" + Binder.getCallingPid()); + + switch (action) { + case ACTION_SEND_BINDER: { + if (Binder.getCallingUid() == 0) { + receiveFromBridge(data.readStrongBinder()); + if (reply != null) { + reply.writeNoException(); + } + return true; + } + break; + } + case ACTION_GET_BINDER: { + String InstallerPackageName = ConfigManager.getInstallerPackageName(); + boolean isInstaller = false; + PackageManager pm = getPackageManager(); + if (pm == null) return false; + for (String pkg : pm.getPackagesForUid(Binder.getCallingUid())) { + isInstaller = isInstaller || InstallerPackageName.equals(pkg); + } + if (!isInstaller) { + return false; + } + + if (reply != null) { + reply.writeNoException(); + Log.d(TAG, "saved binder is " + serviceBinder.toString()); + reply.writeStrongBinder(serviceBinder); + } + return true; + } + } + return false; + } + + public static boolean execTransact(int code, long dataObj, long replyObj, int flags) { + Log.d(TAG, String.valueOf(code)); + if (code != TRANSACTION_CODE) return false; + + Parcel data = ParcelUtils.fromNativePointer(dataObj); + Parcel reply = ParcelUtils.fromNativePointer(replyObj); + + if (data == null) { + return false; + } + + boolean res = false; + + try { + String descriptor = ParcelUtils.readInterfaceDescriptor(data); + data.setDataPosition(0); + + if (descriptor.equals(DESCRIPTOR)) { + res = onTransact(code, data, reply, flags); + } + } catch (Exception e) { + if ((flags & IBinder.FLAG_ONEWAY) != 0) { + Log.w(TAG, "Caught a Exception from the binder stub implementation. " + Log.getStackTraceString(e)); + } else { + reply.setDataPosition(0); + reply.writeException(e); + } + res = true; + } + + if (res) { + if (data != null) data.recycle(); + if (reply != null) reply.recycle(); + } + + return res; + } +} diff --git a/core/src/main/java/io/github/lsposed/lspd/service/LSPosedService.java b/core/src/main/java/io/github/lsposed/lspd/service/LSPosedService.java new file mode 100644 index 00000000..2562f440 --- /dev/null +++ b/core/src/main/java/io/github/lsposed/lspd/service/LSPosedService.java @@ -0,0 +1,53 @@ +package io.github.lsposed.lspd.service; + +import android.os.Build; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; + +import de.robv.android.xposed.XposedBridge; + +public class LSPosedService extends ILSPosedService.Stub { + public static final String TAG = "LSPosedService"; + + // call by ourselves + public static void start() { + Log.i(TAG, "starting server..."); + + Looper.prepare(); + new LSPosedService(); + Looper.loop(); + + Log.i(TAG, "server exited"); + System.exit(0); + } + + public LSPosedService() { + BridgeService.send(this, new BridgeService.Listener() { + @Override + public void onSystemServerRestarted() { + Log.w(TAG, "system restarted..."); + } + + @Override + public void onResponseFromBridgeService(boolean response) { + if (response) { + Log.i(TAG, "sent service to bridge"); + } else { + Log.w(TAG, "no response from bridge"); + } + } + }); + } + + @Override + public IBinder asBinder() { + return this; + } + + @Override + public int getVersion() { + return XposedBridge.getXposedVersion(); + } +} diff --git a/core/src/main/java/io/github/lsposed/lspd/service/PackageReceiver.java b/core/src/main/java/io/github/lsposed/lspd/service/PackageReceiver.java index fa1c98f0..eba4f7f4 100644 --- a/core/src/main/java/io/github/lsposed/lspd/service/PackageReceiver.java +++ b/core/src/main/java/io/github/lsposed/lspd/service/PackageReceiver.java @@ -32,10 +32,13 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.widget.Toast; +import io.github.lsposed.lspd.nativebridge.ConfigManager; import io.github.lsposed.lspd.util.Utils; import java.io.File; @@ -50,8 +53,6 @@ import java.util.Scanner; import de.robv.android.xposed.XposedHelpers; -import static io.github.lsposed.lspd.service.ServiceProxy.CONFIG_PATH; - public class PackageReceiver { private static final BroadcastReceiver RECEIVER = new BroadcastReceiver() { @@ -102,7 +103,7 @@ public class PackageReceiver { private Map loadEnabledModules(int uid) { HashMap result = new HashMap<>(); try { - File enabledModules = new File(CONFIG_PATH, uid + "/" + ENABLED_MODULES_LIST_FILENAME); + File enabledModules = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME); if (!enabledModules.exists()) return result; Scanner scanner = new Scanner(enabledModules); while (scanner.hasNextLine()) { @@ -125,8 +126,8 @@ public class PackageReceiver { if (!enabledModules.containsKey(packageName)) return false; try { - File moduleListFile = new File(CONFIG_PATH, uid + "/" + MODULES_LIST_FILENAME); - File enabledModuleListFile = new File(CONFIG_PATH, uid + "/" + ENABLED_MODULES_LIST_FILENAME); + File moduleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + MODULES_LIST_FILENAME); + File enabledModuleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME); if (moduleListFile.exists() && !moduleListFile.canWrite()) { moduleListFile.delete(); moduleListFile.createNewFile(); @@ -144,7 +145,7 @@ public class PackageReceiver { enabledModulesList.println(module.getKey()); } else { Utils.logI(String.format("remove obsolete package %s", packageName)); - File prefsDir = new File(CONFIG_PATH, uid + "/prefs/" + packageName); + File prefsDir = new File(ConfigManager.getMiscPath(), uid + "/prefs/" + packageName); File[] fileList = prefsDir.listFiles(); if (fileList != null) { for (File childFile : fileList) { @@ -212,9 +213,9 @@ public class PackageReceiver { Intent broadCast = new Intent(activated ? MODULE_UPDATED : MODULE_NOT_ACTIVATAED); broadCast.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 0x01000000); broadCast.setData(intent.getData()); - broadCast.setPackage(ServiceProxy.INSTALLER_PACKAGE_NAME); + broadCast.setPackage(ConfigManager.getInstallerPackageName()); XposedHelpers.callMethod(context, "sendBroadcastAsUser", broadCast, userHandle); - Utils.logI("broadcast to " + ServiceProxy.INSTALLER_PACKAGE_NAME); + Utils.logI("broadcast to " + ConfigManager.getInstallerPackageName()); } catch (Throwable t) { Utils.logW("send broadcast failed", t); Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show(); diff --git a/core/src/main/java/io/github/lsposed/lspd/service/ParcelUtils.java b/core/src/main/java/io/github/lsposed/lspd/service/ParcelUtils.java new file mode 100644 index 00000000..78d2d1b2 --- /dev/null +++ b/core/src/main/java/io/github/lsposed/lspd/service/ParcelUtils.java @@ -0,0 +1,42 @@ +package io.github.lsposed.lspd.service; + +import android.os.Build; +import android.os.Parcel; + +import java.lang.reflect.Method; + +public class ParcelUtils { + + public static String readInterfaceDescriptor(Parcel parcel) { + parcel.readInt(); + if (Build.VERSION.SDK_INT >= 29) { + parcel.readInt(); + } + if (Build.VERSION.SDK_INT >= 30) { + parcel.readInt(); + } + return parcel.readString(); + } + + private static Method obtainMethod; + + public static Parcel fromNativePointer(long ptr) { + if (ptr == 0) return null; + + if (obtainMethod == null) { + try { + //noinspection JavaReflectionMemberAccess + obtainMethod = Parcel.class.getDeclaredMethod("obtain", long.class); + obtainMethod.setAccessible(true); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + try { + return (Parcel) obtainMethod.invoke(null, ptr); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/src/main/java/io/github/lsposed/lspd/service/ServiceProxy.java b/core/src/main/java/io/github/lsposed/lspd/service/ServiceProxy.java deleted file mode 100644 index 080b18dd..00000000 --- a/core/src/main/java/io/github/lsposed/lspd/service/ServiceProxy.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 LSPosed Contributors - */ - -package io.github.lsposed.lspd.service; - -import android.os.Handler; -import android.os.IBinder; -import android.os.IServiceManager; -import android.os.Looper; -import android.os.ServiceManager; - -import io.github.lsposed.common.KeepAll; -import io.github.lsposed.lspd.util.Utils; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -public class ServiceProxy implements InvocationHandler, KeepAll { - - public static String CONFIG_PATH = null; - public static String INSTALLER_PACKAGE_NAME = null; - - private static IServiceManager original; - - public synchronized static void install() throws ReflectiveOperationException { - if (original != null) return; - - Method method = ServiceManager.class.getDeclaredMethod("getIServiceManager"); - Field field = ServiceManager.class.getDeclaredField("sServiceManager"); - - method.setAccessible(true); - field.setAccessible(true); - - original = (IServiceManager) method.invoke(null); - field.set(null, Proxy.newProxyInstance( - ServiceProxy.class.getClassLoader(), - new Class[]{IServiceManager.class}, - new ServiceProxy() - )); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - switch (method.getName()) { - case "addService": { - if (args.length > 1 && args[0] instanceof String && args[1] instanceof IBinder) { - final String name = (String) args[0]; - final IBinder service = (IBinder) args[1]; - args[1] = onAddService(name, service); - } - return method.invoke(original, args); - } -// case "getService": -// if(args.length == 1 && args[0] instanceof String && method.getReturnType() == IBinder.class) { -// final String name = (String) args[0]; -// final IBinder service = (IBinder)method.invoke(original, args); -// return onGetService(name, service); -// } -// return method.invoke(original, args); - default: - return method.invoke(original, args); - } - } - - private IBinder onAddService(String name, IBinder service) { - if ("activity".equals(name)) { - try { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - PackageReceiver.register(); - } - }); - } catch (Throwable e) { - Utils.logW("Error in registering package receiver", e); - } - return service; - } - return service; - } - -// protected IBinder onGetService(String name, IBinder service) { -// return service; -// } -} diff --git a/core/template_override/customize.sh b/core/template_override/customize.sh index cf77f62b..d26836c6 100644 --- a/core/template_override/customize.sh +++ b/core/template_override/customize.sh @@ -170,6 +170,7 @@ extract "${ZIPFILE}" 'module.prop' "${MODPATH}" extract "${ZIPFILE}" 'system.prop' "${MODPATH}" extract "${ZIPFILE}" 'sepolicy.rule' "${MODPATH}" extract "${ZIPFILE}" 'post-fs-data.sh' "${MODPATH}" +extract "${ZIPFILE}" 'service.sh' "${MODPATH}" extract "${ZIPFILE}" 'uninstall.sh' "${MODPATH}" extract "${ZIPFILE}" 'system/framework/lspd.dex' "${MODPATH}" diff --git a/core/template_override/post-fs-data.sh b/core/template_override/post-fs-data.sh index e4cac816..89d5565c 100644 --- a/core/template_override/post-fs-data.sh +++ b/core/template_override/post-fs-data.sh @@ -165,5 +165,6 @@ if [[ ! -z "${MISC_PATH}" ]]; then print_log_head "${LOG_PATH}/modules.log" # start_verbose_log_catcher start_log_catcher all "LSPosed:V XSharedPreferences:V LSPosed-Bridge:V LSPosedManager:V *:F" true ${LOG_VERBOSE} + echo 'starting service' fi rm -f /data/adb/lspd/new_install diff --git a/core/template_override/service.sh b/core/template_override/service.sh index f0e75aa9..f2b03e3a 100644 --- a/core/template_override/service.sh +++ b/core/template_override/service.sh @@ -25,4 +25,9 @@ MODDIR=${0%/*} if [[ -f "${MODDIR}/reboot_twice_flag" ]]; then rm -f "${MODDIR}/reboot_twice_flag" reboot -fi \ No newline at end of file +fi + +MISC_PATH=$(cat /data/adb/lspd/misc_path) +BASE_PATH="/data/misc/$MISC_PATH" + +/system/bin/app_process -Djava.class.path=${BASE_PATH}/framework/lspd.dex /system/bin --nice-name=lspd io.github.lsposed.lspd.core.Main diff --git a/hiddenapi-stubs/src/main/java/android/ddm/DdmHandleAppName.java b/hiddenapi-stubs/src/main/java/android/ddm/DdmHandleAppName.java new file mode 100644 index 00000000..1ed326b7 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/ddm/DdmHandleAppName.java @@ -0,0 +1,7 @@ +package android.ddm; + +public class DdmHandleAppName { + public static void setAppName(String name, int userId) { + throw new RuntimeException("STUB"); + } +} diff --git a/service/.gitignore b/service/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/service/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/service/build.gradle b/service/build.gradle new file mode 100644 index 00000000..dc40fc49 --- /dev/null +++ b/service/build.gradle @@ -0,0 +1,21 @@ +plugins { + id 'com.android.library' +} + +android { + compileSdkVersion androidCompileSdkVersion.toInteger() + ndkVersion androidCompileNdkVersion + buildToolsVersion androidBuildToolsVersion + + defaultConfig { + minSdkVersion androidMinSdkVersion.toInteger() + targetSdkVersion androidTargetSdkVersion.toInteger() + versionCode 1 + versionName "1.0" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} diff --git a/service/proguard-rules.pro b/service/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/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/service/src/main/AndroidManifest.xml b/service/src/main/AndroidManifest.xml new file mode 100644 index 00000000..6ab17fc5 --- /dev/null +++ b/service/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/service/src/main/aidl/io/github/lsposed/lspd/service/ILSPosedService.aidl b/service/src/main/aidl/io/github/lsposed/lspd/service/ILSPosedService.aidl new file mode 100644 index 00000000..1eb4f2fd --- /dev/null +++ b/service/src/main/aidl/io/github/lsposed/lspd/service/ILSPosedService.aidl @@ -0,0 +1,5 @@ +package io.github.lsposed.lspd.service; + +interface ILSPosedService { + int getVersion() = 1; +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 9cf6a60b..fcdea69c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,3 @@ rootProject.name = "LSPosed" +include ':service' include ':core', ':hiddenapi-stubs', ':sandhook-hooklib', ':sandhook-annotation', ':app', ':key-selector'