Skip to content

Commit e19225a

Browse files
cjhopmanFacebook Github Bot 9
authored andcommitted
assert that ShadowNodeRegistry is only accessed from one thread
Reviewed By: astreet Differential Revision: D3461859 fbshipit-source-id: 790e831d2ca239110e00a5723be40e870ceab020
1 parent c1f7aa3 commit e19225a

File tree

4 files changed

+45
-3
lines changed

4 files changed

+45
-3
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
package com.facebook.react.common;
11+
12+
import javax.annotation.Nullable;
13+
14+
import com.facebook.infer.annotation.Assertions;
15+
16+
/**
17+
* Simple class for asserting that operations only run on a single thread.
18+
*/
19+
public class SingleThreadAsserter {
20+
private @Nullable Thread mThread = null;
21+
22+
public void assertNow() {
23+
Thread current = Thread.currentThread();
24+
if (mThread == null) {
25+
mThread = current;
26+
}
27+
Assertions.assertCondition(mThread == current);
28+
}
29+
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/ShadowNodeRegistry.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import android.util.SparseArray;
1313
import android.util.SparseBooleanArray;
1414

15+
import com.facebook.react.common.SingleThreadAsserter;
16+
1517
/**
1618
* Simple container class to keep track of {@link ReactShadowNode}s associated with a particular
1719
* UIManagerModule instance.
@@ -20,19 +22,25 @@
2022

2123
private final SparseArray<ReactShadowNode> mTagsToCSSNodes;
2224
private final SparseBooleanArray mRootTags;
25+
private final SingleThreadAsserter mThreadAsserter;
2326

2427
public ShadowNodeRegistry() {
2528
mTagsToCSSNodes = new SparseArray<>();
2629
mRootTags = new SparseBooleanArray();
30+
mThreadAsserter = new SingleThreadAsserter();
2731
}
2832

2933
public void addRootNode(ReactShadowNode node) {
34+
// TODO(6242243): This should be asserted... but UIManagerModule is
35+
// thread-unsafe and calls this on the wrong thread.
36+
//mThreadAsserter.assertNow();
3037
int tag = node.getReactTag();
3138
mTagsToCSSNodes.put(tag, node);
3239
mRootTags.put(tag, true);
3340
}
3441

3542
public void removeRootNode(int tag) {
43+
mThreadAsserter.assertNow();
3644
if (!mRootTags.get(tag)) {
3745
throw new IllegalViewOperationException(
3846
"View with tag " + tag + " is not registered as a root view");
@@ -43,10 +51,12 @@ public void removeRootNode(int tag) {
4351
}
4452

4553
public void addNode(ReactShadowNode node) {
54+
mThreadAsserter.assertNow();
4655
mTagsToCSSNodes.put(node.getReactTag(), node);
4756
}
4857

4958
public void removeNode(int tag) {
59+
mThreadAsserter.assertNow();
5060
if (mRootTags.get(tag)) {
5161
throw new IllegalViewOperationException(
5262
"Trying to remove root node " + tag + " without using removeRootNode!");
@@ -55,18 +65,22 @@ public void removeNode(int tag) {
5565
}
5666

5767
public ReactShadowNode getNode(int tag) {
68+
mThreadAsserter.assertNow();
5869
return mTagsToCSSNodes.get(tag);
5970
}
6071

6172
public boolean isRootNode(int tag) {
73+
mThreadAsserter.assertNow();
6274
return mRootTags.get(tag);
6375
}
6476

6577
public int getRootNodeCount() {
78+
mThreadAsserter.assertNow();
6679
return mRootTags.size();
6780
}
6881

6982
public int getRootTag(int index) {
83+
mThreadAsserter.assertNow();
7084
return mRootTags.keyAt(index);
7185
}
7286
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public void registerRootView(
9999
rootCSSNode.setThemedContext(context);
100100
rootCSSNode.setStyleWidth(width);
101101
rootCSSNode.setStyleHeight(height);
102+
102103
mShadowNodeRegistry.addRootNode(rootCSSNode);
103104

104105
// register it within NativeViewHierarchyManager

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,7 @@ private static Map<String, Object> createConstants(List<ViewManager> viewManager
141141
* CatalystApplicationFragment as an example.
142142
*
143143
* TODO(6242243): Make addMeasuredRootView thread safe
144-
* NB: this method is horribly not-thread-safe, the only reason it works right now is because
145-
* it's called exactly once and is called before any JS calls are made. As soon as that fact no
146-
* longer holds, this method will need to be fixed.
144+
* NB: this method is horribly not-thread-safe.
147145
*/
148146
public int addMeasuredRootView(final SizeMonitoringFrameLayout rootView) {
149147
final int tag = mNextRootViewTag;

0 commit comments

Comments
 (0)