• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma clang diagnostic push
20 #pragma clang diagnostic ignored "-Wconversion"
21 #pragma clang diagnostic ignored "-Wextra"
22 
23 #include <chrono>
24 
25 #include <android/native_window.h>
26 #include <binder/IPCThreadState.h>
27 #include <gtest/gtest.h>
28 #include <gui/Surface.h>
29 #include <gui/SurfaceComposerClient.h>
30 #include <private/gui/ComposerService.h>
31 #include <ui/GraphicBuffer.h>
32 #include <ui/Rect.h>
33 
34 #include "ColorUtils.h"
35 
36 namespace android {
37 
38 namespace {
39 
40 using namespace std::chrono_literals;
41 using Transaction = SurfaceComposerClient::Transaction;
42 
43 std::ostream& operator<<(std::ostream& os, const Color& color) {
44     os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
45     return os;
46 }
47 
48 class TransactionUtils {
49 public:
50     // Fill a region with the specified color.
fillANativeWindowBufferColor(const ANativeWindow_Buffer & buffer,const Rect & rect,const Color & color)51     static void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
52                                              const Color& color) {
53         Rect r(0, 0, buffer.width, buffer.height);
54         if (!r.intersect(rect, &r)) {
55             return;
56         }
57 
58         int32_t width = r.right - r.left;
59         int32_t height = r.bottom - r.top;
60 
61         for (int32_t row = 0; row < height; row++) {
62             uint8_t* dst = static_cast<uint8_t*>(buffer.bits) +
63                     (buffer.stride * (r.top + row) + r.left) * 4;
64             for (int32_t column = 0; column < width; column++) {
65                 dst[0] = color.r;
66                 dst[1] = color.g;
67                 dst[2] = color.b;
68                 dst[3] = color.a;
69                 dst += 4;
70             }
71         }
72     }
73 
74     // Fill a region with the specified color.
fillGraphicBufferColor(const sp<GraphicBuffer> & buffer,const Rect & rect,const Color & color)75     static void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect,
76                                        const Color& color) {
77         Rect r(0, 0, buffer->width, buffer->height);
78         if (!r.intersect(rect, &r)) {
79             return;
80         }
81 
82         int32_t width = r.right - r.left;
83         int32_t height = r.bottom - r.top;
84 
85         uint8_t* pixels;
86         buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
87                      reinterpret_cast<void**>(&pixels));
88 
89         for (int32_t row = 0; row < height; row++) {
90             uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
91             for (int32_t column = 0; column < width; column++) {
92                 dst[0] = color.r;
93                 dst[1] = color.g;
94                 dst[2] = color.b;
95                 dst[3] = color.a;
96                 dst += 4;
97             }
98         }
99         buffer->unlock();
100     }
101 
102     // 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)103     static void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels,
104                                   const Rect& rect, const Color& color, uint8_t tolerance) {
105         int32_t x = rect.left;
106         int32_t y = rect.top;
107         int32_t width = rect.right - rect.left;
108         int32_t height = rect.bottom - rect.top;
109 
110         int32_t bufferWidth = int32_t(outBuffer->getWidth());
111         int32_t bufferHeight = int32_t(outBuffer->getHeight());
112         if (x + width > bufferWidth) {
113             x = std::min(x, bufferWidth);
114             width = bufferWidth - x;
115         }
116         if (y + height > bufferHeight) {
117             y = std::min(y, bufferHeight);
118             height = bufferHeight - y;
119         }
120 
121         auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
122             uint8_t tmp = a >= b ? a - b : b - a;
123             return tmp <= tolerance;
124         };
125         for (int32_t j = 0; j < height; j++) {
126             const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
127             for (int32_t i = 0; i < width; i++) {
128                 const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
129                 ASSERT_TRUE(std::equal(src, src + 4, expected, colorCompare))
130                         << "pixel @ (" << x + i << ", " << y + j << "): "
131                         << "expected (" << color << "), "
132                         << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
133                 src += 4;
134             }
135         }
136     }
137 
138     static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const Color& color,
139                                  bool unlock = true) {
140         fillSurfaceRGBA8(sc, color.r, color.g, color.b, unlock);
141     }
142 
143     // Fill an RGBA_8888 formatted surface with a single color.
144     static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
145                                  bool unlock = true) {
146         ANativeWindow_Buffer outBuffer;
147         sp<Surface> s = sc->getSurface();
148         ASSERT_TRUE(s != nullptr);
149         ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
150         uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
151         for (int y = 0; y < outBuffer.height; y++) {
152             for (int x = 0; x < outBuffer.width; x++) {
153                 uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
154                 pixel[0] = r;
155                 pixel[1] = g;
156                 pixel[2] = b;
157                 pixel[3] = 255;
158             }
159         }
160         if (unlock) {
161             ASSERT_EQ(NO_ERROR, s->unlockAndPost());
162         }
163     }
164 
165     static void setFrame(Transaction& t, const sp<SurfaceControl>& sc, Rect source, Rect dest,
166                          int32_t transform = 0) {
167         uint32_t sourceWidth = source.getWidth();
168         uint32_t sourceHeight = source.getHeight();
169 
170         if (transform & ui::Transform::ROT_90) {
171             std::swap(sourceWidth, sourceHeight);
172         }
173 
174         float dsdx = dest.getWidth() / static_cast<float>(sourceWidth);
175         float dsdy = dest.getHeight() / static_cast<float>(sourceHeight);
176 
177         t.setMatrix(sc, dsdx, 0, 0, dsdy);
178         t.setPosition(sc, dest.left, dest.top);
179     }
180 };
181 
182 enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
183 
184 // Environment for starting up binder threads. This is required for testing
185 // virtual displays, as BufferQueue parameters may be queried over binder.
186 class BinderEnvironment : public ::testing::Environment {
187 public:
SetUp()188     void SetUp() override { ProcessState::self()->startThreadPool(); }
189 };
190 
191 /** RAII Wrapper around get/seteuid */
192 class UIDFaker {
193     uid_t oldId;
194 
195 public:
UIDFaker(uid_t uid)196     UIDFaker(uid_t uid) {
197         oldId = geteuid();
198         seteuid(uid);
199     }
~UIDFaker()200     ~UIDFaker() { seteuid(oldId); }
201 };
202 } // namespace
203 } // namespace android
204 
205 // TODO(b/129481165): remove the #pragma below and fix conversion issues
206 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"