From 71575ce7cfaf72e1faaf5b99331bb71e766df209 Mon Sep 17 00:00:00 2001 From: Pascal Hartig Date: Thu, 13 Jun 2019 11:15:01 -0700 Subject: [PATCH] Hook up stacktraces to leak notification Summary: Transfer it from the device, reformat the notification to make use of it. Reviewed By: danielbuechele Differential Revision: D15779267 fbshipit-source-id: 747dc7f895528618ff6a07c15b7f72bf6a1adde9 --- .../plugins/fresco/FrescoFlipperPlugin.java | 12 ++++++++++ src/plugins/fresco/__tests__/index.node.js | 6 ++++- src/plugins/fresco/api.js | 1 + src/plugins/fresco/index.js | 22 +++++++++++++++++-- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/facebook/flipper/plugins/fresco/FrescoFlipperPlugin.java b/android/src/main/java/com/facebook/flipper/plugins/fresco/FrescoFlipperPlugin.java index a8f6b8533..a8646a08a 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/fresco/FrescoFlipperPlugin.java +++ b/android/src/main/java/com/facebook/flipper/plugins/fresco/FrescoFlipperPlugin.java @@ -39,6 +39,8 @@ import com.facebook.imagepipeline.image.CloseableBitmap; import com.facebook.imagepipeline.image.CloseableImage; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -521,6 +523,16 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin new FlipperObject.Builder() .put("identityHashCode", System.identityHashCode(reference)) .put("className", reference.get().getClass().getName()); + if (stacktrace != null) { + builder.put("stacktrace", getStackTraceString(stacktrace)); + } send(FRESCO_CLOSEABLE_REFERENCE_LEAK_EVENT, builder.build()); } + + public static String getStackTraceString(Throwable tr) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + tr.printStackTrace(pw); + return sw.toString(); + } } diff --git a/src/plugins/fresco/__tests__/index.node.js b/src/plugins/fresco/__tests__/index.node.js index 788c6514c..0468f7345 100644 --- a/src/plugins/fresco/__tests__/index.node.js +++ b/src/plugins/fresco/__tests__/index.node.js @@ -265,10 +265,12 @@ test('closeable reference metrics on input', () => { { identityHashCode: 'deadbeef', className: 'com.facebook.imagepipeline.memory.NativeMemoryChunk', + stacktrace: null, }, { identityHashCode: 'f4c3b00c', className: 'com.facebook.flipper.SomeMemoryAbstraction', + stacktrace: null, }, ]; const persistedState = { @@ -287,10 +289,12 @@ test('notifications for leaks', () => { { identityHashCode: 'deadbeef', className: 'com.facebook.imagepipeline.memory.NativeMemoryChunk', + stacktrace: null, }, { identityHashCode: 'f4c3b00c', className: 'com.facebook.flipper.SomeMemoryAbstraction', + stacktrace: null, }, ]; const persistedStateWithoutTracking = { @@ -308,6 +312,6 @@ test('notifications for leaks', () => { }; const notifs = notificationReducer(persistedStateWithTracking); expect(notifs).toHaveLength(2); - expect(notifs[0].message).toContain('deadbeef'); + expect(notifs[0].message).toMatchSnapshot(); expect(notifs[1].title).toContain('SomeMemoryAbstraction'); }); diff --git a/src/plugins/fresco/api.js b/src/plugins/fresco/api.js index 7c3d79a0d..4867ab3a4 100644 --- a/src/plugins/fresco/api.js +++ b/src/plugins/fresco/api.js @@ -71,4 +71,5 @@ export type FrescoDebugOverlayEvent = {| export type AndroidCloseableReferenceLeakEvent = {| identityHashCode: string, className: string, + stacktrace: ?string, |}; diff --git a/src/plugins/fresco/index.js b/src/plugins/fresco/index.js index fce354805..8ed1abc64 100644 --- a/src/plugins/fresco/index.js +++ b/src/plugins/fresco/index.js @@ -15,6 +15,7 @@ import type { AndroidCloseableReferenceLeakEvent, CacheInfo, } from './api.js'; +import {Fragment} from 'react'; import type {ImagesMap} from './ImagePool.js'; import type {MetricType, MiddlewareAPI} from 'flipper'; import React from 'react'; @@ -60,6 +61,10 @@ const EmptySidebar = styled(FlexRow)({ fontSize: 16, }); +export const InlineFlexRow = styled(FlexRow)({ + display: 'inline-block', +}); + const surfaceDefaultText = 'SELECT ALL SURFACES'; const debugLog = (...args) => { @@ -196,8 +201,21 @@ export default class extends FlipperPlugin { .map((event: AndroidCloseableReferenceLeakEvent, index) => ({ id: event.identityHashCode, title: `Leaked CloseableReference: ${event.className}`, - message: `CloseableReference leaked for ${event.className} - (identity hashcode: ${event.identityHashCode})`, + message: ( + + + CloseableReference leaked for{' '} + {event.className} + (identity hashcode: {event.identityHashCode}). + + + Stacktrace: + + + {event.stacktrace || ''} + + + ), severity: 'error', category: 'closeablereference_leak', }));