Merge tag 'android-security-11.0.0_r57' into int/11/fp3

Android security 11.0.0 release 57

* tag 'android-security-11.0.0_r57':
  Only treat PNG_COLOR_TYPE_RGB as 565

Change-Id: I655ea2ee7aa739e46f49d3f9e612da0978185eb9
diff --git a/Android.bp b/Android.bp
index 122324c..a4fcc43 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,8 +14,10 @@
         "-Wno-implicit-fallthrough",
         "-Wno-missing-field-initializers",
         "-Wno-thread-safety-analysis",
+        "-Wno-unknown-warning-option",
         "-Wno-unused-parameter",
         "-Wno-unused-variable",
+        "-Wno-array-suspicious",
         "-fvisibility=hidden",
     ],
 
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index a67d2e2..3826d94 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -12,6 +12,12 @@
 #include "src/core/SkUtils.h"
 #include "src/core/SkXfermodePriv.h"
 
+#include <semaphore.h>
+#include <assert.h>
+#include <pthread.h>
+#include <cutils/log.h>
+#include <sys/sysinfo.h>
+
 static inline int upscale_31_to_32(int value) {
     SkASSERT((unsigned)value <= 31);
     return value + (value >> 4);
@@ -1015,14 +1021,77 @@
     }
 }
 
-void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
-    SkASSERT(x >= 0 && y >= 0 &&
-             x + width <= fDevice.width() && y + height <= fDevice.height());
+#define BUF_MAX 8192
+#define __ATOMIC_INLINE__ static __inline__ __attribute__((always_inline))
 
