Skip to content

Commit

Permalink
Try to work around
Browse files Browse the repository at this point in the history
  • Loading branch information
TWiStErRob committed Aug 9, 2023
1 parent 1c4b54c commit 0256771
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package net.twisterrob.inventory.android;

import android.os.Bundle;

import net.twisterrob.android.test.junit.AndroidJUnitRunner;
import net.twisterrob.inventory.android.hacks.ViewCompatHacks;

public class InventoryJUnitRunner extends AndroidJUnitRunner {
// Empty for now, useful for quick debugging.
@Override public void onCreate(Bundle arguments) {
super.onCreate(arguments);
ViewCompatHacks.patchFor293190504();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package net.twisterrob.inventory.android.hacks

import java.util.LinkedList
import java.util.WeakHashMap
import kotlin.collections.MutableMap.MutableEntry

private typealias Change<K, V> = DeferredWeakHashMapFor293190504<K, V>.() -> Unit

/**
* See https://issuetracker.google.com/issues/293190504
*
* This is a workaround for not allowing concurrent modifications
* to [androidx.core.view.ViewCompat.AccessibilityPaneVisibilityManager]'s internal state.
*
* Any structure-modifying changes made to the map while iterating
* is deferred until the iteration is over.
*
* This prevents the nested `put` call in `checkPaneVisibility`
* from cleaning up the weak queue mid-iteration.
*/
internal class DeferredWeakHashMapFor293190504<K, V> : WeakHashMap<K, V>() {
@Volatile
private var locked = false
private val changes: MutableList<Change<K, V>> = LinkedList()

override fun put(key: K, value: V): V? {
return if (!locked) {
super.put(key, value)
} else {
changes.add { put(key, value) }
// Should be super.get(key), but reads also mutate the map because it's weak.
null
}
}

override fun remove(key: K?): V? {
return if (!locked) {
super.remove(key)
} else {
changes.add { remove(key) }
// Should be super.get(key), but reads also mutate the map because it's weak.
null
}
}

override val entries: MutableSet<MutableEntry<K, V>>
get() = DeferringEntrySet(super.entries)

private inner class DeferringEntrySet(
private val backingSet: MutableSet<MutableEntry<K, V>>
) : MutableSet<MutableEntry<K, V>> by backingSet {

override fun iterator(): MutableIterator<MutableEntry<K, V>> {
check(!locked) { "Already iterating, only one supported." }
locked = true
val iterator = backingSet.iterator()
return object : MutableIterator<MutableEntry<K, V>> by iterator {
override fun hasNext(): Boolean {
val hasNext = iterator.hasNext()
// Assuming a for(:) loop will not do anything after this.
if (!hasNext) {
locked = false
changes.forEach { it(this@DeferredWeakHashMapFor293190504) }
}
return hasNext
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.twisterrob.inventory.android.hacks;

import java.lang.reflect.Field;

public class ViewCompatHacks {
/**
* Replace the {@link java.util.WeakHashMap} in {@link androidx.core.view.ViewCompat} with a
* {@link DeferredWeakHashMapFor293190504} to prevent concurrent modification.
*
* @see <a href="https://issuetracker.google.com/issues/293190504">Issue</a>
* @see <a href="https://github.com/TWiStErRob/net.twisterrob.inventory/issues/302">Issue</a>
*/
public static void patchFor293190504() {
try {
Field sAccessibilityPaneVisibilityManager = Class
.forName("androidx.core.view.ViewCompat")
.getDeclaredField("sAccessibilityPaneVisibilityManager");
sAccessibilityPaneVisibilityManager.setAccessible(true);
Field mPanesToVisible = Class
.forName("androidx.core.view.ViewCompat$AccessibilityPaneVisibilityManager")
.getDeclaredField("mPanesToVisible");
mPanesToVisible.setAccessible(true);

Object target = sAccessibilityPaneVisibilityManager.get(null);
mPanesToVisible.set(target, new DeferredWeakHashMapFor293190504<>());
} catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
}

0 comments on commit 0256771

Please sign in to comment.