Remove all hacks around ref counting in Bitmap
Test: refactoring cl.
bug:27762775

Change-Id: If7ebb8d5ee3a3085c1ef9ffc277cf6feaeab89e1
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 6acb76d..e797321 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -31,152 +31,160 @@
 #define DEBUG_PARCEL 0
 #define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
 
+static jclass   gBitmap_class;
+static jfieldID gBitmap_nativePtr;
+static jmethodID gBitmap_constructorMethodID;
+static jmethodID gBitmap_reinitMethodID;
+static jmethodID gBitmap_getAllocationByteCountMethodID;
+
 namespace android {
 
-class WrappedPixelRef : public SkPixelRef {
+class Bitmap {
 public:
-    WrappedPixelRef(Bitmap* wrapper, void* storage,
-            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
-            : SkPixelRef(info)
-            , mBitmap(*wrapper)
-            , mStorage(storage) {
-        reconfigure(info, rowBytes, ctable);
+    Bitmap(PixelRef* pixelRef)
+        : mPixelRef(pixelRef) { }
+
+    void freePixels() {
+        mInfo = mPixelRef->info();
+        mHasHardwareMipMap = mPixelRef->hasHardwareMipMap();
+        mAllocationSize = mPixelRef->getAllocationByteCount();
+        mRowBytes = mPixelRef->rowBytes();
+        mGenerationId = mPixelRef->getGenerationID();
+        mPixelRef.reset();
     }
 
-    ~WrappedPixelRef() {
-        // Tell SkRefCnt that everything is as it expects by forcing
-        // the refcnt to 1
-        internal_dispose_restore_refcnt_to_1();
-        SkSafeUnref(mColorTable);
+    bool valid() {
+        return !!mPixelRef;
     }
 
-    void reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
-        if (kIndex_8_SkColorType != newInfo.colorType()) {
-            ctable = nullptr;
+    PixelRef* pixelRef() { return mPixelRef.get(); }
+
+    void assertValid() {
+        LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
+    }
+
+    void getSkBitmap(SkBitmap* outBitmap) {
+        assertValid();
+        mPixelRef->getSkBitmap(outBitmap);
+    }
+
+    bool hasHardwareMipMap() {
+        if (mPixelRef) {
+            return mPixelRef->hasHardwareMipMap();
         }
-        mRowBytes = rowBytes;
-        if (mColorTable != ctable) {
-            SkSafeUnref(mColorTable);
-            mColorTable = ctable;
-            SkSafeRef(mColorTable);
-        }
-
-        // Need to validate the alpha type to filter against the color type
-        // to prevent things like a non-opaque RGB565 bitmap
-        SkAlphaType alphaType;
-        LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
-                newInfo.colorType(), newInfo.alphaType(), &alphaType),
-                "Failed to validate alpha type!");
-
-        // Dirty hack is dirty
-        // TODO: Figure something out here, Skia's current design makes this
-        // really hard to work with. Skia really, really wants immutable objects,
-        // but with the nested-ref-count hackery going on that's just not
-        // feasible without going insane trying to figure it out
-        SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
-        *myInfo = newInfo;
-        changeAlphaType(alphaType);
-
-        // Docs say to only call this in the ctor, but we're going to call
-        // it anyway even if this isn't always the ctor.
-        // TODO: Fix this too as part of the above TODO
-        setPreLocked(mStorage, mRowBytes, mColorTable);
-    }
-
-    // Can't mark as override since SkPixelRef::rowBytes isn't virtual
-    // but that's OK since we just want BitmapWrapper to be able to rely
-    // on calling rowBytes() on an unlocked pixelref, which it will be
-    // doing on a WrappedPixelRef type, not a SkPixelRef, so static
-    // dispatching will do what we want.
-    size_t rowBytes() const { return mRowBytes; }
-    SkColorTable* colorTable() const { return mColorTable; }
-
-    bool hasHardwareMipMap() const {
         return mHasHardwareMipMap;
     }
 
     void setHasHardwareMipMap(bool hasMipMap) {
-        mHasHardwareMipMap = hasMipMap;
+        assertValid();
+        mPixelRef->setHasHardwareMipMap(hasMipMap);
     }
 
-protected:
-    virtual bool onNewLockPixels(LockRec* rec) override {
-        rec->fPixels = mStorage;
-        rec->fRowBytes = mRowBytes;
-        rec->fColorTable = mColorTable;
-        return true;
+    void setAlphaType(SkAlphaType alphaType) {
+        assertValid();
+        mPixelRef->setAlphaType(alphaType);
     }
 
-    virtual void onUnlockPixels() override {
-        // nothing
+    const SkImageInfo& info() {
+        if (mPixelRef) {
+            return mPixelRef->info();
+        }
+        return mInfo;
     }
 
-    virtual size_t getAllocatedSizeInBytes() const override {
-        return info().getSafeSize(mRowBytes);
+    size_t getAllocationByteCount() const {
+        if (mPixelRef) {
+            return mPixelRef->getAllocationByteCount();
+        }
+        return mAllocationSize;
     }
 
+    size_t rowBytes() const {
+        if (mPixelRef) {
+            return mPixelRef->rowBytes();
+        }
+        return mRowBytes;
+    }
+
+    uint32_t getGenerationID() const {
+        if (mPixelRef) {
+            return mPixelRef->getGenerationID();
+        }
+        return mGenerationId;
+    }
+
+    ~Bitmap() { }
+
 private:
-    Bitmap& mBitmap;
-    void* mStorage;
-    size_t mRowBytes = 0;
-    SkColorTable* mColorTable = nullptr;
-    bool mHasHardwareMipMap = false;
-
-    virtual void internal_dispose() const override {
-        mBitmap.onStrongRefDestroyed();
-    }
+    sk_sp<PixelRef> mPixelRef;
+    SkImageInfo mInfo;
+    bool mHasHardwareMipMap;
+    size_t mAllocationSize;
+    size_t mRowBytes;
+    uint32_t mGenerationId;
 };
 
-Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
-        : mPixelStorageType(PixelStorageType::Heap) {
-    mPixelStorage.heap.address = address;
-    mPixelStorage.heap.size = size;
-    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
-    // Note: this will trigger a call to onStrongRefDestroyed(), but
-    // we want the pixel ref to have a ref count of 0 at this point
-    mPixelRef->unref();
+void PixelRef::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
+    if (kIndex_8_SkColorType != newInfo.colorType()) {
+        ctable = nullptr;
+    }
+    mRowBytes = rowBytes;
+    if (mColorTable.get() != ctable) {
+        mColorTable.reset(ctable);
+    }
+
+    // Need to validate the alpha type to filter against the color type
+    // to prevent things like a non-opaque RGB565 bitmap
+    SkAlphaType alphaType;
+    LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
+            newInfo.colorType(), newInfo.alphaType(), &alphaType),
+            "Failed to validate alpha type!");
+
+    // Dirty hack is dirty
+    // TODO: Figure something out here, Skia's current design makes this
+    // really hard to work with. Skia really, really wants immutable objects,
+    // but with the nested-ref-count hackery going on that's just not
+    // feasible without going insane trying to figure it out
+    SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
+    *myInfo = newInfo;
+    changeAlphaType(alphaType);
+
+    // Docs say to only call this in the ctor, but we're going to call
+    // it anyway even if this isn't always the ctor.
+    // TODO: Fix this too as part of the above TODO
+    setPreLocked(getStorage(), mRowBytes, mColorTable.get());
 }
 
-Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
-            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
-        : mPixelStorageType(PixelStorageType::External) {
+PixelRef::PixelRef(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+            : SkPixelRef(info)
+            , mPixelStorageType(PixelStorageType::Heap) {
+    mPixelStorage.heap.address = address;
+    mPixelStorage.heap.size = size;
+    reconfigure(info, rowBytes, ctable);
+}
+
+PixelRef::PixelRef(void* address, void* context, FreeFunc freeFunc,
+                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+            : SkPixelRef(info)
+            , mPixelStorageType(PixelStorageType::External) {
     mPixelStorage.external.address = address;
     mPixelStorage.external.context = context;
     mPixelStorage.external.freeFunc = freeFunc;
-    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
-    // Note: this will trigger a call to onStrongRefDestroyed(), but
-    // we want the pixel ref to have a ref count of 0 at this point
-    mPixelRef->unref();
+    reconfigure(info, rowBytes, ctable);
 }
 
-Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
-            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
-        : mPixelStorageType(PixelStorageType::Ashmem) {
+PixelRef::PixelRef(void* address, int fd, size_t mappedSize,
+                const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+            : SkPixelRef(info)
+            , mPixelStorageType(PixelStorageType::Ashmem) {
     mPixelStorage.ashmem.address = address;
     mPixelStorage.ashmem.fd = fd;
     mPixelStorage.ashmem.size = mappedSize;
-    mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
-    // Note: this will trigger a call to onStrongRefDestroyed(), but
-    // we want the pixel ref to have a ref count of 0 at this point
-    mPixelRef->unref();
-}
-Bitmap::~Bitmap() {
-    doFreePixels();
+    reconfigure(info, rowBytes, ctable);
 }
 
-void Bitmap::freePixels() {
-    AutoMutex _lock(mLock);
-    if (mPinnedRefCount == 0) {
-        doFreePixels();
-        mPixelStorageType = PixelStorageType::Invalid;
-    }
-}
-
-void Bitmap::doFreePixels() {
+PixelRef::~PixelRef() {
     switch (mPixelStorageType) {
-    case PixelStorageType::Invalid:
-        // already free'd, nothing to do
-        break;
     case PixelStorageType::External:
         mPixelStorage.external.freeFunc(mPixelStorage.external.address,
                 mPixelStorage.external.context);
@@ -191,20 +199,41 @@
     }
 
     if (android::uirenderer::Caches::hasInstance()) {
-        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(
-                mPixelRef->getStableID());
+        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
     }
 }
 
-bool Bitmap::hasHardwareMipMap() {
-    return mPixelRef->hasHardwareMipMap();
+bool PixelRef::hasHardwareMipMap() const {
+    return mHasHardwareMipMap;
 }
 
-void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
-    mPixelRef->setHasHardwareMipMap(hasMipMap);
+void PixelRef::setHasHardwareMipMap(bool hasMipMap) {
+    mHasHardwareMipMap = hasMipMap;
 }
 
-int Bitmap::getAshmemFd() const {
+void* PixelRef::getStorage() const {
+    switch (mPixelStorageType) {
+    case PixelStorageType::External:
+        return mPixelStorage.external.address;
+    case PixelStorageType::Ashmem:
+        return mPixelStorage.ashmem.address;
+    case PixelStorageType::Heap:
+        return mPixelStorage.heap.address;
+    }
+}
+
+bool PixelRef::onNewLockPixels(LockRec* rec) {
+    rec->fPixels = getStorage();
+    rec->fRowBytes = mRowBytes;
+    rec->fColorTable = mColorTable.get();
+    return true;
+}
+
+size_t PixelRef::getAllocatedSizeInBytes() const {
+    return info().getSafeSize(mRowBytes);
+}
+
+int PixelRef::getAshmemFd() const {
     switch (mPixelStorageType) {
     case PixelStorageType::Ashmem:
         return mPixelStorage.ashmem.fd;
@@ -213,7 +242,7 @@
     }
 }
 
-size_t Bitmap::getAllocationByteCount() const {
+size_t PixelRef::getAllocationByteCount() const {
     switch (mPixelStorageType) {
     case PixelStorageType::Heap:
         return mPixelStorage.heap.size;
@@ -222,104 +251,24 @@
     }
 }
 
-const SkImageInfo& Bitmap::info() const {
-    return mPixelRef->info();
-}
-
-size_t Bitmap::rowBytes() const {
-    return mPixelRef->rowBytes();
-}
-
-SkPixelRef* Bitmap::peekAtPixelRef() const {
-    assertValid();
-    return mPixelRef.get();
-}
-
-SkPixelRef* Bitmap::refPixelRef() {
-    assertValid();
-    android::AutoMutex _lock(mLock);
-    return refPixelRefLocked();
-}
-
-SkPixelRef* Bitmap::refPixelRefLocked() {
-    mPixelRef->ref();
-    if (mPixelRef->unique()) {
-        // We just restored this from 0, pin the pixels and inc the strong count
-        // Note that there *might be* an incoming onStrongRefDestroyed from whatever
-        // last unref'd
-        mPinnedRefCount++;
-    }
-    return mPixelRef.get();
-}
-
-void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
-        SkColorTable* ctable) {
-    mPixelRef->reconfigure(info, rowBytes, ctable);
-}
-
-void Bitmap::reconfigure(const SkImageInfo& info) {
+void PixelRef::reconfigure(const SkImageInfo& info) {
     reconfigure(info, info.minRowBytes(), nullptr);
 }
 
-void Bitmap::setAlphaType(SkAlphaType alphaType) {
+void PixelRef::setAlphaType(SkAlphaType alphaType) {
     if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
         return;
     }
 
-    mPixelRef->changeAlphaType(alphaType);
+    changeAlphaType(alphaType);
 }
 
-void Bitmap::detachFromJava() {
-    bool disposeSelf;
-    {
-        android::AutoMutex _lock(mLock);
-        mAttachedToJava = false;
-        disposeSelf = shouldDisposeSelfLocked();
-    }
-    if (disposeSelf) {
-        delete this;
-    }
+void PixelRef::getSkBitmap(SkBitmap* outBitmap) {
+    outBitmap->setInfo(info(), rowBytes());
+    outBitmap->setPixelRef(this);
+    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
 }
 
-bool Bitmap::shouldDisposeSelfLocked() {
-    return mPinnedRefCount == 0 && !mAttachedToJava;
-}
-
-
-void Bitmap::onStrongRefDestroyed() {
-    bool disposeSelf = false;
-    {
-        android::AutoMutex _lock(mLock);
-        if (mPinnedRefCount > 0) {
-            mPinnedRefCount--;
-            if (mPinnedRefCount == 0) {
-                disposeSelf = shouldDisposeSelfLocked();
-            }
-        }
-    }
-    if (disposeSelf) {
-        delete this;
-    }
-}
-
-void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
-    assertValid();
-    android::AutoMutex _lock(mLock);
-    // Safe because mPixelRef is a WrappedPixelRef type, otherwise rowBytes()
-    // would require locking the pixels first.
-    outBitmap->setInfo(mPixelRef->info(), mPixelRef->rowBytes());
-    outBitmap->setPixelRef(refPixelRefLocked())->unref();
-    outBitmap->setHasHardwareMipMap(hasHardwareMipMap());
-}
-
-void Bitmap::assertValid() const {
-    LOG_ALWAYS_FATAL_IF(mPixelStorageType == PixelStorageType::Invalid,
-            "Error, cannot access an invalid/free'd bitmap here!");
-}
-
-} // namespace android
-
-using namespace android;
 
 // Convenience class that does not take a global ref on the pixels, relying
 // on the caller already having a local JNI ref
@@ -333,7 +282,7 @@
     }
 
     void* pixels() {
-        return mBitmap->peekAtPixelRef()->pixels();
+        return mBitmap->pixelRef()->pixels();
     }
 
     bool valid() {
@@ -344,6 +293,78 @@
     Bitmap* mBitmap;
 };
 
+namespace bitmap {
+
+// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
+static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
+    // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
+    // irrelevant. This just tests to ensure that the SkAlphaType is not
+    // opposite of isPremultiplied.
+    if (isPremultiplied) {
+        SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
+    } else {
+        SkASSERT(info.alphaType() != kPremul_SkAlphaType);
+    }
+}
+
+void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
+        bool isPremultiplied)
+{
+    // The caller needs to have already set the alpha type properly, so the
+    // native SkBitmap stays in sync with the Java Bitmap.
+    assert_premultiplied(info, isPremultiplied);
+
+    env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
+            info.width(), info.height(), isPremultiplied);
+}
+
+int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
+{
+    return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
+}
+
+jobject createBitmap(JNIEnv* env, PixelRef* pixelRef,
+        int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
+        int density) {
+    bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
+    bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
+    // The caller needs to have already set the alpha type properly, so the
+    // native SkBitmap stays in sync with the Java Bitmap.
+    assert_premultiplied(pixelRef->info(), isPremultiplied);
+    Bitmap* bitmap = new Bitmap(pixelRef);
+    jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
+            reinterpret_cast<jlong>(bitmap), pixelRef->width(), pixelRef->height(), density, isMutable,
+            isPremultiplied, ninePatchChunk, ninePatchInsets);
+
+    if (env->ExceptionCheck() != 0) {
+        ALOGE("*** Uncaught exception returned from Java call!\n");
+        env->ExceptionDescribe();
+    }
+    return obj;
+}
+
+void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
+    LocalScopedBitmap bitmap(bitmapHandle);
+    bitmap->getSkBitmap(outBitmap);
+}
+
+PixelRef* toPixelRef(JNIEnv* env, jobject bitmap) {
+    SkASSERT(env);
+    SkASSERT(bitmap);
+    SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
+    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
+    LocalScopedBitmap localBitmap(bitmapHandle);
+    localBitmap->assertValid();
+    return localBitmap->pixelRef();
+}
+
+} // namespace bitmap
+
+} // namespace android
+
+using namespace android;
+using namespace android::bitmap;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Conversions to/from SkColor, for get/setPixels, and the create method, which
 // is basically like setPixels
@@ -649,8 +670,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 static int getPremulBitmapCreateFlags(bool isMutable) {
-    int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
-    if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
+    int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
+    if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
     return flags;
 }
 
@@ -674,7 +695,7 @@
     SkBitmap bitmap;
     bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
 
-    Bitmap* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
+    PixelRef* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
     if (!nativeBitmap) {
         return NULL;
     }
@@ -684,7 +705,7 @@
                 0, 0, width, height, bitmap);
     }
 
-    return GraphicsJNI::createBitmap(env, nativeBitmap,
+    return createBitmap(env, nativeBitmap,
             getPremulBitmapCreateFlags(isMutable));
 }
 
@@ -699,29 +720,28 @@
     if (!src.copyTo(&result, dstCT, &allocator)) {
         return NULL;
     }
-    Bitmap* bitmap = allocator.getStorageObjAndReset();
-    return GraphicsJNI::createBitmap(env, bitmap,
-            getPremulBitmapCreateFlags(isMutable));
+    auto pixelRef = allocator.getStorageObjAndReset();
+    return createBitmap(env, pixelRef, getPremulBitmapCreateFlags(isMutable));
 }
 
-static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
+static PixelRef* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
     SkBitmap result;
 
     AshmemPixelAllocator allocator(env);
     if (!src.copyTo(&result, dstCT, &allocator)) {
         return NULL;
     }
-    Bitmap* bitmap = allocator.getStorageObjAndReset();
-    bitmap->peekAtPixelRef()->setImmutable();
-    return bitmap;
+    auto pixelRef = allocator.getStorageObjAndReset();
+    pixelRef->setImmutable();
+    return pixelRef;
 }
 
 static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
     SkBitmap src;
     reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
     SkColorType dstCT = src.colorType();
-    Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
-    jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+    auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
+    jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
     return ret;
 }
 
@@ -729,13 +749,13 @@
     SkBitmap src;
     reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
-    Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
-    jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+    auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
+    jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
     return ret;
 }
 
 static void Bitmap_destruct(Bitmap* bitmap) {
-    bitmap->detachFromJava();
+    delete bitmap;
 }
 
 static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
