Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49ca44e9 authored by Andy Hung's avatar Andy Hung
Browse files

MediaMetrics: Convert to AIDL

Test: adb shell dumpsys media.metrics
Test: atest mediametrics_tests
Bug: 173831888
Change-Id: I3ae121c7cd03719e9a9732bca5f545189b9e47a4
parent 7d48a358
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@ cc_library {
    name: "libmediametrics",

    srcs: [
        "IMediaMetricsService.cpp",
        "MediaMetricsItem.cpp",
        "MediaMetrics.cpp",
    ],
@@ -17,6 +16,7 @@ cc_library {
        "libcutils",
        "liblog",
        "libutils",
        "mediametricsservice-aidl-unstable-cpp",
    ],

    export_include_dirs: ["include"],
@@ -58,3 +58,21 @@ cc_library {
        "//frameworks/base/media/jni",
    ],
}

aidl_interface {
    name: "mediametricsservice-aidl",
    unstable: true,
    local_include_dir: "aidl",
    vendor_available: true,
    srcs: [
        "aidl/android/media/IMediaMetricsService.aidl",
    ],
    double_loadable: true,
    backend: {
        cpp: {
            apex_available: [
                "//apex_available:platform",
            ],
        },
    },
}
+70 −30
Original line number Diff line number Diff line
@@ -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 @@ std::string mediametrics::Item::toString() const {
// 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);

    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;
    } else {
        return false;
    }
}

//static
@@ -327,7 +329,7 @@ class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {

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 @@ void BaseItem::dropInstance() {
}

// 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 @@ sp<IMediaMetricsService> BaseItem::getService() {
        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 {
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

/**
 * MediaMetrics service interface
 *
 * {@hide}
 */
interface IMediaMetricsService {
    oneway void submitBuffer(in byte[] buffer);
}
+0 −73
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_IMEDIAANALYTICSSERVICE_H
#define ANDROID_IMEDIAANALYTICSSERVICE_H

#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>

#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <utils/List.h>

#include <binder/IServiceManager.h>

#include <media/MediaMetricsItem.h>

namespace android {

class IMediaMetricsService: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaMetricsService);

    /**
     * Submits the indicated record to the mediaanalytics service, where
     * it will be merged (if appropriate) with incomplete records that
     * share the same key and sessionID.
     *
     * \param item the item to submit.
     * \return status which is negative if an error is detected (some errors
               may be silent and return 0 - success).
     */
    virtual status_t submit(mediametrics::Item *item) = 0;

    virtual status_t submitBuffer(const char *buffer, size_t length) = 0;
};

// ----------------------------------------------------------------------------

class BnMediaMetricsService: public BnInterface<IMediaMetricsService>
{
public:
    status_t onTransact(uint32_t code,
                        const Parcel& data,
                        Parcel* reply,
                        uint32_t flags = 0) override;

protected:
    // Internal call where release is true if the service is to delete the item.
    virtual status_t submitInternal(
            mediametrics::Item *item, bool release) = 0;
};

}; // namespace android

#endif // ANDROID_IMEDIASTATISTICSSERVICE_H
+8 −5
Original line number Diff line number Diff line
@@ -32,7 +32,8 @@

namespace android {

class IMediaMetricsService;
namespace media { class IMediaMetricsService; }

class Parcel;

/*
@@ -239,7 +240,10 @@ class BaseItem {
public:
    // are we collecting metrics data
    static bool isEnabled();
    static sp<IMediaMetricsService> getService();
    // returns the MediaMetrics service if active.
    static sp<media::IMediaMetricsService> getService();
    // submits a raw buffer directly to the MediaMetrics service - this is highly optimized.
    static status_t submitBuffer(const char *buffer, size_t len);

protected:
    static constexpr const char * const EnabledProperty = "media.metrics.enabled";
@@ -247,10 +251,9 @@ protected:
    static const int EnabledProperty_default = 1;

    // let's reuse a binder connection
    static sp<IMediaMetricsService> sMediaMetricsService;
    static sp<media::IMediaMetricsService> sMediaMetricsService;

    static void dropInstance();
    static bool submitBuffer(const char *buffer, size_t len);

    template <typename T>
    struct is_item_type {
@@ -573,7 +576,7 @@ public:

    bool record() {
        return updateHeader()
                && BaseItem::submitBuffer(getBuffer(), getLength());
                && BaseItem::submitBuffer(getBuffer(), getLength()) == OK;
    }

    bool isValid () const {
Loading