diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java index db1907d6d0462f..912bb70f28b850 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -31,6 +31,8 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.hardware.SensorManager; +import android.net.Uri; +import android.os.AsyncTask; import android.view.WindowManager; import android.widget.Toast; @@ -50,6 +52,11 @@ import com.facebook.react.devsupport.StackTraceHelper.StackFrame; import com.facebook.react.modules.debug.DeveloperSettings; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; + /** * Interface for accessing and interacting with development features. Following features * are supported through this manager class: @@ -114,6 +121,40 @@ private static enum ErrorType { private int mLastErrorCookie = 0; private @Nullable ErrorType mLastErrorType; + + private static class JscProfileTask extends AsyncTask { + private static final MediaType JSON = + MediaType.parse("application/json; charset=utf-8"); + + private final String mSourceUrl; + + private JscProfileTask(String sourceUrl) { + mSourceUrl = sourceUrl; + } + + @Override + protected Void doInBackground(String... jsonData) { + try { + String jscProfileUrl = + Uri.parse(mSourceUrl).buildUpon() + .path("/jsc-profile") + .query(null) + .build() + .toString(); + OkHttpClient client = new OkHttpClient(); + for (String json: jsonData) { + RequestBody body = RequestBody.create(JSON, json); + Request request = + new Request.Builder().url(jscProfileUrl).post(body).build(); + client.newCall(request).execute(); + } + } catch (IOException e) { + FLog.e(ReactConstants.TAG, "Failed not talk to server", e); + } + return null; + } + } + public DevSupportManagerImpl( Context applicationContext, ReactInstanceDevCommandsHandler reactInstanceCommandsHandler, @@ -389,6 +430,11 @@ public void onOptionSelected() { ? "Started JSC Sampling Profiler" : "Stopped JSC Sampling Profiler", Toast.LENGTH_LONG).show(); + if (result != null) { + new JscProfileTask(getSourceUrl()).executeOnExecutor( + AsyncTask.THREAD_POOL_EXECUTOR, + result); + } } } catch (JSCSamplingProfiler.ProfilerException e) { showNewJavaError(e.getMessage(), e); diff --git a/local-cli/server/middleware/jscProfilerMiddleware.js b/local-cli/server/middleware/jscProfilerMiddleware.js new file mode 100644 index 00000000000000..d656a4906a5f73 --- /dev/null +++ b/local-cli/server/middleware/jscProfilerMiddleware.js @@ -0,0 +1,36 @@ +/** + * 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. + */ +'use strict'; + +const fs = require('fs'); + +module.exports = function(req, res, next) { + if (req.url !== '/jsc-profile') { + next(); + return; + } + + console.log('Dumping JSC profile information...'); + const dumpName = '/tmp/jsc-profile_' + Date.now() + '.cpuprofile'; + fs.writeFile(dumpName, req.rawBody, (err) => { + var response = ''; + if (err) { + response = + 'An error occured when trying to save the profile at ' + dumpName; + console.error(response, err); + } else { + response = + 'Your profile was generated at\n\n' + dumpName + '\n\n' + + 'Open `Chrome Dev Tools > Profiles > Load` ' + + 'and select the profile to visualize it.'; + console.log(response); + } + res.end(response); + }); +}; diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 5718fcfc95ac07..91988dbca75022 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -13,6 +13,7 @@ const connect = require('connect'); const cpuProfilerMiddleware = require('./middleware/cpuProfilerMiddleware'); const getDevToolsMiddleware = require('./middleware/getDevToolsMiddleware'); const http = require('http'); +const jscProfilerMiddleware = require('./middleware/jscProfilerMiddleware'); const loadRawBodyMiddleware = require('./middleware/loadRawBodyMiddleware'); const messageSocket = require('./util/messageSocket.js'); const openStackFrameInEditorMiddleware = require('./middleware/openStackFrameInEditorMiddleware'); @@ -41,6 +42,7 @@ function runServer(args, config, readyCallback) { .use(systraceProfileMiddleware) .use(heapCaptureMiddleware) .use(cpuProfilerMiddleware) + .use(jscProfilerMiddleware) .use(indexPageMiddleware) .use(packagerServer.processRequest.bind(packagerServer));