Remove legacy JSC HeapCapture (#48239)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48239

The native method this module references (`nativeCaptureHeap`) no longer exists, and Metro no longer emits this command.

Changelog: [Android][Removed] Removed JSCHeapCapture module, deprecated PackagerCommandListener#onCaptureHeapCommand

Reviewed By: fabriziocucci

Differential Revision: D67140120

fbshipit-source-id: 7c318366c38868c8a0c589473b6abadd0a09bdde
This commit is contained in:
Pieter De Baets
2024-12-12 14:43:18 -08:00
committed by Facebook GitHub Bot
parent a2db0ba9c4
commit e06fa5d102
9 changed files with 15 additions and 248 deletions
@@ -16,7 +16,6 @@ registerModule('Systrace', () => require('../Performance/Systrace'));
if (!(global.RN$Bridgeless === true)) {
registerModule('JSTimers', () => require('./Timers/JSTimers'));
}
registerModule('HeapCapture', () => require('../HeapCapture/HeapCapture'));
registerModule('SamplingProfiler', () =>
require('../Performance/SamplingProfiler'),
);
@@ -1,29 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
import NativeJSCHeapCapture from './NativeJSCHeapCapture';
const HeapCapture = {
captureHeap: function (path: string) {
let error = null;
try {
global.nativeCaptureHeap(path);
console.log('HeapCapture.captureHeap succeeded: ' + path);
} catch (e) {
console.log('HeapCapture.captureHeap error: ' + e.toString());
error = e.toString();
}
if (NativeJSCHeapCapture) {
NativeJSCHeapCapture.captureComplete(path, error);
}
},
};
module.exports = HeapCapture;
@@ -1,13 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
export * from '../../src/private/specs/modules/NativeJSCHeapCapture';
import NativeJSCHeapCapture from '../../src/private/specs/modules/NativeJSCHeapCapture';
export default NativeJSCHeapCapture;
@@ -4748,18 +4748,6 @@ declare export default typeof EventPolyfill;
"
`;
exports[`public API should not change unintentionally Libraries/HeapCapture/HeapCapture.js 1`] = `
"declare const HeapCapture: { captureHeap: (path: string) => void };
declare module.exports: HeapCapture;
"
`;
exports[`public API should not change unintentionally Libraries/HeapCapture/NativeJSCHeapCapture.js 1`] = `
"export * from \\"../../src/private/specs/modules/NativeJSCHeapCapture\\";
declare export default typeof NativeJSCHeapCapture;
"
`;
exports[`public API should not change unintentionally Libraries/Image/AssetRegistry.js 1`] = `
"declare module.exports: $FlowFixMe;
"
@@ -2119,7 +2119,7 @@ public class com/facebook/react/devsupport/DevServerHelper {
public abstract interface class com/facebook/react/devsupport/DevServerHelper$PackagerCommandListener {
public abstract fun customCommandHandlers ()Ljava/util/Map;
public abstract fun onCaptureHeapCommand (Lcom/facebook/react/packagerconnection/Responder;)V
public fun onCaptureHeapCommand (Lcom/facebook/react/packagerconnection/Responder;)V
public abstract fun onPackagerConnected ()V
public abstract fun onPackagerDevMenuCommand ()V
public abstract fun onPackagerDisconnected ()V
@@ -2223,24 +2223,6 @@ public class com/facebook/react/devsupport/InspectorPackagerConnection : com/fac
public fun sendEventToAllConnections (Ljava/lang/String;)V
}
public class com/facebook/react/devsupport/JSCHeapCapture : com/facebook/fbreact/specs/NativeJSCHeapCaptureSpec {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
public fun captureComplete (Ljava/lang/String;Ljava/lang/String;)V
public fun captureHeap (Ljava/lang/String;Lcom/facebook/react/devsupport/JSCHeapCapture$CaptureCallback;)V
}
public abstract interface class com/facebook/react/devsupport/JSCHeapCapture$CaptureCallback {
public abstract fun onFailure (Lcom/facebook/react/devsupport/JSCHeapCapture$CaptureException;)V
public abstract fun onSuccess (Ljava/io/File;)V
}
public class com/facebook/react/devsupport/JSCHeapCapture$CaptureException : java/lang/Exception {
}
public abstract interface class com/facebook/react/devsupport/JSCHeapCapture$HeapCapture : com/facebook/react/bridge/JavaScriptModule {
public abstract fun captureHeap (Ljava/lang/String;)V
}
public class com/facebook/react/devsupport/JSDebuggerWebSocketClient : okhttp3/WebSocketListener {
public fun <init> ()V
public fun closeQuietly ()V
@@ -11,9 +11,6 @@ import androidx.annotation.Nullable;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.ClassFinder;
import com.facebook.react.devsupport.JSCHeapCapture;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.module.annotations.ReactModuleList;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
@@ -22,20 +19,17 @@ import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.views.debuggingoverlay.DebuggingOverlayManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Provider;
/**
* Package defining core framework modules (e.g. UIManager). It should be used for modules that
* require special integration with other framework parts (e.g. with the list of packages to load
* view managers from).
*/
@ReactModuleList(
nativeModules = {
JSCHeapCapture.class,
})
@ReactModuleList(nativeModules = {})
/* package */
public class DebugCorePackage extends BaseReactPackage implements ViewManagerOnDemandReactPackage {
private @Nullable Map<String, ModuleSpec> mViewManagers;
@@ -44,59 +38,17 @@ public class DebugCorePackage extends BaseReactPackage implements ViewManagerOnD
@Override
public @Nullable NativeModule getModule(String name, ReactApplicationContext reactContext) {
switch (name) {
case JSCHeapCapture.NAME:
return new JSCHeapCapture(reactContext);
default:
return null;
}
return null;
}
@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
if (!ClassFinder.canLoadClassesFromAnnotationProcessors()) {
return fallbackForMissingClass();
}
try {
Class<?> reactModuleInfoProviderClass =
ClassFinder.findClass("com.facebook.react.DebugCorePackage$$ReactModuleInfoProvider");
return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
} catch (ClassNotFoundException e) {
return fallbackForMissingClass();
} catch (InstantiationException e) {
throw new RuntimeException(
"No ReactModuleInfoProvider for DebugCorePackage$$ReactModuleInfoProvider", e);
} catch (IllegalAccessException e) {
throw new RuntimeException(
"No ReactModuleInfoProvider for DebugCorePackage$$ReactModuleInfoProvider", e);
}
}
private ReactModuleInfoProvider fallbackForMissingClass() {
// In OSS case, the annotation processor does not run. We fall back on creating this by hand
Class<? extends NativeModule>[] moduleList = new Class[] {JSCHeapCapture.class};
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
for (Class<? extends NativeModule> moduleClass : moduleList) {
ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
reactModuleInfoMap.put(
reactModule.name(),
new ReactModuleInfo(
reactModule.name(),
moduleClass.getName(),
reactModule.canOverrideExistingModule(),
reactModule.needsEagerInit(),
reactModule.isCxxModule(),
ReactModuleInfo.classIsTurboModule(moduleClass)));
}
return () -> reactModuleInfoMap;
}
private static void appendMap(
Map<String, ModuleSpec> map, String name, Provider<? extends NativeModule> provider) {
map.put(name, ModuleSpec.viewManagerSpec(provider));
return new ReactModuleInfoProvider() {
@Override
public Map<String, ReactModuleInfo> getReactModuleInfos() {
return Collections.emptyMap();
}
};
}
/**
@@ -105,8 +57,9 @@ public class DebugCorePackage extends BaseReactPackage implements ViewManagerOnD
private Map<String, ModuleSpec> getViewManagersMap() {
if (mViewManagers == null) {
Map<String, ModuleSpec> viewManagers = new HashMap<>();
appendMap(viewManagers, DebuggingOverlayManager.REACT_CLASS, DebuggingOverlayManager::new);
viewManagers.put(
DebuggingOverlayManager.REACT_CLASS,
ModuleSpec.viewManagerSpec(DebuggingOverlayManager::new));
mViewManagers = viewManagers;
}
return mViewManagers;
@@ -27,7 +27,6 @@ import com.facebook.react.packagerconnection.NotificationOnlyHandler;
import com.facebook.react.packagerconnection.PackagerConnectionSettings;
import com.facebook.react.packagerconnection.ReconnectingWebSocket.ConnectionCallback;
import com.facebook.react.packagerconnection.RequestHandler;
import com.facebook.react.packagerconnection.RequestOnlyHandler;
import com.facebook.react.packagerconnection.Responder;
import com.facebook.react.util.RNLog;
import java.io.File;
@@ -76,7 +75,8 @@ public class DevServerHelper {
void onPackagerDevMenuCommand();
void onCaptureHeapCommand(final Responder responder);
@Deprecated(forRemoval = true)
default void onCaptureHeapCommand(final Responder responder) {}
// Allow apps to provide listeners for custom packager commands.
@Nullable
@@ -155,14 +155,6 @@ public class DevServerHelper {
commandListener.onPackagerDevMenuCommand();
}
});
handlers.put(
"captureHeap",
new RequestOnlyHandler() {
@Override
public void onRequest(@Nullable Object params, Responder responder) {
commandListener.onCaptureHeapCommand(responder);
}
});
Map<String, RequestHandler> customHandlers = commandListener.customCommandHandlers();
if (customHandlers != null) {
handlers.putAll(customHandlers);
@@ -63,7 +63,6 @@ import com.facebook.react.devsupport.interfaces.StackFrame;
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
import com.facebook.react.packagerconnection.RequestHandler;
import com.facebook.react.packagerconnection.Responder;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
@@ -865,29 +864,6 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
return mLastErrorType;
}
private void handleCaptureHeap(final Responder responder) {
if (mCurrentReactContext == null) {
return;
}
JSCHeapCapture heapCapture = mCurrentReactContext.getNativeModule(JSCHeapCapture.class);
if (heapCapture != null) {
heapCapture.captureHeap(
mApplicationContext.getCacheDir().getPath(),
new JSCHeapCapture.CaptureCallback() {
@Override
public void onSuccess(File capture) {
responder.respond(capture.toString());
}
@Override
public void onFailure(JSCHeapCapture.CaptureException error) {
responder.error(error.toString());
}
});
}
}
private void updateLastErrorInfo(
@Nullable final String message,
final StackFrame[] stack,
@@ -1076,11 +1052,6 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
UiThreadUtil.runOnUiThread(() -> showDevOptionsDialog());
}
@Override
public void onCaptureHeapCommand(final Responder responder) {
UiThreadUtil.runOnUiThread(() -> handleCaptureHeap(responder));
}
@Override
public @Nullable Map<String, RequestHandler> customCommandHandlers() {
return mCustomPackagerCommandHandlers;
@@ -1,76 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.devsupport;
import androidx.annotation.Nullable;
import com.facebook.fbreact.specs.NativeJSCHeapCaptureSpec;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
import java.io.File;
// This module is being called only by Java via the static method "captureHeap" that
// requires it to already be initialized, thus we eagerly initialize this module
@ReactModule(name = NativeJSCHeapCaptureSpec.NAME, needsEagerInit = true)
public class JSCHeapCapture extends NativeJSCHeapCaptureSpec {
public interface HeapCapture extends JavaScriptModule {
void captureHeap(String path);
}
public static class CaptureException extends Exception {
CaptureException(String message) {
super(message);
}
}
public interface CaptureCallback {
void onSuccess(File capture);
void onFailure(CaptureException error);
}
private @Nullable CaptureCallback mCaptureInProgress;
public JSCHeapCapture(ReactApplicationContext reactContext) {
super(reactContext);
mCaptureInProgress = null;
}
public synchronized void captureHeap(String path, final CaptureCallback callback) {
if (mCaptureInProgress != null) {
callback.onFailure(new CaptureException("Heap capture already in progress."));
return;
}
File f = new File(path + "/capture.json");
f.delete();
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();
if (reactApplicationContext != null) {
HeapCapture heapCapture = reactApplicationContext.getJSModule(HeapCapture.class);
if (heapCapture == null) {
callback.onFailure(new CaptureException("Heap capture js module not registered."));
return;
}
mCaptureInProgress = callback;
heapCapture.captureHeap(f.getPath());
}
}
@Override
public synchronized void captureComplete(String path, String error) {
if (mCaptureInProgress != null) {
if (error == null) {
mCaptureInProgress.onSuccess(new File(path));
} else {
mCaptureInProgress.onFailure(new CaptureException(error));
}
mCaptureInProgress = null;
}
}
}