Skip to content

Commit 1f539b1

Browse files
fix(YouTube): Always use single threaded layout to resolve layout bugs in unpatched YouTube (#5226)
1 parent c5e5d25 commit 1f539b1

File tree

3 files changed

+73
-7
lines changed

3 files changed

+73
-7
lines changed

extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/LithoFilterPatch.java

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,36 @@ private static void findAsciiStrings(StringBuilder builder, byte[] buffer) {
7474
}
7575
}
7676

77+
/**
78+
* Litho layout fixed thread pool size override.
79+
* <p>
80+
* Unpatched YouTube uses a layout fixed thread pool between 1 and 3 threads:
81+
* <pre>
82+
* 1 thread - > Device has less than 6 cores
83+
* 2 threads -> Device has over 6 cores and less than 6GB of memory
84+
* 3 threads -> Device has over 6 cores and more than 6GB of memory
85+
* </pre>
86+
*
87+
* Using more than 1 thread causes layout issues such as the You tab watch/playlist shelf
88+
* that is sometimes incorrectly hidden (ReVanced is not hiding it), and seems to
89+
* fix a race issue if using the active navigation tab status with litho filtering.
90+
*/
91+
private static final int LITHO_LAYOUT_THREAD_POOL_SIZE = 1;
92+
93+
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
94+
95+
/**
96+
* Placeholder for actual filters.
97+
*/
98+
private static final class DummyFilter extends Filter { }
99+
77100
private static final Filter[] filters = new Filter[] {
78101
new DummyFilter() // Replaced by patch.
79102
};
80103

81104
private static final StringTrieSearch pathSearchTree = new StringTrieSearch();
82105
private static final StringTrieSearch identifierSearchTree = new StringTrieSearch();
83106

84-
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
85-
86107
/**
87108
* Because litho filtering is multi-threaded and the buffer is passed in from a different injection point,
88109
* the buffer is saved to a ThreadLocal so each calling thread does not interfere with other threads.
@@ -213,9 +234,28 @@ private static boolean handleFiltering(@Nullable String lithoIdentifier, StringB
213234

214235
return false;
215236
}
216-
}
217237

218-
/**
219-
* Placeholder for actual filters.
220-
*/
221-
final class DummyFilter extends Filter { }
238+
/**
239+
* Injection point.
240+
*/
241+
public static int getExecutorCorePoolSize(int originalCorePoolSize) {
242+
if (originalCorePoolSize != LITHO_LAYOUT_THREAD_POOL_SIZE) {
243+
Logger.printDebug(() -> "Overriding core thread pool size from: " + originalCorePoolSize
244+
+ " to: " + LITHO_LAYOUT_THREAD_POOL_SIZE);
245+
}
246+
247+
return LITHO_LAYOUT_THREAD_POOL_SIZE;
248+
}
249+
250+
/**
251+
* Injection point.
252+
*/
253+
public static int getExecutorMaxThreads(int originalMaxThreads) {
254+
if (originalMaxThreads != LITHO_LAYOUT_THREAD_POOL_SIZE) {
255+
Logger.printDebug(() -> "Overriding max thread pool size from: " + originalMaxThreads
256+
+ " to: " + LITHO_LAYOUT_THREAD_POOL_SIZE);
257+
}
258+
259+
return LITHO_LAYOUT_THREAD_POOL_SIZE;
260+
}
261+
}

patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/Fingerprints.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package app.revanced.patches.youtube.misc.litho.filter
22

33
import app.revanced.patcher.fingerprint
4+
import app.revanced.util.containsLiteralInstruction
45
import app.revanced.util.literal
56
import com.android.tools.smali.dexlib2.AccessFlags
67
import com.android.tools.smali.dexlib2.Opcode
@@ -52,6 +53,15 @@ internal val emptyComponentFingerprint = fingerprint {
5253
}
5354
}
5455

56+
internal val lithoThreadExecutorFingerprint = fingerprint {
57+
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
58+
parameters("I", "I", "I")
59+
custom { method, classDef ->
60+
classDef.superclass == "Ljava/util/concurrent/ThreadPoolExecutor;" &&
61+
method.containsLiteralInstruction(1L) // 1L = default thread timeout.
62+
}
63+
}
64+
5565
internal val lithoComponentNameUpbFeatureFlagFingerprint = fingerprint {
5666
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
5767
returns("Z")

patches/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,22 @@ val lithoFilterPatch = bytecodePatch(
209209

210210
// endregion
211211

212+
213+
// region Change Litho thread executor to 1 thread to fix layout issue in unpatched YouTube.
214+
215+
lithoThreadExecutorFingerprint.method.addInstructions(
216+
0,
217+
"""
218+
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getExecutorCorePoolSize(I)I
219+
move-result p1
220+
invoke-static { p2 }, $EXTENSION_CLASS_DESCRIPTOR->getExecutorMaxThreads(I)I
221+
move-result p2
222+
"""
223+
)
224+
225+
// endregion
226+
227+
212228
// region A/B test of new Litho native code.
213229

214230
// Turn off native code that handles litho component names. If this feature is on then nearly

0 commit comments

Comments
 (0)