1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <chrono>
20 
21 #include <android/native_window.h>
22 #include <binder/IPCThreadState.h>
23 #include <gtest/gtest.h>
24 #include <gui/Surface.h>
25 #include <gui/SurfaceComposerClient.h>
26 #include <private/gui/ComposerService.h>
27 #include <ui/GraphicBuffer.h>
28 #include <ui/Rect.h>
29 
30 #include "ColorUtils.h"
31 
32 namespace android {
33 
34 namespace {
35 
36 using namespace std::chrono_literals;
37 using Transaction = SurfaceComposerClient::Transaction;
38 
39 std::ostream& operator<<(std::ostream& os, const Color& color) {
40     os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
41     return os;
42 }
43 
44 class TransactionUtils {
45 public:
46     // Fill a region with the specified color.
fillANativeWindowBufferColor(const ANativeWindow_Buffer & buffer,const Rect & rect,const Color & color)47     static void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
48                                              const Color& color) {
49         Rect r(0, 0, buffer.width, buffer.height);
50         if (!r.intersect(rect, &r)) {
51             return;
52         }
53 
54         int32_t width = r.right - r.left;
55         int32_t height = r.bottom - r.top;
56 
57         for (int32_t row = 0; row < height; row++) {
58             uint8_t* dst = static_cast<uint8_t*>(buffer.bits) +
59                     (buffer.stride * (r.top + row) + r.left) * 4;
60             for (int32_t column = 0; column < width; column++) {
61                 dst[0] = color.r;
62                 dst[1] = color.g;
63                 dst[2] = color.b;
64                 dst[3] = color.a;
65                 dst += 4;
66             }
67         }
68     }
69 
70     // Fill a region with the specified color.
fillGraphicBufferColor(const sp<GraphicBuffer> & buffer,const Rect & rect,const Color & color)71     static void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect,
72                                        const Color& color) {
73         Rect r(0, 0, buffer->width, buffer->height);
74         if (!r.intersect(rect, &r)) {
75             return;
76         }
77 
78         int32_t width = r.right - r.left;
79         int32_t height = r.bottom - r.top;
80 
81         uint8_t* pixels;
82         buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
83                      reinterpret_cast<void**>(&pixels));
84 
85         for (int32_t row = 0; row < height; row++) {
86             uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
87             for (int32_t column = 0; column < width; column++) {
88                 dst[0] = color.r;
89                 dst[1] = color.g;
90                 dst[2] = color.b;
91                 dst[3] = color.a;
92                 dst += 4;
93             }
94         }
95         buffer->unlock();
96     }
97 
98     // Check if a region has the specified color.
expectBufferColor(const sp<GraphicBuffer> & outBuffer,uint8_t * pixels,const Rect & rect,const Color & color,uint8_t tolerance)99     static void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels,
100                                   const Rect& rect, const Color& color, uint8_t tolerance) {
101         int32_t x = rect.left;
102         int32_t y = rect.top;
103         int32_t width = rect.right - rect.left;
104         int32_t height = rect.bottom - rect.top;
105 
106         int32_t bufferWidth = int32_t(outBuffer->getWidth());
107         int32_t bufferHeight = int32_t(outBuffer->getHeight());
108         if (x + width > bufferWidth) {
109             x = std::min(x, bufferWidth);
110             width = bufferWidth - x;
111         }
112         if (y + height > bufferHeight) {
113             y = std::min(y, bufferHeight);
114             height = bufferHeight - y;
115         }
116 
117         auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
118             uint8_t tmp = a >= b ? a - b : b - a;
119             return tmp <= tolerance;
120         };
121         for (int32_t j = 0; j < height; j++) {
122             const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
123             for (int32_t i = 0; i < width; i++) {
124                 const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
125                 EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
126                         << "pixel @ (" << x + i << ", " << y + j << "): "
127                         << "expected (" << color << "), "
128                         << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
129                 src += 4;
130             }
131         }
132     }
133 
134     static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const Color& color,
135                                  bool unlock = true) {
136         fillSurfaceRGBA8(sc, color.r, color.g, color.b, unlock);
137     }
138 
139     // Fill an RGBA_8888 formatted surface with a single color.
140     static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
141                                  bool unlock = true) {
142         ANativeWindow_Buffer outBuffer;
143         sp<Surface> s = sc->getSurface();
144         ASSERT_TRUE(s != nullptr);
145         ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
146         uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
147         for (int y = 0; y < outBuffer.height; y++) {
148             for (int x = 0; x < outBuffer.width; x++) {
149                 uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
150                 pixel[0] = r;
151                 pixel[1] = g;
152                 pixel[2] = b;
153                 pixel[3] = 255;
154             }
155         }
156         if (unlock) {
157             ASSERT_EQ(NO_ERROR, s->unlockAndPost());
158         }
159     }
160 };
161 
162 enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
163 
164 // Environment for starting up binder threads. This is required for testing
165 // virtual displays, as BufferQueue parameters may be queried over binder.
166 class BinderEnvironment : public ::testing::Environment {
167 public:
SetUp()168     void SetUp() override { ProcessState::self()->startThreadPool(); }
169 };
170 
171 /** RAII Wrapper around get/seteuid */
172 class UIDFaker {
173     uid_t oldId;
174 
175 public:
UIDFaker(uid_t uid)176     UIDFaker(uid_t uid) {
177         oldId = geteuid();
178         seteuid(uid);
179     }
~UIDFaker()180     ~UIDFaker() { seteuid(oldId); }
181 };
182 } // namespace
183 } // namespace android
184