RESTRICT AUTOMERGE: Fix uninitialized errors in SkPngCodec

Bug: 117838472
Test: Iae4d7f393c892111b12282c5eae31d79912721f9

- Initialize rowsDecoded in SkSampledCodec. Otherwise,
fillIncompleteImage may be called with an uninitialized
value. This change was originally uploaded to AOSP as
https://android-review.googlesource.com/c/platform/external/skia/+/785816
- If SkPngCodec hits an error, still transform from the
interlace buffer (if needed) and set rowsDecoded properly.
- Do not copy uninitialized memory from the interlace buffer.
- Make BRD treat kErrorInInput like kIncompleteInput. The two errors
are different for the purposes of incremental decode. For a direct
decode, they're essentially the same - part was decoded, but then
the decode was interrupted. This allows testing images with
errors on the bots without reporting a failure.

Originally uploaded as https://skia-review.googlesource.com/c/skia/+/161822

- Also includes SkPngCodec SafetyNet logging from
https://skia-review.googlesource.com/c/skia/+/170354

Change-Id: Ie170abf65393feb4edba60aa941f2783fe18cd8b
(cherry picked from commit fc165d5cccf133574058cd0c5ba3a95ea6ad2bb8)
diff --git a/src/android/SkBitmapRegionCodec.cpp b/src/android/SkBitmapRegionCodec.cpp
index 6b17a90..682c705 100644
--- a/src/android/SkBitmapRegionCodec.cpp
+++ b/src/android/SkBitmapRegionCodec.cpp
@@ -106,10 +106,14 @@
 
     SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, bitmap->rowBytes(),
             &options);
-    if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) {
-        SkCodecPrintf("Error: Could not get pixels.\n");
-        return false;
+    switch (result) {
+        case SkCodec::kSuccess:
+        case SkCodec::kIncompleteInput:
+        case SkCodec::kErrorInInput:
+            return true;
+        default:
+            SkCodecPrintf("Error: Could not get pixels with message \"%s\".\n",
+                          SkCodec::ResultToString(result));
+            return false;
     }
-
-    return true;
 }
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
index 31a407c..aa62138 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -25,6 +25,10 @@
 #include "png.h"
 #include <algorithm>
 
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    #include "SkAndroidFrameworkUtils.h"
+#endif
+
 // This warning triggers false postives way too often in here.
 #if defined(__GNUC__) && !defined(__clang__)
     #pragma GCC diagnostic ignored "-Wclobbered"
@@ -481,6 +485,14 @@
     }
 }
 
+static SkCodec::Result log_and_return_error(bool success) {
+    if (success) return SkCodec::kIncompleteInput;
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    SkAndroidFrameworkUtils::SafetyNetLog("117838472");
+#endif
+    return SkCodec::kErrorInInput;
+}
+
 class SkPngNormalDecoder : public SkPngCodec {
 public:
     SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
@@ -528,19 +540,16 @@
         fFirstRow = 0;
         fLastRow = height - 1;
 
-        if (!this->processData()) {
-            return kErrorInInput;
-        }
-
-        if (fRowsWrittenToOutput == height) {
-            return SkCodec::kSuccess;
+        const bool success = this->processData();
+        if (success && fRowsWrittenToOutput == height) {
+            return kSuccess;
         }
 
         if (rowsDecoded) {
             *rowsDecoded = fRowsWrittenToOutput;
         }
 
-        return SkCodec::kIncompleteInput;
+        return log_and_return_error(success);
     }
 
     void allRowsCallback(png_bytep row, int rowNum) {
@@ -560,25 +569,22 @@
         fRowsNeeded = fLastRow - fFirstRow + 1;
     }
 
-    SkCodec::Result decode(int* rowsDecoded) override {
+    Result decode(int* rowsDecoded) override {
         if (this->swizzler()) {
             const int sampleY = this->swizzler()->sampleY();
             fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
         }
 
-        if (!this->processData()) {
-            return kErrorInInput;
-        }
-
-        if (fRowsWrittenToOutput == fRowsNeeded) {
-            return SkCodec::kSuccess;
+        const bool success = this->processData();
+        if (success && fRowsWrittenToOutput == fRowsNeeded) {
+            return kSuccess;
         }
 
         if (rowsDecoded) {
             *rowsDecoded = fRowsWrittenToOutput;
         }
 
-        return SkCodec::kIncompleteInput;
+        return log_and_return_error(success);
     }
 
     void rowCallback(png_bytep row, int rowNum) {
@@ -670,7 +676,7 @@
         }
     }
 
-    SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
+    Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
         const int height = this->getInfo().height();
         this->setUpInterlaceBuffer(height);
         png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback,
@@ -680,10 +686,7 @@
         fLastRow = height - 1;
         fLinesDecoded = 0;
 
-        if (!this->processData()) {
-            return kErrorInInput;
-        }
-
+        const bool success = this->processData();
         png_bytep srcRow = fInterlaceBuffer.get();
         // FIXME: When resuming, this may rewrite rows that did not change.
         for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
@@ -691,15 +694,15 @@
             dst = SkTAddOffset<void>(dst, rowBytes);
             srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
         }
-        if (fInterlacedComplete) {
-            return SkCodec::kSuccess;
+        if (success && fInterlacedComplete) {
+            return kSuccess;
         }
 
         if (rowsDecoded) {
             *rowsDecoded = fLinesDecoded;
         }
 
-        return SkCodec::kIncompleteInput;
+        return log_and_return_error(success);
     }
 
     void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
@@ -713,45 +716,45 @@
         fLinesDecoded = 0;
     }
 
