diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java index ac88185cf..552304724 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java @@ -74,6 +74,29 @@ public final class LithoFilterPatch { } } + /** + * Litho layout fixed thread pool size override. + *
+ * Unpatched YouTube uses a layout fixed thread pool between 1 and 3 threads: + *
+ * 1 thread - > Device has less than 6 cores + * 2 threads -> Device has over 6 cores and less than 6GB of memory + * 3 threads -> Device has over 6 cores and more than 6GB of memory + *+ * + * Using more than 1 thread causes layout issues such as the You tab watch/playlist shelf + * that is sometimes incorrectly hidden (ReVanced is not hiding it), and seems to + * fix a race issue if using the active navigation tab status with litho filtering. + */ + private static final int LITHO_LAYOUT_THREAD_POOL_SIZE = 1; + + private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + + /** + * Placeholder for actual filters. + */ + private static final class DummyFilter extends Filter { } + private static final Filter[] filters = new Filter[] { new DummyFilter() // Replaced by patch. }; @@ -81,8 +104,6 @@ public final class LithoFilterPatch { private static final StringTrieSearch pathSearchTree = new StringTrieSearch(); private static final StringTrieSearch identifierSearchTree = new StringTrieSearch(); - private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - /** * Because litho filtering is multi-threaded and the buffer is passed in from a different injection point, * the buffer is saved to a ThreadLocal so each calling thread does not interfere with other threads. @@ -213,9 +234,28 @@ public final class LithoFilterPatch { return false; } -} -/** - * Placeholder for actual filters. - */ -final class DummyFilter extends Filter { } \ No newline at end of file + /** + * Injection point. + */ + public static int getExecutorCorePoolSize(int originalCorePoolSize) { + if (originalCorePoolSize != LITHO_LAYOUT_THREAD_POOL_SIZE) { + Logger.printDebug(() -> "Overriding core thread pool size from: " + originalCorePoolSize + + " to: " + LITHO_LAYOUT_THREAD_POOL_SIZE); + } + + return LITHO_LAYOUT_THREAD_POOL_SIZE; + } + + /** + * Injection point. + */ + public static int getExecutorMaxThreads(int originalMaxThreads) { + if (originalMaxThreads != LITHO_LAYOUT_THREAD_POOL_SIZE) { + Logger.printDebug(() -> "Overriding max thread pool size from: " + originalMaxThreads + + " to: " + LITHO_LAYOUT_THREAD_POOL_SIZE); + } + + return LITHO_LAYOUT_THREAD_POOL_SIZE; + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt index d14955e9c..8ef0161d1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt @@ -1,6 +1,7 @@ package app.revanced.patches.youtube.misc.litho.filter import app.revanced.patcher.fingerprint +import app.revanced.util.containsLiteralInstruction import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -52,6 +53,15 @@ internal val emptyComponentFingerprint = fingerprint { } } +internal val lithoThreadExecutorFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + parameters("I", "I", "I") + custom { method, classDef -> + classDef.superclass == "Ljava/util/concurrent/ThreadPoolExecutor;" && + method.containsLiteralInstruction(1L) // 1L = default thread timeout. + } +} + internal val lithoComponentNameUpbFeatureFlagFingerprint = fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returns("Z") diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt index f8b8d05d8..bc17028f2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt @@ -209,6 +209,22 @@ val lithoFilterPatch = bytecodePatch( // endregion + + // region Change Litho thread executor to 1 thread to fix layout issue in unpatched YouTube. + + lithoThreadExecutorFingerprint.method.addInstructions( + 0, + """ + invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getExecutorCorePoolSize(I)I + move-result p1 + invoke-static { p2 }, $EXTENSION_CLASS_DESCRIPTOR->getExecutorMaxThreads(I)I + move-result p2 + """ + ) + + // endregion + + // region A/B test of new Litho native code. // Turn off native code that handles litho component names. If this feature is on then nearly