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

Commit 3f4a68a0 authored by Hangyu Kuang's avatar Hangyu Kuang Committed by Android (Google) Code Review
Browse files

Merge "MediaTranscodingService: Implement service's add/remove client APIs."

parents d2243cf3 9c04b8d1
Loading
Loading
Loading
Loading
+18 −19
Original line number Diff line number Diff line
@@ -17,12 +17,12 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "TranscodingClientManager"

#include <inttypes.h>
#include <media/TranscodingClientManager.h>
#include <utils/Log.h>

namespace android {

class DeathNotifier;
using Status = ::ndk::ScopedAStatus;

// static
@@ -31,9 +31,17 @@ sp<TranscodingClientManager> TranscodingClientManager::getInstance() {
    return sInstance;
}

// static
void TranscodingClientManager::BinderDiedCallback(void* cookie) {
    int32_t clientId = static_cast<int32_t>(reinterpret_cast<intptr_t>(cookie));
    ALOGD("Client %" PRId32 " is dead", clientId);
    // Don't check for pid validity since we know it's already dead.
    sp<TranscodingClientManager> manager = TranscodingClientManager::getInstance();
    manager->removeClient(clientId);
}

TranscodingClientManager::TranscodingClientManager()
    : mDeathRecipient(AIBinder_DeathRecipient_new(
              TranscodingClientManager::DeathNotifier::BinderDiedCallback)) {
    : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
    ALOGD("TranscodingClientManager started");
}

@@ -77,14 +85,13 @@ void TranscodingClientManager::dumpAllClients(int fd, const Vector<String16>& ar

status_t TranscodingClientManager::addClient(std::unique_ptr<ClientInfo> client) {
    // Validate the client.
    if (client == nullptr || client->mClientId <= 0 || client->mClientPid <= 0 ||
        client->mClientUid <= 0 || client->mClientOpPackageName.empty() ||
    if (client == nullptr || client->mClientId < 0 || client->mClientPid < 0 ||
        client->mClientUid < 0 || client->mClientOpPackageName.empty() ||
        client->mClientOpPackageName == "") {
        ALOGE("Invalid client");
        return BAD_VALUE;
    }

    ALOGD("Adding client id %d %s", client->mClientId, client->mClientOpPackageName.c_str());
    std::scoped_lock lock{mLock};

    // Check if the client already exists.
@@ -93,10 +100,11 @@ status_t TranscodingClientManager::addClient(std::unique_ptr<ClientInfo> client)
        return ALREADY_EXISTS;
    }

    // Listen to the death of the client.
    client->mDeathNotifier = new DeathNotifier();
    ALOGD("Adding client id %d pid: %d uid: %d %s", client->mClientId, client->mClientPid,
          client->mClientUid, client->mClientOpPackageName.c_str());

    AIBinder_linkToDeath(client->mClient->asBinder().get(), mDeathRecipient.get(),
                         client->mDeathNotifier.get());
                         reinterpret_cast<void*>(client->mClientId));

    // Adds the new client to the map.
    mClientIdToClientInfoMap[client->mClientId] = std::move(client);
@@ -120,7 +128,7 @@ status_t TranscodingClientManager::removeClient(int32_t clientId) {
    // Check if the client still live. If alive, unlink the death.
    if (client) {
        AIBinder_unlinkToDeath(client->asBinder().get(), mDeathRecipient.get(),
                               it->second->mDeathNotifier.get());
                               reinterpret_cast<void*>(clientId));
    }

    // Erase the entry.
@@ -134,13 +142,4 @@ size_t TranscodingClientManager::getNumOfClients() const {
    return mClientIdToClientInfoMap.size();
}

// static
void TranscodingClientManager::DeathNotifier::BinderDiedCallback(void* cookie) {
    int32_t* pClientId = static_cast<int32_t*>(cookie);
    ALOGD("Client %d is dead", *pClientId);
    // Don't check for pid validity since we know it's already dead.
    sp<TranscodingClientManager> manager = TranscodingClientManager::getInstance();
    manager->removeClient(*pClientId);
}

}  // namespace android
+5 −0
Original line number Diff line number Diff line
@@ -74,6 +74,11 @@ interface IMediaTranscodingService {
    */
    boolean unregisterClient(in int clientId);

    /**
    * Returns the number of clients. This is used for debugging.
    */
    int getNumOfClients();

    /**
     * Submits a transcoding request to MediaTranscodingService.
     *
+3 −19
Original line number Diff line number Diff line
@@ -46,10 +46,6 @@ class MediaTranscodingService;
 * TODO(hkuang): Hook up with MediaMetrics to log all the transactions.
 */
class TranscodingClientManager : public RefBase {
   private:
    // Forward declare it as it will be used in ClientInfo below.
    class DeathNotifier;

   public:
    virtual ~TranscodingClientManager();

@@ -67,8 +63,6 @@ class TranscodingClientManager : public RefBase {
        int32_t mClientUid;
        /* Package name of the client. */
        std::string mClientOpPackageName;
        /* Listener for the death of the client. */
        sp<DeathNotifier> mDeathNotifier;

        ClientInfo(const std::shared_ptr<ITranscodingServiceClient>& client, int64_t clientId,
                   int32_t pid, int32_t uid, const std::string& opPackageName)
@@ -76,8 +70,7 @@ class TranscodingClientManager : public RefBase {
              mClientId(clientId),
              mClientPid(pid),
              mClientUid(uid),
              mClientOpPackageName(opPackageName),
              mDeathNotifier(nullptr) {}
              mClientOpPackageName(opPackageName) {}
    };

    /**
@@ -121,26 +114,17 @@ class TranscodingClientManager : public RefBase {
    friend class MediaTranscodingService;
    friend class TranscodingClientManagerTest;

    class DeathNotifier : public RefBase {
       public:
        DeathNotifier() = default;

        ~DeathNotifier() = default;

        // Implement death recipient
        static void BinderDiedCallback(void* cookie);
    };

    /** Get the singleton instance of the TranscodingClientManager. */
    static sp<TranscodingClientManager> getInstance();

    TranscodingClientManager();

    static void BinderDiedCallback(void* cookie);

    mutable std::mutex mLock;
    std::unordered_map<int32_t, std::unique_ptr<ClientInfo>> mClientIdToClientInfoMap
            GUARDED_BY(mLock);

    std::vector<sp<DeathNotifier>> mDeathNotifiers GUARDED_BY(mLock);
    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
};

+5 −0
Original line number Diff line number Diff line
@@ -5,8 +5,11 @@ cc_library_shared {
    srcs: ["MediaTranscodingService.cpp"],

    shared_libs: [
        "libbase",
        "libbinder_ndk",
        "liblog",
        "libmediatranscoding",
        "libutils",
    ],

    static_libs: [
@@ -27,11 +30,13 @@ cc_binary {
    ],

    shared_libs: [
        "libbase",
        // TODO(hkuang): Use libbinder_ndk
        "libbinder",
        "libutils",
        "liblog",
        "libbase",
        "libmediatranscoding",
        "libmediatranscodingservice",
    ],

+122 −11
Original line number Diff line number Diff line
@@ -16,26 +16,55 @@

//#define LOG_NDEBUG 0
#define LOG_TAG "MediaTranscodingService"
#include "MediaTranscodingService.h"

#include <MediaTranscodingService.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <utils/Vector.h>

namespace android {

// Convenience methods for constructing binder::Status objects for error returns
#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
    Status::fromServiceSpecificErrorWithMessage(      \
            errorCode,                                \
            String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))

// Can MediaTranscoding service trust the caller based on the calling UID?
// TODO(hkuang): Add MediaProvider's UID.
static bool isTrustedCallingUid(uid_t uid) {
    switch (uid) {
    case AID_ROOT:  // root user
    case AID_SYSTEM:
    case AID_SHELL:
    case AID_MEDIA:  // mediaserver
        return true;
    default:
        return false;
    }
}

MediaTranscodingService::MediaTranscodingService() {
    ALOGV("MediaTranscodingService is created");
    mTranscodingClientManager = TranscodingClientManager::getInstance();
}

MediaTranscodingService::~MediaTranscodingService() {
    ALOGE("Should not be in ~MediaTranscodingService");
}

binder_status_t MediaTranscodingService::dump(int /* fd */, const char** /*args*/,
                                              uint32_t /*numArgs*/) {
    // TODO(hkuang): Add implementation.
binder_status_t MediaTranscodingService::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
    String8 result;
    const size_t SIZE = 256;
    char buffer[SIZE];

    snprintf(buffer, SIZE, "MediaTranscodingService: %p\n", this);
    result.append(buffer);
    write(fd, result.string(), result.size());

    Vector<String16> args;
    mTranscodingClientManager->dumpAllClients(fd, args);
    return OK;
}

@@ -51,15 +80,97 @@ void MediaTranscodingService::instantiate() {
}

Status MediaTranscodingService::registerClient(
        const std::shared_ptr<ITranscodingServiceClient>& /*in_client*/,
        const std::string& /* in_opPackageName */, int32_t /* in_clientUid */,
        int32_t /* in_clientPid */, int32_t* /*_aidl_return*/) {
    // TODO(hkuang): Add implementation.
        const std::shared_ptr<ITranscodingServiceClient>& in_client,
        const std::string& in_opPackageName, int32_t in_clientUid, int32_t in_clientPid,
        int32_t* _aidl_return) {
    if (in_client == nullptr) {
        ALOGE("Client can not be null");
        *_aidl_return = kInvalidJobId;
        return Status::fromServiceSpecificError(ERROR_ILLEGAL_ARGUMENT);
    }

    int32_t callingPid = AIBinder_getCallingPid();
    int32_t callingUid = AIBinder_getCallingUid();

    // Check if we can trust clientUid. Only privilege caller could forward the uid on app client's behalf.
    if (in_clientUid == USE_CALLING_UID) {
        in_clientUid = callingUid;
    } else if (!isTrustedCallingUid(callingUid)) {
        ALOGE("MediaTranscodingService::registerClient failed (calling PID %d, calling UID %d) "
              "rejected "
              "(don't trust clientUid %d)",
              in_clientPid, in_clientUid, in_clientUid);
        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                                "Untrusted caller (calling PID %d, UID %d) trying to "
                                "register client",
                                in_clientPid, in_clientUid);
    }

    // Check if we can trust clientPid. Only privilege caller could forward the pid on app client's behalf.
    if (in_clientPid == USE_CALLING_PID) {
        in_clientPid = callingPid;
    } else if (!isTrustedCallingUid(callingUid)) {
        ALOGE("MediaTranscodingService::registerClient client failed (calling PID %d, calling UID "
              "%d) rejected "
              "(don't trust clientPid %d)",
              in_clientPid, in_clientUid, in_clientPid);
        return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                                "Untrusted caller (calling PID %d, UID %d) trying to "
                                "register client",
                                in_clientPid, in_clientUid);
    }

    // We know the clientId must be equal to its pid as we assigned client's pid as its clientId.
    int32_t clientId = in_clientPid;

    // Checks if the client already registers.
    if (mTranscodingClientManager->isClientIdRegistered(clientId)) {
        return Status::fromServiceSpecificError(ERROR_ALREADY_EXISTS);
    }

    // Creates the client and uses its process id as client id.
    std::unique_ptr<TranscodingClientManager::ClientInfo> newClient =
            std::make_unique<TranscodingClientManager::ClientInfo>(
                    in_client, clientId, in_clientPid, in_clientUid, in_opPackageName);
    status_t err = mTranscodingClientManager->addClient(std::move(newClient));
    if (err != OK) {
        *_aidl_return = kInvalidClientId;
        return STATUS_ERROR_FMT(err, "Failed to add client to TranscodingClientManager");
    }

    ALOGD("Assign client: %s pid: %d, uid: %d with id: %d", in_opPackageName.c_str(), in_clientPid,
          in_clientUid, clientId);

    *_aidl_return = clientId;
    return Status::ok();
}

Status MediaTranscodingService::unregisterClient(int32_t /*clientId*/, bool* /*_aidl_return*/) {
    // TODO(hkuang): Add implementation.
Status MediaTranscodingService::unregisterClient(int32_t clientId, bool* _aidl_return) {
    ALOGD("unregisterClient id: %d", clientId);
    int32_t callingUid = AIBinder_getCallingUid();
    int32_t callingPid = AIBinder_getCallingPid();

    // Only the client with clientId or the trusted caller could unregister the client.
    if (callingPid != clientId) {
        if (!isTrustedCallingUid(callingUid)) {
            ALOGE("Untrusted caller (calling PID %d, UID %d) trying to "
                  "unregister client with id: %d",
                  callingUid, callingPid, clientId);
            *_aidl_return = true;
            return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                                    "Untrusted caller (calling PID %d, UID %d) trying to "
                                    "unregister client with id: %d",
                                    callingUid, callingPid, clientId);
        }
    }

    *_aidl_return = (mTranscodingClientManager->removeClient(clientId) == OK);
    return Status::ok();
}

Status MediaTranscodingService::getNumOfClients(int32_t* _aidl_return) {
    ALOGD("MediaTranscodingService::getNumOfClients");
    *_aidl_return = mTranscodingClientManager->getNumOfClients();
    return Status::ok();
}

Loading