blob: 441e2d756f2bcfccc19a39d162b1f3f598b89092 [file] [log] [blame]
Yifan Hong69c22542017-10-03 17:40:24 -07001/*
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
Yifan Hongf86271d2017-11-06 12:52:20 -080017#define LOG_TAG "health_hidl_hal_test"
Yifan Hong69c22542017-10-03 17:40:24 -070018
Yifan Hong94841c92020-01-28 16:11:39 -080019#include <chrono>
Yifan Hong69c22542017-10-03 17:40:24 -070020#include <mutex>
Yifan Hong03b2a342019-03-08 11:37:33 -080021#include <set>
22#include <string>
Yifan Hong94841c92020-01-28 16:11:39 -080023#include <thread>
Yifan Hong69c22542017-10-03 17:40:24 -070024
Yifan Hong69c22542017-10-03 17:40:24 -070025#include <android-base/logging.h>
Yifan Hong94841c92020-01-28 16:11:39 -080026#include <android-base/properties.h>
27#include <android/hardware/health/1.0/types.h>
Yifan Hong69c22542017-10-03 17:40:24 -070028#include <android/hardware/health/2.0/IHealth.h>
29#include <android/hardware/health/2.0/types.h>
Yifan Honge6807dd2019-03-07 13:04:33 -080030#include <gflags/gflags.h>
nelsonli4da3ca52019-12-10 17:17:09 +080031#include <gtest/gtest.h>
32#include <hidl/GtestPrinter.h>
33#include <hidl/ServiceManagement.h>
34#include <log/log.h>
Yifan Hong69c22542017-10-03 17:40:24 -070035
36using ::testing::AssertionFailure;
37using ::testing::AssertionResult;
38using ::testing::AssertionSuccess;
Yifan Hong94841c92020-01-28 16:11:39 -080039using namespace std::chrono_literals;
Yifan Hong69c22542017-10-03 17:40:24 -070040
Yifan Honge6807dd2019-03-07 13:04:33 -080041DEFINE_bool(force, false, "Force test healthd even when the default instance is present.");
42
Yifan Hong94841c92020-01-28 16:11:39 -080043// Return expr if it is evaluated to false.
44#define TEST_AND_RETURN(expr) \
45 do { \
46 auto res = (expr); \
47 if (!res) return res; \
48 } while (0)
49
Yifan Hong69c22542017-10-03 17:40:24 -070050namespace android {
51namespace hardware {
52namespace health {
Yifan Hong69c22542017-10-03 17:40:24 -070053
54using V1_0::BatteryStatus;
Yifan Hong94841c92020-01-28 16:11:39 -080055using V1_0::toString;
56
57namespace V2_0 {
Yifan Hong69c22542017-10-03 17:40:24 -070058
nelsonli4da3ca52019-12-10 17:17:09 +080059class HealthHidlTest : public ::testing::TestWithParam<std::string> {
Yifan Hong69c22542017-10-03 17:40:24 -070060 public:
61 virtual void SetUp() override {
nelsonli4da3ca52019-12-10 17:17:09 +080062 std::string serviceName = GetParam();
Yifan Honge6807dd2019-03-07 13:04:33 -080063
64 if (serviceName == "backup" && !FLAGS_force &&
nelsonli4da3ca52019-12-10 17:17:09 +080065 IHealth::getService() != nullptr) {
Yifan Honge6807dd2019-03-07 13:04:33 -080066 LOG(INFO) << "Skipping tests on healthd because the default instance is present. "
67 << "Use --force if you really want to test healthd.";
68 GTEST_SKIP();
69 }
70
Yifan Hong69c22542017-10-03 17:40:24 -070071 LOG(INFO) << "get service with name:" << serviceName;
72 ASSERT_FALSE(serviceName.empty());
nelsonli4da3ca52019-12-10 17:17:09 +080073 mHealth = IHealth::getService(serviceName);
Yifan Hong69c22542017-10-03 17:40:24 -070074 ASSERT_NE(mHealth, nullptr);
75 }
76
77 sp<IHealth> mHealth;
78};
79
80class Callback : public IHealthInfoCallback {
Yifan Hong69c22542017-10-03 17:40:24 -070081 public:
Hridya Valsarajud31932a2018-01-17 23:09:24 -080082 Return<void> healthInfoChanged(const HealthInfo&) override {
Yifan Hongd6ea57e2017-11-20 14:41:09 -080083 std::lock_guard<std::mutex> lock(mMutex);
84 mInvoked = true;
85 mInvokedNotify.notify_all();
Yifan Hong69c22542017-10-03 17:40:24 -070086 return Void();
87 }
Yifan Hongd6ea57e2017-11-20 14:41:09 -080088 template <typename R, typename P>
89 bool waitInvoke(std::chrono::duration<R, P> duration) {
Yifan Hong69c22542017-10-03 17:40:24 -070090 std::unique_lock<std::mutex> lock(mMutex);
Yifan Hongd6ea57e2017-11-20 14:41:09 -080091 bool r = mInvokedNotify.wait_for(lock, duration, [this] { return this->mInvoked; });
92 mInvoked = false;
93 return r;
Yifan Hong69c22542017-10-03 17:40:24 -070094 }
Yifan Hong69c22542017-10-03 17:40:24 -070095 private:
96 std::mutex mMutex;
Yifan Hongd6ea57e2017-11-20 14:41:09 -080097 std::condition_variable mInvokedNotify;
98 bool mInvoked = false;
Yifan Hong69c22542017-10-03 17:40:24 -070099};
100
101#define ASSERT_OK(r) ASSERT_TRUE(isOk(r))
102#define EXPECT_OK(r) EXPECT_TRUE(isOk(r))
103template <typename T>
104AssertionResult isOk(const Return<T>& r) {
105 return r.isOk() ? AssertionSuccess() : (AssertionFailure() << r.description());
106}
107
108#define ASSERT_ALL_OK(r) ASSERT_TRUE(isAllOk(r))
109// Both isOk() and Result::SUCCESS
110AssertionResult isAllOk(const Return<Result>& r) {
111 if (!r.isOk()) {
112 return AssertionFailure() << r.description();
113 }
114 if (static_cast<Result>(r) != Result::SUCCESS) {
115 return AssertionFailure() << toString(static_cast<Result>(r));
116 }
117 return AssertionSuccess();
118}
119
120/**
121 * Test whether callbacks work. Tested functions are IHealth::registerCallback,
122 * unregisterCallback, and update.
123 */
nelsonli4da3ca52019-12-10 17:17:09 +0800124TEST_P(HealthHidlTest, Callbacks) {
Yifan Hong69c22542017-10-03 17:40:24 -0700125 using namespace std::chrono_literals;
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800126 sp<Callback> firstCallback = new Callback();
127 sp<Callback> secondCallback = new Callback();
Yifan Hong69c22542017-10-03 17:40:24 -0700128
129 ASSERT_ALL_OK(mHealth->registerCallback(firstCallback));
130 ASSERT_ALL_OK(mHealth->registerCallback(secondCallback));
131
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800132 // registerCallback may or may not invoke the callback immediately, so the test needs
133 // to wait for the invocation. If the implementation chooses not to invoke the callback
134 // immediately, just wait for some time.
135 firstCallback->waitInvoke(200ms);
136 secondCallback->waitInvoke(200ms);
Yifan Hong69c22542017-10-03 17:40:24 -0700137
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800138 // assert that the first callback is invoked when update is called.
Yifan Hong69c22542017-10-03 17:40:24 -0700139 ASSERT_ALL_OK(mHealth->update());
140
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800141 ASSERT_TRUE(firstCallback->waitInvoke(1s));
142 ASSERT_TRUE(secondCallback->waitInvoke(1s));
Yifan Hong69c22542017-10-03 17:40:24 -0700143
144 ASSERT_ALL_OK(mHealth->unregisterCallback(firstCallback));
145
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800146 // clear any potentially pending callbacks result from wakealarm / kernel events
147 // If there is none, just wait for some time.
148 firstCallback->waitInvoke(200ms);
149 secondCallback->waitInvoke(200ms);
Yifan Hong69c22542017-10-03 17:40:24 -0700150
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800151 // assert that the second callback is still invoked even though the first is unregistered.
Yifan Hong69c22542017-10-03 17:40:24 -0700152 ASSERT_ALL_OK(mHealth->update());
153
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800154 ASSERT_FALSE(firstCallback->waitInvoke(200ms));
155 ASSERT_TRUE(secondCallback->waitInvoke(1s));
Yifan Hong69c22542017-10-03 17:40:24 -0700156
157 ASSERT_ALL_OK(mHealth->unregisterCallback(secondCallback));
Yifan Hong69c22542017-10-03 17:40:24 -0700158}
159
nelsonli4da3ca52019-12-10 17:17:09 +0800160TEST_P(HealthHidlTest, UnregisterNonExistentCallback) {
Yifan Hongd6ea57e2017-11-20 14:41:09 -0800161 sp<Callback> callback = new Callback();
Yifan Hong69c22542017-10-03 17:40:24 -0700162 auto ret = mHealth->unregisterCallback(callback);
163 ASSERT_OK(ret);
164 ASSERT_EQ(Result::NOT_FOUND, static_cast<Result>(ret)) << "Actual: " << toString(ret);
165}
166
167/**
168 * Pass the test if:
169 * - Property is not supported (res == NOT_SUPPORTED)
170 * - Result is success, and predicate is true
171 * @param res the Result value.
172 * @param valueStr the string representation for actual value (for error message)
173 * @param pred a predicate that test whether the value is valid
174 */
175#define EXPECT_VALID_OR_UNSUPPORTED_PROP(res, valueStr, pred) \
176 EXPECT_TRUE(isPropertyOk(res, valueStr, pred, #pred))
177
178AssertionResult isPropertyOk(Result res, const std::string& valueStr, bool pred,
179 const std::string& predStr) {
180 if (res == Result::SUCCESS) {
181 if (pred) {
182 return AssertionSuccess();
183 }
184 return AssertionFailure() << "value doesn't match.\nActual: " << valueStr
185 << "\nExpected: " << predStr;
186 }
187 if (res == Result::NOT_SUPPORTED) {
188 return AssertionSuccess();
189 }
190 return AssertionFailure() << "Result is not SUCCESS or NOT_SUPPORTED: " << toString(res);
191}
192
Hridya Valsaraju2120ecc2017-12-20 13:27:52 -0800193bool verifyStorageInfo(const hidl_vec<struct StorageInfo>& info) {
194 for (size_t i = 0; i < info.size(); i++) {
195 if (!(0 <= info[i].eol && info[i].eol <= 3 && 0 <= info[i].lifetimeA &&
196 info[i].lifetimeA <= 0x0B && 0 <= info[i].lifetimeB && info[i].lifetimeB <= 0x0B)) {
197 return false;
198 }
199 }
200
201 return true;
202}
203
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800204template <typename T>
205bool verifyEnum(T value) {
Steven Morelandc90461c2018-05-01 16:54:09 -0700206 for (auto it : hidl_enum_range<T>()) {
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800207 if (it == value) {
208 return true;
209 }
210 }
211
212 return false;
213}
214
215bool verifyHealthInfo(const HealthInfo& health_info) {
Hridya Valsaraju075c1822018-04-03 11:19:08 -0700216 if (!verifyStorageInfo(health_info.storageInfos)) {
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800217 return false;
218 }
219
220 using V1_0::BatteryStatus;
221 using V1_0::BatteryHealth;
222
Robin Leeac5a0d32019-10-09 15:48:17 +0200223 if (!((health_info.legacy.batteryCurrent != INT32_MIN) &&
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800224 (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
225 verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800226 verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
227 return false;
228 }
229
Robin Leeac5a0d32019-10-09 15:48:17 +0200230 if (health_info.legacy.batteryPresent) {
231 // If a battery is present, the battery status must be known.
232 if (!((health_info.legacy.batteryChargeCounter > 0) &&
233 (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN))) {
234 return false;
235 }
236 }
237
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800238 return true;
239}
240
241/*
Yifan Hong26c12002018-10-02 14:52:02 -0700242 * Tests the values returned by getChargeCounter() from interface IHealth.
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800243 */
nelsonli4da3ca52019-12-10 17:17:09 +0800244TEST_P(HealthHidlTest, getChargeCounter) {
Yifan Hong69c22542017-10-03 17:40:24 -0700245 EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
246 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
247 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700248}
249
250/*
251 * Tests the values returned by getCurrentNow() from interface IHealth.
252 */
nelsonli4da3ca52019-12-10 17:17:09 +0800253TEST_P(HealthHidlTest, getCurrentNow) {
Yifan Hong69c22542017-10-03 17:40:24 -0700254 EXPECT_OK(mHealth->getCurrentNow([](auto result, auto value) {
255 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
256 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700257}
258
259/*
260 * Tests the values returned by getCurrentAverage() from interface IHealth.
261 */
nelsonli4da3ca52019-12-10 17:17:09 +0800262TEST_P(HealthHidlTest, getCurrentAverage) {
Yifan Hong69c22542017-10-03 17:40:24 -0700263 EXPECT_OK(mHealth->getCurrentAverage([](auto result, auto value) {
264 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
265 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700266}
267
268/*
269 * Tests the values returned by getCapacity() from interface IHealth.
270 */
nelsonli4da3ca52019-12-10 17:17:09 +0800271TEST_P(HealthHidlTest, getCapacity) {
Yifan Hong69c22542017-10-03 17:40:24 -0700272 EXPECT_OK(mHealth->getCapacity([](auto result, auto value) {
273 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), 0 <= value && value <= 100);
274 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700275}
276
277/*
278 * Tests the values returned by getEnergyCounter() from interface IHealth.
279 */
nelsonli4da3ca52019-12-10 17:17:09 +0800280TEST_P(HealthHidlTest, getEnergyCounter) {
Yifan Hong69c22542017-10-03 17:40:24 -0700281 EXPECT_OK(mHealth->getEnergyCounter([](auto result, auto value) {
282 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT64_MIN);
283 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700284}
285
286/*
287 * Tests the values returned by getChargeStatus() from interface IHealth.
288 */
nelsonli4da3ca52019-12-10 17:17:09 +0800289TEST_P(HealthHidlTest, getChargeStatus) {
Yifan Hong69c22542017-10-03 17:40:24 -0700290 EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
Yifan Hong5ac6f5b2020-01-27 16:20:49 -0800291 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyEnum<BatteryStatus>(value));
Yifan Hong69c22542017-10-03 17:40:24 -0700292 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700293}
294
295/*
296 * Tests the values returned by getStorageInfo() from interface IHealth.
297 */
nelsonli4da3ca52019-12-10 17:17:09 +0800298TEST_P(HealthHidlTest, getStorageInfo) {
Hridya Valsaraju2120ecc2017-12-20 13:27:52 -0800299 EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800300 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
Hridya Valsaraju2120ecc2017-12-20 13:27:52 -0800301 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700302}
303
304/*
305 * Tests the values returned by getDiskStats() from interface IHealth.
306 */
nelsonli4da3ca52019-12-10 17:17:09 +0800307TEST_P(HealthHidlTest, getDiskStats) {
Hridya Valsaraju2120ecc2017-12-20 13:27:52 -0800308 EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
Hridya Valsaraju075c1822018-04-03 11:19:08 -0700309 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), true);
Hridya Valsaraju2120ecc2017-12-20 13:27:52 -0800310 }));
Yifan Hong26c12002018-10-02 14:52:02 -0700311}
312
313/*
314 * Tests the values returned by getHealthInfo() from interface IHealth.
315 */
nelsonli4da3ca52019-12-10 17:17:09 +0800316TEST_P(HealthHidlTest, getHealthInfo) {
Hridya Valsaraju87e29602018-01-12 17:46:22 -0800317 EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
318 EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
319 }));
Yifan Hong69c22542017-10-03 17:40:24 -0700320}
321
nelsonli4da3ca52019-12-10 17:17:09 +0800322INSTANTIATE_TEST_SUITE_P(
323 PerInstance, HealthHidlTest,
324 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
325 android::hardware::PrintInstanceNameToString);
Yifan Hong94841c92020-01-28 16:11:39 -0800326
327// For battery current tests, value may not be stable if the battery current has fluctuated.
328// Retry in a bit more time (with the following timeout) and consider the test successful if it
329// has succeed once.
330static constexpr auto gBatteryTestTimeout = 1min;
331// Tests on battery current signs are only enforced on devices launching with Android 11.
332static constexpr int64_t gBatteryTestMinShippingApiLevel = 30;
333static constexpr double gCurrentCompareFactor = 0.50;
334
335// Tuple for all IHealth::get* API return values.
336template <typename T>
337struct HalResult {
338 Result result;
339 T value;
340};
341
342// Needs to be called repeatedly within a period of time to ensure values are initialized.
343static AssertionResult IsBatteryCurrentSignCorrect(HalResult<BatteryStatus> status,
344 HalResult<int32_t> current,
345 bool acceptZeroCurrentAsUnknown) {
346 // getChargeStatus / getCurrentNow / getCurrentAverage / getHealthInfo already tested above.
347 // Here, just skip if not ok.
348 if (status.result != Result::SUCCESS) {
349 return AssertionSuccess() << "getChargeStatus / getHealthInfo returned "
350 << toString(status.result) << ", skipping";
351 }
352
353 if (current.result != Result::SUCCESS) {
354 return AssertionSuccess() << "getCurrentNow / getCurrentAverage returned "
355 << toString(current.result) << ", skipping";
356 }
357
358 // For IHealth.getCurrentNow/Average, if current is not available, it is expected that
359 // current.result == Result::NOT_SUPPORTED, which is checked above. Hence, zero current is
360 // not treated as unknown values.
361 // For IHealth.getHealthInfo, if current is not available, health_info.current_* == 0.
362 // Caller of this function provides current.result == Result::SUCCESS. Hence, just skip the
363 // check.
364 if (current.value == 0 && acceptZeroCurrentAsUnknown) {
365 return AssertionSuccess()
366 << "current is 0, which indicates the value may not be available. Skipping.";
367 }
368
369 switch (status.value) {
370 case BatteryStatus::UNKNOWN:
371 if (current.value != 0) {
372 // BatteryStatus may be UNKNOWN initially with a non-zero current value, but
373 // after it is initialized, it should be known.
374 return AssertionFailure()
375 << "BatteryStatus is UNKNOWN but current is not 0. Actual: "
376 << current.value;
377 }
378 break;
379 case BatteryStatus::CHARGING:
380 if (current.value <= 0) {
381 return AssertionFailure()
382 << "BatteryStatus is CHARGING but current is not positive. Actual: "
383 << current.value;
384 }
385 break;
386 case BatteryStatus::NOT_CHARGING:
387 if (current.value > 0) {
388 return AssertionFailure() << "BatteryStatus is " << toString(status.value)
389 << " but current is positive. Actual: " << current.value;
390 }
391 break;
392 case BatteryStatus::DISCHARGING:
393 if (current.value >= 0) {
394 return AssertionFailure()
395 << "BatteryStatus is " << toString(status.value)
396 << " but current is not negative. Actual: " << current.value;
397 }
398 break;
399 case BatteryStatus::FULL:
400 // Battery current may be positive or negative depending on the load.
401 break;
402 default:
403 return AssertionFailure() << "Unknown BatteryStatus " << toString(status.value);
404 }
405
406 return AssertionSuccess() << "BatteryStatus is " << toString(status.value)
407 << " and current has the correct sign: " << current.value;
408}
409
410static AssertionResult IsValueSimilar(int32_t dividend, int32_t divisor, double factor) {
411 auto difference = abs(dividend - divisor);
412 if (difference > factor * abs(divisor)) {
413 return AssertionFailure() << dividend << " and " << divisor << " are not similar.";
414 }
415 return AssertionSuccess() << dividend << " and " << divisor << " are similar.";
416}
417
418static AssertionResult IsBatteryCurrentSimilar(HalResult<BatteryStatus> status,
419 HalResult<int32_t> currentNow,
420 HalResult<int32_t> currentAverage) {
421 if (status.result == Result::SUCCESS && status.value == BatteryStatus::FULL) {
422 // No reason to test on full battery because battery current load fluctuates.
423 return AssertionSuccess() << "Battery is full, skipping";
424 }
425
426 // getCurrentNow / getCurrentAverage / getHealthInfo already tested above. Here, just skip if
427 // not SUCCESS or value 0.
428 if (currentNow.result != Result::SUCCESS || currentNow.value == 0) {
429 return AssertionSuccess() << "getCurrentNow returned " << toString(currentNow.result)
430 << " with value " << currentNow.value << ", skipping";
431 }
432
433 if (currentAverage.result != Result::SUCCESS || currentAverage.value == 0) {
434 return AssertionSuccess() << "getCurrentAverage returned "
435 << toString(currentAverage.result) << " with value "
436 << currentAverage.value << ", skipping";
437 }
438
439 // Check that the two values are similar. Note that the two tests uses a different
440 // divisor to ensure that they are actually pretty similar. For example,
441 // IsValueSimilar(5,10,0.4) returns true, but IsValueSimlar(10,5,0.4) returns false.
442 TEST_AND_RETURN(IsValueSimilar(currentNow.value, currentAverage.value, gCurrentCompareFactor)
443 << " for now vs. average. Check units.");
444 TEST_AND_RETURN(IsValueSimilar(currentAverage.value, currentNow.value, gCurrentCompareFactor)
445 << " for average vs. now. Check units.");
446 return AssertionSuccess() << "currentNow = " << currentNow.value
447 << " and currentAverage = " << currentAverage.value
448 << " are considered similar.";
449}
450
451// Test that f() returns AssertionSuccess() once in a given period of time.
452template <typename Duration, typename Function>
453static AssertionResult SucceedOnce(Duration d, Function f) {
454 AssertionResult result = AssertionFailure() << "Function never evaluated.";
455 auto end = std::chrono::system_clock::now() + d;
456 while (std::chrono::system_clock::now() <= end) {
457 result = f();
458 if (result) {
459 return result;
460 }
461 std::this_thread::sleep_for(2s);
462 }
463 return result;
464}
465
466uint64_t GetShippingApiLevel() {
467 uint64_t api_level = android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
468 if (api_level != 0) {
469 return api_level;
470 }
471 return android::base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
472}
473
474class BatteryTest : public HealthHidlTest {
475 public:
476 void SetUp() override {
477 HealthHidlTest::SetUp();
478
479 auto shippingApiLevel = GetShippingApiLevel();
480 if (shippingApiLevel < gBatteryTestMinShippingApiLevel) {
481 GTEST_SKIP() << "Skipping on devices with first API level " << shippingApiLevel;
482 }
483 }
484};
485
486TEST_P(BatteryTest, InstantCurrentAgainstChargeStatusInHealthInfo) {
487 auto testOnce = [&]() -> AssertionResult {
488 HalResult<HealthInfo> healthInfo;
489 TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
490 healthInfo = {result, value};
491 })));
492
493 return IsBatteryCurrentSignCorrect(
494 {healthInfo.result, healthInfo.value.legacy.batteryStatus},
495 {healthInfo.result, healthInfo.value.legacy.batteryCurrent},
496 true /* accept zero current as unknown */);
497 };
498 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
499 << "You may want to try again later when current_now becomes stable.";
500}
501
502TEST_P(BatteryTest, AverageCurrentAgainstChargeStatusInHealthInfo) {
503 auto testOnce = [&]() -> AssertionResult {
504 HalResult<HealthInfo> healthInfo;
505 TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
506 healthInfo = {result, value};
507 })));
508 return IsBatteryCurrentSignCorrect(
509 {healthInfo.result, healthInfo.value.legacy.batteryStatus},
510 {healthInfo.result, healthInfo.value.batteryCurrentAverage},
511 true /* accept zero current as unknown */);
512 };
513
514 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
515 << "You may want to try again later when current_average becomes stable.";
516}
517
518TEST_P(BatteryTest, InstantCurrentAgainstAverageCurrentInHealthInfo) {
519 auto testOnce = [&]() -> AssertionResult {
520 HalResult<HealthInfo> healthInfo;
521 TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
522 healthInfo = {result, value};
523 })));
524 return IsBatteryCurrentSimilar({healthInfo.result, healthInfo.value.legacy.batteryStatus},
525 {healthInfo.result, healthInfo.value.legacy.batteryCurrent},
526 {healthInfo.result, healthInfo.value.batteryCurrentAverage});
527 };
528
529 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
530 << "You may want to try again later when current_now and current_average becomes "
531 "stable.";
532}
533
534TEST_P(BatteryTest, InstantCurrentAgainstChargeStatusFromHal) {
535 auto testOnce = [&]() -> AssertionResult {
536 HalResult<BatteryStatus> status;
537 HalResult<int32_t> currentNow;
538 TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
539 status = {result, value};
540 })));
541 TEST_AND_RETURN(isOk(mHealth->getCurrentNow([&](auto result, auto value) {
542 currentNow = {result, value};
543 })));
544
545 return IsBatteryCurrentSignCorrect(status, currentNow,
546 false /* accept zero current as unknown */);
547 };
548
549 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
550 << "You may want to try again later when current_now becomes stable.";
551}
552
553TEST_P(BatteryTest, AverageCurrentAgainstChargeStatusFromHal) {
554 auto testOnce = [&]() -> AssertionResult {
555 HalResult<BatteryStatus> status;
556 TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
557 status = {result, value};
558 })));
559 HalResult<int32_t> currentAverage;
560 TEST_AND_RETURN(isOk(mHealth->getCurrentAverage([&](auto result, auto value) {
561 currentAverage = {result, value};
562 })));
563 return IsBatteryCurrentSignCorrect(status, currentAverage,
564 false /* accept zero current as unknown */);
565 };
566
567 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
568 << "You may want to try again later when current_average becomes stable.";
569}
570
571TEST_P(BatteryTest, InstantCurrentAgainstAverageCurrentFromHal) {
572 auto testOnce = [&]() -> AssertionResult {
573 HalResult<BatteryStatus> status;
574 TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
575 status = {result, value};
576 })));
577 HalResult<int32_t> currentNow;
578 TEST_AND_RETURN(isOk(mHealth->getCurrentNow([&](auto result, auto value) {
579 currentNow = {result, value};
580 })));
581 HalResult<int32_t> currentAverage;
582 TEST_AND_RETURN(isOk(mHealth->getCurrentAverage([&](auto result, auto value) {
583 currentAverage = {result, value};
584 })));
585 return IsBatteryCurrentSimilar(status, currentNow, currentAverage);
586 };
587
588 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
589 << "You may want to try again later when current_average becomes stable.";
590}
591
592AssertionResult IsBatteryStatusCorrect(HalResult<BatteryStatus> status,
593 HalResult<HealthInfo> healthInfo) {
594 // getChargetStatus / getHealthInfo is already tested above. Here, just skip if not ok.
595 if (healthInfo.result != Result::SUCCESS) {
596 return AssertionSuccess() << "getHealthInfo returned " << toString(healthInfo.result)
597 << ", skipping";
598 }
599 if (status.result != Result::SUCCESS) {
600 return AssertionSuccess() << "getChargeStatus returned " << toString(status.result)
601 << ", skipping";
602 }
603
604 const auto& batteryInfo = healthInfo.value.legacy;
605 bool isConnected = batteryInfo.chargerAcOnline || batteryInfo.chargerUsbOnline ||
606 batteryInfo.chargerWirelessOnline;
607
608 std::stringstream message;
609 message << "BatteryStatus is " << toString(status.value) << " and "
610 << (isConnected ? "" : "no ")
611 << "power source is connected: ac=" << batteryInfo.chargerAcOnline
612 << ", usb=" << batteryInfo.chargerUsbOnline
613 << ", wireless=" << batteryInfo.chargerWirelessOnline;
614
615 switch (status.value) {
616 case BatteryStatus::UNKNOWN: {
617 // Don't enforce anything on isConnected on unknown battery status.
618 // Battery-less devices must report UNKNOWN battery status, but may report true
619 // or false on isConnected.
620 } break;
621 case BatteryStatus::CHARGING:
622 case BatteryStatus::NOT_CHARGING:
623 case BatteryStatus::FULL: {
624 if (!isConnected) {
625 return AssertionFailure() << message.str();
626 }
627 } break;
628 case BatteryStatus::DISCHARGING: {
629 if (isConnected) {
630 return AssertionFailure() << message.str();
631 }
632 } break;
633 default: {
634 return AssertionFailure() << "Unknown battery status value " << toString(status.value);
635 } break;
636 }
637
638 return AssertionSuccess() << message.str();
639}
640
641TEST_P(BatteryTest, ConnectedAgainstStatusFromHal) {
642 auto testOnce = [&]() -> AssertionResult {
643 HalResult<BatteryStatus> status;
644 TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
645 status = {result, value};
646 })));
647 HalResult<HealthInfo> healthInfo;
648 TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
649 healthInfo = {result, value};
650 })));
651 return IsBatteryStatusCorrect(status, healthInfo);
652 };
653
654 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
655 << "You may want to try again later when battery_status becomes stable.";
656}
657
658TEST_P(BatteryTest, ConnectedAgainstStatusInHealthInfo) {
659 auto testOnce = [&]() -> AssertionResult {
660 HalResult<HealthInfo> healthInfo;
661 TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
662 healthInfo = {result, value};
663 })));
664 return IsBatteryStatusCorrect({healthInfo.result, healthInfo.value.legacy.batteryStatus},
665 healthInfo);
666 };
667
668 EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
669 << "You may want to try again later when getHealthInfo becomes stable.";
670}
671
672INSTANTIATE_TEST_SUITE_P(
673 PerInstance, BatteryTest,
674 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
675 android::hardware::PrintInstanceNameToString);
676
Yifan Hong69c22542017-10-03 17:40:24 -0700677} // namespace V2_0
678} // namespace health
679} // namespace hardware
680} // namespace android
681
682int main(int argc, char** argv) {
Yifan Hong69c22542017-10-03 17:40:24 -0700683 ::testing::InitGoogleTest(&argc, argv);
Yifan Honge6807dd2019-03-07 13:04:33 -0800684 gflags::ParseCommandLineFlags(&argc, &argv, true /* remove flags */);
nelsonli4da3ca52019-12-10 17:17:09 +0800685 return RUN_ALL_TESTS();
Yifan Hong69c22542017-10-03 17:40:24 -0700686}