Convert to health AIDL HAL

If the AIDL HAL is not available, fallback to the HIDL
HAL.

Test: builds
Fixes: 208912315

Change-Id: I28165924296f2ff3bd8a49537575599bd586e339
diff --git a/Android.bp b/Android.bp
index 3b4bbdd..27dd592 100644
--- a/Android.bp
+++ b/Android.bp
@@ -633,11 +633,13 @@
     ],
     shared_libs: [
         "android.hardware.atrace@1.0",
+        "android.hardware.health-V1-ndk",
         "android.hardware.health@2.0",
         "android.hardware.power.stats-V1-cpp",
         "android.hardware.power.stats@1.0",
         "libbase",
         "libbinder",
+        "libbinder_ndk",
         "libcutils",
         "libhidlbase",
         "libincident",
diff --git a/src/android_internal/BUILD.gn b/src/android_internal/BUILD.gn
index 02d07fb..ed01121 100644
--- a/src/android_internal/BUILD.gn
+++ b/src/android_internal/BUILD.gn
@@ -37,6 +37,7 @@
     ]
     libs = [
       "android.hardware.health@2.0",
+      "android.hardware.health-V1-ndk",
       "android.hardware.power.stats@1.0",
       "android.hardware.power.stats-V1-cpp",
       "android.hardware.atrace@1.0",
@@ -45,6 +46,7 @@
       "cutils",
       "base",
       "binder",
+      "binder_ndk",
       "log",
       "hidlbase",
       "incident",
diff --git a/src/android_internal/health_hal.cc b/src/android_internal/health_hal.cc
index 194cb73..d3e0de0 100644
--- a/src/android_internal/health_hal.cc
+++ b/src/android_internal/health_hal.cc
@@ -16,35 +16,42 @@
 
 #include "src/android_internal/health_hal.h"
 
+#include <android/binder_manager.h>
+#include <aidl/android/hardware/health/IHealth.h>
 #include <android/hardware/health/2.0/IHealth.h>
 #include <healthhalutils/HealthHalUtils.h>
 
 namespace perfetto {
 namespace android_internal {
 
+using HidlHealth = ::android::hardware::health::V2_0::IHealth;
+using ::aidl::android::hardware::health::IHealth;
 using ::android::hardware::Return;
-using ::android::hardware::health::V2_0::IHealth;
 using ::android::hardware::health::V2_0::Result;
 
 namespace {
 
-android::sp<IHealth> g_svc;
+struct HealthService {
+  android::sp<HidlHealth> hidl;
+  std::shared_ptr<IHealth> aidl;
+};
+
+HealthService g_svc;
 
 void ResetService() {
-  g_svc = ::android::hardware::health::V2_0::get_health_service();
+  auto aidl_name = std::string(IHealth::descriptor) + "/default";
+  if (AServiceManager_isDeclared(aidl_name.c_str())) {
+    ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_name.c_str()));
+    g_svc.aidl = IHealth::fromBinder(binder);
+    if (g_svc.aidl != nullptr) {
+      return;
+    }
+  }
+  g_svc.hidl = ::android::hardware::health::V2_0::get_health_service();
 }
 
-}  // namespace
-
-bool GetBatteryCounter(BatteryCounter counter, int64_t* value) {
-  *value = 0;
-  if (!g_svc)
-    ResetService();
-
-  if (!g_svc)
-    return false;
-
-  // The Android VNDK documentation states that for blocking services, the
+bool GetBatteryCounterHidl(BatteryCounter counter, int64_t* value) {
+  // The Android HIDL documentation states that for blocking services, the
   // caller blocks until the reply is received and the callback is called inline
   // in the same thread.
   // See https://source.android.com/devices/architecture/hidl/threading .
@@ -56,7 +63,7 @@
       break;
 
     case BatteryCounter::kCharge:
-      ret = g_svc->getChargeCounter(
+      ret = g_svc.hidl->getChargeCounter(
           [&res, value](Result hal_res, int32_t hal_value) {
             res = hal_res;
             *value = hal_value;
@@ -64,22 +71,23 @@
       break;
 
     case BatteryCounter::kCapacityPercent:
-      ret = g_svc->getCapacity([&res, value](Result hal_res, int32_t hal_value) {
-        res = hal_res;
-        *value = hal_value;
-      });
+      ret = g_svc.hidl->getCapacity(
+          [&res, value](Result hal_res, int32_t hal_value) {
+            res = hal_res;
+            *value = hal_value;
+          });
       break;
 
     case BatteryCounter::kCurrent:
-      ret =
-          g_svc->getCurrentNow([&res, value](Result hal_res, int32_t hal_value) {
+      ret = g_svc.hidl->getCurrentNow(
+          [&res, value](Result hal_res, int32_t hal_value) {
             res = hal_res;
             *value = hal_value;
           });
       break;
 
     case BatteryCounter::kCurrentAvg:
-      ret = g_svc->getCurrentAverage(
+      ret = g_svc.hidl->getCurrentAverage(
           [&res, value](Result hal_res, int32_t hal_value) {
             res = hal_res;
             *value = hal_value;
@@ -88,10 +96,62 @@
   }  // switch(counter)
 
   if (ret.isDeadObject())
-    g_svc.clear();
+    g_svc.hidl.clear();
 
   return ret.isOk() && res == Result::SUCCESS;
 }
 
+bool GetBatteryCounterAidl(BatteryCounter counter, int64_t* value) {
+  ndk::ScopedAStatus status;
+  int32_t value32;
+
+  switch (counter) {
+    case BatteryCounter::kUnspecified:
+      return false;
+
+    case BatteryCounter::kCharge:
+      status = g_svc.aidl->getChargeCounterUah(&value32);
+      break;
+
+    case BatteryCounter::kCapacityPercent:
+      status = g_svc.aidl->getCapacity(&value32);
+      break;
+
+    case BatteryCounter::kCurrent:
+      status = g_svc.aidl->getCurrentNowMicroamps(&value32);
+      break;
+
+    case BatteryCounter::kCurrentAvg:
+      status = g_svc.aidl->getCurrentAverageMicroamps(&value32);
+      break;
+  }  // switch(counter)
+
+  if (status.isOk()) {
+    *value = value32;
+    return true;
+  }
+
+  if (status.getStatus() == STATUS_DEAD_OBJECT)
+    g_svc.aidl.reset();
+
+  return false;
+}
+
+}  // namespace
+
+bool GetBatteryCounter(BatteryCounter counter, int64_t* value) {
+  *value = 0;
+  if (!g_svc.aidl && !g_svc.hidl)
+    ResetService();
+
+  if (!g_svc.aidl && !g_svc.hidl)
+    return false;
+
+  if (g_svc.aidl)
+    return GetBatteryCounterAidl(counter, value);
+
+  return GetBatteryCounterHidl(counter, value);
+}
+
 }  // namespace android_internal
 }  // namespace perfetto
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 53dfbc0..30cd329 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -106,6 +106,7 @@
     'android',
     'android.hardware.atrace@1.0',
     'android.hardware.health@2.0',
+    'android.hardware.health-V1-ndk',
     'android.hardware.power.stats@1.0',
     "android.hardware.power.stats-V1-cpp",
     'base',
@@ -211,8 +212,9 @@
     'traced_probes': [('required', {
         'libperfetto_android_internal', 'trigger_perfetto', 'traced_perf',
         'mm_events'
-    }),],
-    'libperfetto_android_internal': [('static_libs', {'libhealthhalutils'}),],
+    }), ],
+    'libperfetto_android_internal': [
+        ('static_libs', {'libhealthhalutils'}), ],
     'trace_processor_shell': [
         ('strip', {
             'all': True
@@ -873,9 +875,10 @@
     module.defaults = [defaults_module]
     for lib in target.libs:
       # Generally library names should be mangled as 'libXXX', unless they
-      # are HAL libraries (e.g., android.hardware.health@2.0) or AIDL c++
+      # are HAL libraries (e.g., android.hardware.health@2.0) or AIDL c++ / NDK
       # libraries (e.g. "android.hardware.power.stats-V1-cpp")
-      android_lib = lib if '@' in lib or "-cpp" in lib else 'lib' + lib
+      android_lib = lib if '@' in lib or "-cpp" in lib or "-ndk" in lib \
+        else 'lib' + lib
       if lib in shared_library_allowlist:
         module.add_android_shared_lib(android_lib)
       if lib in static_library_allowlist: