Send CloseableRef leaks to Flipper plugin (#455)

Summary:
Pull Request resolved: https://github.com/facebook/flipper/pull/455

Only logging to the console for now, but it's a good start.

Reviewed By: oprisnik

Differential Revision: D15535820

fbshipit-source-id: 8531ec5ef681d01b2428a1f016b2a1d9f1589a34
This commit is contained in:
Pascal Hartig
2019-05-31 16:55:24 -07:00
committed by Facebook Github Bot
parent 7dc3525846
commit faf19452eb
3 changed files with 62 additions and 28 deletions

View File

@@ -13,6 +13,7 @@ import com.facebook.common.internal.Predicate;
import com.facebook.common.memory.manager.DebugMemoryManager; import com.facebook.common.memory.manager.DebugMemoryManager;
import com.facebook.common.memory.manager.NoOpDebugMemoryManager; import com.facebook.common.memory.manager.NoOpDebugMemoryManager;
import com.facebook.common.references.CloseableReference; import com.facebook.common.references.CloseableReference;
import com.facebook.common.references.SharedReference;
import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.info.ImageLoadStatus; import com.facebook.drawee.backends.pipeline.info.ImageLoadStatus;
import com.facebook.drawee.backends.pipeline.info.ImageOriginUtils; import com.facebook.drawee.backends.pipeline.info.ImageOriginUtils;
@@ -31,28 +32,31 @@ import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
import com.facebook.imagepipeline.cache.CountingMemoryCacheInspector; import com.facebook.imagepipeline.cache.CountingMemoryCacheInspector;
import com.facebook.imagepipeline.cache.CountingMemoryCacheInspector.DumpInfoEntry; import com.facebook.imagepipeline.cache.CountingMemoryCacheInspector.DumpInfoEntry;
import com.facebook.imagepipeline.core.ImagePipelineFactory; import com.facebook.imagepipeline.core.ImagePipelineFactory;
import com.facebook.imagepipeline.debug.CloseableReferenceLeakTracker;
import com.facebook.imagepipeline.debug.DebugImageTracker; import com.facebook.imagepipeline.debug.DebugImageTracker;
import com.facebook.imagepipeline.debug.FlipperImageTracker; import com.facebook.imagepipeline.debug.FlipperImageTracker;
import com.facebook.imagepipeline.image.CloseableBitmap; import com.facebook.imagepipeline.image.CloseableBitmap;
import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.image.CloseableImage;
import org.json.JSONArray;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.json.JSONArray;
/** /**
* Allows Sonar to display the contents of Fresco's caches. This is useful for developers to debug * Allows Sonar to display the contents of Fresco's caches. This is useful for developers to debug
* what images are being held in cache as they navigate through their app. * what images are being held in cache as they navigate through their app.
*/ */
public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements ImagePerfDataListener { public class FrescoFlipperPlugin extends BufferingFlipperPlugin
implements ImagePerfDataListener, CloseableReferenceLeakTracker.Listener {
private static final String FRESCO_EVENT = "events"; private static final String FRESCO_EVENT = "events";
private static final String FRESCO_DEBUGOVERLAY_EVENT = "debug_overlay_event"; private static final String FRESCO_DEBUGOVERLAY_EVENT = "debug_overlay_event";
private static final String FRESCO_CLOSEABLE_REFERENCE_LEAK_EVENT =
"closeable_reference_leak_event";
private static final int BITMAP_PREVIEW_WIDTH = 150; private static final int BITMAP_PREVIEW_WIDTH = 150;
private static final int BITMAP_PREVIEW_HEIGHT = 150; private static final int BITMAP_PREVIEW_HEIGHT = 150;
@@ -82,7 +86,8 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
@Nullable FlipperObjectHelper flipperObjectHelper, @Nullable FlipperObjectHelper flipperObjectHelper,
DebugMemoryManager memoryManager, DebugMemoryManager memoryManager,
FlipperPerfLogger perfLogger, FlipperPerfLogger perfLogger,
@Nullable FrescoFlipperDebugPrefHelper debugPrefHelper) { @Nullable FrescoFlipperDebugPrefHelper debugPrefHelper,
@Nullable CloseableReferenceLeakTracker closeableReferenceLeakTracker) {
mFlipperImageTracker = mFlipperImageTracker =
imageTracker instanceof FlipperImageTracker imageTracker instanceof FlipperImageTracker
? (FlipperImageTracker) imageTracker ? (FlipperImageTracker) imageTracker
@@ -92,6 +97,10 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
mMemoryManager = memoryManager; mMemoryManager = memoryManager;
mPerfLogger = perfLogger; mPerfLogger = perfLogger;
mDebugPrefHelper = debugPrefHelper; mDebugPrefHelper = debugPrefHelper;
if (closeableReferenceLeakTracker != null) {
closeableReferenceLeakTracker.setListener(this);
}
} }
public FrescoFlipperPlugin() { public FrescoFlipperPlugin() {
@@ -101,6 +110,7 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
null, null,
new NoOpDebugMemoryManager(), new NoOpDebugMemoryManager(),
new NoOpFlipperPerfLogger(), new NoOpFlipperPerfLogger(),
null,
null); null);
} }
@@ -130,7 +140,8 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
imagePipelineFactory.getBitmapCountingMemoryCache()) imagePipelineFactory.getBitmapCountingMemoryCache())
.dumpCacheContent(); .dumpCacheContent();
final FlipperArray memoryCacheSharedEntries = buildImageIdList(memoryCache.sharedEntries); final FlipperArray memoryCacheSharedEntries =
buildImageIdList(memoryCache.sharedEntries);
final FlipperArray memoryCacheLRUEntries = buildImageIdList(memoryCache.lruEntries); final FlipperArray memoryCacheLRUEntries = buildImageIdList(memoryCache.lruEntries);
final FlipperArray.Builder imageIDListBuilder = new FlipperArray.Builder(); final FlipperArray.Builder imageIDListBuilder = new FlipperArray.Builder();
for (int i = 0; i < memoryCacheSharedEntries.length(); ++i) { for (int i = 0; i < memoryCacheSharedEntries.length(); ++i) {
@@ -433,7 +444,8 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
return; return;
} }
FlipperImageTracker.ImageDebugData data = mFlipperImageTracker.getDebugDataForRequestId(requestId); FlipperImageTracker.ImageDebugData data =
mFlipperImageTracker.getDebugDataForRequestId(requestId);
if (data == null) { if (data == null) {
return; return;
} }
@@ -495,4 +507,13 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
private static void respondError(FlipperResponder responder, String errorReason) { private static void respondError(FlipperResponder responder, String errorReason) {
responder.error(new FlipperObject.Builder().put("reason", errorReason).build()); responder.error(new FlipperObject.Builder().put("reason", errorReason).build());
} }
@Override
public void onCloseableReferenceLeak(SharedReference<Closeable> reference) {
final FlipperObject.Builder builder =
new FlipperObject.Builder()
.put("identityHashCode", System.identityHashCode(reference))
.put("className", reference.get().getClass().getName());
send(FRESCO_CLOSEABLE_REFERENCE_LEAK_EVENT, builder.build());
}
} }