@@ -751,6 +771,7 @@
 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
         jint width, jint height, jint configHandle, jboolean requestPremul) {
     LocalScopedBitmap bitmap(bitmapHandle);
+    bitmap->assertValid();
     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
 
     // ARGB_4444 is a deprecated format, convert automatically to 8888
@@ -773,7 +794,7 @@
         // Otherwise respect the premultiplied request.
         alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
     }
-    bitmap->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType));
+    bitmap->pixelRef()->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType));
 }
 
 // These must match the int values in Bitmap.java
@@ -843,7 +864,7 @@
 
 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
-    return static_cast<jint>(bitmap->peekAtPixelRef()->getGenerationID());
+    return static_cast<jint>(bitmap->getGenerationID());
 }
 
 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -955,7 +976,7 @@
     }
 
     // Map the bitmap in place from the ashmem region if possible otherwise copy.
-    Bitmap* nativeBitmap;
+    PixelRef* nativeBitmap;
     if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
 #if DEBUG_PARCEL
         ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
@@ -1018,7 +1039,7 @@
         blob.release();
     }
 
-    return GraphicsJNI::createBitmap(env, nativeBitmap,
+    return createBitmap(env, nativeBitmap,
             getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
 }
 
@@ -1034,7 +1055,7 @@
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
     SkBitmap bitmap;
 
-    android::Bitmap* androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
+    auto androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
     androidBitmap->getSkBitmap(&bitmap);
 
     p->writeInt32(isMutable);
@@ -1061,7 +1082,7 @@
 
     // Transfer the underlying ashmem region if we have one and it's immutable.
     android::status_t status;
-    int fd = androidBitmap->getAshmemFd();
+    int fd = androidBitmap->pixelRef()->getAshmemFd();
     if (fd >= 0 && !isMutable && p->allowFds()) {
 #if DEBUG_PARCEL
         ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
@@ -1131,7 +1152,7 @@
         env->ReleaseIntArrayElements(offsetXY, array, 0);
     }
 
-    return GraphicsJNI::createBitmap(env, allocator.getStorageObjAndReset(),
+    return createBitmap(env, allocator.getStorageObjAndReset(),
             getPremulBitmapCreateFlags(true));
 }
 
@@ -1307,7 +1328,7 @@
 
 static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
-    SkPixelRef* pixelRef = bitmap.valid() ? bitmap->peekAtPixelRef() : nullptr;
+    SkPixelRef* pixelRef = bitmap->pixelRef();
     SkSafeRef(pixelRef);
     return reinterpret_cast<jlong>(pixelRef);
 }
