MediaMetrics: Convert to AIDL

Test: adb shell dumpsys media.metrics
Test: atest mediametrics_tests
Bug: 173831888
Change-Id: I3ae121c7cd03719e9a9732bca5f545189b9e47a4
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index 7cdbe5f..f4371fd 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -31,8 +31,9 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include <android/media/BnMediaMetricsService.h> // for direct Binder access
+#include <android/media/IMediaMetricsService.h>
 #include <binder/IServiceManager.h>
-#include <media/IMediaMetricsService.h>
 #include <media/MediaMetricsItem.h>
 #include <private/android_filesystem_config.h>
 
@@ -278,17 +279,18 @@
 // calls the appropriate daemon
 bool mediametrics::Item::selfrecord() {
     ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
-    sp<IMediaMetricsService> svc = getService();
-    if (svc != NULL) {
-        status_t status = svc->submit(this);
-        if (status != NO_ERROR) {
-            ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
-            return false;
-        }
-        return true;
-    } else {
+
+    char *str;
+    size_t size;
+    status_t status = writeToByteString(&str, &size);
+    if (status == NO_ERROR) {
+        status = submitBuffer(str, size);
+    }
+    if (status != NO_ERROR) {
+        ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
         return false;
     }
+    return true;
 }
 
 //static
@@ -327,7 +329,7 @@
 
 static sp<MediaMetricsDeathNotifier> sNotifier;
 // static
-sp<IMediaMetricsService> BaseItem::sMediaMetricsService;
+sp<media::IMediaMetricsService> BaseItem::sMediaMetricsService;
 static std::mutex sServiceMutex;
 static int sRemainingBindAttempts = SVC_TRIES;
 
@@ -339,29 +341,67 @@
 }
 
 // static
-bool BaseItem::submitBuffer(const char *buffer, size_t size) {
-/*
-    mediametrics::Item item;
-    status_t status = item.readFromByteString(buffer, size);
-    ALOGD("%s: status:%d, size:%zu, item:%s", __func__, status, size, item.toString().c_str());
-    return item.selfrecord();
-    */
-
+status_t BaseItem::submitBuffer(const char *buffer, size_t size) {
     ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
-    sp<IMediaMetricsService> svc = getService();
-    if (svc != nullptr) {
-        const status_t status = svc->submitBuffer(buffer, size);
-        if (status != NO_ERROR) {
-            ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
-            return false;
-        }
-        return true;
+
+    // Validate size
+    if (size > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
+
+    // Do we have the service available?
+    sp<media::IMediaMetricsService> svc = getService();
+    if (svc == nullptr)  return NO_INIT;
+
+    ::android::status_t status = NO_ERROR;
+    if constexpr (/* DISABLES CODE */ (false)) {
+        // THIS PATH IS FOR REFERENCE ONLY.
+        // It is compiled so that any changes to IMediaMetricsService::submitBuffer()
+        // will lead here.  If this code is changed, the else branch must
+        // be changed as well.
+        //
+        // Use the AIDL calling interface - this is a bit slower as a byte vector must be
+        // constructed. As the call is one-way, the only a transaction error occurs.
+        status = svc->submitBuffer({buffer, buffer + size}).transactionError();
+    } else {
+        // Use the Binder calling interface - this direct implementation avoids
+        // malloc/copy/free for the vector and reduces the overhead for logging.
+        // We based this off of the AIDL generated file:
+        // out/soong/.intermediates/frameworks/av/media/libmediametrics/mediametricsservice-aidl-unstable-cpp-source/gen/android/media/IMediaMetricsService.cpp
+        // TODO: Create an AIDL C++ back end optimized form of vector writing.
+        ::android::Parcel _aidl_data;
+        ::android::Parcel _aidl_reply; // we don't care about this as it is one-way.
+
+        status = _aidl_data.writeInterfaceToken(svc->getInterfaceDescriptor());
+        if (status != ::android::OK) goto _aidl_error;
+
+        status = _aidl_data.writeInt32(static_cast<int32_t>(size));
+        if (status != ::android::OK) goto _aidl_error;
+
+        status = _aidl_data.write(buffer, static_cast<int32_t>(size));
+        if (status != ::android::OK) goto _aidl_error;
+
+        status = ::android::IInterface::asBinder(svc)->transact(
+                ::android::media::BnMediaMetricsService::TRANSACTION_submitBuffer,
+                _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
+
+        // AIDL permits setting a default implementation for additional functionality.
+        // See go/aog/713984. This is not used here.
+        // if (status == ::android::UNKNOWN_TRANSACTION
+        //         && ::android::media::IMediaMetricsService::getDefaultImpl()) {
+        //     status = ::android::media::IMediaMetricsService::getDefaultImpl()
+        //             ->submitBuffer(immutableByteVectorFromBuffer(buffer, size))
+        //             .transactionError();
+        // }
     }
-    return false;
+
+    if (status == NO_ERROR) return NO_ERROR;
+
+    _aidl_error:
+    ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
+    return status;
 }
 
 //static
-sp<IMediaMetricsService> BaseItem::getService() {
+sp<media::IMediaMetricsService> BaseItem::getService() {
     static const char *servicename = "media.metrics";
     static const bool enabled = isEnabled(); // singleton initialized
 
@@ -379,7 +419,7 @@
         if (sm != nullptr) {
             sp<IBinder> binder = sm->getService(String16(servicename));
             if (binder != nullptr) {
-                sMediaMetricsService = interface_cast<IMediaMetricsService>(binder);
+                sMediaMetricsService = interface_cast<media::IMediaMetricsService>(binder);
                 sNotifier = new MediaMetricsDeathNotifier();
                 binder->linkToDeath(sNotifier);
             } else {