summaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
Diffstat (limited to 'android')
-rw-r--r--android/1.0/Android.mk9
-rw-r--r--android/1.0/Gnss.cpp13
-rw-r--r--android/1.1/Android.mk9
-rw-r--r--android/1.1/Gnss.cpp14
-rw-r--r--android/2.0/Android.mk11
-rw-r--r--android/2.0/Gnss.cpp14
-rw-r--r--android/2.0/GnssConfiguration.cpp2
-rw-r--r--android/2.0/location_api/GeofenceAPIClient.cpp2
-rw-r--r--android/2.0/location_api/GnssAPIClient.cpp26
-rw-r--r--android/2.0/location_api/GnssAPIClient.h1
-rw-r--r--android/2.0/location_api/MeasurementAPIClient.cpp4
-rw-r--r--android/Android.mk9
-rw-r--r--android/utils/Android.mk37
-rw-r--r--android/utils/battery_listener.cpp266
-rw-r--r--android/utils/battery_listener.h32
15 files changed, 433 insertions, 16 deletions
diff --git a/android/1.0/Android.mk b/android/1.0/Android.mk
index 5489f86..9337325 100644
--- a/android/1.0/Android.mk
+++ b/android/1.0/Android.mk
@@ -28,7 +28,8 @@ LOCAL_HEADER_LIBRARIES := \
libgps.utils_headers \
libloc_core_headers \
libloc_pla_headers \
- liblocation_api_headers
+ liblocation_api_headers \
+ liblocbatterylistener_headers
LOCAL_SHARED_LIBRARIES := \
liblog \
@@ -38,6 +39,10 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
android.hardware.gnss@1.0 \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
LOCAL_SHARED_LIBRARIES += \
libloc_core \
@@ -46,6 +51,8 @@ LOCAL_SHARED_LIBRARIES += \
liblocation_api \
LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
diff --git a/android/1.0/Gnss.cpp b/android/1.0/Gnss.cpp
index 93b320b..d85e0a4 100644
--- a/android/1.0/Gnss.cpp
+++ b/android/1.0/Gnss.cpp
@@ -19,6 +19,7 @@
*/
#define LOG_TAG "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
#include <fstream>
#include <log_util.h>
@@ -26,6 +27,7 @@
#include <cutils/properties.h>
#include "Gnss.h"
#include <LocationUtil.h>
+#include "battery_listener.h"
typedef const GnssInterface* (getLocationInterface)();
@@ -35,6 +37,7 @@ namespace gnss {
namespace V1_0 {
namespace implementation {
+static sp<Gnss> sGnss;
void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
LOC_LOGE("%s] service died. cookie: %llu, who: %p",
__FUNCTION__, static_cast<unsigned long long>(cookie), &who);
@@ -44,8 +47,17 @@ void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who
}
}
+void location_on_battery_status_changed(bool charging) {
+ LOC_LOGd("battery status changed to %s charging", charging ? "" : "not ");
+ if (sGnss != nullptr) {
+ sGnss->getGnssInterface()->updateBatteryStatus(charging);
+ }
+}
Gnss::Gnss() {
ENTRY_LOG_CALLFLOW();
+ sGnss = this;
+ // register health client to listen on battery change
+ loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
// clear pending GnssConfig
memset(&mPendingConfig, 0, sizeof(GnssConfig));
@@ -58,6 +70,7 @@ Gnss::~Gnss() {
delete mApi;
mApi = nullptr;
}
+ sGnss = nullptr;
}
GnssAPIClient* Gnss::getApi() {
diff --git a/android/1.1/Android.mk b/android/1.1/Android.mk
index 0beaf20..fb72de1 100644
--- a/android/1.1/Android.mk
+++ b/android/1.1/Android.mk
@@ -28,7 +28,8 @@ LOCAL_HEADER_LIBRARIES := \
libgps.utils_headers \
libloc_core_headers \
libloc_pla_headers \
- liblocation_api_headers
+ liblocation_api_headers \
+ liblocbatterylistener_headers
LOCAL_SHARED_LIBRARIES := \
liblog \
@@ -39,6 +40,10 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
android.hardware.gnss@1.0 \
android.hardware.gnss@1.1 \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
LOCAL_SHARED_LIBRARIES += \
libloc_core \
@@ -47,6 +52,8 @@ LOCAL_SHARED_LIBRARIES += \
liblocation_api \
LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
diff --git a/android/1.1/Gnss.cpp b/android/1.1/Gnss.cpp
index 8d5d8a8..bea556f 100644
--- a/android/1.1/Gnss.cpp
+++ b/android/1.1/Gnss.cpp
@@ -19,6 +19,7 @@
*/
#define LOG_TAG "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
#include <fstream>
#include <log_util.h>
@@ -27,6 +28,8 @@
#include "Gnss.h"
#include <LocationUtil.h>
+#include "battery_listener.h"
+
typedef const GnssInterface* (getLocationInterface)();
#define IMAGES_INFO_FILE "/sys/devices/soc0/images"
@@ -38,6 +41,7 @@ namespace gnss {
namespace V1_1 {
namespace implementation {
+static sp<Gnss> sGnss;
static std::string getVersionString() {
static std::string version;
if (!version.empty())
@@ -84,8 +88,17 @@ void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who
}
}
+void location_on_battery_status_changed(bool charging) {
+ LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+ if (sGnss != nullptr) {
+ sGnss->getGnssInterface()->updateBatteryStatus(charging);
+ }
+}
Gnss::Gnss() {
ENTRY_LOG_CALLFLOW();
+ sGnss = this;
+ // register health client to listen on battery change
+ loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
// clear pending GnssConfig
memset(&mPendingConfig, 0, sizeof(GnssConfig));
@@ -98,6 +111,7 @@ Gnss::~Gnss() {
delete mApi;
mApi = nullptr;
}
+ sGnss = nullptr;
}
GnssAPIClient* Gnss::getApi() {
diff --git a/android/2.0/Android.mk b/android/2.0/Android.mk
index c33a792..7c55504 100644
--- a/android/2.0/Android.mk
+++ b/android/2.0/Android.mk
@@ -37,7 +37,8 @@ LOCAL_HEADER_LIBRARIES := \
libgps.utils_headers \
libloc_core_headers \
libloc_pla_headers \
- liblocation_api_headers
+ liblocation_api_headers \
+ liblocbatterylistener_headers
LOCAL_SHARED_LIBRARIES := \
liblog \
@@ -50,7 +51,11 @@ LOCAL_SHARED_LIBRARIES := \
android.hardware.gnss@1.1 \
android.hardware.gnss@2.0 \
android.hardware.gnss.measurement_corrections@1.0 \
- android.hardware.gnss.visibility_control@1.0
+ android.hardware.gnss.visibility_control@1.0 \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
LOCAL_SHARED_LIBRARIES += \
libloc_core \
@@ -59,6 +64,8 @@ LOCAL_SHARED_LIBRARIES += \
liblocation_api \
LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
diff --git a/android/2.0/Gnss.cpp b/android/2.0/Gnss.cpp
index 0390af7..4fa5b63 100644
--- a/android/2.0/Gnss.cpp
+++ b/android/2.0/Gnss.cpp
@@ -19,6 +19,7 @@
*/
#define LOG_TAG "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
#include <fstream>
#include <log_util.h>
@@ -26,6 +27,7 @@
#include <cutils/properties.h>
#include "Gnss.h"
#include "LocationUtil.h"
+#include "battery_listener.h"
typedef const GnssInterface* (getLocationInterface)();
@@ -39,7 +41,7 @@ namespace V2_0 {
namespace implementation {
using ::android::hardware::gnss::visibility_control::V1_0::implementation::GnssVisibilityControl;
-
+static sp<Gnss> sGnss;
static std::string getVersionString() {
static std::string version;
if (!version.empty())
@@ -85,8 +87,17 @@ void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who
}
}
+void location_on_battery_status_changed(bool charging) {
+ LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+ if (sGnss != nullptr) {
+ sGnss->getGnssInterface()->updateBatteryStatus(charging);
+ }
+}
Gnss::Gnss() {
ENTRY_LOG_CALLFLOW();
+ sGnss = this;
+ // register health client to listen on battery change
+ loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
// clear pending GnssConfig
memset(&mPendingConfig, 0, sizeof(GnssConfig));
mGnssDeathRecipient = new GnssDeathRecipient(this);
@@ -98,6 +109,7 @@ Gnss::~Gnss() {
delete mApi;
mApi = nullptr;
}
+ sGnss = nullptr;
}
GnssAPIClient* Gnss::getApi() {
diff --git a/android/2.0/GnssConfiguration.cpp b/android/2.0/GnssConfiguration.cpp
index 671b6e7..d2a8763 100644
--- a/android/2.0/GnssConfiguration.cpp
+++ b/android/2.0/GnssConfiguration.cpp
@@ -255,7 +255,7 @@ bool GnssConfiguration::setBlacklistedSource(
break;
default:
copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
- LOC_LOGe("Invalid constellation %u", copyFromSource.constellation);
+ LOC_LOGe("Invalid constellation %hhu", copyFromSource.constellation);
retVal = false;
break;
}
diff --git a/android/2.0/location_api/GeofenceAPIClient.cpp b/android/2.0/location_api/GeofenceAPIClient.cpp
index fabf8bb..a93c988 100644
--- a/android/2.0/location_api/GeofenceAPIClient.cpp
+++ b/android/2.0/location_api/GeofenceAPIClient.cpp
@@ -141,7 +141,7 @@ void GeofenceAPIClient::geofenceRemoveAll()
// callbacks
void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
{
- LOC_LOGD("%s]: (%zu)", __FUNCTION__, geofenceBreachNotification.count);
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceBreachNotification.count);
if (mGnssGeofencingCbIface != nullptr) {
for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
GnssLocation gnssLocation;
diff --git a/android/2.0/location_api/GnssAPIClient.cpp b/android/2.0/location_api/GnssAPIClient.cpp
index 68cf395..ffe9075 100644
--- a/android/2.0/location_api/GnssAPIClient.cpp
+++ b/android/2.0/location_api/GnssAPIClient.cpp
@@ -61,6 +61,7 @@ GnssAPIClient::GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
mControlClient(new LocationAPIControlClient()),
mLocationCapabilitiesMask(0),
mLocationCapabilitiesCached(false),
+ mTracking(false),
mGnssCbIface_2_0(nullptr)
{
LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
@@ -76,6 +77,7 @@ GnssAPIClient::GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb) :
mControlClient(new LocationAPIControlClient()),
mLocationCapabilitiesMask(0),
mLocationCapabilitiesCached(false),
+ mTracking(false),
mGnssCbIface_2_0(nullptr)
{
LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
@@ -179,6 +181,11 @@ void GnssAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb
bool GnssAPIClient::gnssStart()
{
LOC_LOGD("%s]: ()", __FUNCTION__);
+
+ mMutex.lock();
+ mTracking = true;
+ mMutex.unlock();
+
bool retVal = true;
locAPIStartTracking(mTrackingOptions);
return retVal;
@@ -187,6 +194,11 @@ bool GnssAPIClient::gnssStart()
bool GnssAPIClient::gnssStop()
{
LOC_LOGD("%s]: ()", __FUNCTION__);
+
+ mMutex.lock();
+ mTracking = false;
+ mMutex.unlock();
+
bool retVal = true;
locAPIStopTracking();
return retVal;
@@ -412,12 +424,18 @@ void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
void GnssAPIClient::onTrackingCb(Location location)
{
- LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
mMutex.lock();
auto gnssCbIface(mGnssCbIface);
auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ bool isTracking = mTracking;
mMutex.unlock();
+ LOC_LOGD("%s]: (flags: %02x isTracking: %d)", __FUNCTION__, location.flags, isTracking);
+
+ if (!isTracking) {
+ return;
+ }
+
if (gnssCbIface_2_0 != nullptr) {
V2_0::GnssLocation gnssLocation;
convertGnssLocation(location, gnssLocation);
@@ -517,7 +535,7 @@ void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotificatio
void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
{
- LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, gnssSvNotification.count);
+ LOC_LOGD("%s]: (count: %u)", __FUNCTION__, gnssSvNotification.count);
mMutex.lock();
auto gnssCbIface(mGnssCbIface);
auto gnssCbIface_2_0(mGnssCbIface_2_0);
@@ -561,7 +579,7 @@ void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
auto r = gnssCbIface_2_0->gnssNmeaCb(
static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
if (!r.isOk()) {
- LOC_LOGE("%s] Error from gnssCbIface_2_0 nmea=%s length=%zu description=%s",
+ LOC_LOGE("%s] Error from gnssCbIface_2_0 nmea=%s length=%u description=%s",
__func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
r.description().c_str());
}
@@ -569,7 +587,7 @@ void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
auto r = gnssCbIface->gnssNmeaCb(
static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
if (!r.isOk()) {
- LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%zu description=%s",
+ LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%u description=%s",
__func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
r.description().c_str());
}
diff --git a/android/2.0/location_api/GnssAPIClient.h b/android/2.0/location_api/GnssAPIClient.h
index 493f9ca..63b4561 100644
--- a/android/2.0/location_api/GnssAPIClient.h
+++ b/android/2.0/location_api/GnssAPIClient.h
@@ -102,6 +102,7 @@ private:
LocationCapabilitiesMask mLocationCapabilitiesMask;
bool mLocationCapabilitiesCached;
TrackingOptions mTrackingOptions;
+ bool mTracking;
sp<V2_0::IGnssCallback> mGnssCbIface_2_0;
};
diff --git a/android/2.0/location_api/MeasurementAPIClient.cpp b/android/2.0/location_api/MeasurementAPIClient.cpp
index 23c3b16..dc972ec 100644
--- a/android/2.0/location_api/MeasurementAPIClient.cpp
+++ b/android/2.0/location_api/MeasurementAPIClient.cpp
@@ -170,7 +170,7 @@ void MeasurementAPIClient::measurementClose() {
void MeasurementAPIClient::onGnssMeasurementsCb(
GnssMeasurementsNotification gnssMeasurementsNotification)
{
- LOC_LOGD("%s]: (count: %zu active: %d)",
+ LOC_LOGD("%s]: (count: %u active: %d)",
__FUNCTION__, gnssMeasurementsNotification.count, mTracking);
if (mTracking) {
mMutex.lock();
@@ -217,7 +217,7 @@ void MeasurementAPIClient::onGnssMeasurementsCb(
static void convertGnssMeasurement(GnssMeasurementsData& in,
V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
{
- memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssMeasurement));
+ memset(&out, 0, sizeof(out));
if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
diff --git a/android/Android.mk b/android/Android.mk
index f117def..8233b68 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -1,12 +1,15 @@
LOCAL_PATH := $(call my-dir)
ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+include $(CLEAR_VARS)
+DIR_LIST := $(LOCAL_PATH)
+include $(DIR_LIST)/utils/Android.mk
ifeq ($(GNSS_HIDL_VERSION),2.0)
-include $(LOCAL_PATH)/2.0/Android.mk
+include $(DIR_LIST)/2.0/Android.mk
else
ifeq ($(GNSS_HIDL_VERSION),1.1)
-include $(LOCAL_PATH)/1.1/Android.mk
+include $(DIR_LIST)/1.1/Android.mk
else
-include $(LOCAL_PATH)/1.0/Android.mk
+include $(DIR_LIST)/1.0/Android.mk
endif #GNSS HIDL 1.1
endif #GNSS HIDL 2.0
else #QMAA flag set, build dummy android.hardware.gnss@1.0-impl-qti
diff --git a/android/utils/Android.mk b/android/utils/Android.mk
new file mode 100644
index 0000000..47b4081
--- /dev/null
+++ b/android/utils/Android.mk
@@ -0,0 +1,37 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := liblocbatterylistener
+LOCAL_VENDOR_MODULE := true
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+
+LOCAL_SRC_FILES:= \
+ battery_listener.cpp
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ libcutils \
+ libutils \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
+
+LOCAL_STATIC_LIBRARIES := libhealthhalutils
+LOCAL_CFLAGS += -DBATTERY_LISTENER_ENABLED
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblocbatterylistener_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_HEADER_LIBRARY)
+
+
diff --git a/android/utils/battery_listener.cpp b/android/utils/battery_listener.cpp
new file mode 100644
index 0000000..a790702
--- /dev/null
+++ b/android/utils/battery_listener.cpp
@@ -0,0 +1,266 @@
+/*
+* 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.
+*/
+#include "battery_listener.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_BatteryListener"
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hardware/health/2.0/IHealth.h>
+#include <healthhalutils/HealthHalUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <thread>
+using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V2_0::get_health_service;
+using android::hardware::health::V2_0::HealthInfo;
+using android::hardware::health::V2_0::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_0::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 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_0::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 = hardware::health::V2_0::get_health_service();
+ if (mHealth != NULL)
+ break;
+ usleep(GET_HEALTH_SVC_WAIT_TIME_MS * 1000);
+ tries++;
+ } while(tries < GET_HEALTH_SVC_RETRY_CNT);
+
+ if (mHealth == NULL) {
+ ALOGE("no health service found, retries %d", tries);
+ return NO_INIT;
+ } else {
+ ALOGI("Get health service in %d tries", tries);
+ }
+ mStatus = BatteryStatus::UNKNOWN;
+ auto ret = mHealth->getChargeStatus([&](Result r, BatteryStatus status) {
+ if (r != Result::SUCCESS) {
+ ALOGE("batterylistener: cannot get battery status");
+ return;
+ }
+ mStatus = status;
+ });
+ if (!ret.isOk())
+ ALOGE("batterylistener: get charge status transaction error");
+
+ if (mStatus == BatteryStatus::UNKNOWN)
+ ALOGW("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);
+ ALOGI("healthInfo cb thread: cb %s", c ? "CHARGING" : "NOT CHARGING");
+ l.unlock();
+ mCb(c);
+ l.lock();
+ break;
+ }
+ }
+ });
+ auto reg = mHealth->registerCallback(this);
+ if (!reg.isOk()) {
+ ALOGE("Transaction error in registeringCb to HealthHAL death: %s",
+ reg.description().c_str());
+ }
+
+ auto linked = mHealth->linkToDeath(this, 0 /* cookie */);
+ if (!linked.isOk() || linked == false) {
+ ALOGE("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->unlinkToDeath(this);
+ auto r = mHealth->unlinkToDeath(this);
+ if (!r.isOk() || r == false) {
+ ALOGE("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())) {
+ ALOGE("health not initialized or unknown interface died");
+ return;
+ }
+ ALOGI("health service died, reinit");
+ mDone = true;
+ }
+ 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)
+{
+ ALOGV("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();
+}
+
+static sp<BatteryListenerImpl> batteryListener;
+status_t batteryPropertiesListenerInit(BatteryListenerImpl::cb_fn_t cb)
+{
+ ALOGV("batteryPropertiesListenerInit entry");
+ batteryListener = new BatteryListenerImpl(cb);
+ return NO_ERROR;
+}
+
+status_t batteryPropertiesListenerDeinit()
+{
+ batteryListener.clear();
+ return OK;
+}
+
+bool batteryPropertiesListenerIsCharging()
+{
+ return batteryListener->isCharging();
+}
+
+} // namespace android
+
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn)
+{
+ ALOGV("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/android/utils/battery_listener.h b/android/utils/battery_listener.h
new file mode 100644
index 0000000..bb6b715
--- /dev/null
+++ b/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();