@@ -1326,6 +1347,20 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+static jclass make_globalref(JNIEnv* env, const char classname[])
+{
+    jclass c = env->FindClass(classname);
+    SkASSERT(c);
+    return (jclass) env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+                                const char fieldname[], const char type[])
+{
+    jfieldID id = env->GetFieldID(clazz, fieldname, type);
+    SkASSERT(id);
+    return id;
+}
 
 static const JNINativeMethod gBitmapMethods[] = {
     {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
@@ -1374,6 +1409,11 @@
 
 int register_android_graphics_Bitmap(JNIEnv* env)
 {
+    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
+    gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
+    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
+    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
+    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
     return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
                                          NELEM(gBitmapMethods));
-}
+}
\ No newline at end of file
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index 9ae1f3f..8e631ee 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -20,80 +20,91 @@
 #include <SkBitmap.h>
 #include <SkColorTable.h>
 #include <SkImageInfo.h>
-#include <utils/Mutex.h>
-#include <memory>
+#include <SkPixelRef.h>
 
 namespace android {
 
 enum class PixelStorageType {
-    Invalid,
     External,
     Heap,
     Ashmem,
 };
 
-class WrappedPixelRef;
-
 typedef void (*FreeFunc)(void* addr, void* context);
 
-/**
- * Glue-thingy that deals with managing the interaction between the Java
- * Bitmap object & SkBitmap along with trying to map a notion of strong/weak
- * lifecycles onto SkPixelRef which only has strong counts to avoid requiring
- * two GC passes to free the byte[] that backs a Bitmap.
- *
- * Since not all Bitmaps are byte[]-backed it also supports external allocations,
- * which currently is used by screenshots to wrap a gralloc buffer.
- */
-class Bitmap {
-public:
-    Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes,
-            SkColorTable* ctable);
-    Bitmap(void* address, void* context, FreeFunc freeFunc,
-            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
-    Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
-            size_t rowBytes, SkColorTable* ctable);
+class PixelRef;
 
-    const SkImageInfo& info() const;
+namespace bitmap {
+
+enum BitmapCreateFlags {
+    kBitmapCreateFlag_None = 0x0,
+    kBitmapCreateFlag_Mutable = 0x1,
+    kBitmapCreateFlag_Premultiplied = 0x2,
+};
+
+jobject createBitmap(JNIEnv* env, PixelRef* bitmap,
+            int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL,
+            jobject ninePatchInsets = NULL, int density = -1);
+
+
+void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap);
+
+PixelRef* toPixelRef(JNIEnv* env, jobject bitmap);
+
+/** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in
+    sync with isPremultiplied
+*/
+void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
+        bool isPremultiplied);
+
+int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);
+
+} // namespace bitmap
+
+class PixelRef : public SkPixelRef {
+public:
+    PixelRef(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes,
+            SkColorTable* ctable);
+    PixelRef(void* address, void* context, FreeFunc freeFunc,
+            const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
+    PixelRef(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
+            size_t rowBytes, SkColorTable* ctable);
 
     int width() const { return info().width(); }
     int height() const { return info().height(); }
-    size_t rowBytes() const;
-    SkPixelRef* peekAtPixelRef() const;
-    SkPixelRef* refPixelRef();
-    bool valid() const { return mPixelStorageType != PixelStorageType::Invalid; }
 
+    // Can't mark as override since SkPixelRef::rowBytes isn't virtual
+    // but that's OK since we just want Bitmap to be able to rely
+    // on calling rowBytes() on an unlocked pixelref, which it will be
+    // doing on a PixelRef type, not a SkPixelRef, so static
+    // dispatching will do what we want.
+    size_t rowBytes() const { return mRowBytes; }
     void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
     void reconfigure(const SkImageInfo& info);
     void setAlphaType(SkAlphaType alphaType);
 
     void getSkBitmap(SkBitmap* outBitmap);
-    void detachFromJava();
 
-    void freePixels();
-
-    bool hasHardwareMipMap();
-    void setHasHardwareMipMap(bool hasMipMap);
     int getAshmemFd() const;
     size_t getAllocationByteCount() const;
 
+protected:
+    virtual bool onNewLockPixels(LockRec* rec) override;
+    virtual void onUnlockPixels() override { };
+    virtual size_t getAllocatedSizeInBytes() const override;
 private:
-    friend class WrappedPixelRef;
-
-    ~Bitmap();
+    friend class Bitmap;
+    virtual ~PixelRef();
     void doFreePixels();
-    void onStrongRefDestroyed();
+    void* getStorage() const;
+    void setHasHardwareMipMap(bool hasMipMap);
+    bool hasHardwareMipMap() const;
 
-    void pinPixelsLocked();
-    bool shouldDisposeSelfLocked();
-    void assertValid() const;
-    SkPixelRef* refPixelRefLocked();
-
-    android::Mutex mLock;
-    int mPinnedRefCount = 0;
-    std::unique_ptr<WrappedPixelRef> mPixelRef;
     PixelStorageType mPixelStorageType;
-    bool mAttachedToJava = true;
+
+    size_t mRowBytes = 0;
+    sk_sp<SkColorTable> mColorTable;
+    bool mHasHardwareMipMap = false;
 
     union {
         struct {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 5a540ce..5bb0274 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -162,7 +162,7 @@
 
 class RecyclingPixelAllocator : public SkBitmap::Allocator {
 public:
-    RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size)
+    RecyclingPixelAllocator(android::PixelRef* bitmap, unsigned int size)
             : mBitmap(bitmap), mSize(size) {
     }
 
@@ -190,7 +190,8 @@
         }
 
         mBitmap->reconfigure(info, bitmap->rowBytes(), ctable);
-        bitmap->setPixelRef(mBitmap->refPixelRef())->unref();
+        mBitmap->ref();
+        bitmap->setPixelRef(mBitmap)->unref();
 
         // since we're already allocated, we lockPixels right away
         // HeapAllocator behaves this way too
@@ -199,7 +200,7 @@
     }
 
 private:
-    android::Bitmap* const mBitmap;
+    android::PixelRef* const mBitmap;
     const unsigned int mSize;
 };
 
@@ -326,16 +327,16 @@
         scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
     }
 
