blob: a5ba919dd986520492b892b704b2d149c5d9277b [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android-base/logging.h>
#include <android/hardware/health/translate-ndk.h>
#include <health-shim/shim.h>
using ::android::sp;
using ::android::h2a::translate;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::health::V2_0::Result;
using ::android::hardware::health::V2_0::toString;
using ::ndk::ScopedAStatus;
using HidlHealth = ::android::hardware::health::V2_0::IHealth;
using HidlHealthInfoCallback = ::android::hardware::health::V2_0::IHealthInfoCallback;
using HidlHealthInfo = ::android::hardware::health::V2_0::HealthInfo;
namespace aidl::android::hardware::health {
namespace {
class HealthInfoCallbackShim : public HidlHealthInfoCallback {
using AidlHealthInfoCallback = ::aidl::android::hardware::health::IHealthInfoCallback;
using AidlHealthInfo = ::aidl::android::hardware::health::HealthInfo;
public:
explicit HealthInfoCallbackShim(const std::shared_ptr<AidlHealthInfoCallback>& impl)
: impl_(impl) {}
Return<void> healthInfoChanged(const HidlHealthInfo& info) override {
AidlHealthInfo aidl_info;
// translate() should always return true.
CHECK(translate(info, &aidl_info));
// This is a oneway function, so we can't (and shouldn't) check for errors.
(void)impl_->healthInfoChanged(aidl_info);
return Void();
}
private:
std::shared_ptr<AidlHealthInfoCallback> impl_;
};
ScopedAStatus ResultToStatus(Result result) {
switch (result) {
case Result::SUCCESS:
return ScopedAStatus::ok();
case Result::NOT_SUPPORTED:
return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
case Result::UNKNOWN:
return ScopedAStatus::fromServiceSpecificError(IHealth::STATUS_UNKNOWN);
case Result::NOT_FOUND:
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
case Result::CALLBACK_DIED:
return ScopedAStatus::fromServiceSpecificError(IHealth::STATUS_CALLBACK_DIED);
}
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
IHealth::STATUS_UNKNOWN, ("Unrecognized result value " + toString(result)).c_str());
}
template <typename T>
ScopedAStatus ReturnAndResultToStatus(const Return<T>& ret, Result result) {
if (ret.isOk()) {
return ResultToStatus(result);
}
if (ret.isDeadObject()) {
return ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
}
return ScopedAStatus::fromServiceSpecificErrorWithMessage(IHealth::STATUS_UNKNOWN,
ret.description().c_str());
}
ScopedAStatus ReturnResultToStatus(const Return<Result>& return_result) {
return ReturnAndResultToStatus(return_result, return_result.isOk()
? static_cast<Result>(return_result)
: Result::UNKNOWN);
}
} // namespace
HealthShim::HealthShim(const sp<HidlHealth>& service) : service_(service) {}
ScopedAStatus HealthShim::registerCallback(
const std::shared_ptr<IHealthInfoCallback>& in_callback) {
sp<HidlHealthInfoCallback> shim(new HealthInfoCallbackShim(in_callback));
callback_map_.emplace(in_callback, shim);
return ReturnResultToStatus(service_->registerCallback(shim));
}
ScopedAStatus HealthShim::unregisterCallback(
const std::shared_ptr<IHealthInfoCallback>& in_callback) {
auto it = callback_map_.find(in_callback);
if (it == callback_map_.end()) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
sp<HidlHealthInfoCallback> shim = it->second;
callback_map_.erase(it);
return ReturnResultToStatus(service_->unregisterCallback(shim));
}
ScopedAStatus HealthShim::update() {
return ReturnResultToStatus(service_->update());
}
ScopedAStatus HealthShim::getChargeCounterUah(int32_t* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getChargeCounter([out, &out_result](auto result, auto value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
*out = value;
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getCurrentNowMicroamps(int32_t* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getCurrentNow([out, &out_result](auto result, auto value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
*out = value;
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getCurrentAverageMicroamps(int32_t* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getCurrentAverage([out, &out_result](auto result, auto value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
*out = value;
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getCapacity(int32_t* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getCapacity([out, &out_result](auto result, auto value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
*out = value;
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getEnergyCounterNwh(int64_t* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getEnergyCounter([out, &out_result](auto result, auto value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
*out = value;
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getChargeStatus(BatteryStatus* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getChargeStatus([out, &out_result](auto result, auto value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
*out = static_cast<BatteryStatus>(value);
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getStorageInfo(std::vector<StorageInfo>* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getStorageInfo([out, &out_result](auto result, const auto& value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
out->clear();
out->reserve(value.size());
for (const auto& hidl_info : value) {
auto& aidl_info = out->emplace_back();
// translate() should always return true.
CHECK(translate(hidl_info, &aidl_info));
}
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getDiskStats(std::vector<DiskStats>* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getDiskStats([out, &out_result](auto result, const auto& value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
out->clear();
out->reserve(value.size());
for (const auto& hidl_info : value) {
auto& aidl_info = out->emplace_back();
// translate() should always return true.
CHECK(translate(hidl_info, &aidl_info));
}
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::getHealthInfo(HealthInfo* out) {
Result out_result = Result::UNKNOWN;
auto ret = service_->getHealthInfo([out, &out_result](auto result, const auto& value) {
out_result = result;
if (out_result != Result::SUCCESS) return;
// translate() should always return true.
CHECK(translate(value, out));
});
return ReturnAndResultToStatus(ret, out_result);
}
ScopedAStatus HealthShim::setChargingPolicy(BatteryChargingPolicy in_value) {
in_value = static_cast<BatteryChargingPolicy>(0);
return ResultToStatus(Result::NOT_SUPPORTED);
}
ScopedAStatus HealthShim::getChargingPolicy(BatteryChargingPolicy* out) {
*out = static_cast<BatteryChargingPolicy>(0);
return ResultToStatus(Result::NOT_SUPPORTED);
}
ScopedAStatus HealthShim::getBatteryHealthData(BatteryHealthData* out) {
out->batteryManufacturingDateSeconds = 0;
out->batteryFirstUsageSeconds = 0;
out->batteryPartStatus = BatteryPartStatus::UNSUPPORTED;
return ResultToStatus(Result::NOT_SUPPORTED);
}
} // namespace aidl::android::hardware::health