Implement RadioMessaging for AIDL-HIDL Telephony HAL translator

Bug: 203699028
Test: Boot and grep logcat against radiocompat
Change-Id: I10f0fc0b871fbaf26145c83211770a82af6adc61
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index f708b84..82ab81f 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -39,6 +39,14 @@
         "android.hardware.radio.config@1.1",
         "android.hardware.radio.config@1.2",
         "android.hardware.radio.config@1.3",
+        "android.hardware.radio.messaging-V1-ndk",
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.5",
+        "android.hardware.radio@1.6",
         "libbase",
         "libbinder_ndk",
         "libhidlbase",
diff --git a/radio/aidl/compat/service/hidl-utils.cpp b/radio/aidl/compat/service/hidl-utils.cpp
index d894966..fc0d54d 100644
--- a/radio/aidl/compat/service/hidl-utils.cpp
+++ b/radio/aidl/compat/service/hidl-utils.cpp
@@ -17,6 +17,7 @@
 #include "hidl-utils.h"
 
 #include <android-base/logging.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 
 namespace android::hardware::hidl_utils {
 
@@ -33,4 +34,13 @@
     CHECK(linkStatus.withDefault(false)) << "Failed to link to HAL death";
 }
 
+hidl_vec<hidl_string> listManifestByInterface(const char* descriptor) {
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    hidl_vec<hidl_string> services;
+    manager->listManifestByInterface(descriptor, hidl_utils::fill(&services));
+    CHECK_GT(services.size(), 0u) << "No " << descriptor
+                                  << " services in manifest (missing privileges?)" << std::endl;
+    return services;
+}
+
 }  // namespace android::hardware::hidl_utils
diff --git a/radio/aidl/compat/service/hidl-utils.h b/radio/aidl/compat/service/hidl-utils.h
index 3f81a9b..be3386f 100644
--- a/radio/aidl/compat/service/hidl-utils.h
+++ b/radio/aidl/compat/service/hidl-utils.h
@@ -18,13 +18,61 @@
 
 #include <android/hidl/base/1.0/IBase.h>
 
+#include <functional>
+
 namespace android::hardware::hidl_utils {
 
 /**
- * Link to a given HALs death and restart the current process in such a case.
+ * Helper functor to fetch results from multi-return HIDL calls.
+ * It's meant to be used in place of _hidl_cb callbacks.
  *
+ * Please note extracting these return variables outside of the callback scope requires making
+ * a copy of each return variable. This may be costly for frequently called HIDL methods with
+ * non-negligible return object size. Please be cautious about performance when using this.
+ *
+ * Example usage:
+ *     Result result;
+ *     sp<ISomeInterface> iface;
+ *     hidlObject->someMethod(arg1, arg2, hidl_utils::fill(&result, &iface)).assertOk();
+ *     // use result and iface
+ */
+template <typename... T>
+struct fill : public std::function<void(const T&...)> {
+    /**
+     * Create _hidl_cb functor that copies the call arguments to specified pointers.
+     *
+     * \param args... Targets to copy the call arguments to
+     */
+    fill(T*... args) : mTargets(args...) {}
+
+    void operator()(const T&... args) { copy<0, T...>(args...); }
+
+  private:
+    std::tuple<T*...> mTargets;
+
+    template <int Pos, typename First>
+    inline void copy(const First& first) {
+        *std::get<Pos>(mTargets) = first;
+    }
+
+    template <int Pos, typename First, typename... Rest>
+    inline void copy(const First& first, const Rest&... rest) {
+        *std::get<Pos>(mTargets) = first;
+        copy<Pos + 1, Rest...>(rest...);
+    }
+};
+
+/**
+ * Link to a given HALs death and restart the current process in such a case.
  * \param hal HAL to which death to link
  */
 void linkDeathToDeath(sp<hidl::base::V1_0::IBase> hal);
 
+/**
+ * List HAL instances of a given interface.
+ *
+ * \descriptor HIDL HAL descriptor
+ */
+hidl_vec<hidl_string> listManifestByInterface(const char* descriptor);
+
 }  // namespace android::hardware::hidl_utils
