give us the ability to create a background UI thread

Reviewed By: javache

Differential Revision: D4928689

fbshipit-source-id: 94fa5f3f7c047ad816c7699dcc8bebf9e751b282
This commit is contained in:
Aaron Chiu 2017-04-21 05:25:20 -07:00 committed by Facebook Github Bot
parent b4932082c7
commit 6138e20379
9 changed files with 120 additions and 27 deletions

View File

@ -47,6 +47,7 @@ public class ReactContext extends ContextWrapper {
private @Nullable CatalystInstance mCatalystInstance;
private @Nullable LayoutInflater mInflater;
private @Nullable MessageQueueThread mUiMessageQueueThread;
private @Nullable MessageQueueThread mUiBackgroundMessageQueueThread;
private @Nullable MessageQueueThread mNativeModulesMessageQueueThread;
private @Nullable MessageQueueThread mJSMessageQueueThread;
private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
@ -71,6 +72,7 @@ public class ReactContext extends ContextWrapper {
ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
mUiMessageQueueThread = queueConfig.getUIQueueThread();
mUiBackgroundMessageQueueThread = queueConfig.getUIBackgroundQueueThread();
mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();
mJSMessageQueueThread = queueConfig.getJSQueueThread();
}
@ -279,6 +281,14 @@ public class ReactContext extends ContextWrapper {
Assertions.assertNotNull(mUiMessageQueueThread).runOnQueue(runnable);
}
public void assertOnUiBackgroundQueueThread() {
Assertions.assertNotNull(mUiBackgroundMessageQueueThread).assertIsOnThread();
}
public void runOnUiBackgroundQueueThread(Runnable runnable) {
Assertions.assertNotNull(mUiBackgroundMessageQueueThread).runOnQueue(runnable);
}
public void assertOnNativeModulesQueueThread() {
Assertions.assertNotNull(mNativeModulesMessageQueueThread).assertIsOnThread();
}
@ -307,6 +317,14 @@ public class ReactContext extends ContextWrapper {
Assertions.assertNotNull(mJSMessageQueueThread).runOnQueue(runnable);
}
public void runUIBackgroundRunnable(Runnable runnable) {
if (mUiBackgroundMessageQueueThread == null) {
runOnNativeModulesQueueThread(runnable);
} else {
runOnUiBackgroundQueueThread(runnable);
}
}
/**
* Passes the given exception to the current
* {@link com.facebook.react.bridge.NativeModuleCallExceptionHandler} if one exists, rethrowing

View File

@ -61,7 +61,6 @@ public class MessageQueueThreadImpl implements MessageQueueThread {
mHandler.post(runnable);
}
@DoNotStrip
@Override
public <T> Future<T> callOnQueue(final Callable<T> callable) {
@ -143,6 +142,8 @@ public class MessageQueueThreadImpl implements MessageQueueThread {
switch (spec.getThreadType()) {
case MAIN_UI:
return createForMainThread(spec.getName(), exceptionHandler);
case BACKGROUND_UI:
return startUIBackgroundThread(spec.getName(), spec.getStackSize(), exceptionHandler);
case NEW_BACKGROUND:
return startNewBackgroundThread(spec.getName(), spec.getStackSize(), exceptionHandler);
default:
@ -176,13 +177,27 @@ public class MessageQueueThreadImpl implements MessageQueueThread {
return mqt;
}
public static MessageQueueThreadImpl startUIBackgroundThread(
final String name,
long stackSize,
QueueThreadExceptionHandler exceptionHandler) {
return startNewBackgroundThread(name, stackSize, exceptionHandler, true);
}
public static MessageQueueThreadImpl startNewBackgroundThread(
final String name,
QueueThreadExceptionHandler exceptionHandler) {
final String name,
QueueThreadExceptionHandler exceptionHandler) {
return startNewBackgroundThread(
name,
MessageQueueThreadSpec.DEFAULT_STACK_SIZE_BYTES,
exceptionHandler);
name,
MessageQueueThreadSpec.DEFAULT_STACK_SIZE_BYTES,
exceptionHandler);
}
public static MessageQueueThreadImpl startNewBackgroundThread(
final String name,
long stackSize,
QueueThreadExceptionHandler exceptionHandler) {
return startNewBackgroundThread(name, stackSize, exceptionHandler, false);
}
/**
@ -190,17 +205,20 @@ public class MessageQueueThreadImpl implements MessageQueueThread {
* running on it. Give it a name for easier debugging and optionally a suggested stack size.
* When this method exits, the new MessageQueueThreadImpl is ready to receive events.
*/
public static MessageQueueThreadImpl startNewBackgroundThread(
final String name,
long stackSize,
QueueThreadExceptionHandler exceptionHandler) {
private static MessageQueueThreadImpl startNewBackgroundThread(
final String name,
long stackSize,
QueueThreadExceptionHandler exceptionHandler,
final boolean forUIManagerModule) {
final SimpleSettableFuture<Looper> looperFuture = new SimpleSettableFuture<>();
final SimpleSettableFuture<MessageQueueThread> mqtFuture = new SimpleSettableFuture<>();
Thread bgThread = new Thread(null,
new Runnable() {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
Process.setThreadPriority(forUIManagerModule ?
Process.THREAD_PRIORITY_DEFAULT + Process.THREAD_PRIORITY_MORE_FAVORABLE :
Process.THREAD_PRIORITY_DEFAULT);
Looper.prepare();
looperFuture.set(Looper.myLooper());

View File

@ -22,9 +22,14 @@ public class MessageQueueThreadSpec {
protected static enum ThreadType {
MAIN_UI,
BACKGROUND_UI,
NEW_BACKGROUND,
}
public static MessageQueueThreadSpec newUIBackgroundTreadSpec(String name) {
return new MessageQueueThreadSpec(ThreadType.BACKGROUND_UI, name);
}
public static MessageQueueThreadSpec newBackgroundThreadSpec(String name) {
return new MessageQueueThreadSpec(ThreadType.NEW_BACKGROUND, name);
}

View File

@ -9,6 +9,8 @@
package com.facebook.react.bridge.queue;
import javax.annotation.Nullable;
/**
* Specifies which {@link MessageQueueThread}s must be used to run the various contexts of
* execution within catalyst (Main UI thread, native modules, and JS). Some of these queues *may* be
@ -20,6 +22,8 @@ package com.facebook.react.bridge.queue;
*/
public interface ReactQueueConfiguration {
MessageQueueThread getUIQueueThread();
@Nullable
MessageQueueThread getUIBackgroundQueueThread();
MessageQueueThread getNativeModulesQueueThread();
MessageQueueThread getJSQueueThread();
}

View File

@ -9,6 +9,8 @@
package com.facebook.react.bridge.queue;
import javax.annotation.Nullable;
import java.util.Map;
import android.os.Looper;
@ -18,14 +20,17 @@ import com.facebook.react.common.MapBuilder;
public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
private final MessageQueueThreadImpl mUIQueueThread;
private final @Nullable MessageQueueThreadImpl mUIBackgroundQueueThread;
private final MessageQueueThreadImpl mNativeModulesQueueThread;
private final MessageQueueThreadImpl mJSQueueThread;
private ReactQueueConfigurationImpl(
MessageQueueThreadImpl uiQueueThread,
MessageQueueThreadImpl nativeModulesQueueThread,
MessageQueueThreadImpl jsQueueThread) {
MessageQueueThreadImpl uiQueueThread,
@Nullable MessageQueueThreadImpl uiBackgroundQueueThread,
MessageQueueThreadImpl nativeModulesQueueThread,
MessageQueueThreadImpl jsQueueThread) {
mUIQueueThread = uiQueueThread;
mUIBackgroundQueueThread = uiBackgroundQueueThread;
mNativeModulesQueueThread = nativeModulesQueueThread;
mJSQueueThread = jsQueueThread;
}
@ -35,6 +40,11 @@ public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
return mUIQueueThread;
}
@Override
public @Nullable MessageQueueThread getUIBackgroundQueueThread() {
return mUIBackgroundQueueThread;
}
@Override
public MessageQueueThread getNativeModulesQueueThread() {
return mNativeModulesQueueThread;
@ -65,7 +75,7 @@ public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec();
MessageQueueThreadImpl uiThread =
MessageQueueThreadImpl.create( uiThreadSpec, exceptionHandler);
MessageQueueThreadImpl.create(uiThreadSpec, exceptionHandler);
specsToThreads.put(uiThreadSpec, uiThread);
MessageQueueThreadImpl jsThread = specsToThreads.get(spec.getJSQueueThreadSpec());
@ -80,6 +90,17 @@ public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
MessageQueueThreadImpl.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
}
return new ReactQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread);
MessageQueueThreadImpl uiBackgroundThread =
specsToThreads.get(spec.getUIBackgroundQueueThreadSpec());
if (uiBackgroundThread == null && spec.getUIBackgroundQueueThreadSpec() != null) {
uiBackgroundThread =
MessageQueueThreadImpl.create(spec.getUIBackgroundQueueThreadSpec(), exceptionHandler);
}
return new ReactQueueConfigurationImpl(
uiThread,
uiBackgroundThread,
nativeModulesThread,
jsThread);
}
}

View File

@ -25,16 +25,23 @@ public class ReactQueueConfigurationSpec {
private static final long LEGACY_STACK_SIZE_BYTES = 2000000;
private final @Nullable MessageQueueThreadSpec mUIBackgroundQueueThreadSpec;
private final MessageQueueThreadSpec mNativeModulesQueueThreadSpec;
private final MessageQueueThreadSpec mJSQueueThreadSpec;
private ReactQueueConfigurationSpec(
MessageQueueThreadSpec nativeModulesQueueThreadSpec,
MessageQueueThreadSpec jsQueueThreadSpec) {
@Nullable MessageQueueThreadSpec uiBackgroundQueueThreadSpec,
MessageQueueThreadSpec nativeModulesQueueThreadSpec,
MessageQueueThreadSpec jsQueueThreadSpec) {
mUIBackgroundQueueThreadSpec = uiBackgroundQueueThreadSpec;
mNativeModulesQueueThreadSpec = nativeModulesQueueThreadSpec;
mJSQueueThreadSpec = jsQueueThreadSpec;
}
public @Nullable MessageQueueThreadSpec getUIBackgroundQueueThreadSpec() {
return mUIBackgroundQueueThreadSpec;
}
public MessageQueueThreadSpec getNativeModulesQueueThreadSpec() {
return mNativeModulesQueueThreadSpec;
}
@ -57,15 +64,36 @@ public class ReactQueueConfigurationSpec {
.build();
}
public static ReactQueueConfigurationSpec createWithSeparateUIBackgroundThread() {
MessageQueueThreadSpec spec = Build.VERSION.SDK_INT < 21 ?
MessageQueueThreadSpec.newBackgroundThreadSpec("native_modules", LEGACY_STACK_SIZE_BYTES) :
MessageQueueThreadSpec.newBackgroundThreadSpec("native_modules");
return builder()
.setJSQueueThreadSpec(MessageQueueThreadSpec.newBackgroundThreadSpec("js"))
.setNativeModulesQueueThreadSpec(spec)
.setUIBackgroundQueueThreadSpec(
MessageQueueThreadSpec.newUIBackgroundTreadSpec("ui_background"))
.build();
}
public static class Builder {
private @Nullable MessageQueueThreadSpec mUIBackgroundQueueSpec;
private @Nullable MessageQueueThreadSpec mNativeModulesQueueSpec;
private @Nullable MessageQueueThreadSpec mJSQueueSpec;
public Builder setUIBackgroundQueueThreadSpec(MessageQueueThreadSpec spec) {
Assertions.assertCondition(
mUIBackgroundQueueSpec == null,
"Setting UI background queue multiple times!");
mUIBackgroundQueueSpec = spec;
return this;
}
public Builder setNativeModulesQueueThreadSpec(MessageQueueThreadSpec spec) {
Assertions.assertCondition(
mNativeModulesQueueSpec == null,
"Setting native modules queue spec multiple times!");
mNativeModulesQueueSpec == null,
"Setting native modules queue spec multiple times!");
mNativeModulesQueueSpec = spec;
return this;
}
@ -78,8 +106,9 @@ public class ReactQueueConfigurationSpec {
public ReactQueueConfigurationSpec build() {
return new ReactQueueConfigurationSpec(
Assertions.assertNotNull(mNativeModulesQueueSpec),
Assertions.assertNotNull(mJSQueueSpec));
mUIBackgroundQueueSpec,
Assertions.assertNotNull(mNativeModulesQueueSpec),
Assertions.assertNotNull(mJSQueueSpec));
}
}
}

View File

@ -15,8 +15,8 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.Set;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.BaseJavaModule;

View File

@ -31,10 +31,8 @@ import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
@ -212,7 +210,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
new SizeMonitoringFrameLayout.OnSizeChangedListener() {
@Override
public void onSizeChanged(final int width, final int height, int oldW, int oldH) {
reactApplicationContext.runOnNativeModulesQueueThread(
reactApplicationContext.runUIBackgroundRunnable(
new GuardedRunnable(reactApplicationContext) {
@Override
public void runGuarded() {

View File

@ -306,7 +306,7 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe
if (getChildCount() > 0) {
final int viewTag = getChildAt(0).getId();
ReactContext reactContext = (ReactContext) getContext();
reactContext.runOnNativeModulesQueueThread(
reactContext.runUIBackgroundRunnable(
new GuardedRunnable(reactContext) {
@Override
public void runGuarded() {