1 /*
2  * Copyright (C) 2021 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 #include <android-base/logging.h>
18 #include <android/hardware/health/translate-ndk.h>
19 #include <health-shim/shim.h>
20 
21 using ::android::sp;
22 using ::android::h2a::translate;
23 using ::android::hardware::Return;
24 using ::android::hardware::Void;
25 using ::android::hardware::health::V2_0::Result;
26 using ::android::hardware::health::V2_0::toString;
27 using ::ndk::ScopedAStatus;
28 using HidlHealth = ::android::hardware::health::V2_0::IHealth;
29 using HidlHealthInfoCallback = ::android::hardware::health::V2_0::IHealthInfoCallback;
30 using HidlHealthInfo = ::android::hardware::health::V2_0::HealthInfo;
31 
32 namespace aidl::android::hardware::health {
33 
34 namespace {
35 
36 class HealthInfoCallbackShim : public HidlHealthInfoCallback {
37     using AidlHealthInfoCallback = ::aidl::android::hardware::health::IHealthInfoCallback;
38     using AidlHealthInfo = ::aidl::android::hardware::health::HealthInfo;
39 
40   public:
HealthInfoCallbackShim(const std::shared_ptr<AidlHealthInfoCallback> & impl)41     explicit HealthInfoCallbackShim(const std::shared_ptr<AidlHealthInfoCallback>& impl)
42         : impl_(impl) {}
healthInfoChanged(const HidlHealthInfo & info)43     Return<void> healthInfoChanged(const HidlHealthInfo& info) override {
44         AidlHealthInfo aidl_info;
45         // translate() should always return true.
46         CHECK(translate(info, &aidl_info));
47         // This is a oneway function, so we can't (and shouldn't) check for errors.
48         (void)impl_->healthInfoChanged(aidl_info);
49         return Void();
50     }
51 
52   private:
53     std::shared_ptr<AidlHealthInfoCallback> impl_;
54 };
55 
ResultToStatus(Result result)56 ScopedAStatus ResultToStatus(Result result) {
57     switch (result) {
58         case Result::SUCCESS:
59             return ScopedAStatus::ok();
60         case Result::NOT_SUPPORTED:
61             return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
62         case Result::UNKNOWN:
63             return ScopedAStatus::fromServiceSpecificError(IHealth::STATUS_UNKNOWN);
64         case Result::NOT_FOUND:
65             return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
66         case Result::CALLBACK_DIED:
67             return ScopedAStatus::fromServiceSpecificError(IHealth::STATUS_CALLBACK_DIED);
68     }
69     return ScopedAStatus::fromServiceSpecificErrorWithMessage(
70             IHealth::STATUS_UNKNOWN, ("Unrecognized result value " + toString(result)).c_str());
71 }
72 
73 template <typename T>
ReturnAndResultToStatus(const Return<T> & ret,Result result)74 ScopedAStatus ReturnAndResultToStatus(const Return<T>& ret, Result result) {
75     if (ret.isOk()) {
76         return ResultToStatus(result);
77     }
78     if (ret.isDeadObject()) {
79         return ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
80     }
81     return ScopedAStatus::fromServiceSpecificErrorWithMessage(IHealth::STATUS_UNKNOWN,
82                                                               ret.description().c_str());
83 }
84 
ReturnResultToStatus(const Return<Result> & return_result)85 ScopedAStatus ReturnResultToStatus(const Return<Result>& return_result) {
86     return ReturnAndResultToStatus(return_result, return_result.isOk()
87                                                           ? static_cast<Result>(return_result)
88                                                           : Result::UNKNOWN);
89 }
90 
91 }  // namespace
92 
HealthShim(const sp<HidlHealth> & service)93 HealthShim::HealthShim(const sp<HidlHealth>& service) : service_(service) {}
94 
registerCallback(const std::shared_ptr<IHealthInfoCallback> & in_callback)95 ScopedAStatus HealthShim::registerCallback(
96         const std::shared_ptr<IHealthInfoCallback>& in_callback) {
97     sp<HidlHealthInfoCallback> shim(new HealthInfoCallbackShim(in_callback));
98     callback_map_.emplace(in_callback, shim);
99     return ReturnResultToStatus(service_->registerCallback(shim));
100 }
101 
unregisterCallback(const std::shared_ptr<IHealthInfoCallback> & in_callback)102 ScopedAStatus HealthShim::unregisterCallback(
103         const std::shared_ptr<IHealthInfoCallback>& in_callback) {
104     auto it = callback_map_.find(in_callback);
105     if (it == callback_map_.end()) {
106         return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
107     }
108     sp<HidlHealthInfoCallback> shim = it->second;
109     callback_map_.erase(it);
110     return ReturnResultToStatus(service_->unregisterCallback(shim));
111 }
112 
update()113 ScopedAStatus HealthShim::update() {
114     return ReturnResultToStatus(service_->update());
115 }
116 
getChargeCounterUah(int32_t * out)117 ScopedAStatus HealthShim::getChargeCounterUah(int32_t* out) {
118     Result out_result = Result::UNKNOWN;
119     auto ret = service_->getChargeCounter([out, &out_result](auto result, auto value) {
120         out_result = result;
121         if (out_result != Result::SUCCESS) return;
122         *out = value;
123     });
124     return ReturnAndResultToStatus(ret, out_result);
125 }
126 
getCurrentNowMicroamps(int32_t * out)127 ScopedAStatus HealthShim::getCurrentNowMicroamps(int32_t* out) {
128     Result out_result = Result::UNKNOWN;
129     auto ret = service_->getCurrentNow([out, &out_result](auto result, auto value) {
130         out_result = result;
131         if (out_result != Result::SUCCESS) return;
132         *out = value;
133     });
134     return ReturnAndResultToStatus(ret, out_result);
135 }
136 
getCurrentAverageMicroamps(int32_t * out)137 ScopedAStatus HealthShim::getCurrentAverageMicroamps(int32_t* out) {
138     Result out_result = Result::UNKNOWN;
139     auto ret = service_->getCurrentAverage([out, &out_result](auto result, auto value) {
140         out_result = result;
141         if (out_result != Result::SUCCESS) return;
142         *out = value;
143     });
144     return ReturnAndResultToStatus(ret, out_result);
145 }
146 
getCapacity(int32_t * out)147 ScopedAStatus HealthShim::getCapacity(int32_t* out) {
148     Result out_result = Result::UNKNOWN;
149     auto ret = service_->getCapacity([out, &out_result](auto result, auto value) {
150         out_result = result;
151         if (out_result != Result::SUCCESS) return;
152         *out = value;
153     });
154     return ReturnAndResultToStatus(ret, out_result);
155 }
156 
getEnergyCounterNwh(int64_t * out)157 ScopedAStatus HealthShim::getEnergyCounterNwh(int64_t* out) {
158     Result out_result = Result::UNKNOWN;
159     auto ret = service_->getEnergyCounter([out, &out_result](auto result, auto value) {
160         out_result = result;
161         if (out_result != Result::SUCCESS) return;
162         *out = value;
163     });
164     return ReturnAndResultToStatus(ret, out_result);
165 }
166 
getChargeStatus(BatteryStatus * out)167 ScopedAStatus HealthShim::getChargeStatus(BatteryStatus* out) {
168     Result out_result = Result::UNKNOWN;
169     auto ret = service_->getChargeStatus([out, &out_result](auto result, auto value) {
170         out_result = result;
171         if (out_result != Result::SUCCESS) return;
172         *out = static_cast<BatteryStatus>(value);
173     });
174     return ReturnAndResultToStatus(ret, out_result);
175 }
176 
getStorageInfo(std::vector<StorageInfo> * out)177 ScopedAStatus HealthShim::getStorageInfo(std::vector<StorageInfo>* out) {
178     Result out_result = Result::UNKNOWN;
179     auto ret = service_->getStorageInfo([out, &out_result](auto result, const auto& value) {
180         out_result = result;
181         if (out_result != Result::SUCCESS) return;
182         out->clear();
183         out->reserve(value.size());
184         for (const auto& hidl_info : value) {
185             auto& aidl_info = out->emplace_back();
186             // translate() should always return true.
187             CHECK(translate(hidl_info, &aidl_info));
188         }
189     });
190     return ReturnAndResultToStatus(ret, out_result);
191 }
192 
getDiskStats(std::vector<DiskStats> * out)193 ScopedAStatus HealthShim::getDiskStats(std::vector<DiskStats>* out) {
194     Result out_result = Result::UNKNOWN;
195     auto ret = service_->getDiskStats([out, &out_result](auto result, const auto& value) {
196         out_result = result;
197         if (out_result != Result::SUCCESS) return;
198         out->clear();
199         out->reserve(value.size());
200         for (const auto& hidl_info : value) {
201             auto& aidl_info = out->emplace_back();
202             // translate() should always return true.
203             CHECK(translate(hidl_info, &aidl_info));
204         }
205     });
206     return ReturnAndResultToStatus(ret, out_result);
207 }
208 
getHealthInfo(HealthInfo * out)209 ScopedAStatus HealthShim::getHealthInfo(HealthInfo* out) {
210     Result out_result = Result::UNKNOWN;
211     auto ret = service_->getHealthInfo([out, &out_result](auto result, const auto& value) {
212         out_result = result;
213         if (out_result != Result::SUCCESS) return;
214         // translate() should always return true.
215         CHECK(translate(value, out));
216     });
217     return ReturnAndResultToStatus(ret, out_result);
218 }
219 
setChargingPolicy(BatteryChargingPolicy in_value)220 ScopedAStatus HealthShim::setChargingPolicy(BatteryChargingPolicy in_value) {
221     in_value = static_cast<BatteryChargingPolicy>(0);
222     return ResultToStatus(Result::NOT_SUPPORTED);
223 }
224 
getChargingPolicy(BatteryChargingPolicy * out)225 ScopedAStatus HealthShim::getChargingPolicy(BatteryChargingPolicy* out) {
226     *out = static_cast<BatteryChargingPolicy>(0);
227     return ResultToStatus(Result::NOT_SUPPORTED);
228 }
229 
getBatteryHealthData(BatteryHealthData * out)230 ScopedAStatus HealthShim::getBatteryHealthData(BatteryHealthData* out) {
231     out->batteryManufacturingDateSeconds = 0;
232     out->batteryFirstUsageSeconds = 0;
233     out->batteryPartStatus = BatteryPartStatus::UNSUPPORTED;
234     return ResultToStatus(Result::NOT_SUPPORTED);
235 }
236 
237 }  // namespace aidl::android::hardware::health
238