-    android::Bitmap* reuseBitmap = nullptr;
+    android::PixelRef* reuseBitmap = nullptr;
     unsigned int existingBufferSize = 0;
     if (javaBitmap != NULL) {
-        reuseBitmap = GraphicsJNI::getBitmap(env, javaBitmap);
-        if (reuseBitmap->peekAtPixelRef()->isImmutable()) {
+        reuseBitmap = bitmap::toPixelRef(env, javaBitmap);
+        if (reuseBitmap->isImmutable()) {
             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
             javaBitmap = NULL;
             reuseBitmap = nullptr;
         } else {
-            existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
+            existingBufferSize = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
         }
     }
 
@@ -529,18 +530,18 @@
 
     bool isPremultiplied = !requireUnpremultiplied;
     if (javaBitmap != nullptr) {
-        GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
+        bitmap::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
         outputBitmap.notifyPixelsChanged();
         // If a java bitmap was passed in for reuse, pass it back
         return javaBitmap;
     }
 
     int bitmapCreateFlags = 0x0;
-    if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
-    if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+    if (isMutable) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Mutable;
+    if (isPremultiplied) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
 
     // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
+    return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
             bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
 }
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 21850bd..7d0915b 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -148,14 +148,14 @@
     }
 
     // Recycle a bitmap if possible.
-    android::Bitmap* recycledBitmap = nullptr;
+    android::PixelRef* recycledBitmap = nullptr;
     size_t recycledBytes = 0;
     if (javaBitmap) {
-        recycledBitmap = GraphicsJNI::getBitmap(env, javaBitmap);
-        if (recycledBitmap->peekAtPixelRef()->isImmutable()) {
+        recycledBitmap = bitmap::toPixelRef(env, javaBitmap);
+        if (recycledBitmap->isImmutable()) {
             ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
         }
-        recycledBytes = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
+        recycledBytes = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
     }
 
     // Set up the pixel allocator
@@ -198,9 +198,9 @@
 
     int bitmapCreateFlags = 0;
     if (!requireUnpremul) {
-        bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+        bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
     }
-    return GraphicsJNI::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
+    return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
 }
 
 static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 8cee814..8a55052 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -157,12 +157,6 @@
 static jfieldID gPointF_xFieldID;
 static jfieldID gPointF_yFieldID;
 
-static jclass   gBitmap_class;
-static jfieldID gBitmap_nativePtr;
-static jmethodID gBitmap_constructorMethodID;
-static jmethodID gBitmap_reinitMethodID;
-static jmethodID gBitmap_getAllocationByteCountMethodID;
-
 static jclass   gBitmapConfig_class;
 static jfieldID gBitmapConfig_nativeInstanceID;
 
