Permalink
Browse files

Track bitmap created by PlatformBitmapFactory directly

Summary: Add callercontext to PlatformBitmapFactory, so can track uses of PlatformBitmapFactory.createBitmap()

Reviewed By: kirwan

Differential Revision: D3627698

fbshipit-source-id: 5b0087c115f0449de2d4abe201dfd0e37bdd68fe
  • Loading branch information...
1 parent 21cdb8b commit b3a41a9838a1fd886db35d7f9984ac52a813f692 @aagnes aagnes committed with Facebook Github Bot 3 Aug 30, 2016
Showing with 277 additions and 37 deletions.
  1. +2 −1 ...ated-base/src/main/java/com/facebook/imagepipeline/animated/factory/AnimatedImageFactoryImpl.java
  2. +7 −1 animated-base/src/test/java/com/facebook/imagepipeline/animated/impl/AnimatedFrameCacheTest.java
  3. +4 −4 ...if/src/test/java/com/facebook/imagepipeline/animated/factory/AnimatedImageFactoryGifImplTest.java
  4. +4 −4 ...p/src/test/java/com/facebook/imagepipeline/animated/factory/AnimatedImageFactoryWebPImplTest.java
  5. +87 −2 imagepipeline-base/src/main/java/com/facebook/imagepipeline/bitmaps/PlatformBitmapFactory.java
  6. +11 −3 ...ipeline-base/src/main/java/com/facebook/imagepipeline/cache/BitmapCountingMemoryCacheFactory.java
  7. +23 −1 imagepipeline-base/src/main/java/com/facebook/imagepipeline/cache/CountingMemoryCache.java
  8. +95 −12 imagepipeline-base/src/test/java/com/facebook/imagepipeline/cache/CountingMemoryCacheTest.java
  9. +1 −1 imagepipeline/src/main/java/com/facebook/imagepipeline/bitmaps/ArtBitmapFactory.java
  10. +1 −1 imagepipeline/src/main/java/com/facebook/imagepipeline/bitmaps/GingerbreadBitmapFactory.java
  11. +1 −1 imagepipeline/src/main/java/com/facebook/imagepipeline/bitmaps/HoneycombBitmapFactory.java
  12. +10 −3 imagepipeline/src/main/java/com/facebook/imagepipeline/cache/EncodedCountingMemoryCacheFactory.java
  13. +13 −0 imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineExperiments.java
  14. +5 −2 imagepipeline/src/main/java/com/facebook/imagepipeline/core/ImagePipelineFactory.java
  15. +1 −1 imagepipeline/src/main/java/com/facebook/imagepipeline/request/BasePostprocessor.java
  16. +12 −0 tools/stetho/src/main/java/com/facebook/imagepipeline/cache/CountingMemoryCacheInspector.java
