ImageDecoder: use kYes_ZeroInitialized memory

Bug: 183115528
Test: (A)ImageDecoderTest(s) (verify correctness)
Test: monitor showmap_pss_bytes dashboards (verify memory impact)

This lets the decoder leave zero initialized memory untouched. An
Android feature makes untouched zero initialized memory cheaper, and
BitmapFactory takes advantage of it. Do the same for ImageDecoder.

This feature was originally brought up in b/10016979. ImageDecoder saved
memory in other ways, and as I understand it, Android has shifted
towards using (Animated)VectorDrawables. Both of these may have
contributed to us not noticing when we switched from BitmapFactory to
ImageDecoder.

Change-Id: Iecfd1bbfdcc38e1f0bf380b4f4ea5b861cfcf08a
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index ade63e5..5d9fad5 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -45,7 +45,8 @@
     return SkColorSpace::MakeSRGB();
 }
 
-ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker)
+ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker,
+                           SkCodec::ZeroInitialized zeroInit)
     : mCodec(std::move(codec))
     , mPeeker(std::move(peeker))
     , mDecodeSize(mCodec->codec()->dimensions())
@@ -57,6 +58,7 @@
     mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() }
                                     : mDecodeSize;
     this->rewind();
+    mOptions.fZeroInitialized = zeroInit;
 }
 
 ImageDecoder::~ImageDecoder() = default;
@@ -446,10 +448,17 @@
                 ALOGE("Failed to invert matrix!");
             }
         }
+
+        // Even if the client did not provide zero initialized memory, the
+        // memory we decode into is.
+        mOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
     }
 
     auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
 
+    // The next call to decode() may not provide zero initialized memory.
+    mOptions.fZeroInitialized = SkCodec::kNo_ZeroInitialized;
+
     if (scale || handleOrigin || mCropRect) {
         SkBitmap scaledBm;
         if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index cbfffd5..cef2233 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -34,8 +34,8 @@
     std::unique_ptr<SkAndroidCodec> mCodec;
     sk_sp<SkPngChunkReader> mPeeker;
 
-    ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,
-                 sk_sp<SkPngChunkReader> peeker = nullptr);
+    ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker = nullptr,
+                 SkCodec::ZeroInitialized zeroInit = SkCodec::kNo_ZeroInitialized);
     ~ImageDecoder();
 
     SkISize getSampledDimensions(int sampleSize) const;
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index ad7741b..f7b8c01 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -141,7 +141,8 @@
     }
 
     const bool isNinePatch = peeker->mPatch != nullptr;
-    ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker));
+    ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker),
+                                             SkCodec::kYes_ZeroInitialized);
     return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
                           reinterpret_cast<jlong>(decoder), decoder->width(), decoder->height(),
                           animated, isNinePatch);