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