//frameworks\base\libs\hwui\jni\BitmapFactory.cpp static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream, jobject padding, jobject options, jlong inBitmapHandle, jlong colorSpaceHandle){ ...... //代码省略 // Scale is necessary due to density differences. if (scale != 1.0f) { willScale = true; scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f); scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f); }
android::Bitmap* reuseBitmap = nullptr; unsignedint existingBufferSize = 0; if (javaBitmap != nullptr) { reuseBitmap = &bitmap::toBitmap(inBitmapHandle); if (reuseBitmap->isImmutable()) { ALOGW("Unable to reuse an immutable bitmap as an image decoder target."); javaBitmap = nullptr; reuseBitmap = nullptr; } else { existingBufferSize = reuseBitmap->getAllocationByteCount(); } }
HeapAllocator defaultAllocator; RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize); ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize); SkBitmap::HeapAllocator heapAllocator; SkBitmap::Allocator* decodeAllocator; if (javaBitmap != nullptr && willScale) { // This will allocate pixels using a HeapAllocator, since there will be an extra // scaling step that copies these pixels into Java memory. This allocator // also checks that the recycled javaBitmap is large enough. decodeAllocator = &scaleCheckingAllocator; } elseif (javaBitmap != nullptr) { decodeAllocator = &recyclingAllocator; } elseif (willScale || isHardware) { // This will allocate pixels using a HeapAllocator, // for scale case: there will be an extra scaling step. // for hardware case: there will be extra swizzling & upload to gralloc step. decodeAllocator = &heapAllocator; } else { decodeAllocator = &defaultAllocator; } ...... SkBitmap decodingBitmap; //SkBitmap 是skia库中的类 //decodingBitmap.tryAllocPixels的作用是分配piexel内存,最终调用的是 //decodeAllocator->allocPixelRef(this); if (!decodingBitmap.setInfo(bitmapInfo) || !decodingBitmap.tryAllocPixels(decodeAllocator)) { returnnullptr; }
// Use SkAndroidCodec to perform the decode. SkAndroidCodec::AndroidOptions codecOptions; codecOptions.fZeroInitialized = decodeAllocator == &defaultAllocator ? SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized; codecOptions.fSampleSize = sampleSize; //codec指的是SkAndroidCodec,是skia库中的类。下面这句代码就是真正的解码了 SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(), decodingBitmap.rowBytes(), &codecOptions); ...... //按比例缩放位图 SkBitmap outputBitmap; if (willScale) { // Set the allocator for the outputBitmap. SkBitmap::Allocator* outputAllocator; if (javaBitmap != nullptr) { outputAllocator = &recyclingAllocator; } else { outputAllocator = &defaultAllocator; }
SkColorType scaledColorType = decodingBitmap.colorType(); // FIXME: If the alphaType is kUnpremul and the image has alpha, the // colors may not be correct, since Skia does not yet support drawing // to/from unpremultiplied bitmaps. outputBitmap.setInfo( bitmapInfo.makeWH(scaledWidth, scaledHeight).makeColorType(scaledColorType)); if (!outputBitmap.tryAllocPixels(outputAllocator)) { // This should only fail on OOM. The recyclingAllocator should have // enough memory since we check this before decoding using the // scaleCheckingAllocator. returnnullObjectReturn("allocation failed for scaled bitmap"); }
SkPaint paint; // kSrc_Mode instructs us to overwrite the uninitialized pixels in // outputBitmap. Otherwise we would blend by default, which is not // what we want. paint.setBlendMode(SkBlendMode::kSrc);
SkCanvas canvas(outputBitmap, SkCanvas::ColorBehavior::kLegacy); canvas.scale(scaleX, scaleY); decodingBitmap.setImmutable(); // so .asImage() doesn't make a copy canvas.drawImage(decodingBitmap.asImage(), 0.0f, 0.0f, SkSamplingOptions(SkFilterMode::kLinear), &paint); } else { outputBitmap.swap(decodingBitmap); }
...... //硬件位图 if (isHardware) { //GPU中分配位图内存。原outputBitmap是否需要释放呢?在哪释放? sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(outputBitmap); if (!hardwareBitmap.get()) { returnnullObjectReturn("Failed to allocate a hardware bitmap"); } //创建java层Bitmap,此处的hardwareBitmap.release()不是资源回收的意思,而是取出sk_sp中的Bitmap实例。 return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1); }
// now create the java bitmap return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(), bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1); }
// we must respect the rowBytes value already set on the bitmap instead of // attempting to compute our own. constsize_t rowBytes = bitmap->rowBytes(); if (!Bitmap::computeAllocationSize(rowBytes, bitmap->height(), &size)) { returnnullptr; }
//external\skia\src\core\SkBitmap.cpp bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst) { const SkImageInfo& info = dst->info(); if (kUnknown_SkColorType == info.colorType()) { returnfalse; } sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, dst->rowBytes()); if (!pr) { returnfalse; } dst->setPixelRef(std::move(pr), 0, 0); returntrue; } //external\skia\src\core\SkMallocPixelRef.cpp sk_sp<SkPixelRef> SkMallocPixelRef::MakeAllocate(const SkImageInfo& info, size_t rowBytes){ if (rowBytes == 0) { rowBytes = info.minRowBytes(); // rowBytes can still be zero, if it overflowed (width * bytesPerPixel > size_t) // or if colortype is unknown } if (!is_valid(info) || !info.validRowBytes(rowBytes)) { returnnullptr; } size_t size = info.computeByteSize(rowBytes); if (SkImageInfo::ByteSizeOverflowed(size)) { returnnullptr; } #if defined(SK_BUILD_FOR_FUZZER) if (size > 100000) { returnnullptr; } #endif void* addr = sk_calloc_canfail(size); if (nullptr == addr) { returnnullptr; }
structPixelReffinal : public SkPixelRef { PixelRef(int w, int h, void* s, size_t r) : SkPixelRef(w, h, s, r) {} ~PixelRef() override { sk_free(this->pixels()); } }; returnsk_sp<SkPixelRef>(newPixelRef(info.width(), info.height(), addr, rowBytes)); } //external\skia\include\private\SkMalloc.h staticinlinevoid* sk_calloc_canfail(size_t size){ #if defined(SK_BUILD_FOR_FUZZER) // To reduce the chance of OOM, pretend we can't allocate more than 200kb. if (size > 200000) { returnnullptr; } #endif returnsk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE); } //external\skia\src\ports\SkMemory_malloc.cpp void* sk_malloc_flags(size_t size, unsigned flags){ void* p; if (flags & SK_MALLOC_ZERO_INITIALIZE) { p = calloc(size, 1); } else { #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(__BIONIC__) /* TODO: After b/169449588 is fixed, we will want to change this to restore * original behavior instead of always disabling the flag. * TODO: After b/158870657 is fixed and scudo is used globally, we can assert when an * an error is returned. */ // malloc() generally doesn't initialize its memory and that's a huge security hole, // so Android has replaced its malloc() with one that zeros memory, // but that's a huge performance hit for HWUI, so turn it back off again. (void)mallopt(M_THREAD_DISABLE_MEM_INIT, 1); #endif p = malloc(size); #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && defined(__BIONIC__) (void)mallopt(M_THREAD_DISABLE_MEM_INIT, 0); #endif } if (flags & SK_MALLOC_THROW) { returnthrow_on_failure(size, p); } else { return p; } }
//JavaPixelAllocator就是从Java heap中分配内存,JavaPixelAllocator中通过 //使用dalvik.system.VMRuntime.getRuntime().newNonMovableArray来申请内存 JavaPixelAllocator javaAllocator(env); //复用inBitmap RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize); //ScaleCheckingAllocator内部通过SkBitmap::HeapAllocator来申请native内存,但是 //这个内存只是临时内存,在后面的scale操作时会最终申请java内存,native内存会被释放 ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize); //SkBitmap::HeapAllocator是skia库提供的内存分派类,使用native内存 SkBitmap::HeapAllocator heapAllocator; SkBitmap::Allocator* decodeAllocator; if (javaBitmap != nullptr && willScale) { // This will allocate pixels using a HeapAllocator, since there will be an extra // scaling step that copies these pixels into Java memory. This allocator // also checks that the recycled javaBitmap is large enough. decodeAllocator = &scaleCheckingAllocator; } elseif (javaBitmap != nullptr) { decodeAllocator = &recyclingAllocator; } elseif (willScale) { // This will allocate pixels using a HeapAllocator, since there will be an extra // scaling step that copies these pixels into Java memory. decodeAllocator = &heapAllocator; } else { decodeAllocator = &javaAllocator; } ...... SkBitmap outputBitmap; if (willScale) { // This is weird so let me explain: we could use the scale parameter // directly, but for historical reasons this is how the corresponding // Dalvik code has always behaved. We simply recreate the behavior here. // The result is slightly different from simply using scale because of // the 0.5f rounding bias applied when computing the target image size constfloat sx = scaledWidth / float(decodingBitmap.width()); constfloat sy = scaledHeight / float(decodingBitmap.height());
// Set the allocator for the outputBitmap. SkBitmap::Allocator* outputAllocator; if (javaBitmap != nullptr) { outputAllocator = &recyclingAllocator; //复用inBitmap } else { outputAllocator = &javaAllocator; //使用Java内存 }
SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType()); // FIXME: If the alphaType is kUnpremul and the image has alpha, the // colors may not be correct, since Skia does not yet support drawing // to/from unpremultiplied bitmaps. outputBitmap.setInfo(SkImageInfo::Make(scaledWidth, scaledHeight, scaledColorType, decodingBitmap.alphaType())); if (!outputBitmap.tryAllocPixels(outputAllocator, NULL)) { // This should only fail on OOM. The recyclingAllocator should have // enough memory since we check this before decoding using the // scaleCheckingAllocator. returnnullObjectReturn("allocation failed for scaled bitmap"); }
SkPaint paint; // kSrc_Mode instructs us to overwrite the unininitialized pixels in // outputBitmap. Otherwise we would blend by default, which is not // what we want. paint.setXfermodeMode(SkXfermode::kSrc_Mode); paint.setFilterQuality(kLow_SkFilterQuality);
//android-12.1.0_r27\libcore\luni\src\main\java\libcore\util\NativeAllocationRegistry.java public@NonNull Runnable registerNativeAllocation(@NonNull Object referent, long nativePtr) { ...... CleanerThunk thunk; CleanerRunner result; try { thunk = newCleanerThunk(); Cleanercleaner= Cleaner.create(referent, thunk); //对应sun.misc.Cleaner result = newCleanerRunner(cleaner); //忽略这一行,因为Bitmap调用registerNativeAllocation没有使用返回值 registerNativeAllocation(this.size); } catch (VirtualMachineError vme /* probably OutOfMemoryError */) { applyFreeFunction(freeFunction, nativePtr); throw vme; } // Other exceptions are impossible. // Enable the cleaner only after we can no longer throw anything, including OOME. thunk.setNativePtr(nativePtr); // Ensure that cleaner doesn't get invoked before we enable it. Reference.reachabilityFence(referent); return result; }
/* List of References waiting to be enqueued. The collector adds * References to this list, while the Reference-handler thread removes * them. This list is protected by the above lock object. The * list uses the discovered field to link its elements. */ privatestatic Reference<Object> pending = null;
staticbooleantryHandlePending(boolean waitForNotify) { Reference<Object> r; Cleaner c; try { synchronized (lock) { if (pending != null) { r = pending; // 'instanceof' might throw OutOfMemoryError sometimes // so do this before un-linking 'r' from the 'pending' chain... c = r instanceof Cleaner ? (Cleaner) r : null; // unlink 'r' from 'pending' chain pending = r.discovered; //pending链表指向下一个Reference r.discovered = null; } else { // The waiting on the lock may cause an OutOfMemoryError // because it may try to allocate exception objects. if (waitForNotify) { lock.wait(); //pending为空,线程阻塞等待。 //当GC每次执行收集流程之前都会获取lock,然后将被回收的Reference放到pending链表中,然后唤醒阻塞线程 } // retry if waited return waitForNotify; } } } catch (OutOfMemoryError x) { // Give other threads CPU time so they hopefully drop some live references // and GC reclaims some space. // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above // persistently throws OOME for some time... Thread.yield(); // retry returntrue; } catch (InterruptedException x) { // retry returntrue; }
// Fast path for cleaners if (c != null) { c.clean(); //执行Cleaner的clean()方法 returntrue; }
ReferenceQueue<? super Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); //将其他Reference加入到ReferenceQueue中。 returntrue; }