From 0d7cfd3797e1a97686c2c90ba1c09b18652ffec9 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Fri, 1 Sep 2023 21:54:50 +0800 Subject: [PATCH 01/34] Fix `IContentProvider` for Android P and below (#2735) Fix #2734 --- .../main/java/org/lsposed/lspd/service/LSPModuleService.java | 2 ++ .../stubs/src/main/java/android/content/IContentProvider.java | 3 +++ 2 files changed, 5 insertions(+) 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/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; From 8d73414d2dbd81ec9fdb1f84123887c0c1161a50 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 4 Sep 2023 01:05:22 +0800 Subject: [PATCH 02/34] Fix processName = null (#2739) --- .../src/main/java/org/lsposed/lspd/service/ConfigManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..0710b560873 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -129,7 +129,7 @@ public boolean equals(@Nullable Object o) { @Override public int hashCode() { - return processName.hashCode() ^ uid; + return Objects.hashCode(processName) ^ uid; } } From 134cd71fa0087c4705cee41c32e0ea28dccb4683 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 4 Sep 2023 01:18:48 +0800 Subject: [PATCH 03/34] Wrap whole onTransact (#2740) --- .../lsposed/lspd/service/BridgeService.java | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) 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; } From bbcb9cad5cfe8a52c3dbd54190491e00d8f2c8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E7=A7=8B=E6=9E=AB=E5=BD=B1?= <18218380+naicfeng@users.noreply.github.com> Date: Tue, 5 Sep 2023 19:00:45 +0800 Subject: [PATCH 04/34] fix magiskDb file does not exist (#2459) --- daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java | 1 + 1 file changed, 1 insertion(+) 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 0710b560873..6eb6695f5a8 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -1136,6 +1136,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)) { From bfa7b49c6050ea51d59736c98a866c592ea5c5ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:11:06 +0800 Subject: [PATCH 05/34] Bump androidx.core:core from 1.10.1 to 1.12.0 (#2744) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dbff9678d4d..305be5ab9aa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ androidx-activity = { module = "androidx.activity:activity", version = "1.7.2" } androidx-annotation = { module = "androidx.annotation:annotation", version = "1.6.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" } From 57af13cfb2aa9a8d83789f13bf79aafb28447465 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:19:39 +0000 Subject: [PATCH 06/34] Bump androidx.annotation:annotation from 1.6.0 to 1.7.0 (#2745) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 305be5ab9aa..9438aa379d8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ rikkax-widget-borderview = { module = "dev.rikka.rikkax.widget:borderview", vers 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-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.12.0" } From b2ab117380ce4d6a35d56b0285999b659dcb067d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:33:55 +0000 Subject: [PATCH 07/34] Bump nav from 2.7.1 to 2.7.2 (#2743) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9438aa379d8..5d380788313 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agp = "8.1.1" kotlin = "1.9.10" -nav = "2.7.1" +nav = "2.7.2" appcenter = "5.0.2" libxposed = "100" glide = "4.16.0" From b89c62f931d1750ee67b058038c05e4832dff6e1 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Wed, 20 Sep 2023 14:29:25 +0800 Subject: [PATCH 08/34] Upgrade to NDK 26 (#2762) --- build.gradle.kts | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 63721 bytes gradlew | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) 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/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf41af1ab109bc7f253b2b887023340..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch delta 28216 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 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 From 3c6d5d64d26d6739352c2865cc98e2f9a9a33f31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:23:57 +0000 Subject: [PATCH 09/34] Bump nav from 2.7.2 to 2.7.3 (#2763) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5d380788313..bf846aa2b9d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agp = "8.1.1" kotlin = "1.9.10" -nav = "2.7.2" +nav = "2.7.3" appcenter = "5.0.2" libxposed = "100" glide = "4.16.0" From b07fd258d20c4a864975776f27167eb1a3726494 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sun, 24 Sep 2023 12:19:27 +0800 Subject: [PATCH 10/34] [skip ci] Remove predefined titles of issue template (#2768) --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 - .github/ISSUE_TEMPLATE/feature_request.yml | 1 - 2 files changed, 2 deletions(-) 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: From cc31605423af93064137a3563b7fad3b80a7df0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 02:58:17 +0800 Subject: [PATCH 11/34] Bump agp from 8.1.1 to 8.1.2 (#2771) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bf846aa2b9d..48f9a479569 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.1.1" +agp = "8.1.2" kotlin = "1.9.10" nav = "2.7.3" appcenter = "5.0.2" From 888a7dbeb685d17c82bb4cc8d62e3c96ac580ca6 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 5 Oct 2023 01:06:57 +0800 Subject: [PATCH 12/34] Upgrade cxx (#2780) --- .gitmodules | 6 +-- core/src/main/jni/include/config_bridge.h | 42 ++++++++++---------- core/src/main/jni/include/context.h | 2 +- core/src/main/jni/src/context.cpp | 4 ++ daemon/src/main/jni/dex2oat.cpp | 1 + daemon/src/main/jni/logcat.cpp | 1 + daemon/src/main/jni/logging.h | 1 + external/CMakeLists.txt | 39 +++++++++--------- external/cxx | 2 +- external/lsplant | 2 +- magisk-loader/src/main/jni/src/config_impl.h | 32 +++++++-------- magisk-loader/src/main/jni/src/service.cpp | 2 + magisk-loader/src/main/jni/src/service.h | 2 +- 13 files changed, 71 insertions(+), 65 deletions(-) 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/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/src/context.cpp b/core/src/main/jni/src/context.cpp index 1d057300569..69375dddfee 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 lspd::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/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 c8021286453..2334cf8a5b1 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; 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/external/CMakeLists.txt b/external/CMakeLists.txt index 82bdcfb85b6..1c6af93b7f0 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 +# ios.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,18 @@ 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 + ) +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 +88,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..bbabd25043f 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit 9c33903c87a240ae38dbf7fdf49c0748addd073d +Subproject commit bbabd25043f4fd8056cf5df55e2839de824467a1 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..7493cd2e968 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -33,6 +33,8 @@ using namespace lsplant; namespace lspd { + std::unique_ptr Service::instance_; + jboolean Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, va_list args) { 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; From cf198fde881581173b6aff6f52e2f18278302db0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:59:29 +0000 Subject: [PATCH 13/34] Bump nav from 2.7.3 to 2.7.4 (#2782) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48f9a479569..91d987c8e2e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agp = "8.1.2" kotlin = "1.9.10" -nav = "2.7.3" +nav = "2.7.4" appcenter = "5.0.2" libxposed = "100" glide = "4.16.0" From 1a6264ab7ab2a10562f079b5a4f40eb8998bfb9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:16:23 +0000 Subject: [PATCH 14/34] Bump androidx.activity:activity from 1.7.2 to 1.8.0 (#2783) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 91d987c8e2e..195ed108fbf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,7 +35,7 @@ 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-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" } From 5c85a20601866b97bc03312acc5647ff42299ee3 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 5 Oct 2023 02:41:45 +0800 Subject: [PATCH 15/34] Fix Service initialization (#2784) --- core/src/main/jni/src/context.cpp | 2 +- magisk-loader/src/main/jni/src/service.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/jni/src/context.cpp b/core/src/main/jni/src/context.cpp index 69375dddfee..92272460741 100644 --- a/core/src/main/jni/src/context.cpp +++ b/core/src/main/jni/src/context.cpp @@ -33,7 +33,7 @@ using namespace lsplant; namespace lspd { - std::unique_ptr lspd::Context::instance_; + std::unique_ptr Context::instance_; std::unique_ptr ConfigBridge::instance_; Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) { diff --git a/magisk-loader/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp index 7493cd2e968..1c92f4d1bea 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -33,7 +33,7 @@ using namespace lsplant; namespace lspd { - std::unique_ptr Service::instance_; + std::unique_ptr Service::instance_ = std::make_unique(); jboolean Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, From c7e6c7793467e3272f829f713ed74adef8a6ec8c Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 5 Oct 2023 09:43:27 +0800 Subject: [PATCH 16/34] Upgrade gradle (#2785) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 932612aa9c0f69489d839dd523a468a397757310 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 09:13:24 +0800 Subject: [PATCH 17/34] Bump com.google.android.material:material from 1.9.0 to 1.10.0 (#2790) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 195ed108fbf..37d7d8b2274 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" } From 50c343d152f82b2c8a1e9b8cfa75836a8273b3ff Mon Sep 17 00:00:00 2001 From: LoveSy Date: Fri, 6 Oct 2023 13:43:59 +0800 Subject: [PATCH 18/34] No cache setOverrideTable (#2789) --- core/src/main/jni/include/symbol_cache.h | 4 +--- core/src/main/jni/src/symbol_cache.cpp | 21 ++++----------------- magisk-loader/src/main/jni/src/service.cpp | 10 ++++++---- 3 files changed, 11 insertions(+), 24 deletions(-) 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/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/magisk-loader/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp index 1c92f4d1bea..6027c734636 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -29,6 +29,7 @@ #include "utils/jni_helper.hpp" #include "symbol_cache.h" #include "config_bridge.h" +#include "elf_util.h" using namespace lsplant; @@ -197,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)); @@ -205,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, From 7674396eff2d99aa7a02ed02bd0a29058b9594ba Mon Sep 17 00:00:00 2001 From: rawer886 Date: Sat, 7 Oct 2023 17:37:34 +0800 Subject: [PATCH 19/34] Fix the 'lspd' process name (#2793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ActivityThread#systemMain -> ActivityThread#attach will also change the process name to 'system_process', so that there are two 'system_process' processes in the system. https://android.googlesource.com/platform/frameworks/base/+/0e40462e11d27eb859b829b112cecb8c6f0d7afb/core/java/android/app/ActivityThread.java#5119 ![截屏2023-10-07 16 16 30](https://github.com/LSPosed/LSPosed/assets/8243689/ee137210-ffa3-497a-aca1-5c215dd9eaed) Co-authored-by: jiayg --- .../main/java/org/lsposed/lspd/service/ServiceManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 35dfd650feacb9365890b50bf9ade1b8ba4459d8 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Sat, 7 Oct 2023 22:37:58 +0800 Subject: [PATCH 20/34] Move manager APK to module path (#2787) --- .../java/org/lsposed/lspd/service/ConfigFileManager.java | 2 +- magisk-loader/build.gradle.kts | 6 ++---- magisk-loader/magisk_module/customize.sh | 2 +- magisk-loader/magisk_module/post-fs-data.sh | 1 + 4 files changed, 5 insertions(+), 6 deletions(-) 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/magisk-loader/build.gradle.kts b/magisk-loader/build.gradle.kts index 8ceccadacef..11120904f52 100644 --- a/magisk-loader/build.gradle.kts +++ b/magisk-loader/build.gradle.kts @@ -317,7 +317,7 @@ 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") @@ -332,11 +332,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/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 $@&" From 7fef809d01aa707f5f3d4c45830975bdc849be00 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 7 Oct 2023 23:11:26 +0800 Subject: [PATCH 21/34] Use phmap instead of absl (#2781) --- core/src/main/jni/src/jni/dex_parser.cpp | 11 ++-- core/src/main/jni/src/jni/hook_bridge.cpp | 61 +++++++++-------------- daemon/src/main/jni/obfuscation.h | 4 +- external/CMakeLists.txt | 5 +- external/lsplant | 2 +- 5 files changed, 36 insertions(+), 47 deletions(-) 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/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/external/CMakeLists.txt b/external/CMakeLists.txt index 1c6af93b7f0..84e990170da 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -24,9 +24,9 @@ set(LIBCXX_SOURCES # filesystem/operations.cpp functional.cpp future.cpp -# use absl instead -# hash.cpp + hash.cpp # ios.cpp +# ios.instantiations.cpp # iostream.cpp # locale.cpp memory.cpp @@ -61,6 +61,7 @@ set(LIBCXX_EXPORT_FLAGS -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCXXABI_NO_EXCEPTIONS + -D_LIBCPP_HAS_NO_LOCALIZATION ) set(LIBCXX_FLAGS -fvisibility-global-new-delete-hidden diff --git a/external/lsplant b/external/lsplant index bbabd25043f..c18f2761772 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit bbabd25043f4fd8056cf5df55e2839de824467a1 +Subproject commit c18f27617727f04b0785709ff63a63457bc5dd6c From dd66cf2b074357bcef346571978f8fbc0de13a82 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Mon, 9 Oct 2023 15:04:41 +0800 Subject: [PATCH 22/34] Fix remote preferences listener not working on system_server (#2794) --- .../lsposed/lspd/impl/LSPosedRemotePreferences.java | 9 ++++----- .../java/org/lsposed/lspd/service/ConfigManager.java | 9 +++++++-- .../lspd/service/LSPInjectedModuleService.java | 12 ++++++------ 3 files changed, 17 insertions(+), 13 deletions(-) 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/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java index 6eb6695f5a8..470b45b7db1 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java @@ -215,6 +215,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; @@ -229,7 +234,7 @@ public List getModulesForSystemServer() { } 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 +553,6 @@ private synchronized void cacheModules() { var module = new Module(); module.packageName = packageName; module.apkPath = apkPath; - module.service = new LSPInjectedModuleService(module); modules.add(module); } @@ -590,6 +594,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); 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; From d487932696850128ff915b6c11aa82d9c65f5aae Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 10 Oct 2023 10:01:20 +0800 Subject: [PATCH 23/34] Fix class verification of hooker crash for sdk 34 (#2797) --- external/lsplant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/lsplant b/external/lsplant index c18f2761772..780cbe09a35 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit c18f27617727f04b0785709ff63a63457bc5dd6c +Subproject commit 780cbe09a35b45a5f02de0e4fcb640ea936a2710 From 15e480132add2e88db90b065c9111478a9d367f0 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Tue, 10 Oct 2023 11:57:43 +0800 Subject: [PATCH 24/34] Fix AdjustThreadVisibilityCounter inline (#2799) --- external/lsplant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/lsplant b/external/lsplant index 780cbe09a35..a4f6979c28d 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit 780cbe09a35b45a5f02de0e4fcb640ea936a2710 +Subproject commit a4f6979c28de2ad68f536f20cbda9dd765b13c1d From 254a8adb2714877fdd5e134949e09362a8edd3b5 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 11 Oct 2023 01:06:21 +0800 Subject: [PATCH 25/34] Officially announce Android 14 support (#2801) Co-authored-by: LoveSy --- README.md | 2 +- external/lsplant | 2 +- magisk-loader/magisk_module/module.prop | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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/external/lsplant b/external/lsplant index a4f6979c28d..899766f2bdd 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit a4f6979c28de2ad68f536f20cbda9dd765b13c1d +Subproject commit 899766f2bddaa786c99d81da909fe084ed99ff7b 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} From c423c6e7059a6fd0c2cd6a86245348a373300e90 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Wed, 11 Oct 2023 09:08:36 +0800 Subject: [PATCH 26/34] Add tag `LSPosedContext` to module log (#2803) --- daemon/src/main/jni/logcat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/src/main/jni/logcat.cpp b/daemon/src/main/jni/logcat.cpp index 2334cf8a5b1..1dffc263267 100644 --- a/daemon/src/main/jni/logcat.cpp +++ b/daemon/src/main/jni/logcat.cpp @@ -220,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; } From 159a3adcf8e0832a3e45dccedbb54767dd9f7c4d Mon Sep 17 00:00:00 2001 From: LoveSy Date: Wed, 11 Oct 2023 09:28:37 +0800 Subject: [PATCH 27/34] Fix wrong NewXSharedPreference path because of inline (#2804) --- .../main/java/org/lsposed/lspd/deopt/InlinedMethodCallers.java | 1 + .../main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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/LoadedApkGetCLHooker.java index f36f8644bfb..48b60491fef 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java @@ -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) { From c5e1a544bf8704990b6f81d9d111f5cad2e7d1f1 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Wed, 11 Oct 2023 11:10:18 +0800 Subject: [PATCH 28/34] Update ApplicationInfo if it was system_server cached (#2805) --- .../java/org/lsposed/lspd/service/ConfigManager.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 470b45b7db1..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; @@ -231,6 +233,11 @@ 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); } @@ -579,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; } From cbee741d55be758b3061c1ec6e79d1cfbcf37a76 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Wed, 11 Oct 2023 11:20:08 +0800 Subject: [PATCH 29/34] Fix some missing onPackageLoad on Android U because of inline (#2802) --- .../src/main/java/org/lsposed/lspd/core/Startup.java | 6 ++++-- ...GetCLHooker.java => LoadedApkCreateCLHooker.java} | 12 ++++++------ .../org/lsposed/lspd/hooker/LoadedApkCtorHooker.java | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) rename core/src/main/java/org/lsposed/lspd/hooker/{LoadedApkGetCLHooker.java => LoadedApkCreateCLHooker.java} (93%) 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/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 48b60491fef..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); } 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); } From bb8b8bfab5cf99eef68097bdbc9b140145f6f82c Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 11 Oct 2023 15:34:43 +0800 Subject: [PATCH 30/34] Update lsplant (#2806) --- external/lsplant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/lsplant b/external/lsplant index 899766f2bdd..a612522188d 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit 899766f2bddaa786c99d81da909fe084ed99ff7b +Subproject commit a612522188d903a523fc6760cd4ee257c3224d8c From 8d80428d94367df261447685b9cbe82a608eb35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=97=E5=AE=AB=E9=9B=AA=E7=8F=8A?= Date: Wed, 11 Oct 2023 17:58:00 +0800 Subject: [PATCH 31/34] Add deploy optimizations tip for module developers (#2674) --- .../manager/ui/fragment/HomeFragment.java | 29 +++++++++++++++++ app/src/main/res/layout/fragment_home.xml | 32 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 63 insertions(+) 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 @@ + + + + + + + + + + + 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 From 82d138cc6c800090334a9b87cd00b50aa6dbaa41 Mon Sep 17 00:00:00 2001 From: XposedBot Date: Wed, 11 Oct 2023 19:41:20 +0800 Subject: [PATCH 32/34] [translation] Update translation from Crowdin (#2807) --- app/src/main/res/values-ar/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 ++ app/src/main/res/values-fa/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-in/strings.xml | 14 +++++++------- app/src/main/res/values-it/strings.xml | 4 +++- app/src/main/res/values-ko/strings.xml | 2 ++ app/src/main/res/values-ku/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-ro/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 ++ app/src/main/res/values-zh-rCN/strings.xml | 2 ++ daemon/src/main/res/values-fa/strings.xml | 4 ++-- 13 files changed, 26 insertions(+), 16 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 58d33180fb8..c09470e44d5 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -64,7 +64,7 @@ يرجى تثبيت أحدث إصدار من 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..3617e071d64 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/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 به روز رسانی شده لطفا دستگاه را خاموش و روشن کنید From 9a8c18648fe50f3cc495457a62029731a3827a47 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 11 Oct 2023 19:56:52 +0800 Subject: [PATCH 33/34] Fix rerunApk (#2809) --- magisk-loader/build.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/magisk-loader/build.gradle.kts b/magisk-loader/build.gradle.kts index 11120904f52..d2dea7957ce 100644 --- a/magisk-loader/build.gradle.kts +++ b/magisk-loader/build.gradle.kts @@ -321,6 +321,11 @@ 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) } From f8927757e8704d96611e1f3d75f702e3f0ce061f Mon Sep 17 00:00:00 2001 From: XposedBot Date: Wed, 11 Oct 2023 20:06:50 +0800 Subject: [PATCH 34/34] [translation] Update translation from Crowdin (#2808) --- app/src/main/res/values-zh-rCN/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3617e071d64..33dce858edd 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -52,7 +52,7 @@ 模块可能会随机失效。]]> 需要更新 请安装新版 LSPosed - 开发人员建议 + 给模块开发者的提示 请在 Android Studio 上禁用部署优化,或使用 `gradlew installDebug` 命令进行安装,否则无法更新模块。 API 版本 框架版本