• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
20 #include <android/gui/BnRegionSamplingListener.h>
21 #include <binder/ProcessState.h>
22 #include <gui/AidlStatusUtil.h>
23 #include <gui/DisplayEventReceiver.h>
24 #include <gui/ISurfaceComposer.h>
25 #include <gui/Surface.h>
26 #include <gui/SurfaceComposerClient.h>
27 #include <private/gui/ComposerServiceAIDL.h>
28 #include <utils/Looper.h>
29 
30 using namespace std::chrono_literals;
31 using android::gui::aidl_utils::statusTFromBinderStatus;
32 
33 namespace android::test {
34 
35 struct ChoreographerSync {
ChoreographerSyncandroid::test::ChoreographerSync36     ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
37     ~ChoreographerSync() = default;
38 
notifyandroid::test::ChoreographerSync39     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 
wait_vsync_notifyandroid::test::ChoreographerSync59     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 
65 private:
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 
75 struct ChoreographerSim {
makeandroid::test::ChoreographerSim76     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 
~ChoreographerSimandroid::test::ChoreographerSim85     ~ChoreographerSim() {
86         poll_ = false;
87         looper->wake();
88         choreographer_thread_.join();
89     }
90 
request_render_waitandroid::test::ChoreographerSim91     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 
105 private:
ChoreographerSimandroid::test::ChoreographerSim106     ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
107           : display_event_receiver_{std::move(receiver)},
108             choreographer_{*display_event_receiver_},
109             looper{new Looper(false)} {
__anon3a7db5280302null110         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 
140 struct Listener : android::gui::BnRegionSamplingListener {
onSampleCollectedandroid::test::Listener141     binder::Status onSampleCollected(float medianLuma) override {
142         std::unique_lock<decltype(mutex)> lk(mutex);
143         received = true;
144         mLuma = medianLuma;
145         cv.notify_all();
146         return binder::Status::ok();
147     };
wait_eventandroid::test::Listener148     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 
lumaandroid::test::Listener153     float luma() {
154         std::unique_lock<decltype(mutex)> lk(mutex);
155         return mLuma;
156     }
157 
resetandroid::test::Listener158     void reset() {
159         std::unique_lock<decltype(mutex)> lk(mutex);
160         received = false;
161     }
162 
163 private:
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)
171 std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
172 
173 struct RegionSamplingTest : ::testing::Test {
174 protected:
RegionSamplingTestandroid::test::RegionSamplingTest175     RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
176 
SetUpTestSuiteandroid::test::RegionSamplingTest177     static void SetUpTestSuite() {
178         gChoreographerSim = ChoreographerSim::make();
179         ASSERT_NE(gChoreographerSim, nullptr);
180     }
181 
SetUpandroid::test::RegionSamplingTest182     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,
189                                                       ISurfaceComposerClient::eFXSurfaceEffect);
190         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 
fill_renderandroid::test::RegionSamplingTest217     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 
TEST_F(RegionSamplingTest,invalidLayerHandle_doesNotCrash)246 TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
247     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
248     sp<Listener> listener = new Listener();
249     gui::ARect sampleArea;
250     sampleArea.left = 100;
251     sampleArea.top = 100;
252     sampleArea.right = 200;
253     sampleArea.bottom = 200;
254     // 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.
257     binder::Status status =
258             composer->addRegionSamplingListener(sampleArea, IInterface::asBinder(composer),
259                                                 listener);
260     ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
261     composer->removeRegionSamplingListener(listener);
262 }
263 
TEST_F(RegionSamplingTest,DISABLED_CollectsLuma)264 TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
265     fill_render(rgba_green);
266 
267     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
268     sp<Listener> listener = new Listener();
269     gui::ARect sampleArea;
270     sampleArea.left = 100;
271     sampleArea.top = 100;
272     sampleArea.right = 200;
273     sampleArea.bottom = 200;
274     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 
TEST_F(RegionSamplingTest,DISABLED_CollectsChangingLuma)282 TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
283     fill_render(rgba_green);
284 
285     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
286     sp<Listener> listener = new Listener();
287     gui::ARect sampleArea;
288     sampleArea.left = 100;
289     sampleArea.top = 100;
290     sampleArea.right = 200;
291     sampleArea.bottom = 200;
292     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 
TEST_F(RegionSamplingTest,DISABLED_CollectsLumaFromTwoRegions)307 TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
308     fill_render(rgba_green);
309     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
310     sp<Listener> greenListener = new Listener();
311     gui::ARect greenSampleArea;
312     greenSampleArea.left = 100;
313     greenSampleArea.top = 100;
314     greenSampleArea.right = 200;
315     greenSampleArea.bottom = 200;
316     composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
317 
318     sp<Listener> grayListener = new Listener();
319     gui::ARect graySampleArea;
320     graySampleArea.left = 500;
321     graySampleArea.top = 100;
322     graySampleArea.right = 600;
323     graySampleArea.bottom = 200;
324     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 
TEST_F(RegionSamplingTest,DISABLED_TestIfInvalidInputParameters)337 TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) {
338     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
339     sp<Listener> listener = new Listener();
340 
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;
352     // Invalid input sampleArea
353     EXPECT_EQ(BAD_VALUE,
354               statusTFromBinderStatus(composer->addRegionSamplingListener(invalidRect,
355                                                                           mTopLayer->getHandle(),
356                                                                           listener)));
357     listener->reset();
358     // Invalid input binder
359     EXPECT_EQ(NO_ERROR,
360               statusTFromBinderStatus(
361                       composer->addRegionSamplingListener(sampleArea, NULL, listener)));
362     // Invalid input listener
363     EXPECT_EQ(BAD_VALUE,
364               statusTFromBinderStatus(composer->addRegionSamplingListener(sampleArea,
365                                                                           mTopLayer->getHandle(),
366                                                                           NULL)));
367     EXPECT_EQ(BAD_VALUE, statusTFromBinderStatus(composer->removeRegionSamplingListener(NULL)));
368     // remove the listener
369     composer->removeRegionSamplingListener(listener);
370 }
371 
TEST_F(RegionSamplingTest,DISABLED_TestCallbackAfterRemoveListener)372 TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) {
373     fill_render(rgba_green);
374     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
375     sp<Listener> listener = new Listener();
376     gui::ARect sampleArea;
377     sampleArea.left = 100;
378     sampleArea.top = 100;
379     sampleArea.right = 200;
380     sampleArea.bottom = 200;
381     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 
TEST_F(RegionSamplingTest,DISABLED_CollectsLumaFromMovingLayer)394 TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) {
395     sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService();
396     sp<Listener> listener = new Listener();
397     Rect sampleArea{100, 100, 200, 200};
398     gui::ARect sampleAreaA;
399     sampleAreaA.left = sampleArea.left;
400     sampleAreaA.top = sampleArea.top;
401     sampleAreaA.right = sampleArea.right;
402     sampleAreaA.bottom = sampleArea.bottom;
403 
404     // Test: listener in (100, 100). See layer before move, no layer after move.
405     fill_render(rgba_blue);
406     composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener);
407     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);
418     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);
423     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 
432 } // namespace android::test
433