Merge tag 'android-security-13.0.0_r8' into int/13/fp3

Android Security 13.0.0 Release 8 (10286630)

* tag 'android-security-13.0.0_r8':
  Enforce program stack limits on function parameters.

Change-Id: Id7310d4be98f3716ec9e06073e505705aa016681
diff --git a/gm/alpha_image.cpp b/gm/alpha_image.cpp
index 95e23f8..6edafe1 100644
--- a/gm/alpha_image.cpp
+++ b/gm/alpha_image.cpp
@@ -17,6 +17,7 @@
 #include "include/core/SkPaint.h"
 #include "include/core/SkRefCnt.h"
 #include "include/core/SkShader.h"
+#include "tools/Resources.h"
 
 static SkBitmap make_alpha_image(int w, int h) {
     SkBitmap bm;
@@ -84,3 +85,41 @@
     paint.setShader(image->makeShader(SkSamplingOptions()));
     canvas->drawRect({ 0, 0, 64, 64 }, paint);
 }
+
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+// For a long time, the CPU backend treated A8 bitmaps as coverage, rather than alpha. This was
+// inconsistent with the GPU backend (skbug.com/9692). When this was fixed, it altered behavior
+// for some Android apps (b/231400686). This GM verifies that our Android framework workaround
+// produces the old result (mandrill with a round-rect border).
+DEF_SIMPLE_GM(alpha_bitmap_is_coverage_ANDROID, canvas, 128, 128) {
+    SkBitmap maskBitmap;
+    maskBitmap.allocPixels(SkImageInfo::MakeA8(128, 128));
+    {
+        SkCanvas maskCanvas(maskBitmap);
+        maskCanvas.clear(SK_ColorWHITE);
+
+        SkPaint maskPaint;
+        maskPaint.setAntiAlias(true);
+        maskPaint.setColor(SK_ColorWHITE);
+        maskPaint.setBlendMode(SkBlendMode::kClear);
+        maskCanvas.drawRoundRect({0, 0, 128, 128}, 16, 16, maskPaint);
+    }
+
+    SkBitmap offscreenBitmap;
+    offscreenBitmap.allocN32Pixels(128, 128);
+    {
+        SkCanvas offscreenCanvas(offscreenBitmap);
+        offscreenCanvas.drawImage(GetResourceAsImage("images/mandrill_128.png"), 0, 0);
+
+        SkPaint clearPaint;
+        clearPaint.setAntiAlias(true);
+        clearPaint.setBlendMode(SkBlendMode::kClear);
+        // At tip-of-tree (or at any time on the GPU backend), this draw produces full coverage,
+        // completely erasing the mandrill. With the workaround enabled, the alpha border is treated
+        // as coverage, so we only apply kClear to those pixels, just erasing the outer border.
+        offscreenCanvas.drawImage(maskBitmap.asImage(), 0, 0, SkSamplingOptions{}, &clearPaint);
+    }
+
+    canvas->drawImage(offscreenBitmap.asImage(), 0, 0);
+}
+#endif
diff --git a/gm/runtimeshader.cpp b/gm/runtimeshader.cpp
index 94b3e0d..bd865ce 100644
--- a/gm/runtimeshader.cpp
+++ b/gm/runtimeshader.cpp
@@ -889,3 +889,50 @@
     // Now draw the offscreen surface back to our original canvas:
     canvas->drawImage(surface->makeImageSnapshot(), 0, 0);
 }
+
+// skbug.com/13598 GPU was double applying the local matrix.
+DEF_SIMPLE_GM(local_matrix_shader_rt, canvas, 256, 256) {
+    SkString passthrough(R"(
+        uniform shader s;
+        half4 main(float2 p) { return s.eval(p); }
+    )");
+    auto [rte, error] = SkRuntimeEffect::MakeForShader(passthrough, {});
+    if (!rte) {
+        SkDebugf("%s\n", error.c_str());
+        return;
+    }
+
+    auto image     = GetResourceAsImage("images/mandrill_128.png");
+    auto imgShader = image->makeShader(SkSamplingOptions{});
+
+    auto r = SkRect::MakeWH(image->width(), image->height());
+
+    auto lm = SkMatrix::RotateDeg(90.f, {image->width()/2.f, image->height()/2.f});
+
+    SkPaint paint;
+
+    // image
+    paint.setShader(imgShader);
+    canvas->drawRect(r, paint);
+
+    // passthrough(image)
+    canvas->save();
+    canvas->translate(image->width(), 0);
+    paint.setShader(rte->makeShader(nullptr, &imgShader, 1));
+    canvas->drawRect(r, paint);
+    canvas->restore();
+
+    // localmatrix(image)
+    canvas->save();
+    canvas->translate(0, image->height());
+    paint.setShader(imgShader->makeWithLocalMatrix(lm));
+    canvas->drawRect(r, paint);
+    canvas->restore();
+
+    // localmatrix(passthrough(image)) This was the bug.
+    canvas->save();
+    canvas->translate(image->width(), image->height());
+    paint.setShader(rte->makeShader(nullptr, &imgShader, 1)->makeWithLocalMatrix(lm));
+    canvas->drawRect(r, paint);
+    canvas->restore();
+}
diff --git a/include/config/SkUserConfigManual.h b/include/config/SkUserConfigManual.h
index 5f11d96..528e406 100644
--- a/include/config/SkUserConfigManual.h
+++ b/include/config/SkUserConfigManual.h
@@ -32,4 +32,8 @@
   #define SK_DISABLE_DAA  // skbug.com/6886
 
   #define SK_ABORT(...) __android_log_assert(nullptr, "skia", ##__VA_ARGS__)
