Added method handler for Sampling Profiler that uses only JSCcontext and JSC API
Reviewed By: cwdick Differential Revision: D4689688 fbshipit-source-id: d1f9df0b3dcb21420cf813888c19f2d9a9aa5646
This commit is contained in:
parent
cb3b744d08
commit
9468c5a733
|
@ -108,8 +108,8 @@ public class DevServerHelper {
|
||||||
|
|
||||||
public interface PackagerCommandListener {
|
public interface PackagerCommandListener {
|
||||||
void onPackagerReloadCommand();
|
void onPackagerReloadCommand();
|
||||||
void onCaptureHeapCommand(@Nullable final Responder responder);
|
void onCaptureHeapCommand(final Responder responder);
|
||||||
void onPokeSamplingProfilerCommand(@Nullable final Responder responder);
|
void onPokeSamplingProfilerCommand(final Responder responder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface SymbolicationListener {
|
public interface SymbolicationListener {
|
||||||
|
|
|
@ -45,6 +45,7 @@ import com.facebook.react.devsupport.interfaces.StackFrame;
|
||||||
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
||||||
import com.facebook.react.packagerconnection.JSPackagerClient;
|
import com.facebook.react.packagerconnection.JSPackagerClient;
|
||||||
import com.facebook.react.packagerconnection.Responder;
|
import com.facebook.react.packagerconnection.Responder;
|
||||||
|
import com.facebook.react.packagerconnection.SamplingProfilerPackagerMethod;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -433,7 +434,7 @@ public class DevSupportManagerImpl implements
|
||||||
new DevOptionHandler() {
|
new DevOptionHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onOptionSelected() {
|
public void onOptionSelected() {
|
||||||
handlePokeSamplingProfiler(null);
|
handlePokeSamplingProfiler();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
options.put(
|
options.put(
|
||||||
|
@ -690,11 +691,17 @@ public class DevSupportManagerImpl implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPokeSamplingProfilerCommand(@Nullable final Responder responder) {
|
public void onPokeSamplingProfilerCommand(final Responder responder) {
|
||||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
handlePokeSamplingProfiler(responder);
|
if (mCurrentContext == null) {
|
||||||
|
responder.error("JSCContext is missing, unable to profile");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SamplingProfilerPackagerMethod method =
|
||||||
|
new SamplingProfilerPackagerMethod(mCurrentContext.getJavaScriptContext());
|
||||||
|
method.onRequest(null, responder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -719,7 +726,7 @@ public class DevSupportManagerImpl implements
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePokeSamplingProfiler(@Nullable final Responder responder) {
|
private void handlePokeSamplingProfiler() {
|
||||||
try {
|
try {
|
||||||
List<String> pokeResults = JSCSamplingProfiler.poke(60000);
|
List<String> pokeResults = JSCSamplingProfiler.poke(60000);
|
||||||
for (String result : pokeResults) {
|
for (String result : pokeResults) {
|
||||||
|
@ -729,16 +736,9 @@ public class DevSupportManagerImpl implements
|
||||||
? "Started JSC Sampling Profiler"
|
? "Started JSC Sampling Profiler"
|
||||||
: "Stopped JSC Sampling Profiler",
|
: "Stopped JSC Sampling Profiler",
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
if (responder != null) {
|
new JscProfileTask(getSourceUrl()).executeOnExecutor(
|
||||||
// Responder is provided, so there is a client waiting our response
|
AsyncTask.THREAD_POOL_EXECUTOR,
|
||||||
responder.respond(result == null ? "started" : result);
|
result);
|
||||||
} else if (result != null) {
|
|
||||||
// The profile was not initiated by external client, so process the
|
|
||||||
// profile if there is one in the result
|
|
||||||
new JscProfileTask(getSourceUrl()).executeOnExecutor(
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR,
|
|
||||||
result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (JSCSamplingProfiler.ProfilerException e) {
|
} catch (JSCSamplingProfiler.ProfilerException e) {
|
||||||
showNewJavaError(e.getMessage(), e);
|
showNewJavaError(e.getMessage(), e);
|
||||||
|
|
|
@ -7,12 +7,16 @@ android_library(
|
||||||
"PUBLIC",
|
"PUBLIC",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
|
react_native_dep("java/com/facebook/jni:jni"),
|
||||||
|
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
|
||||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||||
|
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
|
||||||
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
||||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||||
react_native_dep("third-party/java/okhttp:okhttp3"),
|
react_native_dep("third-party/java/okhttp:okhttp3"),
|
||||||
react_native_dep("third-party/java/okhttp:okhttp3-ws"),
|
react_native_dep("third-party/java/okhttp:okhttp3-ws"),
|
||||||
react_native_dep("third-party/java/okio:okio"),
|
react_native_dep("third-party/java/okio:okio"),
|
||||||
react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo-moduleless"),
|
react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo-moduleless"),
|
||||||
|
react_native_target("jni/packagerconnection:jni"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.facebook.react.packagerconnection;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import com.facebook.jni.HybridData;
|
||||||
|
import com.facebook.proguard.annotations.DoNotStrip;
|
||||||
|
import com.facebook.soloader.SoLoader;
|
||||||
|
|
||||||
|
public class SamplingProfilerPackagerMethod extends RequestOnlyHandler {
|
||||||
|
static {
|
||||||
|
SoLoader.loadLibrary("packagerconnectionjnifb");
|
||||||
|
}
|
||||||
|
|
||||||
|
final private static class SamplingProfilerJniMethod {
|
||||||
|
|
||||||
|
@DoNotStrip
|
||||||
|
private final HybridData mHybridData;
|
||||||
|
|
||||||
|
public SamplingProfilerJniMethod(long javaScriptContext) {
|
||||||
|
if (Looper.myLooper() == null) {
|
||||||
|
Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
mHybridData = initHybrid(javaScriptContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoNotStrip
|
||||||
|
private native void poke(Responder responder);
|
||||||
|
|
||||||
|
@DoNotStrip
|
||||||
|
private static native HybridData initHybrid(long javaScriptContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SamplingProfilerJniMethod mJniMethod;
|
||||||
|
|
||||||
|
public SamplingProfilerPackagerMethod(long javaScriptContext) {
|
||||||
|
mJniMethod = new SamplingProfilerJniMethod(javaScriptContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequest(@Nullable Object params, Responder responder) {
|
||||||
|
mJniMethod.poke(responder);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE := packagerconnectionjnifb
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
JSPackagerClientResponder.h \
|
||||||
|
SamplingProfilerPackagerMethod.cpp \
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../
|
||||||
|
|
||||||
|
LOCAL_CFLAGS += -Wall -Werror -fvisibility=hidden -fexceptions -frtti
|
||||||
|
CXX11_FLAGS := -std=c++11
|
||||||
|
LOCAL_CFLAGS += $(CXX11_FLAGS)
|
||||||
|
LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
|
||||||
|
|
||||||
|
LOCAL_LDLIBS += -landroid
|
||||||
|
LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
|
$(call import-module,fb)
|
||||||
|
$(call import-module,jsc)
|
||||||
|
$(call import-module,folly)
|
||||||
|
$(call import-module,fbgloginit)
|
||||||
|
$(call import-module,jni)
|
||||||
|
$(call import-module,jscwrapper)
|
|
@ -0,0 +1,35 @@
|
||||||
|
include_defs("//ReactAndroid/DEFS")
|
||||||
|
|
||||||
|
cxx_library(
|
||||||
|
name = "jni",
|
||||||
|
srcs = glob(["*.cpp"]),
|
||||||
|
compiler_flags = [
|
||||||
|
"-Wall",
|
||||||
|
"-Werror",
|
||||||
|
"-fexceptions",
|
||||||
|
"-std=c++1y",
|
||||||
|
"-frtti",
|
||||||
|
],
|
||||||
|
header_namespace = "",
|
||||||
|
headers = glob(
|
||||||
|
["*.h"],
|
||||||
|
),
|
||||||
|
preprocessor_flags = [
|
||||||
|
"-DLOG_TAG=\"PackagerConnectionJNI\"",
|
||||||
|
"-DWITH_FBSYSTRACE=1",
|
||||||
|
"-DWITH_INSPECTOR=1",
|
||||||
|
],
|
||||||
|
soname = "libpackagerconnectionjnifb.$(ext)",
|
||||||
|
visibility = [
|
||||||
|
"PUBLIC",
|
||||||
|
],
|
||||||
|
xcode_public_headers_symlinks = True,
|
||||||
|
deps = JSC_DEPS + [
|
||||||
|
"//native/fb:fb",
|
||||||
|
"//native/third-party/android-ndk:android",
|
||||||
|
"//xplat/folly:molly",
|
||||||
|
"//xplat/fbgloginit:fbgloginit",
|
||||||
|
"//xplat/fbsystrace:fbsystrace",
|
||||||
|
react_native_xplat_target("jschelpers:jschelpers"),
|
||||||
|
],
|
||||||
|
)
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "JSPackagerClientResponder.h"
|
||||||
|
|
||||||
|
#include <jni/LocalString.h>
|
||||||
|
|
||||||
|
using namespace facebook::jni;
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
void JSPackagerClientResponder::respond(alias_ref<jobject> result) {
|
||||||
|
static auto method =
|
||||||
|
javaClassStatic()->getMethod<void(alias_ref<jobject>)>("respond");
|
||||||
|
method(self(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSPackagerClientResponder::respond(const std::string &result) {
|
||||||
|
respond(LocalString(result).string());
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSPackagerClientResponder::error(alias_ref<jobject> result) {
|
||||||
|
static auto method =
|
||||||
|
javaClassStatic()->getMethod<void(alias_ref<jobject>)>("error");
|
||||||
|
method(self(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSPackagerClientResponder::error(const std::string &result) {
|
||||||
|
error(LocalString(result).string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include <fb/fbjni.h>
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
class JSPackagerClientResponder
|
||||||
|
: public jni::JavaClass<JSPackagerClientResponder> {
|
||||||
|
public:
|
||||||
|
static constexpr auto kJavaDescriptor =
|
||||||
|
"Lcom/facebook/react/packagerconnection/Responder;";
|
||||||
|
|
||||||
|
void respond(jni::alias_ref<jobject> result);
|
||||||
|
void respond(const std::string& result);
|
||||||
|
|
||||||
|
void error(jni::alias_ref<jobject> result);
|
||||||
|
void error(const std::string& result);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include <fb/fbjni.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "SamplingProfilerJniMethod.h"
|
||||||
|
|
||||||
|
using namespace facebook::jni;
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||||
|
return initialize(vm, [] { SamplingProfilerJniMethod::registerNatives(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "SamplingProfilerJniMethod.h"
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace facebook::jni;
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
/* static */ jni::local_ref<SamplingProfilerJniMethod::jhybriddata>
|
||||||
|
SamplingProfilerJniMethod::initHybrid(jni::alias_ref<jclass>,
|
||||||
|
jlong javaScriptContext) {
|
||||||
|
return makeCxxInstance(javaScriptContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void SamplingProfilerJniMethod::registerNatives() {
|
||||||
|
registerHybrid(
|
||||||
|
{makeNativeMethod("initHybrid", SamplingProfilerJniMethod::initHybrid),
|
||||||
|
makeNativeMethod("poke", SamplingProfilerJniMethod::poke)});
|
||||||
|
}
|
||||||
|
|
||||||
|
SamplingProfilerJniMethod::SamplingProfilerJniMethod(jlong javaScriptContext) {
|
||||||
|
context_ = reinterpret_cast<JSGlobalContextRef>(javaScriptContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SamplingProfilerJniMethod::poke(
|
||||||
|
jni::alias_ref<JSPackagerClientResponder::javaobject> responder) {
|
||||||
|
if (!JSC_JSSamplingProfilerEnabled(context_)) {
|
||||||
|
responder->error("The JSSamplingProfiler is disabled. See this "
|
||||||
|
"https://fburl.com/u4lw7xeq for some help");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValueRef jsResult = JSC_JSPokeSamplingProfiler(context_);
|
||||||
|
if (JSC_JSValueGetType(context_, jsResult) == kJSTypeNull) {
|
||||||
|
responder->respond("started");
|
||||||
|
} else {
|
||||||
|
JSStringRef resultStrRef = JSValueToStringCopy(context_, jsResult, nullptr);
|
||||||
|
size_t length = JSStringGetLength(resultStrRef);
|
||||||
|
char buffer[length + 1];
|
||||||
|
JSStringGetUTF8CString(resultStrRef, buffer, length + 1);
|
||||||
|
JSStringRelease(resultStrRef);
|
||||||
|
responder->respond(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include <JavaScriptCore/JSProfilerPrivate.h>
|
||||||
|
#include <JavaScriptCore/JSValueRef.h>
|
||||||
|
#include <fb/fbjni.h>
|
||||||
|
#include <jschelpers/JSCHelpers.h>
|
||||||
|
|
||||||
|
#include "JSPackagerClientResponder.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
class SamplingProfilerJniMethod
|
||||||
|
: public jni::HybridClass<SamplingProfilerJniMethod> {
|
||||||
|
public:
|
||||||
|
static constexpr auto kJavaDescriptor =
|
||||||
|
"Lcom/facebook/react/packagerconnection/"
|
||||||
|
"SamplingProfilerPackagerMethod$SamplingProfilerJniMethod;";
|
||||||
|
|
||||||
|
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass> jthis,
|
||||||
|
jlong javaScriptContext);
|
||||||
|
|
||||||
|
static void registerNatives();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend HybridBase;
|
||||||
|
|
||||||
|
explicit SamplingProfilerJniMethod(jlong javaScriptContext);
|
||||||
|
|
||||||
|
void poke(jni::alias_ref<JSPackagerClientResponder::javaobject> responder);
|
||||||
|
|
||||||
|
JSGlobalContextRef context_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue