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"