-    uint32_t*  device = fDevice.writable_addr32(x, y);
-    size_t     deviceRB = fDevice.rowBytes();
-    auto*      shaderContext = fShaderContext;
-    SkPMColor* span = fBuffer;
+__ATOMIC_INLINE__ int __atomic_dec(volatile int *ptr) {
+  return __sync_fetch_and_sub (ptr, 1);
+}
+
+__ATOMIC_INLINE__ int __atomic_inc(volatile int *ptr) {
+  return __sync_fetch_and_add (ptr, 1);
+}
+
+static volatile int worker_thread_inited_ARGB32 = 0;
+static volatile int worker_thread_busy_ARGB32 = 0;
+
+#define MAX_WORKER_THREADS_NUM_ARGB32 3
+
+static pthread_t worker_threads_ARGB32[MAX_WORKER_THREADS_NUM_ARGB32];
+sem_t sem_todo_ARGB32[MAX_WORKER_THREADS_NUM_ARGB32];
+sem_t sem_done_ARGB32[MAX_WORKER_THREADS_NUM_ARGB32];
+static volatile void* work_ARGB32[MAX_WORKER_THREADS_NUM_ARGB32] = {0};
+static int worker_thread_num_ARGB32 = 0;
+
+extern const char* __progname;
+static int is_not_zygote_ARGB32(){
+    const char * buf = __progname;
+    const char * zygote = "zygote";
+    /*
+     * adb shell cat /proc/192/cmdline
+     * zygote/bin/app_process-Xzygote/system/bin--zygote--start-system-server
+     */
+    return strncmp(buf, zygote, 6);
+}
+
+struct shadeSpanArg {
+    SkShaderBase::Context* shaderContext;
+    int x;
+    int y;
+    int width;
+    int height;
+    uint32_t* device;
+    size_t deviceRB;
+    bool fShadeDirectlyIntoDevice;
+    bool fConstInY;
+    SkXfermode* fXfermode;
+    SkBlitRow::Proc32 fProc32;
+    SkPMColor* fBuffer;
+};
+
+
+void blitRect_core(
+        SkShaderBase::Context* shaderContext,
+        int x,
+        int y,
+        int width,
+        int height,
+        uint32_t* device,
+        size_t deviceRB,
+        bool fShadeDirectlyIntoDevice,
+        bool fConstInY,
+        SkXfermode* fXfermode,
+        SkBlitRow::Proc32 fProc32,
+        SkPMColor* fbuffer)
+{
+    SkPMColor*  span = NULL;
+    if (fbuffer) {
+       span = fbuffer;
+    } else {
+       SkASSERT(width <= BUF_MAX);
+       uint32_t buffer[BUF_MAX];
+       span = (SkPMColor*)buffer;
+    }
 
     if (fConstInY) {
         if (fShadeDirectlyIntoDevice) {
@@ -1081,6 +1150,180 @@
     }
 }
 
+void* worker_blitRect_ARGB32(void * arg) {
+
+    long id=(long)arg;
+
+    //worker thread
+    while(1){
+        sem_wait(&sem_todo_ARGB32[id]);
+        if (work_ARGB32[id] != 0) {
+            struct shadeSpanArg* arg= (struct shadeSpanArg*)work_ARGB32[id];
+            SkShaderBase::Context* shaderContext =arg->shaderContext;
+            int x = arg->x;
+            int y = arg->y;
+            int width = arg->width;
+            int height = arg->height;
+            uint32_t* device = arg->device;
+            size_t deviceRB = arg->deviceRB;
+
+            bool fShadeDirectlyIntoDevice = arg->fShadeDirectlyIntoDevice;
+            bool fConstInY = arg->fConstInY;
+            SkXfermode* fXfermode = arg->fXfermode;
+            SkBlitRow::Proc32 fProc32 = arg->fProc32;
+            SkPMColor* fBuffer = arg->fBuffer;
+
+            blitRect_core(
+                    shaderContext,
+                    x,
+                    y,
+                    width,
+                    height,
+                    device,
+                    deviceRB,
+                    fShadeDirectlyIntoDevice,
+                    fConstInY,
+                    fXfermode,
+                    fProc32,
+                    fBuffer
+                    );
+
+            work_ARGB32[id] = 0;
+        }
+        sem_post(&sem_done_ARGB32[id]);
+    }
+}
+
+
+void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
+    SkASSERT(x >= 0 && y >= 0 &&
+             x + width <= fDevice.width() && y + height <= fDevice.height());
+
+    uint32_t*  device = fDevice.writable_addr32(x, y);
+    size_t     deviceRB = fDevice.rowBytes();
+    auto*      shaderContext = fShaderContext;
+
+    //Disable this since some issue found
+    if (false && ((height * width) > (750 * 400)) && (width <= BUF_MAX) && height >= 4) {
+        if (__atomic_inc(&worker_thread_busy_ARGB32) == 0) {
+            if (!worker_thread_inited_ARGB32) {
+                if (__atomic_inc(&worker_thread_inited_ARGB32) == 0) {
+                    //Only start the other thread in non-zygote mode.
+                    if (!is_not_zygote_ARGB32()){
+                        __atomic_dec(&worker_thread_busy_ARGB32);
+                        __atomic_dec(&worker_thread_inited_ARGB32);
+                        goto fb;
+                    }
+                    long i;
+                    worker_thread_num_ARGB32 = (get_nprocs_conf()/2 -1);
+                    if (worker_thread_num_ARGB32 > MAX_WORKER_THREADS_NUM_ARGB32) {
+                       worker_thread_num_ARGB32 =  MAX_WORKER_THREADS_NUM_ARGB32;
+                    } else if (worker_thread_num_ARGB32 <= 2) {
+                       worker_thread_num_ARGB32 = 1;
+                    }
+                    for(i = 0; i < worker_thread_num_ARGB32; i++){
+                        sem_init(&sem_todo_ARGB32[i], 0, 0);
+                        sem_init(&sem_done_ARGB32[i], 0, 0);
+                        pthread_create(&worker_threads_ARGB32[i], NULL, worker_blitRect_ARGB32, (void*)i);
+                    }
+
+                }
+            }
+            if (worker_thread_num_ARGB32 > 0) {
+                struct shadeSpanArg msg[worker_thread_num_ARGB32];
+                if (worker_thread_num_ARGB32 == 1) {
+                    msg[0].y = y + (height >>1);
+                    msg[0].height = height - (height >> 1);
+                    msg[0].device = (uint32_t*)((char*)device + (deviceRB * (height >> 1)));
+
+                    height = (height >> 1);
+                } else if (worker_thread_num_ARGB32 == 3) {
+                    msg[0].y = (y + (height >> 2));
+                    msg[0].height = ((height >> 1) - (height >> 2));
+                    msg[0].device = (uint32_t*)((char*)device + (deviceRB * (height >> 2)));
+
+                    msg[1].y = (y + (height >> 1));
+                    msg[1].height = ((height - (height >> 1)) >> 1);
+                    msg[1].device = (uint32_t*)((char*)device + (deviceRB * (height >> 1)));
+
+                    msg[2].y = (y + (height >> 1) + ((height - (height >> 1)) >> 1));
+                    msg[2].height = ((height - (height >> 1)) - ((height - (height >> 1)) >> 1));
+                    msg[2].device = (uint32_t*)((char*)device + (deviceRB * ((height >> 1) + ((height - (height >> 1)) >> 1))));
+
+                    height = (height >> 2);
+                } else {
+                    __atomic_dec(&worker_thread_busy_ARGB32);
+                    goto fb;
+                }
+
+                for (int i = 0; i < worker_thread_num_ARGB32; i++) {
+                    msg[i].shaderContext = shaderContext;
+                    msg[i].x = x;
+                    msg[i].width = width;
+                    msg[i].deviceRB = (deviceRB);
+                    msg[i].fShadeDirectlyIntoDevice = fShadeDirectlyIntoDevice;
+                    msg[i].fConstInY = fConstInY;
+                    msg[i].fXfermode = fXfermode;
+                    msg[i].fProc32 = fProc32;
+                    msg[i].fBuffer = NULL;
+
+                    assert(work_ARGB32[i] == 0);
+                    work_ARGB32[i] = &msg[i];
+
+                    sem_post(&sem_todo_ARGB32[i]);
+                }
+
+                blitRect_core(
+                        shaderContext,
+                        x,
+                        y,
+                        width,
+                        height,
+                        device,
+                        deviceRB,
+                        fShadeDirectlyIntoDevice,
+                        fConstInY,
+                        fXfermode,
+                        fProc32,
+                        NULL
+                        );
+
+                for (int i = 0; i < worker_thread_num_ARGB32; i++) {
+                    sem_wait(&sem_done_ARGB32[i]);
+                   /* Need to set to NULL value. No point in still storing addresso of local
+                    * variable, after function returns
+                    */
+                    work_ARGB32[i] = NULL;
+                }
+                __atomic_dec(&worker_thread_busy_ARGB32);
+            }
+            else {
+                __atomic_dec(&worker_thread_busy_ARGB32);
+                goto fb;
+            }
+
+            return;
+        }
+  }
+
+
+fb:
+    blitRect_core(
+            shaderContext,
+            x,
+            y,
+            width,
+            height,
+            device,
+            deviceRB,
+            fShadeDirectlyIntoDevice,
+            fConstInY,
+            fXfermode,
+            fProc32,
+            fBuffer
+            );
+}
+
 void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
                                         const int16_t runs[]) {
     SkPMColor* span = fBuffer;
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index 3fd6366..08f5d2b 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -20,6 +20,12 @@
 #include "src/core/SkUtils.h"
 #include "src/shaders/SkShaderBase.h"
 
+#include <semaphore.h>
+#include <assert.h>
+#include <pthread.h>
+#include <cutils/log.h>
+#include <sys/sysinfo.h>
+
 class SkRasterPipelineBlitter final : public SkBlitter {
 public:
     // This is our common entrypoint for creating the blitter once we've sorted out shaders.
@@ -77,6 +83,63 @@
     typedef SkBlitter INHERITED;
 };
 
+#define __ATOMIC_INLINE__ static __inline__ __attribute__((always_inline))
+__ATOMIC_INLINE__ int __atomic_dec(volatile int *ptr) {
+  return __sync_fetch_and_sub (ptr, 1);
+}
+__ATOMIC_INLINE__ int __atomic_inc(volatile int *ptr) {
+  return __sync_fetch_and_add (ptr, 1);
+}
+static volatile int worker_thread_inited = 0;
+static volatile int worker_thread_busy = 0;
+#define MAX_WORKER_THREADS_NUM 3
+
+static pthread_t worker_threads[MAX_WORKER_THREADS_NUM];
+sem_t sem_todo[MAX_WORKER_THREADS_NUM];
+sem_t sem_done[MAX_WORKER_THREADS_NUM];
+static volatile void* work[MAX_WORKER_THREADS_NUM] = {0};
+static int worker_thread_num = 0;
+
+extern const char* __progname;
+
+static int is_not_zygote(){
+
+    const char* buf = __progname;
+    const char* zygote = "zygote";
+    /*
+     * adb shell cat /proc/192/cmdline
+     * zygote/bin/app_process-Xzygote/system/bin--zygote--start-system-server
+     */
+    return strncmp(buf, zygote, 6);
+}
+
+struct shadeSpanArg {
+    int x;
+    int y;
+    int width;
+    int height;
+    std::function<void(size_t, size_t, size_t, size_t)> func;
+};
+
+void* worker_blitRect(void* arg) {
+    long id = (long)arg;
+    while(1) {
+        sem_wait(&sem_todo[id]);
+        if (work[id] != 0) {
+            struct shadeSpanArg* arg = (struct shadeSpanArg*)work[id];
+            int x = arg->x;
+            int y = arg->y;
+            int width = arg->width;
+            int height = arg->height;
+            if (arg->func) {
+               arg->func(x, y, width, height);
+            }
+            work[id] = 0;
+        }
+        sem_post(&sem_done[id]);
+    }
+}
+
 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
                                          const SkPaint& paint,
                                          const SkMatrix& ctm,
@@ -308,6 +371,85 @@
         fBlitRect = p.compile();
     }
 
