1 /*
2 * Copyright (C) 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 #define LOG_TAG "health_hidl_hal_test"
18
19 #include <mutex>
20 #include <set>
21 #include <string>
22
23 #include <android-base/logging.h>
24 #include <android/hardware/health/1.0/types.h>
25 #include <android/hardware/health/2.0/types.h>
26 #include <android/hardware/health/2.1/IHealth.h>
27 #include <android/hardware/health/2.1/IHealthInfoCallback.h>
28 #include <android/hardware/health/2.1/types.h>
29 #include <gmock/gmock.h>
30 #include <gtest/gtest.h>
31 #include <hidl/GtestPrinter.h>
32 #include <hidl/ServiceManagement.h>
33
34 using ::android::hardware::health::V1_0::BatteryStatus;
35 using ::android::hardware::health::V2_0::Result;
36 using ::testing::AnyOf;
37 using ::testing::AssertionFailure;
38 using ::testing::AssertionResult;
39 using ::testing::AssertionSuccess;
40 using namespace std::chrono_literals;
41
42 using ::android::hardware::health::V1_0::toString;
43 using ::android::hardware::health::V2_0::toString;
44 using ::android::hardware::health::V2_1::toString;
45
46 // Return expr if it is evaluated to false.
47 #define TEST_AND_RETURN(expr) \
48 do { \
49 auto res = (expr); \
50 if (!res) return res; \
51 } while (0)
52
53 // Return a descriptive AssertionFailure() if expr is evaluated to false.
54 #define TEST_AND_RETURN_FAILURE(expr) \
55 do { \
56 auto res = (expr); \
57 if (!res) { \
58 return AssertionFailure() << #expr " is false"; \
59 } \
60 } while (0)
61
62 namespace android {
63 namespace hardware {
64 namespace health {
65
66 namespace V2_0 {
operator <<(std::ostream & os,const Result & res)67 std::ostream& operator<<(std::ostream& os, const Result& res) {
68 return os << toString(res);
69 }
70 } // namespace V2_0
71
72 namespace V2_1 {
73
74 class HealthHidlTest : public testing::TestWithParam<std::string> {
75 public:
SetUp()76 virtual void SetUp() override {
77 service_ = IHealth::getService(GetParam());
78 ASSERT_NE(nullptr, service_.get()) << "Instance '" << GetParam() << "'' is not available.";
79 }
80
81 sp<IHealth> service_;
82 };
83
84 class CallbackBase {
85 public:
healthInfoChangedInternal()86 Return<void> healthInfoChangedInternal() {
87 std::lock_guard<std::mutex> lock(mutex_);
88 invoked_ = true;
89 invoked_notify_.notify_all();
90 return Void();
91 }
92 template <typename R, typename P>
waitInvoke(std::chrono::duration<R,P> duration)93 bool waitInvoke(std::chrono::duration<R, P> duration) {
94 std::unique_lock<std::mutex> lock(mutex_);
95 bool r = invoked_notify_.wait_for(lock, duration, [this] { return this->invoked_; });
96 invoked_ = false;
97 return r;
98 }
99
100 private:
101 std::mutex mutex_;
102 std::condition_variable invoked_notify_;
103 bool invoked_ = false;
104 };
105
106 class Callback_2_0 : public android::hardware::health::V2_0::IHealthInfoCallback,
107 public CallbackBase {
healthInfoChanged(const android::hardware::health::V2_0::HealthInfo &)108 Return<void> healthInfoChanged(const android::hardware::health::V2_0::HealthInfo&) override {
109 return healthInfoChangedInternal();
110 }
111 };
112
113 class Callback_2_1 : public android::hardware::health::V2_1::IHealthInfoCallback,
114 public CallbackBase {
healthInfoChanged(const android::hardware::health::V2_0::HealthInfo &)115 Return<void> healthInfoChanged(const android::hardware::health::V2_0::HealthInfo&) override {
116 ADD_FAILURE() << "android::hardware::health::V2_1::IHealthInfoCallback::healthInfoChanged "
117 << "is called, but it shouldn't be";
118 return Void();
119 }
healthInfoChanged_2_1(const HealthInfo &)120 Return<void> healthInfoChanged_2_1(const HealthInfo&) override {
121 return healthInfoChangedInternal();
122 }
123 };
124
125 template <typename T>
IsOk(const Return<T> & r)126 AssertionResult IsOk(const Return<T>& r) {
127 return r.isOk() ? AssertionSuccess() : (AssertionFailure() << r.description());
128 }
129
130 // Both IsOk() and Result::SUCCESS
ResultIsSuccess(const Return<Result> & r)131 AssertionResult ResultIsSuccess(const Return<Result>& r) {
132 if (!r.isOk()) {
133 return AssertionFailure() << r.description();
134 }
135 if (static_cast<Result>(r) != Result::SUCCESS) {
136 return AssertionFailure() << toString(static_cast<Result>(r));
137 }
138 return AssertionSuccess();
139 }
140
141 /**
142 * Test whether callbacks work. Tested functions are IHealth::registerCallback,
143 * unregisterCallback, and update.
144 */
145 template <typename Callback>
TestCallbacks(sp<IHealth> service)146 AssertionResult TestCallbacks(sp<IHealth> service) {
147 sp<Callback> first = new Callback();
148 sp<Callback> second = new Callback();
149
150 TEST_AND_RETURN(ResultIsSuccess(service->registerCallback(first)));
151 TEST_AND_RETURN(ResultIsSuccess(service->registerCallback(second)));
152
153 // registerCallback may or may not invoke the callback immediately, so the test needs
154 // to wait for the invocation. If the implementation chooses not to invoke the callback
155 // immediately, just wait for some time.
156 first->waitInvoke(200ms);
157 second->waitInvoke(200ms);
158
159 // assert that the first callback is invoked when update is called.
160 TEST_AND_RETURN(ResultIsSuccess(service->update()));
161
162 TEST_AND_RETURN_FAILURE(first->waitInvoke(1s));
163 TEST_AND_RETURN_FAILURE(second->waitInvoke(1s));
164
165 TEST_AND_RETURN(ResultIsSuccess(service->unregisterCallback(first)));
166
167 // clear any potentially pending callbacks result from wakealarm / kernel events
168 // If there is none, just wait for some time.
169 first->waitInvoke(200ms);
170 second->waitInvoke(200ms);
171
172 // assert that the second callback is still invoked even though the first is unregistered.
173 TEST_AND_RETURN(ResultIsSuccess(service->update()));
174
175 TEST_AND_RETURN_FAILURE(!first->waitInvoke(200ms));
176 TEST_AND_RETURN_FAILURE(second->waitInvoke(1s));
177
178 TEST_AND_RETURN(ResultIsSuccess(service->unregisterCallback(second)));
179 return AssertionSuccess();
180 }
181
TEST_P(HealthHidlTest,Callbacks_2_0)182 TEST_P(HealthHidlTest, Callbacks_2_0) {
183 EXPECT_TRUE(TestCallbacks<Callback_2_0>(service_));
184 }
185
TEST_P(HealthHidlTest,Callbacks_2_1)186 TEST_P(HealthHidlTest, Callbacks_2_1) {
187 EXPECT_TRUE(TestCallbacks<Callback_2_1>(service_));
188 }
189
190 template <typename Callback>
TestUnregisterNonExistentCallback(sp<IHealth> service)191 AssertionResult TestUnregisterNonExistentCallback(sp<IHealth> service) {
192 sp<Callback> callback = new Callback();
193 auto ret = service->unregisterCallback(callback);
194 TEST_AND_RETURN(IsOk(ret));
195 if (static_cast<Result>(ret) != Result::NOT_FOUND) {
196 return AssertionFailure()
197 << "Unregistering non-existent callback should return NOT_FOUND, but returned "
198 << static_cast<Result>(ret);
199 }
200 return AssertionSuccess();
201 }
202
TEST_P(HealthHidlTest,UnregisterNonExistentCallback_2_0)203 TEST_P(HealthHidlTest, UnregisterNonExistentCallback_2_0) {
204 EXPECT_TRUE(TestUnregisterNonExistentCallback<Callback_2_0>(service_));
205 }
206
TEST_P(HealthHidlTest,UnregisterNonExistentCallback_2_1)207 TEST_P(HealthHidlTest, UnregisterNonExistentCallback_2_1) {
208 EXPECT_TRUE(TestUnregisterNonExistentCallback<Callback_2_1>(service_));
209 }
210
211 template <typename T>
IsEnum(T value)212 AssertionResult IsEnum(T value) {
213 for (auto it : hidl_enum_range<T>()) {
214 if (it == value) {
215 return AssertionSuccess();
216 }
217 }
218
219 return AssertionFailure() << static_cast<std::underlying_type_t<T>>(value) << " is not valid";
220 }
221
222 #define FULL_CHARGE_DESIGN_CAP_MIN ((long)100 * 1000)
223 #define FULL_CHARGE_DESIGN_CAP_MAX ((long)100000 * 1000)
224
225 /*
226 * Tests the values returned by getHealthInfo() from interface IHealth.
227 */
TEST_P(HealthHidlTest,getHealthInfo_2_1)228 TEST_P(HealthHidlTest, getHealthInfo_2_1) {
229 EXPECT_TRUE(IsOk(service_->getHealthInfo_2_1([](auto result, const auto& value) {
230 if (result == Result::NOT_SUPPORTED) {
231 return;
232 }
233 ASSERT_EQ(Result::SUCCESS, result);
234
235 EXPECT_TRUE(IsEnum(value.batteryCapacityLevel)) << " BatteryCapacityLevel";
236 EXPECT_GE(value.batteryChargeTimeToFullNowSeconds, -1);
237
238 if (value.batteryFullChargeDesignCapacityUah != 0) {
239 EXPECT_GT((long)value.batteryFullChargeDesignCapacityUah, FULL_CHARGE_DESIGN_CAP_MIN)
240 << "batteryFullChargeDesignCapacityUah should be greater than 100 mAh, or 0 if "
241 "unknown";
242
243 EXPECT_LT((long)value.batteryFullChargeDesignCapacityUah, FULL_CHARGE_DESIGN_CAP_MAX)
244 << "batteryFullChargeDesignCapacityUah should be less than 100,000 mAh, or 0 "
245 "if unknown";
246 }
247 })));
248 }
249
TEST_P(HealthHidlTest,getHealthConfig)250 TEST_P(HealthHidlTest, getHealthConfig) {
251 EXPECT_TRUE(IsOk(service_->getHealthConfig([](auto result, const auto&) {
252 EXPECT_THAT(result, AnyOf(Result::SUCCESS, Result::NOT_SUPPORTED));
253 })));
254 }
255
TEST_P(HealthHidlTest,shouldKeepScreenOn)256 TEST_P(HealthHidlTest, shouldKeepScreenOn) {
257 EXPECT_TRUE(IsOk(service_->shouldKeepScreenOn([](auto result, const auto&) {
258 EXPECT_THAT(result, AnyOf(Result::SUCCESS, Result::NOT_SUPPORTED));
259 })));
260 }
261
262 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HealthHidlTest);
263 INSTANTIATE_TEST_SUITE_P(
264 PerInstance, HealthHidlTest,
265 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
266 android::hardware::PrintInstanceNameToString);
267
268 } // namespace V2_1
269 } // namespace health
270 } // namespace hardware
271 } // namespace android
272
main(int argc,char ** argv)273 int main(int argc, char** argv) {
274 ::testing::InitGoogleTest(&argc, argv);
275 int status = RUN_ALL_TESTS();
276 LOG(INFO) << "Test result = " << status;
277 return status;
278 }
279