Implement BackgroundExecutor for layouts

Summary:
As a followup to D22743723 (https://github.com/facebook/react-native/commit/d53fc8a3cd44c7ec7e6eade985daf3d4feb2d736) on the iOS side, I implement a BackgroundExecutor that can be used from C++ to schedule layouts on their own thread, off the JS and UI thread.

This is a potential perf improvement that we will experiment with.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D22826795

fbshipit-source-id: 899bd67fe1b86f52910951e9536b59a1414a304c
This commit is contained in:
Joshua Gross
2020-07-29 15:38:31 -07:00
committed by Facebook GitHub Bot
parent a1ed73dd64
commit 949dedca9f
5 changed files with 123 additions and 0 deletions
@@ -0,0 +1,46 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
import com.facebook.proguard.annotations.DoNotStrip;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@DoNotStrip
public class BackgroundExecutor {
private static final String TAG = "FabricBackgroundExecutor";
private final ExecutorService mExecutorService;
@DoNotStrip
private BackgroundExecutor() {
mExecutorService = Executors.newFixedThreadPool(1);
}
@DoNotStrip
private void queueRunnable(Runnable runnable) {
// Very rarely, an NPE is hit here - probably has to do with deallocation
// race conditions and the JNI.
// It's not clear yet which of these is most prevalent, or if either is a concern.
// If we don't find these logs in production then we can probably safely remove the logging,
// but it's also cheap to leave it here.
if (runnable == null) {
ReactSoftException.logSoftException(TAG, new ReactNoCrashSoftException("runnable is null"));
return;
}
final ExecutorService executorService = mExecutorService;
if (executorService == null) {
ReactSoftException.logSoftException(
TAG, new ReactNoCrashSoftException("executorService is null"));
return;
}
executorService.execute(runnable);
}
}
@@ -278,6 +278,12 @@ void Binding::installFabricUIManager(
toolbox.synchronousEventBeatFactory = synchronousBeatFactory;
toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory;
if (reactNativeConfig_->getBool(
"react_fabric:enable_background_executor_android")) {
backgroundExecutor_ = std::make_unique<JBackgroundExecutor>();
toolbox.backgroundExecutor = backgroundExecutor_->get();
}
if (enableLayoutAnimations) {
animationDriver_ = std::make_shared<LayoutAnimationDriver>(this);
}
@@ -19,6 +19,7 @@
#include <mutex>
#include "ComponentFactoryDelegate.h"
#include "EventBeatManager.h"
#include "JBackgroundExecutor.h"
namespace facebook {
namespace react {
@@ -115,6 +116,7 @@ class Binding : public jni::HybridClass<Binding>,
virtual void onAllAnimationsComplete() override;
LayoutAnimationDriver *getAnimationDriver();
std::shared_ptr<LayoutAnimationDriver> animationDriver_;
std::unique_ptr<JBackgroundExecutor> backgroundExecutor_;
std::shared_ptr<Scheduler> scheduler_;
std::mutex schedulerMutex_;
@@ -0,0 +1,35 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fbjni/fbjni.h>
#include <react/jni/JNativeRunnable.h>
#include "JBackgroundExecutor.h"
namespace facebook {
namespace react {
using namespace facebook::jni;
using facebook::react::JNativeRunnable;
using facebook::react::Runnable;
BackgroundExecutor JBackgroundExecutor::get() {
auto self = JBackgroundExecutor::create();
return [self](std::function<void()> &&runnable) {
static auto method =
findClassStatic(JBackgroundExecutor::JBackgroundExecutorJavaDescriptor)
->getMethod<void(Runnable::javaobject)>("queueRunnable");
auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable));
method(self, static_ref_cast<Runnable>(jrunnable).get());
};
}
} // namespace react
} // namespace facebook
@@ -0,0 +1,34 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <fbjni/fbjni.h>
#include <react/uimanager/primitives.h>
namespace facebook {
namespace react {
using namespace facebook::jni;
class JBackgroundExecutor : public JavaClass<JBackgroundExecutor> {
public:
static auto constexpr kJavaDescriptor =
"Lcom/facebook/react/bridge/BackgroundExecutor;";
constexpr static auto JBackgroundExecutorJavaDescriptor =
"com/facebook/react/bridge/BackgroundExecutor";
static global_ref<javaobject> create() {
return make_global(newInstance());
}
BackgroundExecutor get();
};
} // namespace react
} // namespace facebook