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";