@@ -342,24 +336,15 @@
     return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
 }
 
-android::Bitmap* GraphicsJNI::getBitmap(JNIEnv* env, jobject bitmap) {
-    SkASSERT(env);
-    SkASSERT(bitmap);
-    SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
-    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
-    android::Bitmap* b = reinterpret_cast<android::Bitmap*>(bitmapHandle);
-    SkASSERT(b);
-    return b;
-}
-
 void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
-    getBitmap(env, bitmap)->getSkBitmap(outBitmap);
+    android::bitmap::toPixelRef(env, bitmap)->getSkBitmap(outBitmap);
 }
 
 SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject bitmap) {
-    return getBitmap(env, bitmap)->refPixelRef();
+    SkPixelRef* pixelRef = android::bitmap::toPixelRef(env, bitmap);
+    pixelRef->ref();
+    return pixelRef;
 }
-
 SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
     SkASSERT(env);
     if (NULL == jconfig) {
@@ -394,50 +379,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////
 
-// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
-static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
-    // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
-    // irrelevant. This just tests to ensure that the SkAlphaType is not
-    // opposite of isPremultiplied.
-    if (isPremultiplied) {
-        SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
-    } else {
-        SkASSERT(info.alphaType() != kPremul_SkAlphaType);
-    }
-}
-
-jobject GraphicsJNI::createBitmap(JNIEnv* env, android::Bitmap* bitmap,
-        int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
-        int density) {
-    bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
-    bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
-    // The caller needs to have already set the alpha type properly, so the
-    // native SkBitmap stays in sync with the Java Bitmap.
-    assert_premultiplied(bitmap->info(), isPremultiplied);
-
-    jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
-            reinterpret_cast<jlong>(bitmap), bitmap->width(), bitmap->height(), density, isMutable,
-            isPremultiplied, ninePatchChunk, ninePatchInsets);
-    hasException(env); // For the side effect of logging.
-    return obj;
-}
-
-void GraphicsJNI::reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
-        bool isPremultiplied)
-{
-    // The caller needs to have already set the alpha type properly, so the
-    // native SkBitmap stays in sync with the Java Bitmap.
-    assert_premultiplied(info, isPremultiplied);
-
-    env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
-            info.width(), info.height(), isPremultiplied);
-}
-
-int GraphicsJNI::getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
-{
-    return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
-}
-
 jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
 {
     SkASSERT(bitmap != NULL);
@@ -482,7 +423,7 @@
     return true;
 }
 