+    //Disable this since some issue found
+    if (false && (w * h) > (750 * 400) && h >= 4) {
+        if (__atomic_inc(&worker_thread_busy) == 0) {
+            if (!worker_thread_inited) {
+                if (__atomic_inc(&worker_thread_inited) == 0) {
+                //Only start the other thread in non-zygote mode.
+                    if (!is_not_zygote()) {
+                        __atomic_dec(&worker_thread_busy);
+                        __atomic_dec(&worker_thread_inited);
+                        goto fb;
+                    }
+                    long i;
+                    worker_thread_num = (get_nprocs_conf()/2 -1);
+                    if (worker_thread_num > MAX_WORKER_THREADS_NUM) {
+                        worker_thread_num = MAX_WORKER_THREADS_NUM;
+                    } else if (worker_thread_num <= 2) {
+                        worker_thread_num = 1;
+                    }
+                    for (i = 0; i < worker_thread_num; i++) {
+                        sem_init(&sem_todo[i], 0, 0);
+                        sem_init(&sem_done[i], 0, 0);
+                        pthread_create(&worker_threads[i], NULL, worker_blitRect, (void *)i);
+                    }
+                }
+            }
+            if (worker_thread_num > 0) {
+                struct shadeSpanArg msg[worker_thread_num];
+
+                if (worker_thread_num == 1) {
+                    msg[0].y = y + (h >> 1);
+                    msg[0].height = h - (h >> 1);
+
+                    h = (h >> 1);
+                } else if (worker_thread_num == 3) {
+                    msg[0].y = (y + (h >> 2));
+                    msg[0].height = ((h >> 1) - (h >> 2));
+
+                    msg[1].y = (y + (h >> 1));
+                    msg[1].height = (h - (h >> 1)) >> 1;
+
+                    msg[2].y = (y + (h >> 1) + ((h - (h >> 1)) >> 1));
+                    msg[2].height = h - (h >> 1) - ((h - (h >> 1)) >> 1);
+
+                    h = (h >> 2);
+                } else {
+                    __atomic_dec(&worker_thread_busy);
+                    goto fb;
+                }
+
+                for (int i = 0; i < worker_thread_num; i++) {
+                    msg[i].x = x;
+                    msg[i].width = w;
+                    msg[i].func = fBlitRect;
+                    assert( work[i] == 0);
+                    work[i] = &msg[i];
+
+                    sem_post(&sem_todo[i]);
+                }
+
+                fBlitRect(x,y,w,h);
+
+                for (int i = 0; i < worker_thread_num; i++) {
+                    sem_wait(&sem_done[i]);
+
+                   /* Need to set to NULL value. No point in still storing addresso of local
+                    * variable, after function returns
+                    */
+                    work[i] = NULL;
+                }
+                __atomic_dec(&worker_thread_busy);
+            } else {
+                __atomic_dec(&worker_thread_busy);
+                goto fb;
+            }
+            return;
+        }
+  }
+
+fb:
     fBlitRect(x,y,w,h);
 }