Request all metadata for Images plugin before export

Summary:
Fresco plugin on the desktop side used to ask for all the image list along with the metadata when it was mounted. The mobile side never sent the image list and other information if not requested from it. That means, although Fresco plugin is a background plugin, there weren't any messages sent from the mobile side. Thus there was no trace available for Images plugin when the trace was exported. This diff, adds a hook which gets called before the export, where we request all the metadata from the mobile SDK.

BUG:

{F159305887}

Reviewed By: passy

Differential Revision: D15407962

fbshipit-source-id: 0012de2ab29d0f62e92d00f4926b04b1e394b62a
This commit is contained in:
Pritesh Nandgaonkar
2019-05-23 05:44:32 -07:00
committed by Facebook Github Bot
parent 7576e1c61d
commit 914cbf6ccd
4 changed files with 214 additions and 79 deletions

View File

@@ -35,8 +35,12 @@ import com.facebook.imagepipeline.debug.DebugImageTracker;
import com.facebook.imagepipeline.debug.FlipperImageTracker;
import com.facebook.imagepipeline.image.CloseableBitmap;
import com.facebook.imagepipeline.image.CloseableImage;
import org.json.JSONArray;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
@@ -70,6 +74,7 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
private final DebugMemoryManager mMemoryManager;
private final FlipperPerfLogger mPerfLogger;
@Nullable private final FrescoFlipperDebugPrefHelper mDebugPrefHelper;
private final List<FlipperObject> mEvents = new ArrayList<>();
public FrescoFlipperPlugin(
DebugImageTracker imageTracker,
@@ -111,7 +116,62 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
@Override
public void onConnect(FlipperConnection connection) {
super.onConnect(connection);
connection.receive(
"getAllImageData",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) {
if (!ensureFrescoInitialized(responder)) {
return;
}
final ImagePipelineFactory imagePipelineFactory = Fresco.getImagePipelineFactory();
final CountingMemoryCacheInspector.DumpInfo memoryCache =
new CountingMemoryCacheInspector<>(
imagePipelineFactory.getBitmapCountingMemoryCache())
.dumpCacheContent();
final FlipperArray memoryCacheSharedEntries = buildImageIdList(memoryCache.sharedEntries);
final FlipperArray memoryCacheLRUEntries = buildImageIdList(memoryCache.lruEntries);
final FlipperArray.Builder imageIDListBuilder = new FlipperArray.Builder();
for (int i = 0; i < memoryCacheSharedEntries.length(); ++i) {
final String imageID = memoryCacheSharedEntries.getString(i);
imageIDListBuilder.put(imageID);
}
for (int i = 0; i < memoryCacheLRUEntries.length(); ++i) {
final String imageID = memoryCacheLRUEntries.getString(i);
imageIDListBuilder.put(imageID);
}
final FlipperArray imageIDs = imageIDListBuilder.build();
final FlipperObject levels =
getImageList(memoryCache, memoryCacheSharedEntries, memoryCacheLRUEntries);
final FlipperArray.Builder imageDataListBuilder = new FlipperArray.Builder();
for (int i = 0; i < imageIDs.length(); ++i) {
final String imageID = imageIDs.getString(i);
final CacheKey cacheKey = mFlipperImageTracker.getCacheKey(imageID);
if (cacheKey == null) {
continue;
}
final CloseableReference<CloseableImage> ref =
imagePipelineFactory.getBitmapCountingMemoryCache().get(cacheKey);
if (ref == null) {
continue;
}
final CloseableBitmap bitmap = (CloseableBitmap) ref.get();
final String encodedBitmap =
bitmapToBase64Preview(bitmap.getUnderlyingBitmap(), mPlatformBitmapFactory);
imageDataListBuilder.put(
getImageData(
imageID, encodedBitmap, bitmap, mFlipperImageTracker.getUriString(cacheKey)));
}
responder.success(
new FlipperObject.Builder()
.put("levels", levels)
.put("imageDataList", imageDataListBuilder.build())
.put("events", new FlipperArray(new JSONArray(mEvents)))
.build());
}
});
connection.receive(
"listImages",
new FlipperReceiver() {
@@ -127,29 +187,11 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
new CountingMemoryCacheInspector<>(
imagePipelineFactory.getBitmapCountingMemoryCache())
.dumpCacheContent();
responder.success(
new FlipperObject.Builder()
.put(
"levels",
new FlipperArray.Builder()
.put(
new FlipperObject.Builder()
.put("cacheType", "On screen bitmaps")
.put("sizeBytes", memoryCache.size - memoryCache.lruSize)
.put("imageIds", buildImageIdList(memoryCache.sharedEntries))
.build())
.put(
new FlipperObject.Builder()
.put("cacheType", "Bitmap memory cache")
.put("clearKey", "memory")
.put("sizeBytes", memoryCache.size)
.put("maxSizeBytes", memoryCache.maxSize)
.put("imageIds", buildImageIdList(memoryCache.lruEntries))
.build())
// TODO (t31947642): list images on disk
.build())
.build());
getImageList(
memoryCache,
buildImageIdList(memoryCache.sharedEntries),
buildImageIdList(memoryCache.lruEntries)));
mPerfLogger.endMarker("Sonar.Fresco.listImages");
}
});
@@ -185,14 +227,8 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
bitmapToBase64Preview(bitmap.getUnderlyingBitmap(), mPlatformBitmapFactory);
responder.success(
new FlipperObject.Builder()
.put("imageId", imageId)
.put("uri", mFlipperImageTracker.getUriString(cacheKey))
.put("width", bitmap.getWidth())
.put("height", bitmap.getHeight())
.put("sizeBytes", bitmap.getSizeInBytes())
.put("data", encodedBitmap)
.build());
getImageData(
imageId, encodedBitmap, bitmap, mFlipperImageTracker.getUriString(cacheKey)));
mPerfLogger.endMarker("Sonar.Fresco.getImage");
}
@@ -266,6 +302,45 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
}
}
private FlipperObject getImageList(
CountingMemoryCacheInspector.DumpInfo memoryCache,
FlipperArray memoryCacheSharedEntries,
FlipperArray memoryCacheLRUEntries) {
return new FlipperObject.Builder()
.put(
"levels",
new FlipperArray.Builder()
.put(
new FlipperObject.Builder()
.put("cacheType", "On screen bitmaps")
.put("sizeBytes", memoryCache.size - memoryCache.lruSize)
.put("imageIds", memoryCacheSharedEntries)
.build())
.put(
new FlipperObject.Builder()
.put("cacheType", "Bitmap memory cache")
.put("clearKey", "memory")
.put("sizeBytes", memoryCache.size)
.put("maxSizeBytes", memoryCache.maxSize)
.put("imageIds", memoryCacheLRUEntries)
.build())
// TODO (t31947642): list images on disk
.build())
.build();
}
private FlipperObject getImageData(
String imageID, String encodedBitmap, CloseableBitmap bitmap, String uriString) {
return new FlipperObject.Builder()
.put("imageId", imageID)
.put("uri", uriString)
.put("width", bitmap.getWidth())
.put("height", bitmap.getHeight())
.put("sizeBytes", bitmap.getSizeInBytes())
.put("data", encodedBitmap)
.build();
}
private boolean ensureFrescoInitialized(FlipperResponder responder) {
mPerfLogger.startMarker("Sonar.Fresco.ensureFrescoInitialized");
try {
@@ -403,8 +478,9 @@ public class FrescoFlipperPlugin extends BufferingFlipperPlugin implements Image
.put("height", imagePerfData.getOnScreenHeightPx())
.build());
}
send(FRESCO_EVENT, response.build());
FlipperObject responseObject = response.build();
mEvents.add(responseObject);
send(FRESCO_EVENT, responseObject);
}
public void onImageVisibilityUpdated(ImagePerfData imagePerfData, int visibilityState) {

View File

@@ -3,7 +3,7 @@
// This source code is licensed under the MIT license found in the LICENSE file
// in the root directory of this source tree.
buildscript {
buildscript {
repositories {
google()
jcenter()

View File

@@ -15,7 +15,7 @@ import type {
CacheInfo,
} from './api.js';
import type {ImagesMap} from './ImagePool.js';
import type {MetricType} from 'flipper';
import type {MetricType, MiddlewareAPI} from 'flipper';
import React from 'react';
import ImagesCacheOverview from './ImagesCacheOverview.js';
import {
@@ -65,6 +65,12 @@ const debugLog = (...args) => {
}
};
type ImagesMetaData = {|
levels: ImagesListResponse,
events: Array<ImageEventWithId>,
imageDataList: Array<ImageData>,
|};
export default class extends FlipperPlugin<PluginState, *, PersistedState> {
static defaultPersistedState: PersistedState = {
images: [],
@@ -73,6 +79,52 @@ export default class extends FlipperPlugin<PluginState, *, PersistedState> {
surfaceList: new Set(),
};
static exportPersistedState = (
callClient: (string, ?Object) => Promise<Object>,
persistedState: ?PersistedState,
store: ?MiddlewareAPI,
): Promise<?PersistedState> => {
if (persistedState) {
return Promise.resolve(persistedState);
}
const defaultPromise = Promise.resolve(persistedState);
if (!store) {
return defaultPromise;
}
return callClient('getAllImageData').then((data: ImagesMetaData) => {
if (!data) {
return;
}
const {levels, events, imageDataList} = data;
let pluginData: PersistedState = {
images: [...levels.levels],
surfaceList: new Set(),
events: [],
imagesMap: {},
};
events.forEach((event: ImageEventWithId, index) => {
const {attribution} = event;
if (attribution instanceof Array && attribution.length > 0) {
const surface = attribution[0].trim();
if (surface.length > 0) {
pluginData.surfaceList.add(surface);
}
}
pluginData = {
...pluginData,
events: [{eventId: index, ...event}, ...pluginData.events],
};
});
imageDataList.forEach((imageData: ImageData) => {
const {imageId} = imageData;
pluginData.imagesMap[imageId] = imageData;
});
return pluginData;
});
};
static metricsReducer = (
persistedState: PersistedState,
): Promise<MetricType> => {
@@ -113,42 +165,6 @@ export default class extends FlipperPlugin<PluginState, *, PersistedState> {
coldStartFilter: false,
};
init() {
debugLog('init()');
this.updateCaches('init');
this.client.subscribe('events', (event: ImageEvent) => {
const {surfaceList} = this.props.persistedState;
const {attribution} = event;
if (attribution instanceof Array && attribution.length > 0) {
const surface = attribution[0].trim();
if (surface.length > 0) {
surfaceList.add(surface);
}
}
this.props.setPersistedState({
events: [
{eventId: this.nextEventId, ...event},
...this.props.persistedState.events,
],
});
this.nextEventId++;
});
this.client.subscribe(
'debug_overlay_event',
(event: FrescoDebugOverlayEvent) => {
this.setState({isDebugOverlayEnabled: event.enabled});
},
);
this.imagePool = new ImagePool(this.getImage, (images: ImagesMap) =>
this.props.setPersistedState({imagesMap: images}),
);
}
teardown() {
this.imagePool.clear();
}
filterImages = (
images: ImagesList,
events: Array<ImageEventWithId>,
@@ -183,6 +199,49 @@ export default class extends FlipperPlugin<PluginState, *, PersistedState> {
return imageList;
};
init() {
debugLog('init()');
this.updateCaches('init');
this.client.subscribe('events', (event: ImageEvent) => {
const {surfaceList} = this.props.persistedState;
const {attribution} = event;
if (attribution instanceof Array && attribution.length > 0) {
const surface = attribution[0].trim();
if (surface.length > 0) {
surfaceList.add(surface);
}
}
this.props.setPersistedState({
events: [
{eventId: this.nextEventId, ...event},
...this.props.persistedState.events,
],
});
this.nextEventId++;
});
this.client.subscribe(
'debug_overlay_event',
(event: FrescoDebugOverlayEvent) => {
this.setState({isDebugOverlayEnabled: event.enabled});
},
);
this.imagePool = new ImagePool(this.getImage, (images: ImagesMap) =>
this.props.setPersistedState({imagesMap: images}),
);
let images = this.filterImages(
this.props.persistedState.images,
this.props.persistedState.events,
this.state.selectedSurface,
this.state.coldStartFilter,
);
this.setState({images});
}
teardown() {
this.imagePool.clear();
}
updateImagesOnUI = (
images: ImagesList,
surface: string,

View File

@@ -319,6 +319,15 @@ export function importDataToStore(data: string, store: Store) {
const {pluginStates} = json.store;
const keys = Object.keys(pluginStates);
keys.forEach(key => {
store.dispatch({
type: 'SET_PLUGIN_STATE',
payload: {
pluginKey: key,
state: pluginStates[key],
},
});
});
clients.forEach(client => {
const clientPlugins = keys
.filter(key => {
@@ -340,15 +349,6 @@ export function importDataToStore(data: string, store: Store) {
),
});
});
keys.forEach(key => {
store.dispatch({
type: 'SET_PLUGIN_STATE',
payload: {
pluginKey: key,
state: pluginStates[key],
},
});
});
}
export const importFileToStore = (file: string, store: Store) => {