Home | History | Annotate | Download | only in fakehwc
      1 /*
      2  * Copyright (C) 2017 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 //#define LOG_NDEBUG 0
     18 #undef LOG_TAG
     19 #define LOG_TAG "FakeComposer"
     20 
     21 #include "FakeComposerClient.h"
     22 
     23 #include <gui/SurfaceComposerClient.h>
     24 
     25 #include <log/log.h>
     26 
     27 #include <gtest/gtest.h>
     28 
     29 #include <inttypes.h>
     30 #include <time.h>
     31 #include <algorithm>
     32 #include <condition_variable>
     33 #include <iostream>
     34 #include <mutex>
     35 #include <set>
     36 #include <thread>
     37 
     38 constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
     39 
     40 using namespace sftest;
     41 
     42 using android::Condition;
     43 using android::Mutex;
     44 
     45 using Clock = std::chrono::steady_clock;
     46 using TimePoint = std::chrono::time_point<Clock>;
     47 
     48 namespace {
     49 
     50 // Internal state of a layer in the HWC API.
     51 class LayerImpl {
     52 public:
     53     LayerImpl() = default;
     54 
     55     bool mValid = true;
     56     RenderState mRenderState;
     57     uint32_t mZ = 0;
     58 };
     59 
     60 // Struct for storing per frame rectangle state. Contains the render
     61 // state shared to the test case. Basically a snapshot and a subset of
     62 // LayerImpl sufficient to re-create the pixels of a layer for the
     63 // frame.
     64 struct FrameRect {
     65 public:
     66     FrameRect(Layer layer_, const RenderState& state, uint32_t z_)
     67           : layer(layer_), renderState(state), z(z_) {}
     68 
     69     const Layer layer;
     70     const RenderState renderState;
     71     const uint32_t z;
     72 };
     73 
     74 // Collection of FrameRects forming one rendered frame. Could store
     75 // related fences and other data in the future.
     76 class Frame {
     77 public:
     78     Frame() = default;
     79     std::vector<std::unique_ptr<FrameRect>> rectangles;
     80 };
     81 
     82 class DelayedEventGenerator {
     83 public:
     84     explicit DelayedEventGenerator(std::function<void()> onTimerExpired)
     85           : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
     86 
     87     ~DelayedEventGenerator() {
     88         ALOGI("DelayedEventGenerator exiting.");
     89         {
     90             std::unique_lock<std::mutex> lock(mMutex);
     91             mRunning = false;
     92             mWakeups.clear();
     93             mCondition.notify_one();
     94         }
     95         mThread.join();
     96         ALOGI("DelayedEventGenerator exited.");
     97     }
     98 
     99     void wakeAfter(std::chrono::nanoseconds waitTime) {
    100         std::unique_lock<std::mutex> lock(mMutex);
    101         mWakeups.insert(Clock::now() + waitTime);
    102         mCondition.notify_one();
    103     }
    104 
    105 private:
    106     void loop() {
    107         while (true) {
    108             // Lock scope
    109             {
    110                 std::unique_lock<std::mutex> lock(mMutex);
    111                 mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); });
    112                 if (!mRunning && mWakeups.empty()) {
    113                     // This thread should only exit once the destructor has been called and all
    114                     // wakeups have been processed
    115                     return;
    116                 }
    117 
    118                 // At this point, mWakeups will not be empty
    119 
    120                 TimePoint target = *(mWakeups.begin());
    121                 auto status = mCondition.wait_until(lock, target);
    122                 while (status == std::cv_status::no_timeout) {
    123                     // This was either a spurious wakeup or another wakeup was added, so grab the
    124                     // oldest point and wait again
    125                     target = *(mWakeups.begin());
    126                     status = mCondition.wait_until(lock, target);
    127                 }
    128 
    129                 // status must have been timeout, so we can finally clear this point
    130                 mWakeups.erase(target);
    131             }
    132             // Callback *without* locks!
    133             mOnTimerExpired();
    134         }
    135     }
    136 
    137     std::function<void()> mOnTimerExpired;
    138     std::thread mThread;
    139     std::mutex mMutex;
    140     std::condition_variable mCondition;
    141     bool mRunning = true;
    142     std::set<TimePoint> mWakeups;
    143 };
    144 
    145 } // namespace
    146 
    147 FakeComposerClient::FakeComposerClient()
    148       : mEventCallback(nullptr),
    149         mCurrentConfig(NULL_DISPLAY_CONFIG),
    150         mVsyncEnabled(false),
    151         mLayers(),
    152         mDelayedEventGenerator(
    153                 std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })),
    154         mSurfaceComposer(nullptr) {}
    155 
    156 FakeComposerClient::~FakeComposerClient() {}
    157 
    158 bool FakeComposerClient::hasCapability(hwc2_capability_t /*capability*/) {
    159     return false;
    160 }
    161 
    162 std::string FakeComposerClient::dumpDebugInfo() {
    163     return {};
    164 }
    165 
    166 void FakeComposerClient::registerEventCallback(EventCallback* callback) {
    167     ALOGV("registerEventCallback");
    168     mEventCallback = callback;
    169     if (mEventCallback) {
    170         mEventCallback->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
    171     }
    172 }
    173 
    174 void FakeComposerClient::unregisterEventCallback() {
    175     ALOGV("unregisterEventCallback");
    176     mEventCallback = nullptr;
    177 }
    178 
    179 void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
    180     if (mEventCallback) {
    181         mEventCallback->onHotplug(display, state);
    182     }
    183 }
    184 
    185 void FakeComposerClient::refreshDisplay(Display display) {
    186     if (mEventCallback) {
    187         mEventCallback->onRefresh(display);
    188     }
    189 }
    190 
    191 uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
    192     ALOGV("getMaxVirtualDisplayCount");
    193     return 1;
    194 }
    195 
    196 Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
    197                                                PixelFormat* /*format*/, Display* /*outDisplay*/) {
    198     ALOGV("createVirtualDisplay");
    199     return Error::NONE;
    200 }
    201 
    202 Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
    203     ALOGV("destroyVirtualDisplay");
    204     return Error::NONE;
    205 }
    206 
    207 Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
    208     ALOGV("createLayer");
    209     *outLayer = mLayers.size();
    210     auto newLayer = std::make_unique<LayerImpl>();
    211     mLayers.push_back(std::move(newLayer));
    212     return Error::NONE;
    213 }
    214 
    215 Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
    216     ALOGV("destroyLayer");
    217     mLayers[layer]->mValid = false;
    218     return Error::NONE;
    219 }
    220 
    221 Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) {
    222     ALOGV("getActiveConfig");
    223 
    224     // TODO Assert outConfig != nullptr
    225 
    226     // TODO This is my reading of the
    227     // IComposerClient::getActiveConfig, but returning BAD_CONFIG
    228     // seems to not fit SurfaceFlinger plans. See version 2 below.
    229     // if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
    230     //     return Error::BAD_CONFIG;
    231     // }
    232     //*outConfig = mCurrentConfig;
    233     *outConfig = 1; // Very special config for you my friend
    234     return Error::NONE;
    235 }
    236 
    237 Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
    238                                                  uint32_t /*height*/, PixelFormat /*format*/,
    239                                                  Dataspace /*dataspace*/) {
    240     ALOGV("getClientTargetSupport");
    241     return Error::NONE;
    242 }
    243 
    244 Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) {
    245     ALOGV("getColorModes");
    246     return Error::NONE;
    247 }
    248 
    249 Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
    250                                               IComposerClient::Attribute attribute,
    251                                               int32_t* outValue) {
    252     ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
    253           static_cast<int>(config), static_cast<int>(attribute), outValue);
    254 
    255     // TODO: SOOO much fun to be had with these alone
    256     switch (attribute) {
    257         case IComposerClient::Attribute::WIDTH:
    258             *outValue = 1920;
    259             break;
    260         case IComposerClient::Attribute::HEIGHT:
    261             *outValue = 1080;
    262             break;
    263         case IComposerClient::Attribute::VSYNC_PERIOD:
    264             *outValue = 1666666666;
    265             break; // TOOD: Tests break down if lowered to 16ms?
    266         case IComposerClient::Attribute::DPI_X:
    267             *outValue = 240;
    268             break;
    269         case IComposerClient::Attribute::DPI_Y:
    270             *outValue = 240;
    271             break;
    272         default:
    273             LOG_ALWAYS_FATAL("Say what!?! New attribute");
    274     }
    275 
    276     return Error::NONE;
    277 }
    278 
    279 Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) {
    280     ALOGV("getDisplayConfigs");
    281     // TODO assert display == 1, outConfigs != nullptr
    282 
    283     outConfigs->resize(1);
    284     (*outConfigs)[0] = 1;
    285 
    286     return Error::NONE;
    287 }
    288 
    289 Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
    290     ALOGV("getDisplayName");
    291     return Error::NONE;
    292 }
    293 
    294 Error FakeComposerClient::getDisplayType(Display /*display*/,
    295                                          IComposerClient::DisplayType* outType) {
    296     ALOGV("getDisplayType");
    297     // TODO: This setting nothing on the output had no effect on initial trials. Is first display
    298     // assumed to be physical?
    299     *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
    300     return Error::NONE;
    301 }
    302 
    303 Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
    304     ALOGV("getDozeSupport");
    305     return Error::NONE;
    306 }
    307 
    308 Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/,
    309                                              float* /*outMaxLuminance*/,
    310                                              float* /*outMaxAverageLuminance*/,
    311                                              float* /*outMinLuminance*/) {
    312     ALOGV("getHdrCapabilities");
    313     return Error::NONE;
    314 }
    315 
    316 Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) {
    317     ALOGV("setActiveConfig");
    318     mCurrentConfig = config;
    319     return Error::NONE;
    320 }
    321 
    322 Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) {
    323     ALOGV("setColorMode");
    324     return Error::NONE;
    325 }
    326 
    327 Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) {
    328     ALOGV("setPowerMode");
    329     return Error::NONE;
    330 }
    331 
    332 Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) {
    333     mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
    334     ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
    335     return Error::NONE;
    336 }
    337 
    338 Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
    339                                             int32_t /*hint*/) {
    340     ALOGV("setColorTransform");
    341     return Error::NONE;
    342 }
    343 
    344 Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
    345                                           int32_t /*acquireFence*/, int32_t /*dataspace*/,
    346                                           const std::vector<hwc_rect_t>& /*damage*/) {
    347     ALOGV("setClientTarget");
    348     return Error::NONE;
    349 }
    350 
    351 Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
    352                                           int32_t /*releaseFence*/) {
    353     ALOGV("setOutputBuffer");
    354     return Error::NONE;
    355 }
    356 
    357 Error FakeComposerClient::validateDisplay(
    358         Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
    359         std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
    360         uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
    361         std::vector<uint32_t>* /*outRequestMasks*/) {
    362     ALOGV("validateDisplay");
    363     // TODO: Assume touching nothing means All Korrekt!
    364     return Error::NONE;
    365 }
    366 
    367 Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
    368     ALOGV("acceptDisplayChanges");
    369     // Didn't ask for changes because software is omnipotent.
    370     return Error::NONE;
    371 }
    372 
    373 bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
    374     return a->z <= b->z;
    375 }
    376 
    377 Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
    378                                          std::vector<Layer>* /*outLayers*/,
    379                                          std::vector<int32_t>* /*outReleaseFences*/) {
    380     ALOGV("presentDisplay");
    381     // TODO Leaving layers and their fences out for now. Doing so
    382     // means that we've already processed everything. Important to
    383     // test that the fences are respected, though. (How?)
    384 
    385     std::unique_ptr<Frame> newFrame(new Frame);
    386     for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
    387         const LayerImpl& layerImpl = *mLayers[layer];
    388 
    389         if (!layerImpl.mValid) continue;
    390 
    391         auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
    392         newFrame->rectangles.push_back(std::move(rect));
    393     }
    394     std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
    395     {
    396         Mutex::Autolock _l(mStateMutex);
    397         mFrames.push_back(std::move(newFrame));
    398         mFramesAvailable.broadcast();
    399     }
    400     return Error::NONE;
    401 }
    402 
    403 Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
    404                                                  int32_t /*x*/, int32_t /*y*/) {
    405     ALOGV("setLayerCursorPosition");
    406     return Error::NONE;
    407 }
    408 
    409 Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer,
    410                                          int32_t acquireFence) {
    411     ALOGV("setLayerBuffer");
    412     LayerImpl& l = getLayerImpl(layer);
    413     if (buffer != l.mRenderState.mBuffer) {
    414         l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
    415     }
    416     l.mRenderState.mBuffer = buffer;
    417     l.mRenderState.mAcquireFence = acquireFence;
    418 
    419     return Error::NONE;
    420 }
    421 
    422 Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
    423                                                 const std::vector<hwc_rect_t>& /*damage*/) {
    424     ALOGV("setLayerSurfaceDamage");
    425     return Error::NONE;
    426 }
    427 
    428 Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
    429     ALOGV("setLayerBlendMode");
    430     getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
    431     return Error::NONE;
    432 }
    433 
    434 Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
    435                                         IComposerClient::Color color) {
    436     ALOGV("setLayerColor");
    437     getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
    438     getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
    439     getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
    440     getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
    441     return Error::NONE;
    442 }
    443 
    444 Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
    445                                                   int32_t /*type*/) {
    446     ALOGV("setLayerCompositionType");
    447     return Error::NONE;
    448 }
    449 
    450 Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
    451                                             int32_t /*dataspace*/) {
    452     ALOGV("setLayerDataspace");
    453     return Error::NONE;
    454 }
    455 
    456 Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
    457                                                const hwc_rect_t& frame) {
    458     ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
    459           frame.bottom);
    460     getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
    461     return Error::NONE;
    462 }
    463 
    464 Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
    465     ALOGV("setLayerPlaneAlpha");
    466     getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
    467     return Error::NONE;
    468 }
    469 
    470 Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
    471                                                  buffer_handle_t /*stream*/) {
    472     ALOGV("setLayerSidebandStream");
    473     return Error::NONE;
    474 }
    475 
    476 Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
    477                                              const hwc_frect_t& crop) {
    478     ALOGV("setLayerSourceCrop");
    479     getLayerImpl(layer).mRenderState.mSourceCrop = crop;
    480     return Error::NONE;
    481 }
    482 
    483 Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) {
    484     ALOGV("setLayerTransform");
    485     getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
    486     return Error::NONE;
    487 }
    488 
    489 Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
    490                                                 const std::vector<hwc_rect_t>& visible) {
    491     ALOGV("setLayerVisibleRegion");
    492     getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
    493     return Error::NONE;
    494 }
    495 
    496 Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
    497     ALOGV("setLayerZOrder");
    498     getLayerImpl(layer).mZ = z;
    499     return Error::NONE;
    500 }
    501 
    502 //////////////////////////////////////////////////////////////////
    503 
    504 void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
    505     if (mEventCallback) {
    506         uint64_t timestamp = vsyncTime;
    507         ALOGV("Vsync");
    508         if (timestamp == 0) {
    509             struct timespec ts;
    510             clock_gettime(CLOCK_MONOTONIC, &ts);
    511             timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
    512         }
    513         if (mSurfaceComposer != nullptr) {
    514             mSurfaceComposer->injectVSync(timestamp);
    515         } else {
    516             mEventCallback->onVsync(PRIMARY_DISPLAY, timestamp);
    517         }
    518     }
    519 }
    520 
    521 void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) {
    522     mDelayedEventGenerator->wakeAfter(wait);
    523 }
    524 
    525 LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) {
    526     // TODO Change these to an internal state check that can be
    527     // invoked from the gtest? GTest macros do not seem all that safe
    528     // when used outside the test class
    529     EXPECT_GE(handle, static_cast<Layer>(0));
    530     EXPECT_LT(handle, mLayers.size());
    531     return *(mLayers[handle]);
    532 }
    533 
    534 int FakeComposerClient::getFrameCount() const {
    535     return mFrames.size();
    536 }
    537 
    538 static std::vector<RenderState> extractRenderState(
    539         const std::vector<std::unique_ptr<FrameRect>>& internalRects) {
    540     std::vector<RenderState> result;
    541     result.reserve(internalRects.size());
    542     for (const std::unique_ptr<FrameRect>& rect : internalRects) {
    543         result.push_back(rect->renderState);
    544     }
    545     return result;
    546 }
    547 
    548 std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const {
    549     Mutex::Autolock _l(mStateMutex);
    550     return extractRenderState(mFrames[frame]->rectangles);
    551 }
    552 
    553 std::vector<RenderState> FakeComposerClient::getLatestFrame() const {
    554     Mutex::Autolock _l(mStateMutex);
    555     return extractRenderState(mFrames[mFrames.size() - 1]->rectangles);
    556 }
    557 
    558 void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) {
    559     int currentFrame = 0;
    560     {
    561         Mutex::Autolock _l(mStateMutex); // I hope this is ok...
    562         currentFrame = static_cast<int>(mFrames.size());
    563         requestVSync();
    564     }
    565     waitUntilFrame(currentFrame + 1, maxWait);
    566 }
    567 
    568 void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const {
    569     Mutex::Autolock _l(mStateMutex);
    570     while (mFrames.size() < static_cast<size_t>(targetFrame)) {
    571         android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count());
    572         if (result == android::TIMED_OUT) {
    573             ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame,
    574                   mFrames.size(), maxWait.count());
    575             return;
    576         }
    577     }
    578 }
    579 
    580 void FakeComposerClient::clearFrames() {
    581     Mutex::Autolock _l(mStateMutex);
    582     mFrames.clear();
    583     for (const std::unique_ptr<LayerImpl>& layer : mLayers) {
    584         if (layer->mValid) {
    585             layer->mRenderState.mSwapCount = 0;
    586         }
    587     }
    588 }
    589 
    590 void FakeComposerClient::onSurfaceFlingerStart() {
    591     mSurfaceComposer = nullptr;
    592     do {
    593         mSurfaceComposer = new android::SurfaceComposerClient;
    594         android::status_t initResult = mSurfaceComposer->initCheck();
    595         if (initResult != android::NO_ERROR) {
    596             ALOGD("Init result: %d", initResult);
    597             mSurfaceComposer = nullptr;
    598             std::this_thread::sleep_for(10ms);
    599         }
    600     } while (mSurfaceComposer == nullptr);
    601     ALOGD("SurfaceComposerClient created");
    602     mSurfaceComposer->enableVSyncInjections(true);
    603 }
    604 
    605 void FakeComposerClient::onSurfaceFlingerStop() {
    606     mSurfaceComposer->dispose();
    607     mSurfaceComposer.clear();
    608 }
    609 
    610 // Includes destroyed layers, stored in order of creation.
    611 int FakeComposerClient::getLayerCount() const {
    612     return mLayers.size();
    613 }
    614 
    615 Layer FakeComposerClient::getLayer(size_t index) const {
    616     // NOTE: If/when passing calls through to actual implementation,
    617     // this might get more involving.
    618     return static_cast<Layer>(index);
    619 }
    620