diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 759e517dba6..f09dae4e94e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,6 @@ name: Bug report/反馈 Bug description: Report errors or unexpected behavior./反馈错误或异常行为。 labels: [bug] -title: "[Bug] " body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 92f5c21e173..b21432d17be 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -2,7 +2,6 @@ name: Feature request/新特性请求 description: Suggest an idea./提出建议 labels: [enhancement] -title: "[Feature Request] " body: - type: textarea attributes: diff --git a/.gitmodules b/.gitmodules index 9dc2c72534e..10165e6a0ac 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "external/cxx"] - path = external/cxx - url = https://github.com/LSPosed/libcxx.git [submodule "external/lsplant"] path = external/lsplant url = https://github.com/LSPosed/LSPlant.git @@ -10,3 +7,6 @@ [submodule "external/fmt"] path = external/fmt url = https://github.com/fmtlib/fmt.git +[submodule "external/cxx"] + path = external/cxx + url = https://github.com/topjohnwu/libcxx.git diff --git a/README.md b/README.md index 01c5fcdf960..9f9c44e6228 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A Riru / Zygisk module trying to provide an ART hooking framework which delivers ## Supported Versions -Android 8.1 ~ 13 +Android 8.1 ~ 14 ## Install diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/HomeFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/HomeFragment.java index 579fdfea9d1..64b2acf3254 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/HomeFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/HomeFragment.java @@ -23,6 +23,9 @@ import android.app.Dialog; import android.os.Build; import android.os.Bundle; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.Menu; @@ -51,8 +54,12 @@ import org.lsposed.manager.util.UpdateUtil; import org.lsposed.manager.util.chrome.LinkTransformationMethod; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; import rikka.core.util.ClipboardUtils; import rikka.material.app.LocaleDelegate; @@ -146,6 +153,7 @@ private void updateStates(Activity activity, boolean binderAlive, boolean needUp } binding.statusSummary.setText(String.format(LocaleDelegate.getDefaultLocale(), "%s (%d) - %s", ConfigManager.getXposedVersionName(), ConfigManager.getXposedVersionCode(), ConfigManager.getApi())); + binding.developerWarningCard.setVisibility(isDeveloper() ? View.VISIBLE : View.GONE); } else { boolean isMagiskInstalled = ConfigManager.isMagiskInstalled(); if (isMagiskInstalled) { @@ -254,6 +262,27 @@ private String getDevice() { return manufacturer; } + private boolean isDeveloper() { + var developer = new AtomicBoolean(false); + var pids = Paths.get("/data/local/tmp/.studio/ipids"); + try (var dir = Files.list(pids)) { + dir.findFirst().ifPresent(name -> { + var pid = Integer.parseInt(name.getFileName().toString()); + try { + Os.kill(pid, 0); + developer.set(true); + } catch (ErrnoException e) { + if (e.errno != OsConstants.ESRCH) { + developer.set(true); + } + } + }); + } catch (IOException e) { + return false; + } + return developer.get(); + } + public static class AboutDialog extends DialogFragment { @NonNull @Override diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 652bc07fbe2..09fe189b984 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -215,6 +215,38 @@ + + + + + + + + + + + يرجى تثبيت أحدث إصدار من LSPosed إصدار API إصدار إطار العمل - اسم حزمة المدير + Lاسم حزمة المديرo إصدار النظام الجهاز نظام ABI diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ae39fc93f61..9569e2424fa 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -55,6 +55,8 @@ JJ108 Module können gelegentlich außer Kraft gesetzt werden.]]> Aktualisierung erforderlich Bitte installieren Sie die neueste Version von LSPosed + Tipps für Modulentwickler + Bitte deaktiviere Deploy-Optimierungen in Android Studio oder benutze den `gradlew installDebug` Befehl zum Installieren. Andernfalls wird die Modul-Apk nicht aktualisiert. API Version Framework Version Name des Managerpakets diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 4840cd0192b..2cb42fa635a 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -25,7 +25,7 @@ %d ماژول فعال شده %d ماژول فعال شده - سیاهه + گزارش ها تنظیمات بازخورد یا پیشنهاد درباره diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ef44a0f64f8..b81c7c0e836 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -20,7 +20,7 @@ Aperçu - Module + Modules %d module actif %d modules actifs diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 26262ed12ea..206a4e4ca55 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -64,7 +64,7 @@ Didukung Tidak didukung Versi Android tidak tersedia - Crash + Rusak Mount gagal SELinux permisif SELinux policy salah @@ -75,7 +75,7 @@ Selamat datang di LSPosed Anda menggunakan manajer parasit, yang dapat membuat pintasan atau dapat terbuka dari notifikasi. Anda menggunakan manajer parasit, yang dapat dibuka dari notifikasi. - Buat shortcut + Buat pintasan Jangan pernah tampilkan Manajer Parasit Direkomendasikan LSPosed sekarang mendukung parasitisasi sistem untuk menghindari deteksi, Anda dapat membuka manajer parasit dari pemberitahuan. Disarankan untuk menghapus aplikasi saat ini. @@ -83,7 +83,7 @@ Simpan Log Verbose Log Modul - Saving log, please wait + Menyimpan log, harap tunggu Log disimpan Gagal menyimpan:\n%s Hapus log sekarang @@ -134,7 +134,7 @@ Anda tidak memilih aplikasi apa pun. Lanjutkan? Permainan Modul - Denylist + Daftar penolakan Gagal menyimpan ke daftar cakupan Versi: %1$s Direkomendasikan @@ -154,8 +154,8 @@ Mulai ulang diperlukan agar perubahan ini dapat diterapkan Mulai ulang Sembunyikan - %s berada di denylist. Ini mungkin tidak akan berpengaruh. - Berada di denylist + %s ada dalam daftar penolakan. Ini mungkin tidak berpengaruh. + Berada di daftar tolak Lihat di aplikasi lain Informasi aplikasi @@ -200,7 +200,7 @@ Proteksi panggilan API Xposed Blokir kode modul yang dimuat secara dinamis untuk menggunakan Xposed API, ini mungkin mengganggu beberapa modul namun lebih aman - Readme + Baca aku Rilis Informasi Beranda diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4b41bcb5a41..db1e8c9911c 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -54,9 +54,11 @@ In alcuni casi i moduli potrebbero non funzionare.]]> Aggiornamento richiesto Installa la versione più recente di LSPosed + Suggerimenti per lo sviluppatore del modulo + Disattivare le ottimizzazioni di distribuzione su Android Studio, o utilizzare il comando `gradlew installDebug` per eseguire l\'installazione. Altrimenti l\'apk del modulo non verrà aggiornato. Versione API Versione del framework - Nome del pacchetto manager + Nome pacchetto del manager Versione del sistema Dispositivo ABI del sistema diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 6668f1e8833..59be53f2fb9 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -52,6 +52,8 @@ 모듈은 가끔 무효화될 수 있습니다.]]> 업데이트가 필요합니다 최신 버전으로 LSPosed를 설치해 주세요 + 모듈 개발자를 위한 팁 + Android Studio 에서 배포 최적화를 비활성화 하거나, 설치할때 \'gradlew installDebug\' 명령어를 사용해주세요. 그렇지 않으면 모듈 APK 가 업데이트되지 않을 것입니다. API 버전 Framework 버전 관리자 패키지 이름 diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml index 7642672a5a4..dcf58d61d22 100644 --- a/app/src/main/res/values-ku/strings.xml +++ b/app/src/main/res/values-ku/strings.xml @@ -26,7 +26,7 @@ %d مۆدیول چالاک کراوە لۆگەکان - رێکخستن + ڕێکخستنەکان فیدباک یان پێشنیار دەربارە پرسی ڕاپۆرت diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 7cc77af4d05..56c7af64031 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -56,7 +56,7 @@ Por favor, instale a versão mais recente do LSPosed Versão da API Versão do Framework - Nome do pacote do gestor + Nome do pacote do gerenciador Versão do Sistema Aparelho Interfaces Binárias do Sistema diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 1c101b0a2f5..1a9106ff1ec 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -36,7 +36,7 @@ Publicat la %s Actualizat la %s - %d module actualizabile. + %d module actualizabil %d module actualizabile %d module actualizabile. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index db54c37cc2a..69f016313f7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -58,6 +58,8 @@ Некоторые системные настройки нужные для работы удалены или изменены.
Модули могут не работать должным образом]]>
Требуется обновление Установите последнюю версию LSPosed! + Советы разработчику модулей + Пожалуйста, отключите оптимизацию развертывания в Android Studio или используйте для установки команду `gradlew installDebug`. Иначе модуль не обновится Версия API Версия фреймворк Имя пакета менеджера diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 78525d8b6ec..33dce858edd 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -52,6 +52,8 @@ 模块可能会随机失效。]]> 需要更新 请安装新版 LSPosed + 给模块开发者的提示 + 请在 Android Studio 上禁用部署优化,或使用 `gradlew installDebug` 命令进行安装,否则无法更新模块。 API 版本 框架版本 管理器包名 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 55108b26404..9b125ba6fdd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -55,6 +55,8 @@ Modules may invalidate occasionally.]]> Need to update Please install the latest version of LSPosed + Tips for module developer + Please disable deploy optimizations on Android Studio, or use `gradlew installDebug` command to install. Otherwise the module apk will not be updated. API version Framework version Manager package name diff --git a/build.gradle.kts b/build.gradle.kts index e78ee814bfe..dedfc8c2373 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -70,7 +70,7 @@ val androidTargetSdkVersion by extra(34) val androidMinSdkVersion by extra(27) val androidBuildToolsVersion by extra("34.0.0") val androidCompileSdkVersion by extra(34) -val androidCompileNdkVersion by extra("25.2.9519653") +val androidCompileNdkVersion by extra("26.0.10792818") val androidSourceCompatibility by extra(JavaVersion.VERSION_17) val androidTargetCompatibility by extra(JavaVersion.VERSION_17) diff --git a/core/src/main/java/org/lsposed/lspd/core/Startup.java b/core/src/main/java/org/lsposed/lspd/core/Startup.java index 2bd4ff7a5d0..e4d08b96d8c 100644 --- a/core/src/main/java/org/lsposed/lspd/core/Startup.java +++ b/core/src/main/java/org/lsposed/lspd/core/Startup.java @@ -32,13 +32,15 @@ import org.lsposed.lspd.hooker.CrashDumpHooker; import org.lsposed.lspd.hooker.HandleSystemServerProcessHooker; import org.lsposed.lspd.hooker.LoadedApkCtorHooker; -import org.lsposed.lspd.hooker.LoadedApkGetCLHooker; +import org.lsposed.lspd.hooker.LoadedApkCreateCLHooker; import org.lsposed.lspd.hooker.OpenDexFileHooker; import org.lsposed.lspd.impl.LSPosedContext; import org.lsposed.lspd.impl.LSPosedHelper; import org.lsposed.lspd.service.ILSPApplicationService; import org.lsposed.lspd.util.Utils; +import java.util.List; + import dalvik.system.DexFile; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedInit; @@ -57,7 +59,7 @@ private static void startBootstrapHook(boolean isSystem) { LSPosedHelper.hookConstructor(LoadedApkCtorHooker.class, LoadedApk.class, ActivityThread.class, ApplicationInfo.class, CompatibilityInfo.class, ClassLoader.class, boolean.class, boolean.class, boolean.class); - LSPosedHelper.hookMethod(LoadedApkGetCLHooker.class, LoadedApk.class, "getClassLoader"); + LSPosedHelper.hookMethod(LoadedApkCreateCLHooker.class, LoadedApk.class, "createOrUpdateClassLoaderLocked", List.class); LSPosedHelper.hookAllMethods(AttachHooker.class, ActivityThread.class, "attach"); } diff --git a/core/src/main/java/org/lsposed/lspd/deopt/InlinedMethodCallers.java b/core/src/main/java/org/lsposed/lspd/deopt/InlinedMethodCallers.java index 5d46d40206f..9c0425312a7 100644 --- a/core/src/main/java/org/lsposed/lspd/deopt/InlinedMethodCallers.java +++ b/core/src/main/java/org/lsposed/lspd/deopt/InlinedMethodCallers.java @@ -57,6 +57,7 @@ public class InlinedMethodCallers { // callers of Application#attach(Context) {"android.app.Instrumentation", "newApplication", ClassLoader.class, String.class, Context.class}, {"android.app.Instrumentation", "newApplication", ClassLoader.class, Context.class}, + {"android.app.ContextImpl", "getSharedPreferencesPath", String.class} }; // TODO deprecate this diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java similarity index 93% rename from core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java rename to core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java index f36f8644bfb..161c730eba3 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCreateCLHooker.java @@ -56,7 +56,7 @@ @SuppressLint("BlockedPrivateApi") @XposedHooker -public class LoadedApkGetCLHooker implements XposedInterface.Hooker { +public class LoadedApkCreateCLHooker implements XposedInterface.Hooker { private final static Field defaultClassLoaderField; private final static Set loadedApks = ConcurrentHashMap.newKeySet(); @@ -81,12 +81,12 @@ static void addLoadedApk(LoadedApk loadedApk) { public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) { LoadedApk loadedApk = (LoadedApk) callback.getThisObject(); - if (!loadedApks.contains(loadedApk)) { + if (callback.getArgs()[0] != null || !loadedApks.contains(loadedApk)) { return; } try { - Hookers.logD("LoadedApk#getClassLoader starts"); + Hookers.logD("LoadedApk#createClassLoader starts"); String packageName = ActivityThread.currentPackageName(); String processName = ActivityThread.currentProcessName(); @@ -99,8 +99,8 @@ public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) } Object mAppDir = XposedHelpers.getObjectField(loadedApk, "mAppDir"); - ClassLoader classLoader = (ClassLoader) callback.getResult(); - Hookers.logD("LoadedApk#getClassLoader ends: " + mAppDir + " -> " + classLoader); + ClassLoader classLoader = (ClassLoader) XposedHelpers.getObjectField(loadedApk, "mClassLoader"); + Hookers.logD("LoadedApk#createClassLoader ends: " + mAppDir + " -> " + classLoader); if (classLoader == null) { return; @@ -165,7 +165,7 @@ public boolean isFirstPackage() { } }); } catch (Throwable t) { - Hookers.logE("error when hooking LoadedApk#getClassLoader", t); + Hookers.logE("error when hooking LoadedApk#createClassLoader", t); } finally { loadedApks.remove(loadedApk); } @@ -188,7 +188,7 @@ private static void hookNewXSP(XC_LoadPackage.LoadPackageParam lpparam) { } if (xposedminversion > 92 || xposedsharedprefs) { - Utils.logW("New modules detected, hook preferences"); + Utils.logI("New modules detected, hook preferences"); XposedHelpers.findAndHookMethod("android.app.ContextImpl", lpparam.classLoader, "checkMode", int.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java index 00f1f7cedbc..2ddbff32a87 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkCtorHooker.java @@ -72,7 +72,7 @@ public static void afterHookedMethod(XposedInterface.AfterHookCallback callback) return; } - LoadedApkGetCLHooker.addLoadedApk(loadedApk); + LoadedApkCreateCLHooker.addLoadedApk(loadedApk); } catch (Throwable t) { Hookers.logE("error when hooking LoadedApk.", t); } diff --git a/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java b/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java index 4bbe9395762..5c5d3fa37e0 100644 --- a/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java +++ b/core/src/main/java/org/lsposed/lspd/impl/LSPosedRemotePreferences.java @@ -10,10 +10,10 @@ import org.lsposed.lspd.service.ILSPInjectedModuleService; import org.lsposed.lspd.service.IRemotePreferenceCallback; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; -import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; @SuppressWarnings("unchecked") @@ -21,8 +21,7 @@ public class LSPosedRemotePreferences implements SharedPreferences { private final Map mMap = new ConcurrentHashMap<>(); - private static final Object CONTENT = new Object(); - final WeakHashMap mListeners = new WeakHashMap<>(); + final HashSet mListeners = new HashSet<>(); IRemotePreferenceCallback callback = new IRemotePreferenceCallback.Stub() { @Override @@ -42,7 +41,7 @@ synchronized public void onUpdate(Bundle bundle) { } synchronized (mListeners) { for (var key : changes) { - mListeners.keySet().forEach(listener -> listener.onSharedPreferenceChanged(LSPosedRemotePreferences.this, key)); + mListeners.forEach(listener -> listener.onSharedPreferenceChanged(LSPosedRemotePreferences.this, key)); } } } @@ -117,7 +116,7 @@ public Editor edit() { @Override public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { synchronized (mListeners) { - mListeners.put(listener, CONTENT); + mListeners.add(listener); } } diff --git a/core/src/main/jni/include/config_bridge.h b/core/src/main/jni/include/config_bridge.h index 0ac540b94e8..b24d4fec2af 100644 --- a/core/src/main/jni/include/config_bridge.h +++ b/core/src/main/jni/include/config_bridge.h @@ -16,32 +16,30 @@ * * Copyright (C) 2022 LSPosed Contributors */ +#pragma once -// -// Created by Kotori0 on 2022/4/14. -// - -#ifndef LSPOSED_CONFIGBRIDGE_H -#define LSPOSED_CONFIGBRIDGE_H #include -using obfuscation_map_t = std::map; -class ConfigBridge { -public: - inline static ConfigBridge *GetInstance() { - return instance_.get(); - } +namespace lspd { + using obfuscation_map_t = std::map; + + class ConfigBridge { + public: + inline static ConfigBridge *GetInstance() { + return instance_.get(); + } + + inline static std::unique_ptr ReleaseInstance() { + return std::move(instance_); + } - inline static std::unique_ptr ReleaseInstance() { - return std::move(instance_); - } + virtual obfuscation_map_t &obfuscation_map() = 0; - virtual obfuscation_map_t& obfuscation_map() = 0; - virtual void obfuscation_map(obfuscation_map_t) = 0; + virtual void obfuscation_map(obfuscation_map_t) = 0; - virtual ~ConfigBridge() = default; -protected: - inline static std::unique_ptr instance_ = nullptr; -}; + virtual ~ConfigBridge() = default; -#endif //LSPOSED_CONFIGBRIDGE_H + protected: + static std::unique_ptr instance_; + }; +} diff --git a/core/src/main/jni/include/context.h b/core/src/main/jni/include/context.h index 59bd29d5709..ca56bd02da8 100644 --- a/core/src/main/jni/include/context.h +++ b/core/src/main/jni/include/context.h @@ -52,7 +52,7 @@ namespace lspd { virtual ~Context() = default; protected: - inline static std::unique_ptr instance_; + static std::unique_ptr instance_; jobject inject_class_loader_ = nullptr; jclass entry_class_ = nullptr; diff --git a/core/src/main/jni/include/symbol_cache.h b/core/src/main/jni/include/symbol_cache.h index 419a726e843..7369c311326 100644 --- a/core/src/main/jni/include/symbol_cache.h +++ b/core/src/main/jni/include/symbol_cache.h @@ -35,13 +35,11 @@ namespace lspd { struct SymbolCache { std::atomic_flag initialized{}; void *do_dlopen; - void *setTableOverride; SymbolCache() = default; SymbolCache(const SymbolCache &other) : - do_dlopen(other.do_dlopen), - setTableOverride(other.setTableOverride) {} + do_dlopen(other.do_dlopen) {} SymbolCache &operator=(const SymbolCache &other) { new(this)SymbolCache(other); diff --git a/core/src/main/jni/src/context.cpp b/core/src/main/jni/src/context.cpp index 1d057300569..92272460741 100644 --- a/core/src/main/jni/src/context.cpp +++ b/core/src/main/jni/src/context.cpp @@ -31,7 +31,11 @@ using namespace lsplant; + namespace lspd { + std::unique_ptr Context::instance_; + std::unique_ptr ConfigBridge::instance_; + Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) { LOGD("Context::PreloadedDex::PreloadedDex: fd={}, size={}", fd, size); auto *addr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); diff --git a/core/src/main/jni/src/jni/dex_parser.cpp b/core/src/main/jni/src/jni/dex_parser.cpp index 6a1bc7001d1..6d73545f29e 100644 --- a/core/src/main/jni/src/jni/dex_parser.cpp +++ b/core/src/main/jni/src/jni/dex_parser.cpp @@ -22,7 +22,8 @@ #include "slicer/reader.h" #include -#include +#include +#include namespace { using Value = std::tuple /*data*/>; @@ -62,11 +63,11 @@ namespace { }; std::vector class_data; - absl::flat_hash_map> field_annotations; - absl::flat_hash_map> method_annotations; - absl::flat_hash_map> parameter_annotations; + phmap::flat_hash_map> field_annotations; + phmap::flat_hash_map> method_annotations; + phmap::flat_hash_map> parameter_annotations; - absl::flat_hash_map method_bodies; + phmap::flat_hash_map method_bodies; }; template diff --git a/core/src/main/jni/src/jni/hook_bridge.cpp b/core/src/main/jni/src/jni/hook_bridge.cpp index 467a6811196..724013b4ed2 100644 --- a/core/src/main/jni/src/jni/hook_bridge.cpp +++ b/core/src/main/jni/src/jni/hook_bridge.cpp @@ -20,7 +20,7 @@ #include "hook_bridge.h" #include "native_util.h" #include "lsplant.hpp" -#include +#include #include #include #include @@ -58,8 +58,12 @@ struct HookItem { } }; -std::shared_mutex hooked_lock; -absl::flat_hash_map> hooked_methods; +template , + class Eq = phmap::priv::hash_default_eq, + class Alloc = phmap::priv::Allocator>, size_t N = 4> +using SharedHashMap = phmap::parallel_flat_hash_map; + +SharedHashMap> hooked_methods; jmethodID invoke = nullptr; jmethodID callback_ctor = nullptr; @@ -88,22 +92,14 @@ LSP_DEF_NATIVE_METHOD(jboolean, HookBridge, hookMethod, jboolean useModernApi, j #endif auto target = env->FromReflectedMethod(hookMethod); HookItem * hook_item = nullptr; - { - std::shared_lock lk(hooked_lock); - if (auto found = hooked_methods.find(target); found != hooked_methods.end()) { - hook_item = found->second.get(); - } - } - if (!hook_item) { - std::unique_lock lk(hooked_lock); - if (auto &ptr = hooked_methods[target]; !ptr) { - ptr = std::make_unique(); - hook_item = ptr.get(); - newHook = true; - } else { - hook_item = ptr.get(); - } - } + hooked_methods.lazy_emplace_l(target, [&hook_item](auto &it) { + hook_item = it.second.get(); + }, [&hook_item, &target, &newHook](const auto &ctor) { + auto ptr = std::make_unique(); + hook_item = ptr.get(); + ctor(target, std::move(ptr)); + newHook = true; + }); if (newHook) { auto init = env->GetMethodID(hooker, "", "(Ljava/lang/reflect/Executable;)V"); auto callback_method = env->ToReflectedMethod(hooker, env->GetMethodID(hooker, "callback", @@ -139,12 +135,9 @@ LSP_DEF_NATIVE_METHOD(jboolean, HookBridge, hookMethod, jboolean useModernApi, j LSP_DEF_NATIVE_METHOD(jboolean, HookBridge, unhookMethod, jboolean useModernApi, jobject hookMethod, jobject callback) { auto target = env->FromReflectedMethod(hookMethod); HookItem * hook_item = nullptr; - { - std::shared_lock lk(hooked_lock); - if (auto found = hooked_methods.find(target); found != hooked_methods.end()) { - hook_item = found->second.get(); - } - } + hooked_methods.if_contains(target, [&hook_item](const auto &it) { + hook_item = it.second.get(); + }); if (!hook_item) return JNI_FALSE; jobject backup = hook_item->GetBackup(); if (!backup) return JNI_FALSE; @@ -178,12 +171,9 @@ LSP_DEF_NATIVE_METHOD(jobject, HookBridge, invokeOriginalMethod, jobject hookMet jobject thiz, jobjectArray args) { auto target = env->FromReflectedMethod(hookMethod); HookItem * hook_item = nullptr; - { - std::shared_lock lk(hooked_lock); - if (auto found = hooked_methods.find(target); found != hooked_methods.end()) { - hook_item = found->second.get(); - } - } + hooked_methods.if_contains(target, [&hook_item](const auto &it) { + hook_item = it.second.get(); + }); return env->CallObjectMethod(hook_item ? hook_item->GetBackup() : hookMethod, invoke, thiz, args); } @@ -307,12 +297,9 @@ LSP_DEF_NATIVE_METHOD(jboolean, HookBridge, setTrusted, jobject cookie) { LSP_DEF_NATIVE_METHOD(jobjectArray, HookBridge, callbackSnapshot, jclass callback_class, jobject method) { auto target = env->FromReflectedMethod(method); HookItem *hook_item = nullptr; - { - std::shared_lock lk(hooked_lock); - if (auto found = hooked_methods.find(target); found != hooked_methods.end()) { - hook_item = found->second.get(); - } - } + hooked_methods.if_contains(target, [&hook_item](const auto &it) { + hook_item = it.second.get(); + }); if (!hook_item) return nullptr; jobject backup = hook_item->GetBackup(); if (!backup) return nullptr; diff --git a/core/src/main/jni/src/symbol_cache.cpp b/core/src/main/jni/src/symbol_cache.cpp index 2b07315d2de..db27ac6217f 100644 --- a/core/src/main/jni/src/symbol_cache.cpp +++ b/core/src/main/jni/src/symbol_cache.cpp @@ -44,13 +44,6 @@ namespace lspd { } - bool FindLibArt() { - auto &art = GetArt(); - if (!art->isValid()) return false; - return symbol_cache->setTableOverride = art->getSymbAddress( - "_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"); - } - void InitSymbolCache(SymbolCache *other) { LOGD("InitSymbolCache"); if (other && other->initialized.test(std::memory_order_acquire)) { @@ -59,18 +52,12 @@ namespace lspd { symbol_cache->initialized.test_and_set(std::memory_order_relaxed); return; } - auto ok = FindLibArt(); symbol_cache->do_dlopen = SandHook::ElfImg("/linker").getSymbAddress( "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv"); - if (!ok) [[unlikely]] { - GetArt(true); - LOGE("Init symbol cache failed"); - } else { - symbol_cache->initialized.test_and_set(std::memory_order_relaxed); - if (other) { - *other = *symbol_cache; - other->initialized.test_and_set(std::memory_order_acq_rel); - } + symbol_cache->initialized.test_and_set(std::memory_order_relaxed); + if (other) { + *other = *symbol_cache; + other->initialized.test_and_set(std::memory_order_acq_rel); } } } // namespace lspd diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java index f2a6d3f106e..63420c46ce3 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -81,7 +81,7 @@ public class ConfigFileManager { static final Path basePath = Paths.get("/data/adb/lspd"); static final Path modulePath = basePath.resolve("modules"); static final Path daemonApkPath = Paths.get(System.getProperty("java.class.path", null)); - static final Path managerApkPath = basePath.resolve("manager.apk"); + static final Path managerApkPath = daemonApkPath.getParent().resolve("manager.apk"); static final File magiskDbPath = new File("/data/adb/magisk.db"); private static final Path lockPath = basePath.resolve("lock"); private static final Path configDirPath = basePath.resolve("config"); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java index d80a868deab..3786df43ffb 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -87,6 +87,8 @@ import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; +import hidden.HiddenApiBridge; + public class ConfigManager { private static ConfigManager instance = null; @@ -129,7 +131,7 @@ public boolean equals(@Nullable Object o) { @Override public int hashCode() { - return processName.hashCode() ^ uid; + return Objects.hashCode(processName) ^ uid; } } @@ -215,6 +217,11 @@ public List getModulesForSystemServer() { var module = new Module(); module.apkPath = cursor.getString(apkPathIdx); module.packageName = cursor.getString(pkgNameIdx); + var cached = cachedModule.get(module.packageName); + if (cached != null) { + modules.add(cached); + continue; + } var statPath = toGlobalNamespace("/data/user_de/0/" + module.packageName).getAbsolutePath(); try { module.appId = Os.stat(statPath).st_uid; @@ -226,10 +233,15 @@ public List getModulesForSystemServer() { var apkFile = new File(module.apkPath); var pkg = new PackageParser().parsePackage(apkFile, 0, false); module.applicationInfo = pkg.applicationInfo; + module.applicationInfo.sourceDir = module.apkPath; + module.applicationInfo.dataDir = statPath; + module.applicationInfo.deviceProtectedDataDir = statPath; + HiddenApiBridge.ApplicationInfo_credentialProtectedDataDir(module.applicationInfo, statPath); + module.applicationInfo.processName = module.packageName; } catch (PackageParser.PackageParserException e) { Log.w(TAG, "failed to parse " + module.apkPath, e); } - module.service = new LSPInjectedModuleService(module); + module.service = new LSPInjectedModuleService(module.packageName); modules.add(module); } } @@ -548,7 +560,6 @@ private synchronized void cacheModules() { var module = new Module(); module.packageName = packageName; module.apkPath = apkPath; - module.service = new LSPInjectedModuleService(module); modules.add(module); } @@ -575,8 +586,8 @@ private synchronized void cacheModules() { if (oldModule.appId != -1) { Log.d(TAG, m.packageName + " did not change, skip caching it"); } else { - // cache from system server, keep it and set only the appId - oldModule.appId = pkgInfo.applicationInfo.uid; + // cache from system server, update application info + oldModule.applicationInfo = pkgInfo.applicationInfo; } return false; } @@ -590,6 +601,7 @@ private synchronized void cacheModules() { } m.appId = pkgInfo.applicationInfo.uid; m.applicationInfo = pkgInfo.applicationInfo; + m.service = oldModule != null ? oldModule.service : new LSPInjectedModuleService(m.packageName); return true; }).forEach(m -> { var file = ConfigFileManager.loadModule(m.apkPath, dexObfuscate); @@ -1136,6 +1148,7 @@ private void removeModulePrefs(int uid, String packageName) throws IOException { public List getDenyListPackages() { List result = new ArrayList<>(); if (!getApi().equals("Zygisk")) return result; + if (!ConfigFileManager.magiskDbPath.exists()) return result; try (final SQLiteDatabase magiskDb = SQLiteDatabase.openDatabase(ConfigFileManager.magiskDbPath, new SQLiteDatabase.OpenParams.Builder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build())) { try (Cursor cursor = magiskDb.query("settings", new String[]{"value"}, "`key`=?", new String[]{"denylist"}, null, null, null)) { diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java index bfa975c9563..ae1f6e80fe0 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPInjectedModuleService.java @@ -21,12 +21,12 @@ public class LSPInjectedModuleService extends ILSPInjectedModuleService.Stub { private static final String TAG = "LSPosedInjectedModuleService"; - private final Module loadedModule; + private final String mPackageName; Map> callbacks = new ConcurrentHashMap<>(); - LSPInjectedModuleService(Module module) { - loadedModule = module; + LSPInjectedModuleService(String packageName) { + mPackageName = packageName; } @Override @@ -38,7 +38,7 @@ public int getFrameworkPrivilege() { public Bundle requestRemotePreferences(String group, IRemotePreferenceCallback callback) { var bundle = new Bundle(); var userId = Binder.getCallingUid() / PER_USER_RANGE; - bundle.putSerializable("map", ConfigManager.getInstance().getModulePrefs(loadedModule.packageName, userId, group)); + bundle.putSerializable("map", ConfigManager.getInstance().getModulePrefs(mPackageName, userId, group)); if (callback != null) { var groupCallbacks = callbacks.computeIfAbsent(group, k -> ConcurrentHashMap.newKeySet()); groupCallbacks.add(callback); @@ -56,7 +56,7 @@ public ParcelFileDescriptor openRemoteFile(String path) throws RemoteException { ConfigFileManager.ensureModuleFilePath(path); var userId = Binder.getCallingUid() / PER_USER_RANGE; try { - var dir = ConfigFileManager.resolveModuleDir(loadedModule.packageName, FILES_DIR, userId, -1); + var dir = ConfigFileManager.resolveModuleDir(mPackageName, FILES_DIR, userId, -1); return ParcelFileDescriptor.open(dir.resolve(path).toFile(), ParcelFileDescriptor.MODE_READ_ONLY); } catch (Throwable e) { throw new RemoteException(e.getMessage()); @@ -67,7 +67,7 @@ public ParcelFileDescriptor openRemoteFile(String path) throws RemoteException { public String[] getRemoteFileList() throws RemoteException { var userId = Binder.getCallingUid() / PER_USER_RANGE; try { - var dir = ConfigFileManager.resolveModuleDir(loadedModule.packageName, FILES_DIR, userId, -1); + var dir = ConfigFileManager.resolveModuleDir(mPackageName, FILES_DIR, userId, -1); var files = dir.toFile().list(); return files == null ? new String[0] : files; diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java index e0111a01ace..6e1a3ed4adc 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java @@ -97,6 +97,8 @@ private void sendBinder(int uid) { reply = provider.call("android", null, authority, SEND_BINDER, null, extra); } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { reply = provider.call("android", authority, SEND_BINDER, null, extra); + } else { + reply = provider.call("android", SEND_BINDER, null, extra); } if (reply != null) { Log.d(TAG, "sent module binder to " + name); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java index 3df8004b4b7..91c575e9ac8 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java @@ -133,8 +133,6 @@ public static void start(String[] args) { systemServerService.putBinderForSystemServer(); - DdmHandleAppName.setAppName("lspd", 0); - // get config before package service is started // otherwise getInstance will trigger module/scope cache var configManager = ConfigManager.getInstance(); @@ -142,6 +140,8 @@ public static void start(String[] args) { ActivityThread.systemMain(); + DdmHandleAppName.setAppName("lspd", 0); + waitSystemService("package"); waitSystemService("activity"); waitSystemService(Context.USER_SERVICE); diff --git a/daemon/src/main/jni/dex2oat.cpp b/daemon/src/main/jni/dex2oat.cpp index 202c99fff8c..212301d77c6 100644 --- a/daemon/src/main/jni/dex2oat.cpp +++ b/daemon/src/main/jni/dex2oat.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "logging.h" diff --git a/daemon/src/main/jni/logcat.cpp b/daemon/src/main/jni/logcat.cpp index 227443bde6c..47b52de9509 100644 --- a/daemon/src/main/jni/logcat.cpp +++ b/daemon/src/main/jni/logcat.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include using namespace std::string_view_literals; @@ -219,7 +220,7 @@ void Logcat::ProcessBuffer(struct log_msg *buf) { std::string_view tag(entry.tag, entry.tagLen); bool shortcut = false; - if (tag == "LSPosed-Bridge"sv || tag == "XSharedPreferences"sv) [[unlikely]] { + if (tag == "LSPosed-Bridge"sv || tag == "XSharedPreferences"sv || tag == "LSPosedContext") [[unlikely]] { modules_print_count_ += PrintLogLine(entry, modules_file_.get()); shortcut = true; } diff --git a/daemon/src/main/jni/logging.h b/daemon/src/main/jni/logging.h index 34d7f6069b9..86a7220ac4e 100644 --- a/daemon/src/main/jni/logging.h +++ b/daemon/src/main/jni/logging.h @@ -22,6 +22,7 @@ #define _LOGGING_H #include +#include #ifndef LOG_TAG #define LOG_TAG "LSPosed" diff --git a/daemon/src/main/jni/obfuscation.h b/daemon/src/main/jni/obfuscation.h index f721d03e97c..ec9dd151359 100644 --- a/daemon/src/main/jni/obfuscation.h +++ b/daemon/src/main/jni/obfuscation.h @@ -19,12 +19,12 @@ #pragma once #include -#include +#include #include "utils/jni_helper.hpp" class WA: public dex::Writer::Allocator { // addr: {size, fd} - absl::flat_hash_map> allocated_; + phmap::flat_hash_map> allocated_; public: inline void* Allocate(size_t size) override { auto fd = ASharedMemory_create("", size); diff --git a/daemon/src/main/res/values-fa/strings.xml b/daemon/src/main/res/values-fa/strings.xml index fd030b797f3..741ce30e978 100644 --- a/daemon/src/main/res/values-fa/strings.xml +++ b/daemon/src/main/res/values-fa/strings.xml @@ -2,8 +2,8 @@ ماژول Xposed هنوز فعال نشده - %1$s نصب شده اما هنوز فعال نشده - %1$s برای کاربر %2$s نصب شده اما هنوز فعال نشده + ماژول %1$s نصب شده اما هنوز فعال نشده + ماژول %1$s برای کاربر %2$s نصب شده اما هنوز فعال نشده ماژول Xposed به روز رسانی شده %s به‌روزرسانی شده لطفا برنامه‌ها را متوقف کرده و سپس دوباره در محدوده اجرا کنید ماژول Xposed به روز رسانی شده لطفا دستگاه را خاموش و روشن کنید diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 82bdcfb85b6..84e990170da 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -9,37 +9,40 @@ SET_OPTION(Plugin.SymbolResolver OFF) set(LIBCXX_SOURCES algorithm.cpp - any.cpp +# any.cpp atomic.cpp barrier.cpp - bind.cpp +# bind.cpp charconv.cpp chrono.cpp condition_variable.cpp condition_variable_destructor.cpp - debug.cpp +# debug.cpp exception.cpp - filesystem/directory_iterator.cpp - filesystem/int128_builtins.cpp - filesystem/operations.cpp +# filesystem/directory_iterator.cpp +# filesystem/int128_builtins.cpp +# filesystem/operations.cpp functional.cpp future.cpp -# use absl instead -# hash.cpp - ios.cpp - iostream.cpp - locale.cpp + hash.cpp +# ios.cpp +# ios.instantiations.cpp +# iostream.cpp +# locale.cpp memory.cpp mutex.cpp mutex_destructor.cpp new.cpp optional.cpp random.cpp - regex.cpp +# regex.cpp +# ryu/d2fixed.cpp +# ryu/d2s.cpp +# ryu/f2s.cpp shared_mutex.cpp stdexcept.cpp string.cpp - strstream.cpp +# strstream.cpp system_error.cpp thread.cpp # typeinfo.cpp @@ -51,17 +54,19 @@ set(LIBCXX_SOURCES list(TRANSFORM LIBCXX_SOURCES PREPEND cxx/src/) -set(LIBCXX_EXPORT_FLAGS) -set(LIBCXX_FLAGS - -fvisibility-global-new-delete-hidden - -fvisibility=hidden - -fvisibility-inlines-hidden +set(LIBCXX_EXPORT_FLAGS -DLIBCXX_BUILDING_LIBCXXABI -D_LIBCPP_NO_EXCEPTIONS -D_LIBCPP_NO_RTTI -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS - -D__STDC_FORMAT_MACROS + -D_LIBCXXABI_NO_EXCEPTIONS + -D_LIBCPP_HAS_NO_LOCALIZATION + ) +set(LIBCXX_FLAGS + -fvisibility-global-new-delete-hidden + -fvisibility=hidden + -fvisibility-inlines-hidden ) set(LIBCXX_EXPORT_INCLUDES cxx/include) set(LIBCXX_INCLUDES cxx/src) @@ -84,7 +89,6 @@ set(LIBCXXABI_SOURCES ) list(TRANSFORM LIBCXXABI_SOURCES PREPEND cxx/src/abi/) set(LIBCXXABI_FLAGS - -D_LIBCXXABI_NO_EXCEPTIONS -Wno-macro-redefined -Wno-unknown-attributes -DHAS_THREAD_LOCAL) diff --git a/external/cxx b/external/cxx index 82090ae75f7..12c8f4e93f1 160000 --- a/external/cxx +++ b/external/cxx @@ -1 +1 @@ -Subproject commit 82090ae75f7d284f2647a67f3f80f28f54eaddfc +Subproject commit 12c8f4e93f196a700137e983dcceeac43cf807f2 diff --git a/external/lsplant b/external/lsplant index 9c33903c87a..a612522188d 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit 9c33903c87a240ae38dbf7fdf49c0748addd073d +Subproject commit a612522188d903a523fc6760cd4ee257c3224d8c diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dbff9678d4d..37d7d8b2274 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] -agp = "8.1.1" +agp = "8.1.2" kotlin = "1.9.10" -nav = "2.7.1" +nav = "2.7.4" appcenter = "5.0.2" libxposed = "100" glide = "4.16.0" @@ -35,11 +35,11 @@ rikkax-recyclerview = { module = "dev.rikka.rikkax.recyclerview:recyclerview-ktx rikkax-widget-borderview = { module = "dev.rikka.rikkax.widget:borderview", version = "1.1.0" } rikkax-widget-mainswitchbar = { module = "dev.rikka.rikkax.widget:mainswitchbar", version = "1.0.2" } -androidx-activity = { module = "androidx.activity:activity", version = "1.7.2" } -androidx-annotation = { module = "androidx.annotation:annotation", version = "1.6.0" } +androidx-activity = { module = "androidx.activity:activity", version = "1.8.0" } +androidx-annotation = { module = "androidx.annotation:annotation", version = "1.7.0" } androidx-browser = { module = "androidx.browser:browser", version = "1.6.0" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.1.4" } -androidx-core = { module = "androidx.core:core", version = "1.10.1" } +androidx-core = { module = "androidx.core:core", version = "1.12.0" } androidx-fragment = { module = "androidx.fragment:fragment", version = "1.6.1" } androidx-navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "nav" } androidx-navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "nav" } @@ -58,7 +58,7 @@ agp-apksig = { group = "com.android.tools.build", name = "apksig", version.ref = appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" } axml = { module = "de.upb.cs.swt:axml", version = "2.1.3" } commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.13.0" } -material = { module = "com.google.android.material:material", version = "1.9.0" } +material = { module = "com.google.android.material:material", version = "1.10.0" } gson = { module = "com.google.code.gson:gson", version = "2.10.1" } hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version = "4.3" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf..7f93135c49b 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34e8ac..3fa8f862f75 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca147c..0adc8e1a532 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/hiddenapi/stubs/src/main/java/android/content/IContentProvider.java b/hiddenapi/stubs/src/main/java/android/content/IContentProvider.java index f3aba638254..47fb581ddb9 100644 --- a/hiddenapi/stubs/src/main/java/android/content/IContentProvider.java +++ b/hiddenapi/stubs/src/main/java/android/content/IContentProvider.java @@ -7,6 +7,9 @@ import androidx.annotation.RequiresApi; public interface IContentProvider extends IInterface { + Bundle call(String callingPkg, String method, + String arg, Bundle extras) throws RemoteException; + @RequiresApi(29) Bundle call(String callingPkg, String authority, String method, String arg, Bundle extras) throws RemoteException; diff --git a/magisk-loader/build.gradle.kts b/magisk-loader/build.gradle.kts index 9dddd324aad..4db5c61972d 100644 --- a/magisk-loader/build.gradle.kts +++ b/magisk-loader/build.gradle.kts @@ -317,10 +317,15 @@ val reRunDaemon = task("reRunDaemon") { ) isIgnoreExitValue = true } -val tmpApk = "/data/local/tmp/lsp.apk" +val tmpApk = "/data/local/tmp/manager.apk" val pushApk = task("pushApk") { group = "LSPosed" dependsOn(":app:assembleDebug") + doFirst { + exec { + commandLine(adb, "shell", "su", "-c", "rm", "-f", tmpApk) + } + } workingDir(project(":app").layout.buildDirectory.dir("outputs/apk/debug")) commandLine(adb, "push", "app-debug.apk", tmpApk) } @@ -332,11 +337,9 @@ val openApp = task("openApp") { "com.android.shell/.BugreportWarningActivity" ) } -task("reRunApp") { +task("reRunApp") { group = "LSPosed" dependsOn(pushApk) - commandLine(adb, "shell", "su", "-c", "mv -f $tmpApk /data/adb/lspd/manager.apk") - isIgnoreExitValue = true finalizedBy(reRunDaemon) } diff --git a/magisk-loader/magisk_module/customize.sh b/magisk-loader/magisk_module/customize.sh index c920331b711..ee84c3165d2 100644 --- a/magisk-loader/magisk_module/customize.sh +++ b/magisk-loader/magisk_module/customize.sh @@ -87,7 +87,7 @@ extract "$ZIPFILE" 'framework/lspd.dex' "$MODPATH" extract "$ZIPFILE" 'daemon.apk' "$MODPATH" extract "$ZIPFILE" 'daemon' "$MODPATH" rm -f /data/adb/lspd/manager.apk -extract "$ZIPFILE" 'manager.apk' '/data/adb/lspd' +extract "$ZIPFILE" 'manager.apk' "$MODPATH" if [ "$FLAVOR" == "zygisk" ]; then mkdir -p "$MODPATH/zygisk" diff --git a/magisk-loader/magisk_module/module.prop b/magisk-loader/magisk_module/module.prop index 3285e953f55..b8d2a8d8b10 100644 --- a/magisk-loader/magisk_module/module.prop +++ b/magisk-loader/magisk_module/module.prop @@ -3,5 +3,5 @@ name=${api} - LSPosed version=${versionName} (${versionCode}) versionCode=${versionCode} author=${authorList} -description=Another enhanced implementation of Xposed Framework. Supports Android 8.1 ~ 13. ${requirement}. +description=Another enhanced implementation of Xposed Framework. Supports Android 8.1 ~ 14. ${requirement}. updateJson=${updateJson} diff --git a/magisk-loader/magisk_module/post-fs-data.sh b/magisk-loader/magisk_module/post-fs-data.sh index c13b8073ee6..d032edb2b93 100644 --- a/magisk-loader/magisk_module/post-fs-data.sh +++ b/magisk-loader/magisk_module/post-fs-data.sh @@ -20,6 +20,7 @@ MODDIR=${0%/*} rm -f "/data/local/tmp/daemon.apk" +rm -f "/data/local/tmp/manager.apk" cd "$MODDIR" unshare -m sh -c "$MODDIR/daemon $@&" diff --git a/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java b/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java index 5e292450657..f40e7962964 100644 --- a/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/magisk-loader/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -100,39 +100,43 @@ public static ILSPosedService getService() { public static boolean onTransact(@NonNull Parcel data, @Nullable Parcel reply, int flags) { if (!ParcelUtils.safeEnforceInterface(data, DESCRIPTOR)) return false; - ACTION action = ACTION.values()[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(); + try { + ACTION action = ACTION.values()[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; } - return true; - } - break; - } - case ACTION_GET_BINDER: { - IBinder binder = null; - try { - String processName = data.readString(); - IBinder heartBeat = data.readStrongBinder(); - var applicationService = service == null ? null : service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid(), processName, heartBeat); - if (applicationService != null) binder = applicationService.asBinder(); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(e)); + break; } - if (binder != null && reply != null) { - reply.writeNoException(); - Log.d(TAG, "got binder is " + binder); - reply.writeStrongBinder(binder); - return true; + case ACTION_GET_BINDER: { + IBinder binder = null; + try { + String processName = data.readString(); + IBinder heartBeat = data.readStrongBinder(); + var applicationService = service == null ? null : service.requestApplicationService(Binder.getCallingUid(), Binder.getCallingPid(), processName, heartBeat); + if (applicationService != null) binder = applicationService.asBinder(); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } + if (binder != null && reply != null) { + reply.writeNoException(); + Log.d(TAG, "got binder is " + binder); + reply.writeStrongBinder(binder); + return true; + } + return false; } - return false; } + } catch (Throwable e) { + Log.e(TAG, "onTransact", e); } return false; } diff --git a/magisk-loader/src/main/jni/src/config_impl.h b/magisk-loader/src/main/jni/src/config_impl.h index 4b035422c33..08109c52fed 100644 --- a/magisk-loader/src/main/jni/src/config_impl.h +++ b/magisk-loader/src/main/jni/src/config_impl.h @@ -17,28 +17,24 @@ * Copyright (C) 2022 LSPosed Contributors */ -// -// Created by Kotori0 on 2022/4/14. -// - -#ifndef LSPOSED_CONFIGIMPL_H -#define LSPOSED_CONFIGIMPL_H +#pragma once #include "config_bridge.h" #include "service.h" -class ConfigImpl: public ConfigBridge { -public: - inline static void Init() { - instance_ = std::make_unique(); - } - - virtual obfuscation_map_t& obfuscation_map() override { return obfuscation_map_; } - virtual void obfuscation_map(obfuscation_map_t m) override { obfuscation_map_ = std::move(m); } +namespace lspd { + class ConfigImpl : public ConfigBridge { + public: + inline static void Init() { + instance_ = std::make_unique(); + } -private: - inline static std::map obfuscation_map_; -}; + virtual obfuscation_map_t &obfuscation_map() override { return obfuscation_map_; } + virtual void + obfuscation_map(obfuscation_map_t m) override { obfuscation_map_ = std::move(m); } -#endif //LSPOSED_CONFIGIMPL_H + private: + inline static std::map obfuscation_map_; + }; +} diff --git a/magisk-loader/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp index 538b07a6dea..6027c734636 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -29,10 +29,13 @@ #include "utils/jni_helper.hpp" #include "symbol_cache.h" #include "config_bridge.h" +#include "elf_util.h" using namespace lsplant; namespace lspd { + std::unique_ptr Service::instance_ = std::make_unique(); + jboolean Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, va_list args) { @@ -195,7 +198,9 @@ namespace lspd { auto binder_class = JNI_FindClass(env, "android/os/Binder"); exec_transact_backup_methodID_ = JNI_GetMethodID(env, binder_class, "execTransact", "(IJJI)Z"); - if (!symbol_cache->setTableOverride) { + auto *setTableOverride = SandHook::ElfImg("/libart.so").getSymbAddress( + "_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"); + if (!setTableOverride) { LOGE("set table override not found"); } memcpy(&native_interface_replace_, env->functions, sizeof(JNINativeInterface)); @@ -203,9 +208,8 @@ namespace lspd { call_boolean_method_va_backup_ = env->functions->CallBooleanMethodV; native_interface_replace_.CallBooleanMethodV = &call_boolean_method_va_replace; - if (symbol_cache->setTableOverride != nullptr) { - reinterpret_cast(symbol_cache->setTableOverride)( - &native_interface_replace_); + if (setTableOverride != nullptr) { + setTableOverride(&native_interface_replace_); } if (auto activity_thread_class = JNI_FindClass(env, "android/app/IActivityManager$Stub")) { if (auto *set_activity_controller_field = JNI_GetStaticFieldID(env, diff --git a/magisk-loader/src/main/jni/src/service.h b/magisk-loader/src/main/jni/src/service.h index a49ee06c426..d2186370184 100644 --- a/magisk-loader/src/main/jni/src/service.h +++ b/magisk-loader/src/main/jni/src/service.h @@ -89,7 +89,7 @@ namespace lspd { std::map RequestObfuscationMap(JNIEnv *env, const lsplant::ScopedLocalRef &binder); private: - inline static std::unique_ptr instance_ = std::make_unique(); + static std::unique_ptr instance_; bool initialized_ = false; Service() = default;