aboutsummaryrefslogtreecommitdiff
path: root/gps/android/utils
diff options
context:
space:
mode:
Diffstat (limited to 'gps/android/utils')
-rw-r--r--gps/android/utils/Android.bp37
-rw-r--r--gps/android/utils/battery_listener.cpp280
-rw-r--r--gps/android/utils/battery_listener.h32
3 files changed, 349 insertions, 0 deletions
diff --git a/gps/android/utils/Android.bp b/gps/android/utils/Android.bp
new file mode 100644
index 0000000..c3dc17a
--- /dev/null
+++ b/gps/android/utils/Android.bp
@@ -0,0 +1,37 @@
+cc_library_static {
+
+ name: "liblocbatterylistener",
+ vendor: true,
+
+ sanitize: GNSS_SANITIZE,
+
+ cflags: GNSS_CFLAGS + ["-DBATTERY_LISTENER_ENABLED"],
+ local_include_dirs: ["."],
+
+ srcs: ["battery_listener.cpp"],
+
+ shared_libs: [
+ "liblog",
+ "libhidlbase",
+ "libcutils",
+ "libutils",
+ "android.hardware.health@1.0",
+ "android.hardware.health@2.0",
+ "android.hardware.health@2.1",
+ "android.hardware.power@1.2",
+ "libbase",
+ ],
+
+ static_libs: ["libhealthhalutils"],
+
+ header_libs: [
+ "libgps.utils_headers",
+ "libloc_pla_headers",
+ ],
+}
+
+cc_library_headers {
+
+ name: "liblocbatterylistener_headers",
+ export_include_dirs: ["."],
+}
diff --git a/gps/android/utils/battery_listener.cpp b/gps/android/utils/battery_listener.cpp
new file mode 100644
index 0000000..9cbfabd
--- /dev/null
+++ b/gps/android/utils/battery_listener.cpp
@@ -0,0 +1,280 @@
+/*
+* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "battery_listener.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_BatteryListener"
+#define LOG_NDEBUG 0
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <healthhalutils/HealthHalUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <thread>
+#include <log_util.h>
+
+using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V2_1::HealthInfo;
+using android::hardware::health::V2_1::IHealthInfoCallback;
+using android::hardware::health::V2_1::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hidl::manager::V1_0::IServiceManager;
+using namespace std::literals::chrono_literals;
+
+static bool sIsBatteryListened = false;
+namespace android {
+
+#define GET_HEALTH_SVC_RETRY_CNT 5
+#define GET_HEALTH_SVC_WAIT_TIME_MS 500
+
+struct BatteryListenerImpl : public hardware::health::V2_1::IHealthInfoCallback,
+ public hardware::hidl_death_recipient {
+ typedef std::function<void(bool)> cb_fn_t;
+ BatteryListenerImpl(cb_fn_t cb);
+ virtual ~BatteryListenerImpl ();
+ virtual hardware::Return<void> healthInfoChanged(
+ const hardware::health::V2_0::HealthInfo& info);
+ virtual hardware::Return<void> healthInfoChanged_2_1(
+ const hardware::health::V2_1::HealthInfo& info);
+ virtual void serviceDied(uint64_t cookie,
+ const wp<hidl::base::V1_0::IBase>& who);
+ bool isCharging() {
+ std::lock_guard<std::mutex> _l(mLock);
+ return statusToBool(mStatus);
+ }
+ private:
+ sp<hardware::health::V2_1::IHealth> mHealth;
+ status_t init();
+ BatteryStatus mStatus;
+ cb_fn_t mCb;
+ std::mutex mLock;
+ std::condition_variable mCond;
+ std::unique_ptr<std::thread> mThread;
+ bool mDone;
+ bool statusToBool(const BatteryStatus &s) const {
+ return (s == BatteryStatus::CHARGING) ||
+ (s == BatteryStatus::FULL);
+ }
+};
+
+status_t BatteryListenerImpl::init()
+{
+ int tries = 0;
+
+ if (mHealth != NULL)
+ return INVALID_OPERATION;
+
+ do {
+ mHealth = IHealth::getService();
+ if (mHealth != NULL)
+ break;
+ usleep(GET_HEALTH_SVC_WAIT_TIME_MS * 1000);
+ tries++;
+ } while(tries < GET_HEALTH_SVC_RETRY_CNT);
+
+ if (mHealth == NULL) {
+ LOC_LOGe("no health service found, retries %d", tries);
+ return NO_INIT;
+ } else {
+ LOC_LOGi("Get health service in %d tries", tries);
+ }
+ mStatus = BatteryStatus::UNKNOWN;
+ auto ret = mHealth->getChargeStatus([&](Result r, BatteryStatus status) {
+ if (r != Result::SUCCESS) {
+ LOC_LOGe("batterylistener: cannot get battery status");
+ return;
+ }
+ mStatus = status;
+ });
+ if (!ret.isOk()) {
+ LOC_LOGe("batterylistener: get charge status transaction error");
+ }
+ if (mStatus == BatteryStatus::UNKNOWN) {
+ LOC_LOGw("batterylistener: init: invalid battery status");
+ }
+ mDone = false;
+ mThread = std::make_unique<std::thread>([this]() {
+ std::unique_lock<std::mutex> l(mLock);
+ BatteryStatus local_status = mStatus;
+ while (!mDone) {
+ if (local_status == mStatus) {
+ mCond.wait(l);
+ continue;
+ }
+ local_status = mStatus;
+ switch (local_status) {
+ // NOT_CHARGING is a special event that indicates, a battery is connected,
+ // but not charging. This is seen for approx a second
+ // after charger is plugged in. A charging event is eventually received.
+ // We must try to avoid an unnecessary cb to HAL
+ // only to call it again shortly.
+ // An option to deal with this transient event would be to ignore this.
+ // Or process this event with a slight delay (i.e cancel this event
+ // if a different event comes in within a timeout
+ case BatteryStatus::NOT_CHARGING : {
+ auto mStatusnot_ncharging =
+ [this, local_status]() { return mStatus != local_status; };
+ mCond.wait_for(l, 3s, mStatusnot_ncharging);
+ if (mStatusnot_ncharging()) // i.e event changed
+ break;
+ [[clang::fallthrough]]; //explicit fall-through between switch labels
+ }
+ default:
+ bool c = statusToBool(local_status);
+ LOC_LOGi("healthInfo cb thread: cb %s", c ? "CHARGING" : "NOT CHARGING");
+ l.unlock();
+ mCb(c);
+ l.lock();
+ break;
+ }
+ }
+ });
+ auto reg = mHealth->registerCallback(this);
+ if (!reg.isOk()) {
+ LOC_LOGe("Transaction error in registeringCb to HealthHAL death: %s",
+ reg.description().c_str());
+ }
+
+ auto linked = mHealth->linkToDeath(this, 0 /* cookie */);
+ if (!linked.isOk() || linked == false) {
+ LOC_LOGe("Transaction error in linking to HealthHAL death: %s",
+ linked.description().c_str());
+ }
+ return NO_ERROR;
+}
+
+BatteryListenerImpl::BatteryListenerImpl(cb_fn_t cb) :
+ mCb(cb)
+{
+ init();
+}
+
+BatteryListenerImpl::~BatteryListenerImpl()
+{
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mHealth != NULL)
+ mHealth->unregisterCallback(this);
+ auto r = mHealth->unlinkToDeath(this);
+ if (!r.isOk() || r == false) {
+ LOC_LOGe("Transaction error in unregister to HealthHAL death: %s",
+ r.description().c_str());
+ }
+ }
+ mDone = true;
+ mThread->join();
+}
+
+void BatteryListenerImpl::serviceDied(uint64_t cookie __unused,
+ const wp<hidl::base::V1_0::IBase>& who)
+{
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mHealth == NULL || !interfacesEqual(mHealth, who.promote())) {
+ LOC_LOGe("health not initialized or unknown interface died");
+ return;
+ }
+ LOC_LOGi("health service died, reinit");
+ mDone = true;
+ }
+ mHealth = NULL;
+ mCond.notify_one();
+ mThread->join();
+ std::lock_guard<std::mutex> _l(mLock);
+ init();
+}
+
+// this callback seems to be a SYNC callback and so
+// waits for return before next event is issued.
+// therefore we need not have a queue to process
+// NOT_CHARGING and CHARGING concurrencies.
+// Replace single var by a list if this assumption is broken
+Return<void> BatteryListenerImpl::healthInfoChanged(
+ const hardware::health::V2_0::HealthInfo& info) {
+ LOC_LOGv("healthInfoChanged: %d", info.legacy.batteryStatus);
+ std::unique_lock<std::mutex> l(mLock);
+ if (info.legacy.batteryStatus != mStatus) {
+ mStatus = info.legacy.batteryStatus;
+ mCond.notify_one();
+ }
+ return Void();
+}
+
+Return<void> BatteryListenerImpl::healthInfoChanged_2_1(
+ const hardware::health::V2_1::HealthInfo& info) {
+ LOC_LOGv("healthInfoChanged_2_1: %d", info.legacy.legacy.batteryStatus);
+ healthInfoChanged(info.legacy);
+ return Void();
+}
+
+static sp<BatteryListenerImpl> batteryListener;
+
+bool batteryPropertiesListenerIsCharging() {
+ return batteryListener->isCharging();
+}
+
+status_t batteryPropertiesListenerInit(BatteryListenerImpl::cb_fn_t cb) {
+ batteryListener = new BatteryListenerImpl(cb);
+ bool isCharging = batteryPropertiesListenerIsCharging();
+ LOC_LOGv("charging status: %s charging", isCharging ? "" : "not");;
+ if (isCharging) {
+ cb(isCharging);
+ }
+ return NO_ERROR;
+}
+
+status_t batteryPropertiesListenerDeinit() {
+ batteryListener.clear();
+ return OK;
+}
+
+} // namespace android
+
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn) {
+ LOC_LOGv("loc_extn_battery_properties_listener_init entry");
+ if (!sIsBatteryListened) {
+ std::thread t1(android::batteryPropertiesListenerInit,
+ [=](bool charging) { fn(charging); });
+ t1.detach();
+ sIsBatteryListened = true;
+ }
+}
+
+void loc_extn_battery_properties_listener_deinit() {
+ android::batteryPropertiesListenerDeinit();
+}
+
+bool loc_extn_battery_properties_is_charging() {
+ return android::batteryPropertiesListenerIsCharging();
+}
diff --git a/gps/android/utils/battery_listener.h b/gps/android/utils/battery_listener.h
new file mode 100644
index 0000000..bb6b715
--- /dev/null
+++ b/gps/android/utils/battery_listener.h
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+typedef void (* battery_status_change_fn_t)(bool);
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn);
+void loc_extn_battery_properties_listener_deinit();
+bool loc_extn_battery_properties_is_charging();