+
+  // TODO (b/239048372): Remove this flag when we can safely migrate apps to the
+  // new behavior.
+  #define SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE
 #endif // SkUserConfigManual_DEFINED
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index f68f8ee..b910d06 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -273,6 +273,22 @@
 
 /////////////////////// these are not virtual, just helpers
 
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) {
+    if (clip.quickReject(mask.fBounds)) {
+        return;
+    }
+
+    SkRegion::Cliperator clipper(clip, mask.fBounds);
+
+    while (!clipper.done()) {
+        const SkIRect& cr = clipper.rect();
+        this->blitMask(mask, cr);
+        clipper.next();
+    }
+}
+#endif
+
 void SkBlitter::blitRectRegion(const SkIRect& rect, const SkRegion& clip) {
     SkRegion::Cliperator clipper(clip, rect);
 
diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h
index 0ed7cd6..ec58c5a 100644
--- a/src/core/SkBlitter.h
+++ b/src/core/SkBlitter.h
@@ -132,6 +132,9 @@
     }
 
     ///@name non-virtual helpers
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+    void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
+#endif
     void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
     void blitRegion(const SkRegion& clip);
     ///@}
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 60d18e9..30cbaf2 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -705,6 +705,39 @@
     }
 }
 
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
+    if (srcM.fBounds.isEmpty()) {
+        return;
+    }
+
+    const SkMask* mask = &srcM;
+
+    SkMask dstM;
+    if (paint.getMaskFilter() &&
+        as_MFB(paint.getMaskFilter())
+                ->filterMask(&dstM, srcM, fMatrixProvider->localToDevice(), nullptr)) {
+        mask = &dstM;
+    }
+    SkAutoMaskFreeImage ami(dstM.fImage);
+
+    SkAutoBlitterChoose blitterChooser(*this, nullptr, paint);
+    SkBlitter* blitter = blitterChooser.get();
+
+    SkAAClipBlitterWrapper wrapper;
+    const SkRegion* clipRgn;
+
+    if (fRC->isBW()) {
+        clipRgn = &fRC->bwRgn();
+    } else {
+        wrapper.init(*fRC, blitter);
+        clipRgn = &wrapper.getRgn();
+        blitter = wrapper.getBlitter();
+    }
+    blitter->blitMaskRegion(*mask, *clipRgn);
+}
+#endif
+
 static SkScalar fast_len(const SkVector& vec) {
     SkScalar x = SkScalarAbs(vec.fX);
     SkScalar y = SkScalarAbs(vec.fY);
@@ -925,6 +958,94 @@
     this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
 }
 
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkSamplingOptions& sampling,
+                              const SkPaint& paint) const {
+    SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
+
+    // nothing to draw
+    if (fRC->isEmpty()) {
+        return;
+    }
+
+    SkMatrix ctm = fMatrixProvider->localToDevice();
+    if (SkTreatAsSprite(ctm, bitmap.dimensions(), sampling, paint))
+    {
+        int ix = SkScalarRoundToInt(ctm.getTranslateX());
+        int iy = SkScalarRoundToInt(ctm.getTranslateY());
+
+        SkPixmap pmap;
+        if (!bitmap.peekPixels(&pmap)) {
+            return;
+        }
+        SkMask  mask;
+        mask.fBounds.setXYWH(ix, iy, pmap.width(), pmap.height());
+        mask.fFormat = SkMask::kA8_Format;
+        mask.fRowBytes = SkToU32(pmap.rowBytes());
+        // fImage is typed as writable, but in this case it is used read-only
+        mask.fImage = (uint8_t*)pmap.addr8(0, 0);
+
+        this->drawDevMask(mask, paint);
+    } else {    // need to xform the bitmap first
+        SkRect  r;
+        SkMask  mask;
+
+        r.setIWH(bitmap.width(), bitmap.height());
+        ctm.mapRect(&r);
+        r.round(&mask.fBounds);
+
+        // set the mask's bounds to the transformed bitmap-bounds,
+        // clipped to the actual device and further limited by the clip bounds
+        {
+            SkASSERT(fDst.bounds().contains(fRC->getBounds()));
+            SkIRect devBounds = fDst.bounds();
+            devBounds.intersect(fRC->getBounds().makeOutset(1, 1));
+            // need intersect(l, t, r, b) on irect
+            if (!mask.fBounds.intersect(devBounds)) {
+                return;
+            }
+        }
+
+        mask.fFormat = SkMask::kA8_Format;
+        mask.fRowBytes = SkAlign4(mask.fBounds.width());
+        size_t size = mask.computeImageSize();
+        if (0 == size) {
+            // the mask is too big to allocated, draw nothing
+            return;
+        }
+
+        // allocate (and clear) our temp buffer to hold the transformed bitmap
+        SkAutoTMalloc<uint8_t> storage(size);
+        mask.fImage = storage.get();
+        memset(mask.fImage, 0, size);
+
+        // now draw our bitmap(src) into mask(dst), transformed by the matrix
+        {
+            SkBitmap    device;
+            device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
+                                 mask.fImage, mask.fRowBytes);
+
+            SkCanvas c(device);
+            // need the unclipped top/left for the translate
+            c.translate(-SkIntToScalar(mask.fBounds.fLeft),
+                        -SkIntToScalar(mask.fBounds.fTop));
+            c.concat(ctm);
+
+            // We can't call drawBitmap, or we'll infinitely recurse. Instead
+            // we manually build a shader and draw that into our new mask
+            SkPaint tmpPaint;
+            tmpPaint.setAntiAlias(paint.isAntiAlias());
+            tmpPaint.setDither(paint.isDither());
+            SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap, sampling);
+            SkRect rr;
+            rr.setIWH(bitmap.width(), bitmap.height());
+            c.drawRect(rr, paintWithShader);
+        }
+        this->drawDevMask(mask, paint);
+    }
+}
+#endif
+
 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
                         const SkRect& srcR) {
     SkRect  dstR;
@@ -998,6 +1119,16 @@
     SkDraw draw(*this);
     draw.fMatrixProvider = &matrixProvider;
 
+    // For a long time, the CPU backend treated A8 bitmaps as coverage, rather than alpha. This was
+    // inconsistent with the GPU backend (skbug.com/9692). When this was fixed, it altered behavior
+    // for some Android apps (b/231400686). Thus: keep the old behavior in the framework.
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+    if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
+        draw.drawBitmapAsMask(bitmap, sampling, *paint);
+        return;
+    }
+#endif
+
     SkPaint paintWithShader = make_paint_with_image(*paint, bitmap, sampling);
     const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
     if (dstBounds) {
diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h
index dc5fe8e..c87948c 100644
--- a/src/core/SkDraw.h
+++ b/src/core/SkDraw.h
@@ -98,6 +98,10 @@
                            SkMask* mask, SkMask::CreateMode mode,
                            SkStrokeRec::InitStyle style);
 
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+    void drawDevMask(const SkMask& mask, const SkPaint&) const;
+#endif
+
     enum RectType {
         kHair_RectType,
         kFill_RectType,
@@ -117,6 +121,9 @@
                                     SkPoint* strokeSize);
 
 private:
