diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index d3b6ac7953e..e827084d1ed 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -62,9 +62,6 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - - name: Grant Execute Permission for gradlew - run: chmod +x gradlew - - name: Setup ninja uses: seanmiddleditch/gha-setup-ninja@v5 with: @@ -75,14 +72,6 @@ jobs: with: version: latest - - name: Setup ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - max-size: 2G - key: ${{ runner.os }} - restore-keys: ${{ runner.os }} - save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - name: Remove Android's cmake shell: bash run: rm -rf $ANDROID_HOME/cmake diff --git a/.gitmodules b/.gitmodules index 533f7b78365..6b59e25a71f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "external/xz-embedded"] path = external/xz-embedded url = https://github.com/tukaani-project/xz-embedded +[submodule "apache/commons-lang"] + path = apache/commons-lang + url = https://github.com/apache/commons-lang diff --git a/apache/build.gradle.kts b/apache/build.gradle.kts new file mode 100644 index 00000000000..af8055912b2 --- /dev/null +++ b/apache/build.gradle.kts @@ -0,0 +1,16 @@ +val androidSourceCompatibility: JavaVersion by rootProject.extra +val androidTargetCompatibility: JavaVersion by rootProject.extra + +plugins { + id("java-library") +} + +java { + sourceCompatibility = androidSourceCompatibility + targetCompatibility = androidTargetCompatibility + sourceSets { + main { + java.srcDirs("commons-lang/src/main/java", "local") + } + } +} diff --git a/apache/commons-lang b/apache/commons-lang new file mode 160000 index 00000000000..c2cd0525d97 --- /dev/null +++ b/apache/commons-lang @@ -0,0 +1 @@ +Subproject commit c2cd0525d97495daa820d2fcb29d6875b52c09a6 diff --git a/apache/local/org/apache/commons/lang3/reflect/MemberUtilsX.java b/apache/local/org/apache/commons/lang3/reflect/MemberUtilsX.java new file mode 100644 index 00000000000..36c872096fb --- /dev/null +++ b/apache/local/org/apache/commons/lang3/reflect/MemberUtilsX.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.reflect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +public class MemberUtilsX { + public static int compareConstructorFit(final Constructor left, final Constructor right, final Class[] actual) { + return MemberUtils.compareConstructorFit(left, right, actual); + } + + public static int compareMethodFit(final Method left, final Method right, final Class[] actual) { + return MemberUtils.compareMethodFit(left, right, actual); + } +} diff --git a/app/src/main/java/org/lsposed/manager/ConfigManager.java b/app/src/main/java/org/lsposed/manager/ConfigManager.java index 22dfca148bf..983c76fbb50 100644 --- a/app/src/main/java/org/lsposed/manager/ConfigManager.java +++ b/app/src/main/java/org/lsposed/manager/ConfigManager.java @@ -178,6 +178,25 @@ public static boolean setVerboseLogEnabled(boolean enabled) { } } + public static boolean isLogWatchdogEnabled() { + try { + return LSPManagerServiceHolder.getService().isLogWatchdogEnabled(); + } catch (RemoteException e) { + Log.e(App.TAG, Log.getStackTraceString(e)); + return false; + } + } + + public static boolean setLogWatchdog(boolean enabled) { + try { + LSPManagerServiceHolder.getService().setLogWatchdog(enabled); + return true; + } catch (RemoteException e) { + Log.e(App.TAG, Log.getStackTraceString(e)); + return false; + } + } + public static ParcelFileDescriptor getLog(boolean verbose) { try { return verbose ? LSPManagerServiceHolder.getService().getVerboseLog() : LSPManagerServiceHolder.getService().getModulesLog(); diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java index d9c8a85a955..3df1a1c3a52 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java @@ -608,7 +608,9 @@ public void onLoadCleared(@Nullable Drawable placeholder) { holder.root.setAlpha(moduleUtil.isModuleEnabled(item.packageName) ? 1.0f : .5f); holder.itemView.setOnClickListener(v -> { searchView.clearFocus(); - safeNavigate(ModulesFragmentDirections.actionModulesFragmentToAppListFragment(item.packageName, item.userId)); + if (isLoaded()) { + safeNavigate(ModulesFragmentDirections.actionModulesFragmentToAppListFragment(item.packageName, item.userId)); + } }); holder.itemView.setOnLongClickListener(v -> { searchView.clearFocus(); diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/SettingsFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/SettingsFragment.java index 2d06c1e50b3..ed7d759176e 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/SettingsFragment.java @@ -160,6 +160,13 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { prefVerboseLogs.setOnPreferenceChangeListener((preference, newValue) -> ConfigManager.setVerboseLogEnabled(!(boolean) newValue)); } + MaterialSwitchPreference prefEnableLog = findPreference("force_enable_log"); + if (prefEnableLog != null) { + prefEnableLog.setEnabled(!BuildConfig.DEBUG && installed); + prefEnableLog.setChecked(!installed || ConfigManager.isLogWatchdogEnabled()); + prefEnableLog.setOnPreferenceChangeListener((preference, newValue) -> ConfigManager.setLogWatchdog((boolean) newValue)); + } + MaterialSwitchPreference prefDexObfuscate = findPreference("enable_dex_obfuscate"); if (prefDexObfuscate != null) { prefDexObfuscate.setEnabled(installed); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ad115eabd6..a3f506803f5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,6 +175,8 @@ Framework Disable verbose logs Report issues request to include verbose logs + Enable log watchdog + Log watchdog of LSPosed modifies system properties, which could be exploited to detect LSPosed Black dark theme Use the pure black theme if dark theme is enabled Theme diff --git a/app/src/main/res/xml/prefs.xml b/app/src/main/res/xml/prefs.xml index f72192884b8..69b918e6581 100644 --- a/app/src/main/res/xml/prefs.xml +++ b/app/src/main/res/xml/prefs.xml @@ -91,6 +91,14 @@ android:summary="@string/settings_disable_verbose_log_summary" android:title="@string/settings_disable_verbose_log" /> + + = Build.VERSION_CODES.R) permissionManagerWorkaround(); @@ -133,11 +142,6 @@ public static void start(String[] args) { systemServerService.putBinderForSystemServer(); - // get config before package service is started - // otherwise getInstance will trigger module/scope cache - var configManager = ConfigManager.getInstance(); - // --- DO NOT call ConfigManager.getInstance later!!! --- - ActivityThread.systemMain(); DdmHandleAppName.setAppName("org.lsposed.daemon", 0); diff --git a/daemon/src/main/jni/logcat.cpp b/daemon/src/main/jni/logcat.cpp index af5aeb73965..3f0ec340f03 100644 --- a/daemon/src/main/jni/logcat.cpp +++ b/daemon/src/main/jni/logcat.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,7 @@ class Logcat { pid_t my_pid_ = getpid(); bool verbose_ = true; + std::atomic enable_watchdog = std::atomic(false); }; size_t Logcat::PrintLogLine(const AndroidLogEntry &entry, FILE *out) { @@ -241,6 +243,12 @@ void Logcat::ProcessBuffer(struct log_msg *buf) { RefreshFd(false); } else if (msg == "!!refresh_verbose!!"sv) { RefreshFd(true); + } else if (msg == "!!start_watchdog!!"sv) { + enable_watchdog = true; + enable_watchdog.notify_one(); + } else if (msg == "!!stop_watchdog!!"sv) { + enable_watchdog = false; + enable_watchdog.notify_one(); } } } @@ -253,6 +261,7 @@ void Logcat::EnsureLogWatchDog() { constexpr static size_t kErr = -1; std::thread watch_dog([this] { while (true) { + enable_watchdog.wait(false); auto logd_size = GetByteProp(kLogdSizeProp); auto logd_tag = GetStrProp(kLogdTagProp); auto logd_main_size = GetByteProp(kLogdMainSizeProp); @@ -277,8 +286,9 @@ void Logcat::EnsureLogWatchDog() { }, &serial); } if (!__system_property_wait(pi, serial, &serial, nullptr)) break; - if (pi != nullptr) Log("\nResetting log settings\n"); - else std::this_thread::sleep_for(1s); + if (pi != nullptr) { + if (enable_watchdog) Log("\nResetting log settings\n"); + } else std::this_thread::sleep_for(1s); // log tag prop was not found; to avoid frequently trigger wait, sleep for a while } }); diff --git a/dex2oat/src/main/cpp/dex2oat.c b/dex2oat/src/main/cpp/dex2oat.c index 1e120623e96..8db3c79aab0 100644 --- a/dex2oat/src/main/cpp/dex2oat.c +++ b/dex2oat/src/main/cpp/dex2oat.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -31,9 +32,9 @@ #include "logging.h" #if defined(__LP64__) -# define LP_SELECT(lp32, lp64) lp64 +#define LP_SELECT(lp32, lp64) lp64 #else -# define LP_SELECT(lp32, lp64) lp32 +#define LP_SELECT(lp32, lp64) lp32 #endif #define ID_VEC(is64, is_debug) (((is64) << 1) | (is_debug)) @@ -50,23 +51,17 @@ static ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) { static void *recv_fds(int sockfd, char *cmsgbuf, size_t bufsz, int cnt) { struct iovec iov = { - .iov_base = &cnt, - .iov_len = sizeof(cnt), + .iov_base = &cnt, + .iov_len = sizeof(cnt), }; struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsgbuf, - .msg_controllen = bufsz - }; + .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsgbuf, .msg_controllen = bufsz}; xrecvmsg(sockfd, &msg, MSG_WAITALL); struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); - if (msg.msg_controllen != bufsz || - cmsg == NULL || - cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) || - cmsg->cmsg_level != SOL_SOCKET || + if (msg.msg_controllen != bufsz || cmsg == NULL || + cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { return NULL; } @@ -78,8 +73,7 @@ static int recv_fd(int sockfd) { char cmsgbuf[CMSG_SPACE(sizeof(int))]; void *data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1); - if (data == NULL) - return -1; + if (data == NULL) return -1; int result; memcpy(&result, data, sizeof(int)); @@ -88,8 +82,7 @@ static int recv_fd(int sockfd) { static int read_int(int fd) { int val; - if (read(fd, &val, sizeof(val)) != sizeof(val)) - return -1; + if (read(fd, &val, sizeof(val)) != sizeof(val)) return -1; return val; } @@ -105,7 +98,7 @@ int main(int argc, char **argv) { strlcpy(sock.sun_path + 1, kSockName, sizeof(sock.sun_path) - 1); int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); size_t len = sizeof(sa_family_t) + strlen(sock.sun_path + 1) + 1; - if (connect(sock_fd, (struct sockaddr *) &sock, len)) { + if (connect(sock_fd, (struct sockaddr *)&sock, len)) { PLOGE("failed to connect to %s", sock.sun_path + 1); return 1; } @@ -119,7 +112,14 @@ int main(int argc, char **argv) { for (int i = 0; i < argc; i++) new_argv[i] = argv[i]; new_argv[argc] = "--inline-max-code-units=0"; new_argv[argc + 1] = NULL; - fexecve(stock_fd, (char **) new_argv, environ); + + if (getenv("LD_LIBRARY_PATH") == NULL) { + char const *libenv = + "LD_LIBRARY_PATH=/apex/com.android.art/lib64:/apex/com.android.art/lib" + ":/apex/com.android.os.statsd/lib64:/apex/com.android.os.statsd/lib"; + putenv((char *)libenv); + } + fexecve(stock_fd, (char **)new_argv, environ); PLOGE("fexecve failed"); return 2; } diff --git a/external/lsplant b/external/lsplant index d73aa7f9742..acdd096d3ef 160000 --- a/external/lsplant +++ b/external/lsplant @@ -1 +1 @@ -Subproject commit d73aa7f9742b3c13084bb719962cfcd9358dd0f3 +Subproject commit acdd096d3ef4220d6cf27b71308606eaa8741aac diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 05c492804b0..73fe5f49dbc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] -agp = "8.6.0" +agp = "8.6.1" kotlin = "2.0.20" -nav = "2.7.7" +nav = "2.8.0" appcenter = "5.0.4" libxposed = "100" glide = "4.16.0" @@ -35,12 +35,12 @@ 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.9.1" } +androidx-activity = { module = "androidx.activity:activity", version = "1.9.2" } androidx-annotation = { module = "androidx.annotation:annotation", version = "1.8.2" } androidx-browser = { module = "androidx.browser:browser", version = "1.8.0" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.1.4" } androidx-core = { module = "androidx.core:core", version = "1.13.1" } -androidx-fragment = { module = "androidx.fragment:fragment", version = "1.8.2" } +androidx-fragment = { module = "androidx.fragment:fragment", version = "1.8.3" } androidx-navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "nav" } androidx-navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "nav" } androidx-preference = { module = "androidx.preference:preference", version = "1.2.1" } @@ -56,12 +56,11 @@ okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-i agp-apksig = { group = "com.android.tools.build", name = "apksig", version.ref = "agp" } appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" } -commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.17.0" } material = { module = "com.google.android.material:material", version = "1.12.0" } gson = { module = "com.google.code.gson:gson", version = "2.11.0" } hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version = "4.3" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } -kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.8.1" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.9.0" } libxposed-api = { group = "io.github.libxposed", name = "api", version.ref = "libxposed" } libxposed-interface = { group = "io.github.libxposed", name = "interface", version.ref = "libxposed" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b415575..0aaefbcaf0f 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.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/services/manager-service/src/main/aidl/org/lsposed/lspd/ILSPManagerService.aidl b/services/manager-service/src/main/aidl/org/lsposed/lspd/ILSPManagerService.aidl index ca1c0488fc0..ea82be2f6e0 100644 --- a/services/manager-service/src/main/aidl/org/lsposed/lspd/ILSPManagerService.aidl +++ b/services/manager-service/src/main/aidl/org/lsposed/lspd/ILSPManagerService.aidl @@ -87,4 +87,8 @@ interface ILSPManagerService { boolean enableStatusNotification() = 47; void setEnableStatusNotification(boolean enable) = 48; + + void setLogWatchdog(boolean enable) = 49; + + boolean isLogWatchdogEnabled() = 50; } diff --git a/settings.gradle.kts b/settings.gradle.kts index f4cdaa479b9..2d4e03d10f8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,7 @@ dependencyResolutionManagement { rootProject.name = "LSPosed" include( + ":apache", ":app", ":axml", ":core",