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
printSourceRectAligned(::std::ostream & os,const hwc_frect_t & sourceRect,int align)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
printDisplayRectAligned(::std::ostream & os,const hwc_rect_t & displayRect,int align)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
operator <<(::std::ostream & os,const sftest::RenderState & state)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>
valuesMatch(::testing::AssertionResult & message,const T & ref,const T & val,const char * name)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
rectsAreSame(const RenderState & ref,const RenderState & val)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
framesAreSame(const std::vector<RenderState> & ref,const std::vector<RenderState> & val)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
startSurfaceFlinger()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
stopSurfaceFlinger()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
SetUp()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
TearDown()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