diff --git a/radio/aidl/compat/service/radio-compat.xml b/radio/aidl/compat/service/radio-compat.xml
index 60f8ff5..781f2f4 100644
--- a/radio/aidl/compat/service/radio-compat.xml
+++ b/radio/aidl/compat/service/radio-compat.xml
@@ -3,4 +3,15 @@
         <name>android.hardware.radio.config</name>
         <fqname>IRadioConfig/default</fqname>
     </hal>
+<!--
+    Instances other than config are configured per-device, depending on the slot count (framework
+    currently supports slot1, slot2 and slot3 instances) and Radio HALs device wishes to provide.
+    You can either copy the following tags to device manifest or simply uncomment them here for
+    quick testing.
+
+    <hal format="aidl">
+        <name>android.hardware.radio.messaging</name>
+        <fqname>IRadioMessaging/slot1</fqname>
+    </hal>
+-->
 </manifest>
diff --git a/radio/aidl/compat/service/service.cpp b/radio/aidl/compat/service/service.cpp
index c177dd1..4d34cf1 100644
--- a/radio/aidl/compat/service/service.cpp
+++ b/radio/aidl/compat/service/service.cpp
@@ -20,6 +20,9 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <libradiocompat/RadioConfig.h>
+#include <libradiocompat/RadioIndication.h>
+#include <libradiocompat/RadioMessaging.h>
+#include <libradiocompat/RadioResponse.h>
 
 namespace android::hardware::radio::service {
 
@@ -27,6 +30,35 @@
 
 static std::vector<std::shared_ptr<ndk::ICInterface>> gPublishedHals;
 
+template <typename T>
+static void publishRadioHal(sp<V1_5::IRadio> hidlHal, sp<compat::RadioResponse> responseCb,
+                            sp<compat::RadioIndication> indicationCb, const std::string& slot) {
+    const auto instance = T::descriptor + "/"s + slot;
+    if (!AServiceManager_isDeclared(instance.c_str())) {
+        LOG(INFO) << instance << " is not declared in VINTF (this may be intentional)";
+        return;
+    }
+    LOG(DEBUG) << "Publishing " << instance;
+
+    auto aidlHal = ndk::SharedRefBase::make<T>(hidlHal, responseCb, indicationCb);
+    gPublishedHals.push_back(aidlHal);
+    const auto status = AServiceManager_addService(aidlHal->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+}
+
+static void publishRadio(std::string slot) {
+    auto radioHidl = V1_5::IRadio::getService(slot);
+    CHECK(radioHidl) << "HIDL IRadio not present in VINTF";
+
+    hidl_utils::linkDeathToDeath(radioHidl);
+
+    auto responseCb = sp<compat::RadioResponse>::make();
+    auto indicationCb = sp<compat::RadioIndication>::make();
+    radioHidl->setResponseFunctions(responseCb, indicationCb).assertOk();
+
+    publishRadioHal<compat::RadioMessaging>(radioHidl, responseCb, indicationCb, slot);
+}
+
 static void publishRadioConfig() {
     auto hidlHal = config::V1_1::IRadioConfig::getService();
     CHECK(hidlHal) << "HIDL IRadioConfig not present in VINTF";
@@ -47,6 +79,12 @@
 
     publishRadioConfig();
 
+    const auto slots = hidl_utils::listManifestByInterface(V1_0::IRadio::descriptor);
+    LOG(INFO) << "Found " << slots.size() << " slot(s)";
+    for (const auto& slot : slots) {
+        publishRadio(slot);
+    }
+
     LOG(DEBUG) << "Radio HAL compat service is operational";
     ABinderProcess_joinThreadPool();
     LOG(FATAL) << "Radio HAL compat service has stopped";