View File

@@ -67,3 +67,8 @@ export type ImageEvent = {
export type FrescoDebugOverlayEvent = {| export type FrescoDebugOverlayEvent = {|
enabled: boolean, enabled: boolean,
|}; |};
export type AndroidCloseableReferenceLeakEvent = {|
identityHashCode: string,
className: string,
|};

View File

@@ -12,6 +12,7 @@ import type {
ImagesListResponse, ImagesListResponse,
ImageEvent, ImageEvent,
FrescoDebugOverlayEvent, FrescoDebugOverlayEvent,
AndroidCloseableReferenceLeakEvent,
CacheInfo, CacheInfo,
} from './api.js'; } from './api.js';
import type {ImagesMap} from './ImagePool.js'; import type {ImagesMap} from './ImagePool.js';
@@ -225,6 +226,13 @@ export default class extends FlipperPlugin<PluginState, *, PersistedState> {
this.setState({isDebugOverlayEnabled: event.enabled}); this.setState({isDebugOverlayEnabled: event.enabled});
}, },
); );
this.client.subscribe(
'closeable_reference_leak_event',
(event: AndroidCloseableReferenceLeakEvent) => {
// TODO(T45065440): Temporary log, to be turned into counter.
console.warn('CloseableReference leak detected:', event);
},
);
this.imagePool = new ImagePool(this.getImage, (images: ImagesMap) => this.imagePool = new ImagePool(this.getImage, (images: ImagesMap) =>
this.props.setPersistedState({imagesMap: images}), this.props.setPersistedState({imagesMap: images}),
); );