-android::Bitmap* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+android::PixelRef* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
     const SkImageInfo& info = bitmap->info();
     if (info.colorType() == kUnknown_SkColorType) {
         LOG_ALWAYS_FATAL("unknown bitmap configuration");
@@ -503,7 +444,7 @@
         return nullptr;
     }
 
-    android::Bitmap* wrapper = new android::Bitmap(addr, size, info, rowBytes, ctable);
+    auto wrapper = new android::PixelRef(addr, size, info, rowBytes, ctable);
     wrapper->getSkBitmap(bitmap);
     // since we're already allocated, we lockPixels right away
     // HeapAllocator behaves this way too
@@ -566,7 +507,7 @@
     return true;
 }
 
-android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+android::PixelRef* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
                                                      SkColorTable* ctable) {
     int fd;
 
@@ -603,7 +544,7 @@
         return nullptr;
     }
 
-    android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable);
+    auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable);
     wrapper->getSkBitmap(bitmap);
     // since we're already allocated, we lockPixels right away
     // HeapAllocator behaves this way too
@@ -612,7 +553,7 @@
     return wrapper;
 }
 
-android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+android::PixelRef* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
         SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly) {
     const SkImageInfo& info = bitmap->info();
     if (info.colorType() == kUnknown_SkColorType) {
@@ -634,7 +575,7 @@
     // attempting to compute our own.
     const size_t rowBytes = bitmap->rowBytes();
 
-    android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable);
+    auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable);
     wrapper->getSkBitmap(bitmap);
     if (readOnly) {
         bitmap->pixelRef()->setImmutable();
@@ -647,24 +588,15 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-
-HeapAllocator::HeapAllocator() {}
-
-HeapAllocator::~HeapAllocator() {
-    if (mStorage) {
-        mStorage->detachFromJava();
-    }
-}
-
 bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
-    mStorage = GraphicsJNI::allocateHeapPixelRef(bitmap, ctable);
-    return mStorage != nullptr;
+    mStorage.reset(GraphicsJNI::allocateHeapPixelRef(bitmap, ctable));
+    return !!mStorage;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 RecyclingClippingPixelAllocator::RecyclingClippingPixelAllocator(
-        android::Bitmap* recycledBitmap, size_t recycledBytes)
+        android::PixelRef* recycledBitmap, size_t recycledBytes)
     : mRecycledBitmap(recycledBitmap)
     , mRecycledBytes(recycledBytes)
     , mSkiaBitmap(nullptr)
@@ -707,7 +639,8 @@
         // skbug.com/4538: We also need to make sure that the rowBytes on the pixel ref
         //                 match the rowBytes on the bitmap.
         bitmap->setInfo(bitmap->info(), rowBytes);
-        bitmap->setPixelRef(mRecycledBitmap->refPixelRef())->unref();
+        mRecycledBitmap->ref();
+        bitmap->setPixelRef(mRecycledBitmap)->unref();
 
         // Make sure that the recycled bitmap has the correct alpha type.
         mRecycledBitmap->setAlphaType(bitmap->alphaType());
@@ -734,7 +667,8 @@
 
 void RecyclingClippingPixelAllocator::copyIfNecessary() {
     if (mNeedsCopy) {
-        SkPixelRef* recycledPixels = mRecycledBitmap->refPixelRef();
+        mRecycledBitmap->ref();
+        SkPixelRef* recycledPixels = mRecycledBitmap;
         void* dst = recycledPixels->pixels();
         const size_t dstRowBytes = mRecycledBitmap->rowBytes();
         const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(),
@@ -759,16 +693,10 @@
             "env->GetJavaVM failed");
 }
 
