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_TAG "health_hidl_hal_test"
18 
19 #include <chrono>
20 #include <mutex>
21 #include <set>
22 #include <string>
23 #include <thread>
24 
25 #include <android-base/logging.h>
26 #include <android-base/properties.h>
27 #include <android/hardware/health/1.0/types.h>
28 #include <android/hardware/health/2.0/IHealth.h>
29 #include <android/hardware/health/2.0/types.h>
30 #include <gflags/gflags.h>
31 #include <gtest/gtest.h>
32 #include <hidl/GtestPrinter.h>
33 #include <hidl/ServiceManagement.h>
34 #include <log/log.h>
35 
36 using ::testing::AssertionFailure;
37 using ::testing::AssertionResult;
38 using ::testing::AssertionSuccess;
39 using namespace std::chrono_literals;
40 
41 DEFINE_bool(force, false, "Force test healthd even when the default instance is present.");
42 
43 // 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 
50 namespace android {
51 namespace hardware {
52 namespace health {
53 
54 using V1_0::BatteryStatus;
55 using V1_0::toString;
56 
57 namespace V2_0 {
58 
59 class HealthHidlTest : public ::testing::TestWithParam<std::string> {
60    public:
SetUp()61     virtual void SetUp() override {
62         std::string serviceName = GetParam();
63 
64         if (serviceName == "backup" && !FLAGS_force &&
65             IHealth::getService() != nullptr) {
66             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 
71         LOG(INFO) << "get service with name:" << serviceName;
72         ASSERT_FALSE(serviceName.empty());
73         mHealth = IHealth::getService(serviceName);
74         ASSERT_NE(mHealth, nullptr);
75     }
76 
77     sp<IHealth> mHealth;
78 };
79 
80 class Callback : public IHealthInfoCallback {
81    public:
healthInfoChanged(const HealthInfo &)82     Return<void> healthInfoChanged(const HealthInfo&) override {
83         std::lock_guard<std::mutex> lock(mMutex);
84         mInvoked = true;
85         mInvokedNotify.notify_all();
86         return Void();
87     }
88     template <typename R, typename P>
waitInvoke(std::chrono::duration<R,P> duration)89     bool waitInvoke(std::chrono::duration<R, P> duration) {
90         std::unique_lock<std::mutex> lock(mMutex);
91         bool r = mInvokedNotify.wait_for(lock, duration, [this] { return this->mInvoked; });
92         mInvoked = false;
93         return r;
94     }
95    private:
96     std::mutex mMutex;
97     std::condition_variable mInvokedNotify;
98     bool mInvoked = false;
99 };
100 
101 #define ASSERT_OK(r) ASSERT_TRUE(isOk(r))
102 #define EXPECT_OK(r) EXPECT_TRUE(isOk(r))
103 template <typename T>
isOk(const Return<T> & r)104 AssertionResult 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
isAllOk(const Return<Result> & r)110 AssertionResult 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  */
TEST_P(HealthHidlTest,Callbacks)124 TEST_P(HealthHidlTest, Callbacks) {
125     using namespace std::chrono_literals;
126     sp<Callback> firstCallback = new Callback();
127     sp<Callback> secondCallback = new Callback();
128 
129     ASSERT_ALL_OK(mHealth->registerCallback(firstCallback));
130     ASSERT_ALL_OK(mHealth->registerCallback(secondCallback));
131 
132     // 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);
137 
138     // assert that the first callback is invoked when update is called.
139     ASSERT_ALL_OK(mHealth->update());
140 
141     ASSERT_TRUE(firstCallback->waitInvoke(1s));
142     ASSERT_TRUE(secondCallback->waitInvoke(1s));
143 
144     ASSERT_ALL_OK(mHealth->unregisterCallback(firstCallback));
145 
146     // 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);
150 
151     // assert that the second callback is still invoked even though the first is unregistered.
152     ASSERT_ALL_OK(mHealth->update());
153 
154     ASSERT_FALSE(firstCallback->waitInvoke(200ms));
155     ASSERT_TRUE(secondCallback->waitInvoke(1s));
156 
157     ASSERT_ALL_OK(mHealth->unregisterCallback(secondCallback));
158 }
159 
TEST_P(HealthHidlTest,UnregisterNonExistentCallback)160 TEST_P(HealthHidlTest, UnregisterNonExistentCallback) {
161     sp<Callback> callback = new Callback();
162     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 
isPropertyOk(Result res,const std::string & valueStr,bool pred,const std::string & predStr)178 AssertionResult 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 
verifyStorageInfo(const hidl_vec<struct StorageInfo> & info)193 bool 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 
204 template <typename T>
verifyEnum(T value)205 bool verifyEnum(T value) {
206     for (auto it : hidl_enum_range<T>()) {
207         if (it == value) {
208             return true;
209         }
210     }
211 
212     return false;
213 }
214 
verifyHealthInfo(const HealthInfo & health_info)215 bool verifyHealthInfo(const HealthInfo& health_info) {
216     if (!verifyStorageInfo(health_info.storageInfos)) {
217         return false;
218     }
219 
220     using V1_0::BatteryStatus;
221     using V1_0::BatteryHealth;
222 
223     if (!((health_info.legacy.batteryCurrent != INT32_MIN) &&
224           (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
225           verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
226           verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
227         return false;
228     }
229 
230     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 
238     return true;
239 }
240 
241 /*
242  * Tests the values returned by getChargeCounter() from interface IHealth.
243  */
TEST_P(HealthHidlTest,getChargeCounter)244 TEST_P(HealthHidlTest, getChargeCounter) {
245     EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
246         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
247     }));
248 }
249 
250 /*
251  * Tests the values returned by getCurrentNow() from interface IHealth.
252  */
TEST_P(HealthHidlTest,getCurrentNow)253 TEST_P(HealthHidlTest, getCurrentNow) {
254     EXPECT_OK(mHealth->getCurrentNow([](auto result, auto value) {
255         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
256     }));
257 }
258 
259 /*
260  * Tests the values returned by getCurrentAverage() from interface IHealth.
261  */
TEST_P(HealthHidlTest,getCurrentAverage)262 TEST_P(HealthHidlTest, getCurrentAverage) {
263     EXPECT_OK(mHealth->getCurrentAverage([](auto result, auto value) {
264         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
265     }));
266 }
267 
268 /*
269  * Tests the values returned by getCapacity() from interface IHealth.
270  */
TEST_P(HealthHidlTest,getCapacity)271 TEST_P(HealthHidlTest, getCapacity) {
272     EXPECT_OK(mHealth->getCapacity([](auto result, auto value) {
273         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), 0 <= value && value <= 100);
274     }));
275 }
276 
277 /*
278  * Tests the values returned by getEnergyCounter() from interface IHealth.
279  */
TEST_P(HealthHidlTest,getEnergyCounter)280 TEST_P(HealthHidlTest, getEnergyCounter) {
281     EXPECT_OK(mHealth->getEnergyCounter([](auto result, auto value) {
282         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT64_MIN);
283     }));
284 }
285 
286 /*
287  * Tests the values returned by getChargeStatus() from interface IHealth.
288  */
TEST_P(HealthHidlTest,getChargeStatus)289 TEST_P(HealthHidlTest, getChargeStatus) {
290     EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
291         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyEnum<BatteryStatus>(value));
292     }));
293 }
294 
295 /*
296  * Tests the values returned by getStorageInfo() from interface IHealth.
297  */
TEST_P(HealthHidlTest,getStorageInfo)298 TEST_P(HealthHidlTest, getStorageInfo) {
299     EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
300         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
301     }));
302 }
303 
304 /*
305  * Tests the values returned by getDiskStats() from interface IHealth.
306  */
TEST_P(HealthHidlTest,getDiskStats)307 TEST_P(HealthHidlTest, getDiskStats) {
308     EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
309         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), true);
310     }));
311 }
312 
313 /*
314  * Tests the values returned by getHealthInfo() from interface IHealth.
315  */
TEST_P(HealthHidlTest,getHealthInfo)316 TEST_P(HealthHidlTest, getHealthInfo) {
317     EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
318         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
319     }));
320 }
321 
322 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HealthHidlTest);
323 INSTANTIATE_TEST_SUITE_P(
324         PerInstance, HealthHidlTest,
325         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
326         android::hardware::PrintInstanceNameToString);
327 
328 // For battery current tests, value may not be stable if the battery current has fluctuated.
329 // Retry in a bit more time (with the following timeout) and consider the test successful if it
330 // has succeed once.
331 static constexpr auto gBatteryTestTimeout = 1min;
332 // Tests on battery current signs are only enforced on devices launching with Android 11.
333 static constexpr int64_t gBatteryTestMinShippingApiLevel = 30;
334 static constexpr double gCurrentCompareFactor = 0.50;
335 
336 // Tuple for all IHealth::get* API return values.
337 template <typename T>
338 struct HalResult {
339     Result result;
340     T value;
341 };
342 
343 // Needs to be called repeatedly within a period of time to ensure values are initialized.
IsBatteryCurrentSignCorrect(HalResult<BatteryStatus> status,HalResult<int32_t> current,bool acceptZeroCurrentAsUnknown)344 static AssertionResult IsBatteryCurrentSignCorrect(HalResult<BatteryStatus> status,
345                                                    HalResult<int32_t> current,
346                                                    bool acceptZeroCurrentAsUnknown) {
347     // getChargeStatus / getCurrentNow / getCurrentAverage / getHealthInfo already tested above.
348     // Here, just skip if not ok.
349     if (status.result != Result::SUCCESS) {
350         return AssertionSuccess() << "getChargeStatus / getHealthInfo returned "
351                                   << toString(status.result) << ", skipping";
352     }
353 
354     if (current.result != Result::SUCCESS) {
355         return AssertionSuccess() << "getCurrentNow / getCurrentAverage returned "
356                                   << toString(current.result) << ", skipping";
357     }
358 
359     // For IHealth.getCurrentNow/Average, if current is not available, it is expected that
360     // current.result == Result::NOT_SUPPORTED, which is checked above. Hence, zero current is
361     // not treated as unknown values.
362     // For IHealth.getHealthInfo, if current is not available, health_info.current_* == 0.
363     // Caller of this function provides current.result == Result::SUCCESS. Hence, just skip the
364     // check.
365     if (current.value == 0 && acceptZeroCurrentAsUnknown) {
366         return AssertionSuccess()
367                << "current is 0, which indicates the value may not be available. Skipping.";
368     }
369 
370     switch (status.value) {
371         case BatteryStatus::UNKNOWN:
372             if (current.value != 0) {
373                 // BatteryStatus may be UNKNOWN initially with a non-zero current value, but
374                 // after it is initialized, it should be known.
375                 return AssertionFailure()
376                        << "BatteryStatus is UNKNOWN but current is not 0. Actual: "
377                        << current.value;
378             }
379             break;
380         case BatteryStatus::CHARGING:
381             if (current.value <= 0) {
382                 return AssertionFailure()
383                        << "BatteryStatus is CHARGING but current is not positive. Actual: "
384                        << current.value;
385             }
386             break;
387         case BatteryStatus::NOT_CHARGING:
388             if (current.value > 0) {
389                 return AssertionFailure() << "BatteryStatus is " << toString(status.value)
390                                           << " but current is positive. Actual: " << current.value;
391             }
392             break;
393         case BatteryStatus::DISCHARGING:
394             if (current.value >= 0) {
395                 return AssertionFailure()
396                        << "BatteryStatus is " << toString(status.value)
397                        << " but current is not negative. Actual: " << current.value;
398             }
399             break;
400         case BatteryStatus::FULL:
401             // Battery current may be positive or negative depending on the load.
402             break;
403         default:
404             return AssertionFailure() << "Unknown BatteryStatus " << toString(status.value);
405     }
406 
407     return AssertionSuccess() << "BatteryStatus is " << toString(status.value)
408                               << " and current has the correct sign: " << current.value;
409 }
410 
IsValueSimilar(int32_t dividend,int32_t divisor,double factor)411 static AssertionResult IsValueSimilar(int32_t dividend, int32_t divisor, double factor) {
412     auto difference = abs(dividend - divisor);
413     if (difference > factor * abs(divisor)) {
414         return AssertionFailure() << dividend << " and " << divisor << " are not similar.";
415     }
416     return AssertionSuccess() << dividend << " and " << divisor << " are similar.";
417 }
418 
IsBatteryCurrentSimilar(HalResult<BatteryStatus> status,HalResult<int32_t> currentNow,HalResult<int32_t> currentAverage)419 static AssertionResult IsBatteryCurrentSimilar(HalResult<BatteryStatus> status,
420                                                HalResult<int32_t> currentNow,
421                                                HalResult<int32_t> currentAverage) {
422     if (status.result == Result::SUCCESS && status.value == BatteryStatus::FULL) {
423         // No reason to test on full battery because battery current load fluctuates.
424         return AssertionSuccess() << "Battery is full, skipping";
425     }
426 
427     // getCurrentNow / getCurrentAverage / getHealthInfo already tested above. Here, just skip if
428     // not SUCCESS or value 0.
429     if (currentNow.result != Result::SUCCESS || currentNow.value == 0) {
430         return AssertionSuccess() << "getCurrentNow returned " << toString(currentNow.result)
431                                   << " with value " << currentNow.value << ", skipping";
432     }
433 
434     if (currentAverage.result != Result::SUCCESS || currentAverage.value == 0) {
435         return AssertionSuccess() << "getCurrentAverage returned "
436                                   << toString(currentAverage.result) << " with value "
437                                   << currentAverage.value << ", skipping";
438     }
439 
440     // Check that the two values are similar. Note that the two tests uses a different
441     // divisor to ensure that they are actually pretty similar. For example,
442     // IsValueSimilar(5,10,0.4) returns true, but IsValueSimlar(10,5,0.4) returns false.
443     TEST_AND_RETURN(IsValueSimilar(currentNow.value, currentAverage.value, gCurrentCompareFactor)
444                     << " for now vs. average. Check units.");
445     TEST_AND_RETURN(IsValueSimilar(currentAverage.value, currentNow.value, gCurrentCompareFactor)
446                     << " for average vs. now. Check units.");
447     return AssertionSuccess() << "currentNow = " << currentNow.value
448                               << " and currentAverage = " << currentAverage.value
449                               << " are considered similar.";
450 }
451 
452 // Test that f() returns AssertionSuccess() once in a given period of time.
453 template <typename Duration, typename Function>
SucceedOnce(Duration d,Function f)454 static AssertionResult SucceedOnce(Duration d, Function f) {
455     AssertionResult result = AssertionFailure() << "Function never evaluated.";
456     auto end = std::chrono::system_clock::now() + d;
457     while (std::chrono::system_clock::now() <= end) {
458         result = f();
459         if (result) {
460             return result;
461         }
462         std::this_thread::sleep_for(2s);
463     }
464     return result;
465 }
466 
GetShippingApiLevel()467 uint64_t GetShippingApiLevel() {
468     uint64_t api_level = android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
469     if (api_level != 0) {
470         return api_level;
471     }
472     return android::base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
473 }
474 
475 class BatteryTest : public HealthHidlTest {
476   public:
SetUp()477     void SetUp() override {
478         HealthHidlTest::SetUp();
479 
480         auto shippingApiLevel = GetShippingApiLevel();
481         if (shippingApiLevel < gBatteryTestMinShippingApiLevel) {
482             GTEST_SKIP() << "Skipping on devices with first API level " << shippingApiLevel;
483         }
484     }
485 };
486 
TEST_P(BatteryTest,InstantCurrentAgainstChargeStatusInHealthInfo)487 TEST_P(BatteryTest, InstantCurrentAgainstChargeStatusInHealthInfo) {
488     auto testOnce = [&]() -> AssertionResult {
489         HalResult<HealthInfo> healthInfo;
490         TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
491             healthInfo = {result, value};
492         })));
493 
494         return IsBatteryCurrentSignCorrect(
495                 {healthInfo.result, healthInfo.value.legacy.batteryStatus},
496                 {healthInfo.result, healthInfo.value.legacy.batteryCurrent},
497                 true /* accept zero current as unknown */);
498     };
499     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
500             << "You may want to try again later when current_now becomes stable.";
501 }
502 
TEST_P(BatteryTest,AverageCurrentAgainstChargeStatusInHealthInfo)503 TEST_P(BatteryTest, AverageCurrentAgainstChargeStatusInHealthInfo) {
504     auto testOnce = [&]() -> AssertionResult {
505         HalResult<HealthInfo> healthInfo;
506         TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
507             healthInfo = {result, value};
508         })));
509         return IsBatteryCurrentSignCorrect(
510                 {healthInfo.result, healthInfo.value.legacy.batteryStatus},
511                 {healthInfo.result, healthInfo.value.batteryCurrentAverage},
512                 true /* accept zero current as unknown */);
513     };
514 
515     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
516             << "You may want to try again later when current_average becomes stable.";
517 }
518 
TEST_P(BatteryTest,InstantCurrentAgainstAverageCurrentInHealthInfo)519 TEST_P(BatteryTest, InstantCurrentAgainstAverageCurrentInHealthInfo) {
520     auto testOnce = [&]() -> AssertionResult {
521         HalResult<HealthInfo> healthInfo;
522         TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
523             healthInfo = {result, value};
524         })));
525         return IsBatteryCurrentSimilar({healthInfo.result, healthInfo.value.legacy.batteryStatus},
526                                        {healthInfo.result, healthInfo.value.legacy.batteryCurrent},
527                                        {healthInfo.result, healthInfo.value.batteryCurrentAverage});
528     };
529 
530     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
531             << "You may want to try again later when current_now and current_average becomes "
532                "stable.";
533 }
534 
TEST_P(BatteryTest,InstantCurrentAgainstChargeStatusFromHal)535 TEST_P(BatteryTest, InstantCurrentAgainstChargeStatusFromHal) {
536     auto testOnce = [&]() -> AssertionResult {
537         HalResult<BatteryStatus> status;
538         HalResult<int32_t> currentNow;
539         TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
540             status = {result, value};
541         })));
542         TEST_AND_RETURN(isOk(mHealth->getCurrentNow([&](auto result, auto value) {
543             currentNow = {result, value};
544         })));
545 
546         return IsBatteryCurrentSignCorrect(status, currentNow,
547                                            false /* accept zero current as unknown */);
548     };
549 
550     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
551             << "You may want to try again later when current_now becomes stable.";
552 }
553 
TEST_P(BatteryTest,AverageCurrentAgainstChargeStatusFromHal)554 TEST_P(BatteryTest, AverageCurrentAgainstChargeStatusFromHal) {
555     auto testOnce = [&]() -> AssertionResult {
556         HalResult<BatteryStatus> status;
557         TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
558             status = {result, value};
559         })));
560         HalResult<int32_t> currentAverage;
561         TEST_AND_RETURN(isOk(mHealth->getCurrentAverage([&](auto result, auto value) {
562             currentAverage = {result, value};
563         })));
564         return IsBatteryCurrentSignCorrect(status, currentAverage,
565                                            false /* accept zero current as unknown */);
566     };
567 
568     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
569             << "You may want to try again later when current_average becomes stable.";
570 }
571 
TEST_P(BatteryTest,InstantCurrentAgainstAverageCurrentFromHal)572 TEST_P(BatteryTest, InstantCurrentAgainstAverageCurrentFromHal) {
573     auto testOnce = [&]() -> AssertionResult {
574         HalResult<BatteryStatus> status;
575         TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
576             status = {result, value};
577         })));
578         HalResult<int32_t> currentNow;
579         TEST_AND_RETURN(isOk(mHealth->getCurrentNow([&](auto result, auto value) {
580             currentNow = {result, value};
581         })));
582         HalResult<int32_t> currentAverage;
583         TEST_AND_RETURN(isOk(mHealth->getCurrentAverage([&](auto result, auto value) {
584             currentAverage = {result, value};
585         })));
586         return IsBatteryCurrentSimilar(status, currentNow, currentAverage);
587     };
588 
589     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
590             << "You may want to try again later when current_average becomes stable.";
591 }
592 
IsBatteryStatusCorrect(HalResult<BatteryStatus> status,HalResult<HealthInfo> healthInfo)593 AssertionResult IsBatteryStatusCorrect(HalResult<BatteryStatus> status,
594                                        HalResult<HealthInfo> healthInfo) {
595     // getChargetStatus / getHealthInfo is already tested above. Here, just skip if not ok.
596     if (healthInfo.result != Result::SUCCESS) {
597         return AssertionSuccess() << "getHealthInfo returned " << toString(healthInfo.result)
598                                   << ", skipping";
599     }
600     if (status.result != Result::SUCCESS) {
601         return AssertionSuccess() << "getChargeStatus returned " << toString(status.result)
602                                   << ", skipping";
603     }
604 
605     const auto& batteryInfo = healthInfo.value.legacy;
606     bool isConnected = batteryInfo.chargerAcOnline || batteryInfo.chargerUsbOnline ||
607                        batteryInfo.chargerWirelessOnline;
608 
609     std::stringstream message;
610     message << "BatteryStatus is " << toString(status.value) << " and "
611             << (isConnected ? "" : "no ")
612             << "power source is connected: ac=" << batteryInfo.chargerAcOnline
613             << ", usb=" << batteryInfo.chargerUsbOnline
614             << ", wireless=" << batteryInfo.chargerWirelessOnline;
615 
616     switch (status.value) {
617         case BatteryStatus::UNKNOWN: {
618             // Don't enforce anything on isConnected on unknown battery status.
619             // Battery-less devices must report UNKNOWN battery status, but may report true
620             // or false on isConnected.
621         } break;
622         case BatteryStatus::CHARGING:
623         case BatteryStatus::NOT_CHARGING:
624         case BatteryStatus::FULL: {
625             if (!isConnected) {
626                 return AssertionFailure() << message.str();
627             }
628         } break;
629         case BatteryStatus::DISCHARGING: {
630             if (isConnected) {
631                 return AssertionFailure() << message.str();
632             }
633         } break;
634         default: {
635             return AssertionFailure() << "Unknown battery status value " << toString(status.value);
636         } break;
637     }
638 
639     return AssertionSuccess() << message.str();
640 }
641 
TEST_P(BatteryTest,ConnectedAgainstStatusFromHal)642 TEST_P(BatteryTest, ConnectedAgainstStatusFromHal) {
643     auto testOnce = [&]() -> AssertionResult {
644         HalResult<BatteryStatus> status;
645         TEST_AND_RETURN(isOk(mHealth->getChargeStatus([&](auto result, auto value) {
646             status = {result, value};
647         })));
648         HalResult<HealthInfo> healthInfo;
649         TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
650             healthInfo = {result, value};
651         })));
652         return IsBatteryStatusCorrect(status, healthInfo);
653     };
654 
655     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
656             << "You may want to try again later when battery_status becomes stable.";
657 }
658 
TEST_P(BatteryTest,ConnectedAgainstStatusInHealthInfo)659 TEST_P(BatteryTest, ConnectedAgainstStatusInHealthInfo) {
660     auto testOnce = [&]() -> AssertionResult {
661         HalResult<HealthInfo> healthInfo;
662         TEST_AND_RETURN(isOk(mHealth->getHealthInfo([&](auto result, const auto& value) {
663             healthInfo = {result, value};
664         })));
665         return IsBatteryStatusCorrect({healthInfo.result, healthInfo.value.legacy.batteryStatus},
666                                       healthInfo);
667     };
668 
669     EXPECT_TRUE(SucceedOnce(gBatteryTestTimeout, testOnce))
670             << "You may want to try again later when getHealthInfo becomes stable.";
671 }
672 
673 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BatteryTest);
674 INSTANTIATE_TEST_SUITE_P(
675         PerInstance, BatteryTest,
676         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
677         android::hardware::PrintInstanceNameToString);
678 
679 }  // namespace V2_0
680 }  // namespace health
681 }  // namespace hardware
682 }  // namespace android
683 
main(int argc,char ** argv)684 int main(int argc, char** argv) {
685     ::testing::InitGoogleTest(&argc, argv);
686     gflags::ParseCommandLineFlags(&argc, &argv, true /* remove flags */);
687     return RUN_ALL_TESTS();
688 }
689