-    SkCodec::Result decode(int* rowsDecoded) override {
-        if (this->processData() == false) {
-            return kErrorInInput;
-        }
+    Result decode(int* rowsDecoded) override {
+        const bool success = this->processData();
 
         // Now apply Xforms on all the rows that were decoded.
         if (!fLinesDecoded) {
             if (rowsDecoded) {
                 *rowsDecoded = 0;
             }
-            return SkCodec::kIncompleteInput;
+            return log_and_return_error(success);
         }
 
         const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
         const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
-        int rowsWrittenToOutput = 0;
 
         // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it
         // may be too tricky/expensive to handle that correctly.
 
         // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow,
         // since the first row in fInterlaceBuffer corresponds to fFirstRow.
-        png_bytep srcRow = SkTAddOffset<png_byte>(fInterlaceBuffer.get(),
-                                                  fPng_rowbytes * get_start_coord(sampleY));
+        int srcRow = get_start_coord(sampleY);
         void* dst = fDst;
-        for (; rowsWrittenToOutput < rowsNeeded; rowsWrittenToOutput++) {
-            this->applyXformRow(dst, srcRow);
+        int rowsWrittenToOutput = 0;
+        while (rowsWrittenToOutput < rowsNeeded && srcRow < fLinesDecoded) {
+            png_bytep src = SkTAddOffset<png_byte>(fInterlaceBuffer.get(), fPng_rowbytes * srcRow);
+            this->applyXformRow(dst, src);
             dst = SkTAddOffset<void>(dst, fRowBytes);
-            srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY);
+
+            rowsWrittenToOutput++;
+            srcRow += sampleY;
         }
 
-        if (fInterlacedComplete) {
-            return SkCodec::kSuccess;
+        if (success && fInterlacedComplete) {
+            return kSuccess;
         }
 
         if (rowsDecoded) {
             *rowsDecoded = rowsWrittenToOutput;
         }
-        return SkCodec::kIncompleteInput;
+        return log_and_return_error(success);
     }
 
     void setUpInterlaceBuffer(int height) {
diff --git a/src/codec/SkSampledCodec.cpp b/src/codec/SkSampledCodec.cpp
index ac0539f..2282d6b 100644
--- a/src/codec/SkSampledCodec.cpp
+++ b/src/codec/SkSampledCodec.cpp
@@ -113,17 +113,17 @@
         const SkCodec::Result startResult = this->codec()->startIncrementalDecode(
                 scaledInfo, pixels, rowBytes, &codecOptions);
         if (SkCodec::kSuccess == startResult) {
-            int rowsDecoded;
+            int rowsDecoded = 0;
             const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded);
             if (incResult == SkCodec::kSuccess) {
                 return SkCodec::kSuccess;
             }
-            SkASSERT(SkCodec::kIncompleteInput == incResult);
+            SkASSERT(incResult == SkCodec::kIncompleteInput || incResult == SkCodec::kErrorInInput);
 
             // FIXME: Can zero initialized be read from SkCodec::fOptions?
             this->codec()->fillIncompleteImage(scaledInfo, pixels, rowBytes,
                     options.fZeroInitialized, scaledSubsetHeight, rowsDecoded);
-            return SkCodec::kIncompleteInput;
+            return incResult;
         } else if (startResult != SkCodec::kUnimplemented) {
             return startResult;
         }
@@ -244,7 +244,7 @@
 
             sampler->setSampleY(sampleY);
 
-            int rowsDecoded;
+            int rowsDecoded = 0;
             const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded);
             if (incResult == SkCodec::kSuccess) {
                 return SkCodec::kSuccess;