blob: b18b5442573f9ec102431d5024be3705ca884823 [file] [log] [blame]
Kevin DuBois4df38a42019-02-14 12:59:43 -08001/*
2 * Copyright 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#include <gtest/gtest.h>
18#include <thread>
19
Huihong Luoecc1f902021-11-20 11:55:05 -080020#include <android/gui/BnRegionSamplingListener.h>
Kevin DuBois4df38a42019-02-14 12:59:43 -080021#include <binder/ProcessState.h>
Huihong Luo3bdef862022-03-03 11:57:19 -080022#include <gui/AidlStatusUtil.h>
Kevin DuBois4df38a42019-02-14 12:59:43 -080023#include <gui/DisplayEventReceiver.h>
Kevin DuBois4df38a42019-02-14 12:59:43 -080024#include <gui/ISurfaceComposer.h>
25#include <gui/Surface.h>
26#include <gui/SurfaceComposerClient.h>
Huihong Luo02186fb2022-02-23 14:21:54 -080027#include <private/gui/ComposerServiceAIDL.h>
Kevin DuBois4df38a42019-02-14 12:59:43 -080028#include <utils/Looper.h>
29
30using namespace std::chrono_literals;
Huihong Luo3bdef862022-03-03 11:57:19 -080031using android::gui::aidl_utils::statusTFromBinderStatus;
Kevin DuBois4df38a42019-02-14 12:59:43 -080032
33namespace android::test {
34
35struct ChoreographerSync {
36 ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
37 ~ChoreographerSync() = default;
38
39 void notify() const {
40 std::unique_lock<decltype(mutex_)> lk(mutex_);
41
42 auto check_event = [](auto const& ev) -> bool {
43 return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
44 };
45 DisplayEventReceiver::Event ev_;
46 int evs = receiver_.getEvents(&ev_, 1);
47 auto vsync_event_found = check_event(ev_);
48 while (evs) {
49 evs = receiver_.getEvents(&ev_, 1);
50 vsync_event_found |= check_event(ev_);
51 }
52
53 if (vsync_event_found) {
54 notification_arrived_ = true;
55 cv_.notify_all();
56 }
57 }
58
59 void wait_vsync_notify() const {
60 std::unique_lock<decltype(mutex_)> lk(mutex_);
61 cv_.wait(lk, [this] { return notification_arrived_; });
62 notification_arrived_ = false;
63 }
64
65private:
66 ChoreographerSync(ChoreographerSync const&) = delete;
67 ChoreographerSync& operator=(ChoreographerSync const&) = delete;
68
69 std::mutex mutable mutex_;
70 std::condition_variable mutable cv_;
71 bool mutable notification_arrived_ = false;
72 DisplayEventReceiver& receiver_;
73};
74
75struct ChoreographerSim {
76 static std::unique_ptr<ChoreographerSim> make() {
77 auto receiver = std::make_unique<DisplayEventReceiver>();
78 if (!receiver || receiver->initCheck() == NO_INIT) {
79 ALOGE("No display reciever");
80 return nullptr;
81 }
82 return std::unique_ptr<ChoreographerSim>(new ChoreographerSim(std::move(receiver)));
83 }
84
85 ~ChoreographerSim() {
86 poll_ = false;
87 looper->wake();
88 choreographer_thread_.join();
89 }
90
91 void request_render_wait(std::function<void()> const& render_fn) {
92 display_event_receiver_->requestNextVsync();
93 choreographer_.wait_vsync_notify();
94 render_fn();
95
96 // Purpose is to make sure that the content is latched by the time we sample.
97 // Waiting one vsync after queueing could still race with vsync, so wait for two, after
98 // which the content is pretty reliably on screen.
99 display_event_receiver_->requestNextVsync();
100 choreographer_.wait_vsync_notify();
101 display_event_receiver_->requestNextVsync();
102 choreographer_.wait_vsync_notify();
103 }
104
105private:
106 ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
107 : display_event_receiver_{std::move(receiver)},
108 choreographer_{*display_event_receiver_},
109 looper{new Looper(false)} {
110 choreographer_thread_ = std::thread([this] {
111 auto vsync_notify_fd = display_event_receiver_->getFd();
112 looper->addFd(vsync_notify_fd, 0, Looper::EVENT_INPUT,
113 [](int /*fd*/, int /*events*/, void* data) -> int {
114 if (!data) return 0;
115 reinterpret_cast<ChoreographerSync*>(data)->notify();
116 return 1;
117 },
118 const_cast<void*>(reinterpret_cast<void const*>(&choreographer_)));
119
120 while (poll_) {
121 auto const poll_interval =
122 std::chrono::duration_cast<std::chrono::milliseconds>(1s).count();
123 auto rc = looper->pollOnce(poll_interval);
124 if ((rc != Looper::POLL_CALLBACK) && (rc != Looper::POLL_WAKE))
125 ALOGW("Vsync Looper returned: %i\n", rc);
126 }
127 });
128 }
129
130 ChoreographerSim(ChoreographerSim const&) = delete;
131 ChoreographerSim& operator=(ChoreographerSim const&) = delete;
132
133 std::unique_ptr<DisplayEventReceiver> const display_event_receiver_;
134 ChoreographerSync const choreographer_;
135 sp<Looper> looper;
136 std::thread choreographer_thread_;
137 std::atomic<bool> poll_{true};
138};
139
Huihong Luoecc1f902021-11-20 11:55:05 -0800140struct Listener : android::gui::BnRegionSamplingListener {
141 binder::Status onSampleCollected(float medianLuma) override {
Kevin DuBois4df38a42019-02-14 12:59:43 -0800142 std::unique_lock<decltype(mutex)> lk(mutex);
143 received = true;
144 mLuma = medianLuma;
145 cv.notify_all();
Huihong Luoecc1f902021-11-20 11:55:05 -0800146 return binder::Status::ok();
Kevin DuBois4df38a42019-02-14 12:59:43 -0800147 };
148 bool wait_event(std::chrono::milliseconds timeout) {
149 std::unique_lock<decltype(mutex)> lk(mutex);
150 return cv.wait_for(lk, timeout, [this] { return received; });
151 }
152
153 float luma() {
154 std::unique_lock<decltype(mutex)> lk(mutex);
155 return mLuma;
156 }
157
158 void reset() {
159 std::unique_lock<decltype(mutex)> lk(mutex);
160 received = false;
161 }
162
163private:
164 std::condition_variable cv;
165 std::mutex mutex;
166 bool received = false;
167 float mLuma = -0.0f;
168};
169
170// Hoisted to TestSuite setup to avoid flake in test (b/124675919)
171std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
172
173struct RegionSamplingTest : ::testing::Test {
174protected:
175 RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
176
177 static void SetUpTestSuite() {
178 gChoreographerSim = ChoreographerSim::make();
179 ASSERT_NE(gChoreographerSim, nullptr);
180 }
181
182 void SetUp() override {
183 mSurfaceComposerClient = new SurfaceComposerClient;
184 ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
185
186 mBackgroundLayer =
187 mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
188 0, PIXEL_FORMAT_RGBA_8888,
Vishnu Nairfa247b12020-02-11 08:58:26 -0800189 ISurfaceComposerClient::eFXSurfaceEffect);
Kevin DuBois4df38a42019-02-14 12:59:43 -0800190 uint32_t layerPositionBottom = 0x7E000000;
191 SurfaceComposerClient::Transaction{}
192 .setLayer(mBackgroundLayer, layerPositionBottom)
193 .setPosition(mBackgroundLayer, 100, 100)
194 .setColor(mBackgroundLayer, half3{0.5, 0.5, 0.5})
195 .show(mBackgroundLayer)
196 .apply();
197
198 mContentLayer = mSurfaceComposerClient->createSurface(String8("Content RegionSamplingTest"),
199 300, 300, PIXEL_FORMAT_RGBA_8888, 0);
200
201 SurfaceComposerClient::Transaction{}
202 .setLayer(mContentLayer, layerPositionBottom + 1)
203 .setPosition(mContentLayer, 100, 100)
204 .setColor(mContentLayer, half3{0.5, 0.5, 0.5})
205 .show(mContentLayer)
206 .apply();
207
208 mTopLayer = mSurfaceComposerClient->createSurface(String8("TopLayer RegionSamplingTest"), 0,
209 0, PIXEL_FORMAT_RGBA_8888, 0);
210 SurfaceComposerClient::Transaction{}
211 .setLayer(mTopLayer, layerPositionBottom + 2)
212 .setPosition(mTopLayer, 0, 0)
213 .show(mBackgroundLayer)
214 .apply();
215 }
216
217 void fill_render(uint32_t rgba_value) {
218 auto surface = mContentLayer->getSurface();
219 ANativeWindow_Buffer outBuffer;
220 status_t status = surface->lock(&outBuffer, NULL);
221 ASSERT_EQ(status, android::OK);
222 auto b = reinterpret_cast<uint32_t*>(outBuffer.bits);
223 for (auto i = 0; i < outBuffer.height; i++) {
224 for (auto j = 0; j < outBuffer.width; j++) {
225 b[j] = rgba_value;
226 }
227 b += outBuffer.stride;
228 }
229
230 gChoreographerSim->request_render_wait([&surface] { surface->unlockAndPost(); });
231 }
232
233 sp<SurfaceComposerClient> mSurfaceComposerClient;
234 sp<SurfaceControl> mBackgroundLayer;
235 sp<SurfaceControl> mContentLayer;
236 sp<SurfaceControl> mTopLayer;
237
238 uint32_t const rgba_green = 0xFF00FF00;
239 float const luma_green = 0.7152;
240 uint32_t const rgba_blue = 0xFFFF0000;
241 float const luma_blue = 0.0722;
242 float const error_margin = 0.01;
243 float const luma_gray = 0.50;
244};
245
Alec Mouri9a02eda2020-04-21 17:39:34 -0700246TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
Huihong Luo02186fb2022-02-23 14:21:54 -0800247 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
Alec Mouri9a02eda2020-04-21 17:39:34 -0700248 sp<Listener> listener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800249 gui::ARect sampleArea;
250 sampleArea.left = 100;
251 sampleArea.top = 100;
252 sampleArea.right = 200;
253 sampleArea.bottom = 200;
Alec Mouri9a02eda2020-04-21 17:39:34 -0700254 // Passing in composer service as the layer handle should not crash, we'll
255 // treat it as a layer that no longer exists and silently allow sampling to
256 // occur.
Huihong Luo02186fb2022-02-23 14:21:54 -0800257 binder::Status status =
258 composer->addRegionSamplingListener(sampleArea, IInterface::asBinder(composer),
259 listener);
Huihong Luo3bdef862022-03-03 11:57:19 -0800260 ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
Alec Mouri9a02eda2020-04-21 17:39:34 -0700261 composer->removeRegionSamplingListener(listener);
262}
263
Kevin DuBois9dcf0492019-03-05 12:47:47 -0800264TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
Kevin DuBois4df38a42019-02-14 12:59:43 -0800265 fill_render(rgba_green);
266
Huihong Luo02186fb2022-02-23 14:21:54 -0800267 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
Kevin DuBois4df38a42019-02-14 12:59:43 -0800268 sp<Listener> listener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800269 gui::ARect sampleArea;
270 sampleArea.left = 100;
271 sampleArea.top = 100;
272 sampleArea.right = 200;
273 sampleArea.bottom = 200;
Kevin DuBois4df38a42019-02-14 12:59:43 -0800274 composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
275
276 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
277 EXPECT_NEAR(listener->luma(), luma_green, error_margin);
278
279 composer->removeRegionSamplingListener(listener);
280}
281
Kevin DuBois9dcf0492019-03-05 12:47:47 -0800282TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
Kevin DuBois4df38a42019-02-14 12:59:43 -0800283 fill_render(rgba_green);
284
Huihong Luo02186fb2022-02-23 14:21:54 -0800285 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
Kevin DuBois4df38a42019-02-14 12:59:43 -0800286 sp<Listener> listener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800287 gui::ARect sampleArea;
288 sampleArea.left = 100;
289 sampleArea.top = 100;
290 sampleArea.right = 200;
291 sampleArea.bottom = 200;
Kevin DuBois4df38a42019-02-14 12:59:43 -0800292 composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
293
294 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
295 EXPECT_NEAR(listener->luma(), luma_green, error_margin);
296
297 listener->reset();
298
299 fill_render(rgba_blue);
300 EXPECT_TRUE(listener->wait_event(300ms))
301 << "timed out waiting for 2nd luma event to be received";
302 EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
303
304 composer->removeRegionSamplingListener(listener);
305}
306
Kevin DuBois9dcf0492019-03-05 12:47:47 -0800307TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
Kevin DuBois4df38a42019-02-14 12:59:43 -0800308 fill_render(rgba_green);
Huihong Luo02186fb2022-02-23 14:21:54 -0800309 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
Kevin DuBois4df38a42019-02-14 12:59:43 -0800310 sp<Listener> greenListener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800311 gui::ARect greenSampleArea;
312 greenSampleArea.left = 100;
313 greenSampleArea.top = 100;
314 greenSampleArea.right = 200;
315 greenSampleArea.bottom = 200;
Kevin DuBois4df38a42019-02-14 12:59:43 -0800316 composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
317
318 sp<Listener> grayListener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800319 gui::ARect graySampleArea;
320 graySampleArea.left = 500;
321 graySampleArea.top = 100;
322 graySampleArea.right = 600;
323 graySampleArea.bottom = 200;
Kevin DuBois4df38a42019-02-14 12:59:43 -0800324 composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
325
326 EXPECT_TRUE(grayListener->wait_event(300ms))
327 << "timed out waiting for luma event to be received";
328 EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
329 EXPECT_TRUE(greenListener->wait_event(300ms))
330 << "timed out waiting for luma event to be received";
331 EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
332
333 composer->removeRegionSamplingListener(greenListener);
334 composer->removeRegionSamplingListener(grayListener);
335}
336
tangrobinacec5322019-02-21 19:40:26 +0800337TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) {
Huihong Luo02186fb2022-02-23 14:21:54 -0800338 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
tangrobinacec5322019-02-21 19:40:26 +0800339 sp<Listener> listener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800340
341 gui::ARect invalidRect;
342 invalidRect.left = Rect::INVALID_RECT.left;
343 invalidRect.top = Rect::INVALID_RECT.top;
344 invalidRect.right = Rect::INVALID_RECT.right;
345 invalidRect.bottom = Rect::INVALID_RECT.bottom;
346
347 gui::ARect sampleArea;
348 sampleArea.left = 100;
349 sampleArea.top = 100;
350 sampleArea.right = 200;
351 sampleArea.bottom = 200;
tangrobinacec5322019-02-21 19:40:26 +0800352 // Invalid input sampleArea
353 EXPECT_EQ(BAD_VALUE,
Huihong Luo3bdef862022-03-03 11:57:19 -0800354 statusTFromBinderStatus(composer->addRegionSamplingListener(invalidRect,
355 mTopLayer->getHandle(),
356 listener)));
tangrobinacec5322019-02-21 19:40:26 +0800357 listener->reset();
358 // Invalid input binder
Huihong Luo02186fb2022-02-23 14:21:54 -0800359 EXPECT_EQ(NO_ERROR,
Huihong Luo3bdef862022-03-03 11:57:19 -0800360 statusTFromBinderStatus(
361 composer->addRegionSamplingListener(sampleArea, NULL, listener)));
tangrobinacec5322019-02-21 19:40:26 +0800362 // Invalid input listener
363 EXPECT_EQ(BAD_VALUE,
Huihong Luo3bdef862022-03-03 11:57:19 -0800364 statusTFromBinderStatus(composer->addRegionSamplingListener(sampleArea,
365 mTopLayer->getHandle(),
366 NULL)));
367 EXPECT_EQ(BAD_VALUE, statusTFromBinderStatus(composer->removeRegionSamplingListener(NULL)));
tangrobinacec5322019-02-21 19:40:26 +0800368 // remove the listener
369 composer->removeRegionSamplingListener(listener);
370}
371
372TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) {
373 fill_render(rgba_green);
Huihong Luo02186fb2022-02-23 14:21:54 -0800374 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
tangrobinacec5322019-02-21 19:40:26 +0800375 sp<Listener> listener = new Listener();
Huihong Luo02186fb2022-02-23 14:21:54 -0800376 gui::ARect sampleArea;
377 sampleArea.left = 100;
378 sampleArea.top = 100;
379 sampleArea.right = 200;
380 sampleArea.bottom = 200;
tangrobinacec5322019-02-21 19:40:26 +0800381 composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
382 fill_render(rgba_green);
383
384 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
385 EXPECT_NEAR(listener->luma(), luma_green, error_margin);
386
387 listener->reset();
388 composer->removeRegionSamplingListener(listener);
389 fill_render(rgba_green);
390 EXPECT_FALSE(listener->wait_event(100ms))
391 << "callback should stop after remove the region sampling listener";
392}
393
394TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) {
Huihong Luo02186fb2022-02-23 14:21:54 -0800395 sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
tangrobinacec5322019-02-21 19:40:26 +0800396 sp<Listener> listener = new Listener();
397 Rect sampleArea{100, 100, 200, 200};
Huihong Luo02186fb2022-02-23 14:21:54 -0800398 gui::ARect sampleAreaA;
399 sampleAreaA.left = sampleArea.left;
400 sampleAreaA.top = sampleArea.top;
401 sampleAreaA.right = sampleArea.right;
402 sampleAreaA.bottom = sampleArea.bottom;
tangrobinacec5322019-02-21 19:40:26 +0800403
404 // Test: listener in (100, 100). See layer before move, no layer after move.
405 fill_render(rgba_blue);
Huihong Luo02186fb2022-02-23 14:21:54 -0800406 composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
tangrobinacec5322019-02-21 19:40:26 +0800407 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
408 EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
409 listener->reset();
410 SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply();
411 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
412 EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
413 composer->removeRegionSamplingListener(listener);
414
415 // Test: listener offset to (600, 600). No layer before move, see layer after move.
416 fill_render(rgba_green);
417 sampleArea.offsetTo(600, 600);
Huihong Luo02186fb2022-02-23 14:21:54 -0800418 sampleAreaA.left = sampleArea.left;
419 sampleAreaA.top = sampleArea.top;
420 sampleAreaA.right = sampleArea.right;
421 sampleAreaA.bottom = sampleArea.bottom;
422 composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
tangrobinacec5322019-02-21 19:40:26 +0800423 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
424 EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
425 listener->reset();
426 SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply();
427 EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
428 EXPECT_NEAR(listener->luma(), luma_green, error_margin);
429 composer->removeRegionSamplingListener(listener);
430}
431
Kevin DuBois4df38a42019-02-14 12:59:43 -0800432} // namespace android::test