+#if defined(SK_SUPPORT_LEGACY_ALPHA_BITMAP_AS_COVERAGE)
+    void drawBitmapAsMask(const SkBitmap&, const SkSamplingOptions&, const SkPaint&) const;
+#endif
     void drawFixedVertices(const SkVertices* vertices,
                            sk_sp<SkBlender> blender,
                            const SkPaint& paint,
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index 3e5543c..1c08fb8 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -1133,13 +1133,16 @@
                 get_xformed_uniforms(fEffect.get(), fUniforms, args.fDstColorInfo->colorSpace());
         SkASSERT(uniforms);
 
+        // We handle the pre-local matrix at this level so strip it out.
+        GrFPArgs fpArgs = args;
+        fpArgs.fPreLocalMatrix = nullptr;
         auto [success, fp] = make_effect_fp(fEffect,
                                             "runtime_shader",
                                             std::move(uniforms),
                                             /*inputFP=*/nullptr,
                                             /*destColorFP=*/nullptr,
                                             SkMakeSpan(fChildren),
-                                            args);
+                                            fpArgs);
         if (!success) {
             return nullptr;
         }
diff --git a/src/gpu/v1/Device.cpp b/src/gpu/v1/Device.cpp
index a0a4728..bc25933 100644
--- a/src/gpu/v1/Device.cpp
+++ b/src/gpu/v1/Device.cpp
@@ -409,15 +409,6 @@
     GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode);
 
     const SkMatrixProvider* matrixProvider = this;
-#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
-    SkTLazy<SkPostTranslateMatrixProvider> postTranslateMatrixProvider;
-    // This offsetting in device space matches the expectations of the Android framework for non-AA
-    // points and lines.
-    if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
-        static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
-        matrixProvider = postTranslateMatrixProvider.init(*matrixProvider, kOffset, kOffset);
-    }
-#endif
 
     GrPaint grPaint;
     if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint,
diff --git a/src/gpu/v1/SurfaceDrawContext.cpp b/src/gpu/v1/SurfaceDrawContext.cpp
index 5bf6a3b..cfd6a04 100644
--- a/src/gpu/v1/SurfaceDrawContext.cpp
+++ b/src/gpu/v1/SurfaceDrawContext.cpp
@@ -1470,6 +1470,10 @@
 
 void SurfaceDrawContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
                                       const SkRect& bounds) {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(this->validate();)
+    GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawDrawable", fContext);
     GrOp::Owner op(DrawableOp::Make(fContext, std::move(drawable), bounds));
     SkASSERT(op);
     this->addOp(std::move(op));