-AshmemPixelAllocator::~AshmemPixelAllocator() {
-    if (mStorage) {
-        mStorage->detachFromJava();
-    }
-}
-
 bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
     JNIEnv* env = vm2env(mJavaVM);
-    mStorage = GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable);
-    return mStorage != nullptr;
+    mStorage.reset(GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable));
+    return !!mStorage;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -813,11 +741,6 @@
     gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
     gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
 
-    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
-    gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
-    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
-    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
-    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
     gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
     gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V");
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 738ad54..ceda3cd 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -23,12 +23,6 @@
 
 class GraphicsJNI {
 public:
-    enum BitmapCreateFlags {
-        kBitmapCreateFlag_None = 0x0,
-        kBitmapCreateFlag_Mutable = 0x1,
-        kBitmapCreateFlag_Premultiplied = 0x2,
-    };
-
     // returns true if an exception is set (and dumps it out to the Log)
     static bool hasException(JNIEnv*);
 
@@ -51,7 +45,6 @@
     static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
 
     static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
-    static android::Bitmap* getBitmap(JNIEnv*, jobject bitmap);
     static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
     static SkPixelRef* refSkPixelRef(JNIEnv*, jobject bitmap);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
@@ -73,32 +66,16 @@
     */
     static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig);
 
-    /*
-     * Create a java Bitmap object given the native bitmap
-     * bitmap's SkAlphaType must already be in sync with bitmapCreateFlags.
-    */
-    static jobject createBitmap(JNIEnv* env, android::Bitmap* bitmap,
-            int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL,
-            jobject ninePatchInsets = NULL, int density = -1);
-
-    /** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in
-        sync with isPremultiplied
-    */
-    static void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
-            bool isPremultiplied);
-
-    static int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);
-
     static jobject createRegion(JNIEnv* env, SkRegion* region);
 
     static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
 
-    static android::Bitmap* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
+    static android::PixelRef* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
 
-    static android::Bitmap* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+    static android::PixelRef* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
             SkColorTable* ctable);
 
-    static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+    static android::PixelRef* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
             SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly);
 
     /**
@@ -120,23 +97,21 @@
 
 class HeapAllocator : public SkBRDAllocator {
 public:
-   HeapAllocator();
-    ~HeapAllocator();
+   HeapAllocator() { };
+    ~HeapAllocator() { };
 
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) override;
 
     /**
      * Fetches the backing allocation object. Must be called!
      */
-    android::Bitmap* getStorageObjAndReset() {
-        android::Bitmap* result = mStorage;
-        mStorage = NULL;
-        return result;
+    android::PixelRef* getStorageObjAndReset() {
+        return mStorage.release();
     };
 
     SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; }
 private:
-    android::Bitmap* mStorage = nullptr;
+    sk_sp<android::PixelRef> mStorage;
 };
 
 /**
@@ -169,7 +144,7 @@
 class RecyclingClippingPixelAllocator : public SkBRDAllocator {
 public:
 
-    RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap,
+    RecyclingClippingPixelAllocator(android::PixelRef* recycledBitmap,
             size_t recycledBytes);
 
     ~RecyclingClippingPixelAllocator();
@@ -194,7 +169,7 @@
     SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kNo_ZeroInitialized; }
 
 private:
-    android::Bitmap* mRecycledBitmap;
+    android::PixelRef* mRecycledBitmap;
     const size_t     mRecycledBytes;
     SkBitmap*        mSkiaBitmap;
     bool             mNeedsCopy;
@@ -203,17 +178,15 @@
 class AshmemPixelAllocator : public SkBitmap::Allocator {
 public:
     explicit AshmemPixelAllocator(JNIEnv* env);
-    ~AshmemPixelAllocator();
+    ~AshmemPixelAllocator() { };
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
-    android::Bitmap* getStorageObjAndReset() {
-        android::Bitmap* result = mStorage;
-        mStorage = NULL;
-        return result;
+    android::PixelRef* getStorageObjAndReset() {
+        return mStorage.release();
     };
 
 private:
     JavaVM* mJavaVM;
-    android::Bitmap* mStorage = nullptr;
+    sk_sp<android::PixelRef> mStorage;
 };
 
 
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index d5a7a90..d4121ad 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -341,9 +341,8 @@
         jlong paintHandle, jint dstDensity, jint srcDensity) {
 
     Canvas* canvas = get_canvas(canvasHandle);
-    Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
     SkBitmap skiaBitmap;
-    bitmap->getSkBitmap(&skiaBitmap);
+    bitmap::toSkBitmap(bitmapHandle, &skiaBitmap);
     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 73b3f52..5d53b3f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -184,14 +184,14 @@
         return NULL;
     }
 
-    Bitmap* bitmap = new Bitmap(
+    auto pixelRef = new PixelRef(
             (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
             screenshotInfo, rowBytes, nullptr);
     screenshot.release();
-    bitmap->peekAtPixelRef()->setImmutable();
+    pixelRef->setImmutable();
 
-    return GraphicsJNI::createBitmap(env, bitmap,
-            GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
+    return bitmap::createBitmap(env, pixelRef,
+            bitmap::kBitmapCreateFlag_Premultiplied, NULL);
 }
 
 static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,