Home | History | Annotate | Download | only in fakehwc
      1 /*
      2  * Copyright 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 "FakeHwcUtil"
     20 #include <log/log.h>
     21 
     22 #include "FakeComposerUtils.h"
     23 #include "RenderState.h"
     24 
     25 #include "SurfaceFlinger.h" // Get the name of the service...
     26 
     27 #include <binder/IServiceManager.h>
     28 
     29 #include <cutils/properties.h>
     30 
     31 #include <iomanip>
     32 #include <thread>
     33 
     34 using android::String16;
     35 using android::sp;
     36 using namespace std::chrono_literals;
     37 using namespace sftest;
     38 using std::setw;
     39 
     40 namespace sftest {
     41 
     42 // clang-format off
     43 inline void printSourceRectAligned(::std::ostream& os, const hwc_frect_t& sourceRect, int align) {
     44     os << std::fixed << std::setprecision(1) << "("
     45        << setw(align) << sourceRect.left << setw(0) << ","
     46        << setw(align) << sourceRect.top << setw(0) << ","
     47        << setw(align) << sourceRect.right << setw(0) << ","
     48        << setw(align) << sourceRect.bottom << setw(0) << ")";
     49 }
     50 
     51 inline void printDisplayRectAligned(::std::ostream& os, const hwc_rect_t& displayRect, int align) {
     52     os << "("
     53        << setw(align) << displayRect.left << setw(0) << ","
     54        << setw(align) << displayRect.top << setw(0) << ","
     55        << setw(align) << displayRect.right << setw(0) << ","
     56        << setw(align) << displayRect.bottom << setw(0) << ")";
     57 }
     58 // clang-format on
     59 
     60 inline ::std::ostream& operator<<(::std::ostream& os, const sftest::RenderState& state) {
     61     printSourceRectAligned(os, state.mSourceCrop, 7);
     62     os << "->";
     63     printDisplayRectAligned(os, state.mDisplayFrame, 5);
     64     return os << " Swaps:" << state.mSwapCount << " Alpha:" << std::setprecision(3)
     65               << state.mPlaneAlpha << " Xform:" << state.mTransform;
     66 }
     67 
     68 // Helper for verifying the parts of the RenderState
     69 template <typename T>
     70 bool valuesMatch(::testing::AssertionResult& message, const T& ref, const T& val,
     71                  const char* name) {
     72     if (ref != val) {
     73         message = message << "Expected " << name << ":" << ref << ", got:" << val << ".";
     74         return false;
     75     }
     76     return true;
     77 }
     78 
     79 ::testing::AssertionResult rectsAreSame(const RenderState& ref, const RenderState& val) {
     80     // TODO: Message could start as success and be assigned as failure.
     81     // Only problem is that utility assumes it to be failure and just adds stuff. Would
     82     // need still special case the initial failure in the utility?
     83     // TODO: ... or would it be possible to break this back to gtest primitives?
     84     ::testing::AssertionResult message = ::testing::AssertionFailure();
     85     bool passes = true;
     86 
     87     // The work here is mostly about providing good log strings for differences
     88     passes &= valuesMatch(message, ref.mDisplayFrame, val.mDisplayFrame, "display frame");
     89     passes &= valuesMatch(message, ref.mPlaneAlpha, val.mPlaneAlpha, "alpha");
     90     passes &= valuesMatch(message, ref.mSwapCount, val.mSwapCount, "swap count");
     91     passes &= valuesMatch(message, ref.mSourceCrop, val.mSourceCrop, "source crop");
     92     // ... add more
     93     if (passes) {
     94         return ::testing::AssertionSuccess();
     95     }
     96     return message;
     97 }
     98 
     99 ::testing::AssertionResult framesAreSame(const std::vector<RenderState>& ref,
    100                                          const std::vector<RenderState>& val) {
    101     ::testing::AssertionResult message = ::testing::AssertionFailure();
    102     bool passed = true;
    103     if (ref.size() != val.size()) {
    104         message << "Expected " << ref.size() << " rects, got " << val.size() << ".";
    105         passed = false;
    106     }
    107     for (size_t rectIndex = 0; rectIndex < std::min(ref.size(), val.size()); rectIndex++) {
    108         ::testing::AssertionResult rectResult = rectsAreSame(ref[rectIndex], val[rectIndex]);
    109         if (rectResult == false) {
    110             message << "First different rect at " << rectIndex << ": " << rectResult.message();
    111             passed = false;
    112             break;
    113         }
    114     }
    115 
    116     if (passed) {
    117         return ::testing::AssertionSuccess();
    118     } else {
    119         message << "\nReference:";
    120         for (auto state = ref.begin(); state != ref.end(); ++state) {
    121             message << "\n" << *state;
    122         }
    123         message << "\nActual:";
    124         for (auto state = val.begin(); state != val.end(); ++state) {
    125             message << "\n" << *state;
    126         }
    127     }
    128     return message;
    129 }
    130 
    131 void startSurfaceFlinger() {
    132     ALOGI("Start SurfaceFlinger");
    133     system("start surfaceflinger");
    134 
    135     sp<android::IServiceManager> sm(android::defaultServiceManager());
    136     sp<android::IBinder> sf;
    137     while (sf == nullptr) {
    138         std::this_thread::sleep_for(10ms);
    139         sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
    140     }
    141     ALOGV("SurfaceFlinger running");
    142 }
    143 
    144 void stopSurfaceFlinger() {
    145     ALOGI("Stop SurfaceFlinger");
    146     system("stop surfaceflinger");
    147     sp<android::IServiceManager> sm(android::defaultServiceManager());
    148     sp<android::IBinder> sf;
    149     while (sf != nullptr) {
    150         std::this_thread::sleep_for(10ms);
    151         sf = sm->checkService(String16(android::SurfaceFlinger::getServiceName()));
    152     }
    153     ALOGV("SurfaceFlinger stopped");
    154 }
    155 
    156 ////////////////////////////////////////////////
    157 
    158 void FakeHwcEnvironment::SetUp() {
    159     ALOGI("Test env setup");
    160     system("setenforce 0");
    161     system("stop");
    162     property_set("debug.sf.nobootanimation", "1");
    163     {
    164         char value[PROPERTY_VALUE_MAX];
    165         property_get("debug.sf.nobootanimation", value, "0");
    166         LOG_FATAL_IF(atoi(value) != 1, "boot skip not set");
    167     }
    168     // TODO: Try registering the mock as the default service instead.
    169     property_set("debug.sf.hwc_service_name", "mock");
    170     // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
    171     property_set("debug.sf.treble_testing_override", "true");
    172 }
    173 
    174 void FakeHwcEnvironment::TearDown() {
    175     ALOGI("Test env tear down");
    176     system("stop");
    177     // Wait for mock call signaling teardown?
    178     property_set("debug.sf.nobootanimation", "0");
    179     property_set("debug.sf.hwc_service_name", "default");
    180     ALOGI("Test env tear down - done");
    181 }
    182 
    183 } // namespace sftest
    184