@@ -211,7 +211,8 @@ public void onIntermediateResult(int frameNumber, Bitmap bitmap) {
int width,
int height,
Bitmap.Config bitmapConfig) {
- CloseableReference<Bitmap> bitmap = mBitmapFactory.createBitmap(width, height, bitmapConfig);
+ CloseableReference<Bitmap> bitmap =
+ mBitmapFactory.createBitmapInternal(width, height, bitmapConfig);
bitmap.get().eraseColor(Color.TRANSPARENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
bitmap.get().setHasAlpha(true);
@@ -15,6 +15,7 @@
import com.facebook.common.memory.MemoryTrimmableRegistry;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.util.ByteConstants;
+import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
import com.facebook.imagepipeline.cache.BitmapCountingMemoryCacheFactory;
import com.facebook.imagepipeline.cache.CountingMemoryCache;
import com.facebook.imagepipeline.cache.MemoryCacheParams;
@@ -39,6 +40,7 @@
@Mock public MemoryTrimmableRegistry mMemoryTrimmableRegistry;
@Mock public Supplier<MemoryCacheParams> mMemoryCacheParamsSupplier;
+ @Mock public PlatformBitmapFactory mPlatformBitmapFactory;
private CacheKey mCacheKey;
private AnimatedFrameCache mAnimatedFrameCache;
@@ -56,7 +58,11 @@ public void setUp() {
Integer.MAX_VALUE);
when(mMemoryCacheParamsSupplier.get()).thenReturn(params);
CountingMemoryCache<CacheKey, CloseableImage> countingMemoryCache =
- BitmapCountingMemoryCacheFactory.get(mMemoryCacheParamsSupplier, mMemoryTrimmableRegistry);
+ BitmapCountingMemoryCacheFactory.get(
+ mMemoryCacheParamsSupplier,
+ mMemoryTrimmableRegistry,
+ mPlatformBitmapFactory,
+ true);
mCacheKey = new SimpleCacheKey("key");
mAnimatedFrameCache = new AnimatedFrameCache(mCacheKey, countingMemoryCache);
mFrame1 = CloseableReference.of(mock(CloseableImage.class));
@@ -153,7 +153,7 @@ public void testCreateWithPreviewBitmap() throws Exception {
any(AnimatedImageResult.class),
isNull(Rect.class)))
.thenReturn(mockAnimatedDrawableBackend);
- when(mMockBitmapFactory.createBitmap(50, 50, DEFAULT_BITMAP_CONFIG))
+ when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG))
.thenReturn(CloseableReference.of(mockBitmap, FAKE_BITMAP_RESOURCE_RELEASER));
AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class);
PowerMockito.whenNew(AnimatedImageCompositor.class)
@@ -183,7 +183,7 @@ public void testCreateWithPreviewBitmap() throws Exception {
any(AnimatedImageResult.class),
isNull(Rect.class));
verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider);
- verify(mMockBitmapFactory).createBitmap(50, 50, DEFAULT_BITMAP_CONFIG);
+ verify(mMockBitmapFactory).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG);
verifyNoMoreInteractions(mMockBitmapFactory);
verify(mockCompositor).renderFrame(0, mockBitmap);
}
@@ -212,7 +212,7 @@ public void testCreateWithDecodeAlFrames() throws Exception {
isNull(Rect.class)))
.thenReturn(mockAnimatedDrawableBackend);
- when(mMockBitmapFactory.createBitmap(50, 50, DEFAULT_BITMAP_CONFIG))
+ when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG))
.thenReturn(CloseableReference.of(mockBitmap1, FAKE_BITMAP_RESOURCE_RELEASER))
.thenReturn(CloseableReference.of(mockBitmap2, FAKE_BITMAP_RESOURCE_RELEASER));
AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class);
@@ -247,7 +247,7 @@ public void testCreateWithDecodeAlFrames() throws Exception {
any(AnimatedImageResult.class),
isNull(Rect.class));
verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider);
- verify(mMockBitmapFactory, times(2)).createBitmap(50, 50, DEFAULT_BITMAP_CONFIG);
+ verify(mMockBitmapFactory, times(2)).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG);
verifyNoMoreInteractions(mMockBitmapFactory);
verify(mockCompositor).renderFrame(0, mockBitmap1);
verify(mockCompositor).renderFrame(1, mockBitmap2);
@@ -154,7 +154,7 @@ public void testCreateWithPreviewBitmap() throws Exception {
any(AnimatedImageResult.class),
isNull(Rect.class)))
.thenReturn(mockAnimatedDrawableBackend);
- when(mMockBitmapFactory.createBitmap(50, 50, DEFAULT_BITMAP_CONFIG))
+ when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG))
.thenReturn(CloseableReference.of(mockBitmap, FAKE_BITMAP_RESOURCE_RELEASER));
AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class);
PowerMockito.whenNew(AnimatedImageCompositor.class)
@@ -184,7 +184,7 @@ public void testCreateWithPreviewBitmap() throws Exception {
any(AnimatedImageResult.class),
isNull(Rect.class));
verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider);
- verify(mMockBitmapFactory).createBitmap(50, 50, DEFAULT_BITMAP_CONFIG);
+ verify(mMockBitmapFactory).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG);
verifyNoMoreInteractions(mMockBitmapFactory);
verify(mockCompositor).renderFrame(0, mockBitmap);
}
@@ -212,7 +212,7 @@ public void testCreateWithDecodeAlFrames() throws Exception {
isNull(Rect.class)))
.thenReturn(mockAnimatedDrawableBackend);
- when(mMockBitmapFactory.createBitmap(50, 50, DEFAULT_BITMAP_CONFIG))
+ when(mMockBitmapFactory.createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG))
.thenReturn(CloseableReference.of(mockBitmap1, FAKE_BITMAP_RESOURCE_RELEASER))
.thenReturn(CloseableReference.of(mockBitmap2, FAKE_BITMAP_RESOURCE_RELEASER));
AnimatedImageCompositor mockCompositor = mock(AnimatedImageCompositor.class);
@@ -247,7 +247,7 @@ public void testCreateWithDecodeAlFrames() throws Exception {
any(AnimatedImageResult.class),
isNull(Rect.class));
verifyNoMoreInteractions(mMockAnimatedDrawableBackendProvider);
- verify(mMockBitmapFactory, times(2)).createBitmap(50, 50, DEFAULT_BITMAP_CONFIG);
+ verify(mMockBitmapFactory, times(2)).createBitmapInternal(50, 50, DEFAULT_BITMAP_CONFIG);
verifyNoMoreInteractions(mMockBitmapFactory);
verify(mockCompositor).renderFrame(0, mockBitmap1);
verify(mockCompositor).renderFrame(1, mockBitmap2);
@@ -9,6 +9,8 @@
package com.facebook.imagepipeline.bitmaps;
+import javax.annotation.Nullable;
+
import android.graphics.Bitmap;
import com.facebook.common.references.CloseableReference;
@@ -28,10 +30,12 @@
* @throws TooManyBitmapsException if the pool is full
* @throws java.lang.OutOfMemoryError if the Bitmap cannot be allocated
*/
- public abstract CloseableReference<Bitmap> createBitmap(
+ public CloseableReference<Bitmap> createBitmap(
int width,
int height,
- Bitmap.Config bitmapConfig);
+ Bitmap.Config bitmapConfig) {
+ return createBitmap(width, height, bitmapConfig, null);
+ }
/**
* Creates a bitmap of the specified width and height.
@@ -46,4 +50,85 @@
public CloseableReference<Bitmap> createBitmap(int width, int height) {
return createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
+
+ /**
+ * Creates a bitmap of the specified width and height.
+ *
+ * @param width the width of the bitmap
+ * @param height the height of the bitmap
+ * @param bitmapConfig the Bitmap.Config used to create the Bitmap
+ * @param callerContext the Tag to track who create the Bitmap
+ * @return a reference to the bitmap
+ * @throws TooManyBitmapsException if the pool is full
+ * @throws java.lang.OutOfMemoryError if the Bitmap cannot be allocated
+ */
+ public CloseableReference<Bitmap> createBitmap(
+ int width,
+ int height,
+ Bitmap.Config bitmapConfig,
+ @Nullable Object callerContext) {
+ CloseableReference<Bitmap> reference = createBitmapInternal(width, height, bitmapConfig);
+ addBitmapReference(reference.get(), callerContext);
+ return reference;
+ }
+
+ /**
+ * Creates a bitmap of the specified width and height.
+ * The bitmap will be created with the default ARGB_8888 configuration
+ *
+ * @param width the width of the bitmap
+ * @param height the height of the bitmap
+ * @param callerContext the Tag to track who create the Bitmap
+ * @return a reference to the bitmap
+ * @throws TooManyBitmapsException if the pool is full
+ * @throws java.lang.OutOfMemoryError if the Bitmap cannot be allocated
+ */
+ public CloseableReference<Bitmap> createBitmap(
+ int width,
+ int height,
+ @Nullable Object callerContext) {
+ return createBitmap(width, height, Bitmap.Config.ARGB_8888, callerContext);
+ }
+
+ /**
+ * Creates a bitmap of the specified width and height. This is intended for ImagePipeline's
+ * internal use only.
+ *
+ * @param width the width of the bitmap
+ * @param height the height of the bitmap
+ * @param bitmapConfig the Bitmap.Config used to create the Bitmap
+ * @return a reference to the bitmap
+ * @throws TooManyBitmapsException if the pool is full
+ * @throws java.lang.OutOfMemoryError if the Bitmap cannot be allocated
+ */
+ public abstract CloseableReference<Bitmap> createBitmapInternal(
+ int width,
+ int height,
+ Bitmap.Config bitmapConfig);
+
+ private static BitmapCreationObserver sBitmapCreationObserver;
+
+ public void setCreationListener(final BitmapCreationObserver bitmapCreationObserver) {
+ if (sBitmapCreationObserver == null) {
+ sBitmapCreationObserver = bitmapCreationObserver;
+ }
+ }
+
+ public void addBitmapReference(
+ Bitmap bitmap,
+ @Nullable Object callerContext) {
+ if (sBitmapCreationObserver != null) {
+ sBitmapCreationObserver.onBitmapCreated(bitmap, callerContext);
+ }
+ }
+
+ /**
+ * Observer that notifies external creation of bitmap using
+ * {@link PlatformBitmapFactory#createBitmap(int, int)} or
+ * {@link PlatformBitmapFactory#createBitmap(int, int, Bitmap.Config)}.
+ */
+ public interface BitmapCreationObserver {
+
+ void onBitmapCreated(Bitmap bitmap, @Nullable Object callerContext);
+ }
}
@@ -12,12 +12,15 @@
import com.facebook.cache.common.CacheKey;
import com.facebook.common.internal.Supplier;
import com.facebook.common.memory.MemoryTrimmableRegistry;
+import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
import com.facebook.imagepipeline.image.CloseableImage;
public class BitmapCountingMemoryCacheFactory {
public static CountingMemoryCache<CacheKey, CloseableImage> get(
- Supplier<MemoryCacheParams> bitmapMemoryCacheParamsSupplier,
- MemoryTrimmableRegistry memoryTrimmableRegistry) {
+ Supplier<MemoryCacheParams> bitmapMemoryCacheParamsSupplier,
+ MemoryTrimmableRegistry memoryTrimmableRegistry,
+ PlatformBitmapFactory platformBitmapFactory,
+ boolean isExternalCreatedBitmapLogEnabled) {
ValueDescriptor<CloseableImage> valueDescriptor =
new ValueDescriptor<CloseableImage>() {
@@ -30,7 +33,12 @@ public int getSizeInBytes(CloseableImage value) {
CountingMemoryCache.CacheTrimStrategy trimStrategy = new BitmapMemoryCacheTrimStrategy();
CountingMemoryCache<CacheKey, CloseableImage> countingCache =
- new CountingMemoryCache<>(valueDescriptor, trimStrategy, bitmapMemoryCacheParamsSupplier);
+ new CountingMemoryCache<>(
+ valueDescriptor,
+ trimStrategy,
+ bitmapMemoryCacheParamsSupplier,
+ platformBitmapFactory,
+ isExternalCreatedBitmapLogEnabled);
memoryTrimmableRegistry.registerMemoryTrimmable(countingCache);
@@ -14,8 +14,11 @@
import javax.annotation.concurrent.ThreadSafe;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
+import android.graphics.Bitmap;
import android.os.SystemClock;
import com.facebook.common.internal.Preconditions;
@@ -25,6 +28,7 @@
import com.facebook.common.memory.MemoryTrimmable;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.references.ResourceReleaser;
+import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
import com.android.internal.util.Predicate;
@@ -110,6 +114,10 @@ private Entry(K key, CloseableReference<V> valueRef, @Nullable EntryStateObserve
@VisibleForTesting
final CountingLruMap<K, Entry<K, V>> mCachedEntries;
+ @GuardedBy("this")
+ @VisibleForTesting
+ final Map<Bitmap, Object> mOtherEntries = new WeakHashMap<>();
+
private final ValueDescriptor<V> mValueDescriptor;
private final CacheTrimStrategy mCacheTrimStrategy;
@@ -124,14 +132,28 @@ private Entry(K key, CloseableReference<V> valueRef, @Nullable EntryStateObserve
public CountingMemoryCache(
ValueDescriptor<V> valueDescriptor,
CacheTrimStrategy cacheTrimStrategy,
- Supplier<MemoryCacheParams> memoryCacheParamsSupplier) {
+ Supplier<MemoryCacheParams> memoryCacheParamsSupplier,
+ PlatformBitmapFactory platformBitmapFactory,
+ boolean isExternalCreatedBitmapLogEnabled) {
mValueDescriptor = valueDescriptor;
mExclusiveEntries = new CountingLruMap<>(wrapValueDescriptor(valueDescriptor));
mCachedEntries = new CountingLruMap<>(wrapValueDescriptor(valueDescriptor));
mCacheTrimStrategy = cacheTrimStrategy;
mMemoryCacheParamsSupplier = memoryCacheParamsSupplier;
mMemoryCacheParams = mMemoryCacheParamsSupplier.get();
mLastCacheParamsCheck = SystemClock.uptimeMillis();
+
+ if (isExternalCreatedBitmapLogEnabled) {
+ platformBitmapFactory.setCreationListener(
+ new PlatformBitmapFactory.BitmapCreationObserver() {
+ @Override
+ public void onBitmapCreated(
+ Bitmap bitmap,
+ Object callerContext) {
+ mOtherEntries.put(bitmap, callerContext);
+ }
+ });
+ }
}
private ValueDescriptor<Entry<K, V>> wrapValueDescriptor(
Oops, something went wrong.

0 comments on commit b3a41a9

Please sign in to comment.