From 4d54fc723412b0037ab898b8eae116bc0f3b3af7 Mon Sep 17 00:00:00 2001 From: DDC <643063583@qq.com> Date: Tue, 31 Mar 2026 04:53:10 +0800 Subject: [PATCH 1/2] fix: avoid breaking new rear screen apply when allowing third-party themes --- .../systemframework/display/ThemeProvider.kt | 33 ++++- .../rules/thememanager/AllowThirdTheme.java | 11 +- .../utils/guard/RearScreenFlowGuard.java | 137 ++++++++++++++++++ 3 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java diff --git a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt index cf7c35c3af..850819b4af 100644 --- a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt +++ b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt @@ -20,29 +20,54 @@ package com.sevtinge.hyperceiler.libhook.rules.systemframework.display import com.sevtinge.hyperceiler.common.log.XposedLog import com.sevtinge.hyperceiler.libhook.base.BaseHook +import com.sevtinge.hyperceiler.libhook.utils.api.ContextUtils +import com.sevtinge.hyperceiler.libhook.utils.guard.RearScreenFlowGuard import io.github.kyuubiran.ezxhelper.core.finder.MethodFinder.`-Static`.methodFinder import io.github.kyuubiran.ezxhelper.xposed.dsl.HookFactory.`-Static`.createHook import io.github.kyuubiran.ezxhelper.xposed.dsl.HookFactory.`-Static`.createHooks import io.github.libxposed.api.XposedInterface import miui.drm.DrmManager import miui.drm.ThemeReceiver +import java.util.ArrayDeque class ThemeProvider : BaseHook() { + // validateTheme may nest on one thread, so temporary hooks need to be unwound by call depth. + private val hookStack = ThreadLocal.withInitial>> { ArrayDeque() } + override fun init() { - var hook: List? = null try { ThemeReceiver::class.java.methodFinder().filterByName("validateTheme").first().createHook { before { - hook = DrmManager::class.java.methodFinder().filterByName("isLegal").toList().createHooks { - returnConstant(DrmManager.DrmResult.DRM_SUCCESS) + val systemContext = ContextUtils.getContextNoError(ContextUtils.FlAG_ONLY_ANDROID) + val hooks = if (RearScreenFlowGuard.isRearScreenActivityActive(systemContext)) { + emptyList() + } else { + runCatching { + DrmManager::class.java.methodFinder().filterByName("isLegal").toList().createHooks { + returnConstant(DrmManager.DrmResult.DRM_SUCCESS) + } + }.onFailure { throwable -> + XposedLog.e(TAG, packageName, throwable) + }.getOrDefault(emptyList()) } + + currentHookStack().addLast(hooks) } after { - hook?.forEach { it.unhook() } + val stack = currentHookStack() + if (!stack.isEmpty()) { + stack.removeLast().forEach { it.unhook() } + } + if (stack.isEmpty()) { + hookStack.remove() + } } } } catch (t: Throwable) { XposedLog.e(TAG, packageName, t) } } + + private fun currentHookStack(): ArrayDeque> = + checkNotNull(hookStack.get()) } diff --git a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java index 3d9abdcde1..ffbf030820 100644 --- a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java +++ b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java @@ -20,8 +20,10 @@ import com.sevtinge.hyperceiler.libhook.base.BaseHook; import com.sevtinge.hyperceiler.libhook.callback.IMethodHook; +import com.sevtinge.hyperceiler.libhook.utils.api.ContextUtils; import com.sevtinge.hyperceiler.libhook.utils.hookapi.dexkit.DexKit; import com.sevtinge.hyperceiler.libhook.utils.hookapi.dexkit.IDexKit; +import com.sevtinge.hyperceiler.libhook.utils.guard.RearScreenFlowGuard; import org.luckypray.dexkit.DexKitBridge; import org.luckypray.dexkit.query.FindMethod; @@ -34,11 +36,11 @@ import io.github.kyuubiran.ezxhelper.xposed.common.HookParam; import miui.drm.DrmManager; -; - public class AllowThirdTheme extends BaseHook { @Override public void init() { + runOnApplicationAttach(RearScreenFlowGuard::ensureActivityTrackerRegistered); + Method method = DexKit.findMember("CheckRightsIsLegal", new IDexKit() { @Override public BaseData dexkit(DexKitBridge bridge) throws ReflectiveOperationException { @@ -52,6 +54,11 @@ public BaseData dexkit(DexKitBridge bridge) throws ReflectiveOperationException hookMethod(method, new IMethodHook() { @Override public void before(HookParam param) { + if (RearScreenFlowGuard.isRearScreenActivityActive( + ContextUtils.getContextNoError(ContextUtils.FLAG_CURRENT_APP) + )) { + return; + } param.setResult(DrmManager.DrmResult.DRM_SUCCESS); } }); diff --git a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java new file mode 100644 index 0000000000..e0209e50ee --- /dev/null +++ b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java @@ -0,0 +1,137 @@ +/* + * This file is part of HyperCeiler. + * + * HyperCeiler is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Copyright (C) 2023-2026 HyperCeiler Contributions + */ +package com.sevtinge.hyperceiler.libhook.utils.guard; + +import android.app.Activity; +import android.app.ActivityManager; +import android.app.Application; +import android.content.ComponentName; +import android.content.Context; +import android.os.Bundle; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class RearScreenFlowGuard { + private static final String REAR_SCREEN_DETAIL_ACTIVITY = "com.rearScreen.RearScreenDetailActivity"; + private static final AtomicBoolean sLifecycleRegistered = new AtomicBoolean(false); + private static final Set sActiveActivityClassNames = + Collections.synchronizedSet(new HashSet<>()); + + private RearScreenFlowGuard() { + } + + public static void ensureActivityTrackerRegistered(Context context) { + if (context == null) { + return; + } + Context applicationContext = context.getApplicationContext(); + if (!(applicationContext instanceof Application application)) { + return; + } + refreshCurrentActivity(applicationContext); + if (!sLifecycleRegistered.compareAndSet(false, true)) { + return; + } + application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + // No-op. + } + + @Override + public void onActivityStarted(Activity activity) { + sActiveActivityClassNames.add(activity.getClass().getName()); + } + + @Override + public void onActivityResumed(Activity activity) { + sActiveActivityClassNames.add(activity.getClass().getName()); + } + + @Override + public void onActivityPaused(Activity activity) { + // No-op. + } + + @Override + public void onActivityStopped(Activity activity) { + sActiveActivityClassNames.remove(activity.getClass().getName()); + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + // No-op. + } + + @Override + public void onActivityDestroyed(Activity activity) { + sActiveActivityClassNames.remove(activity.getClass().getName()); + } + }); + } + + public static boolean isRearScreenActivityActive() { + return sActiveActivityClassNames.contains(REAR_SCREEN_DETAIL_ACTIVITY); + } + + public static boolean isRearScreenActivityActive(Context context) { + if (isRearScreenActivityActive()) { + return true; + } + if (context == null) { + return false; + } + try { + ActivityManager activityManager = context.getSystemService(ActivityManager.class); + if (activityManager == null) { + return false; + } + List runningTasks = activityManager.getRunningTasks(1); + if (runningTasks == null || runningTasks.isEmpty()) { + return false; + } + ComponentName topActivity = runningTasks.get(0).topActivity; + return topActivity != null && REAR_SCREEN_DETAIL_ACTIVITY.equals(topActivity.getClassName()); + } catch (Throwable ignored) { + return false; + } + } + + private static void refreshCurrentActivity(Context context) { + try { + ActivityManager activityManager = context.getSystemService(ActivityManager.class); + if (activityManager == null) { + return; + } + List runningTasks = activityManager.getRunningTasks(1); + if (runningTasks == null || runningTasks.isEmpty()) { + return; + } + ComponentName topActivity = runningTasks.get(0).topActivity; + if (topActivity != null) { + sActiveActivityClassNames.add(topActivity.getClassName()); + } + } catch (Throwable ignored) { + } + } +} From 2fc6f0e9d4732880ea3ab33f2a2bed274908c4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=92=E6=9F=92=E5=96=B5?= Date: Thu, 9 Apr 2026 21:50:12 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E4=B8=9C=E8=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../libhook/rules/systemframework/display/ThemeProvider.kt | 2 +- .../hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java | 2 +- .../libhook/utils/{ => hookapi}/guard/RearScreenFlowGuard.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/{ => hookapi}/guard/RearScreenFlowGuard.java (98%) diff --git a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt index 4ab9a6b65e..e9037977da 100644 --- a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt +++ b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/display/ThemeProvider.kt @@ -21,7 +21,7 @@ package com.sevtinge.hyperceiler.libhook.rules.systemframework.display import com.sevtinge.hyperceiler.common.log.XposedLog import com.sevtinge.hyperceiler.libhook.base.BaseHook import com.sevtinge.hyperceiler.libhook.utils.api.ContextUtils -import com.sevtinge.hyperceiler.libhook.utils.guard.RearScreenFlowGuard +import com.sevtinge.hyperceiler.libhook.utils.hookapi.guard.RearScreenFlowGuard import com.sevtinge.hyperceiler.libhook.utils.hookapi.tool.chainMethod import io.github.libxposed.api.XposedInterface import miui.drm.DrmManager diff --git a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java index 8c6f9cad1f..fbd7931289 100644 --- a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java +++ b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/thememanager/AllowThirdTheme.java @@ -21,8 +21,8 @@ import com.sevtinge.hyperceiler.libhook.base.BaseHook; import com.sevtinge.hyperceiler.libhook.callback.IMethodHook; import com.sevtinge.hyperceiler.libhook.utils.api.ContextUtils; -import com.sevtinge.hyperceiler.libhook.utils.guard.RearScreenFlowGuard; import com.sevtinge.hyperceiler.libhook.utils.hookapi.dexkit.IDexKit; +import com.sevtinge.hyperceiler.libhook.utils.hookapi.guard.RearScreenFlowGuard; import org.luckypray.dexkit.DexKitBridge; import org.luckypray.dexkit.query.FindMethod; diff --git a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/hookapi/guard/RearScreenFlowGuard.java similarity index 98% rename from library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java rename to library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/hookapi/guard/RearScreenFlowGuard.java index e0209e50ee..b9cdc0f9a5 100644 --- a/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/guard/RearScreenFlowGuard.java +++ b/library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/hookapi/guard/RearScreenFlowGuard.java @@ -16,7 +16,7 @@ * * Copyright (C) 2023-2026 HyperCeiler Contributions */ -package com.sevtinge.hyperceiler.libhook.utils.guard; +package com.sevtinge.hyperceiler.libhook.utils.hookapi.guard; import android.app.Activity; import android.app.ActivityManager;