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