MediaTranscoding: Add TranscodingClientManager.

TranscodingClientManager manages all the clients for
MediaTranscodingService.

Bug: 145233472
Test: Unit test.
Change-Id: I29243eeb6dcc0271c9edc8cc28e1b9b2bf6b3912
diff --git a/media/libmediatranscoding/.clang-format b/media/libmediatranscoding/.clang-format
new file mode 100644
index 0000000..3198d00
--- /dev/null
+++ b/media/libmediatranscoding/.clang-format
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2020 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.
+#
+
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
\ No newline at end of file
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index 9d0c534..7468426 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
 // AIDL interfaces of MediaTranscoding.
 aidl_interface {
     name: "mediatranscoding_aidl_interface",
@@ -14,3 +30,38 @@
         "aidl/android/media/TranscodingResultParcel.aidl",
     ],
 }
+
+cc_library_shared {
+    name: "libmediatranscoding",
+
+    srcs: [
+        "TranscodingClientManager.cpp"
+    ],
+
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    export_include_dirs: ["include"],
+
+    static_libs: [
+        "mediatranscoding_aidl_interface-ndk_platform",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
new file mode 100644
index 0000000..5013a51
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingClientManager"
+
+#include <media/TranscodingClientManager.h>
+#include <utils/Log.h>
+
+namespace android {
+
+class DeathNotifier;
+using Status = ::ndk::ScopedAStatus;
+
+// static
+sp<TranscodingClientManager> TranscodingClientManager::getInstance() {
+    static sp<TranscodingClientManager> sInstance = new TranscodingClientManager();
+    return sInstance;
+}
+
+TranscodingClientManager::TranscodingClientManager()
+    : mDeathRecipient(AIBinder_DeathRecipient_new(
+              TranscodingClientManager::DeathNotifier::BinderDiedCallback)) {
+    ALOGD("TranscodingClientManager started");
+}
+
+TranscodingClientManager::~TranscodingClientManager() {
+    ALOGD("TranscodingClientManager exited");
+}
+
+bool TranscodingClientManager::isClientIdRegistered(int32_t clientId) const {
+    std::scoped_lock lock{mLock};
+    return mClientIdToClientInfoMap.find(clientId) != mClientIdToClientInfoMap.end();
+}
+
+void TranscodingClientManager::dumpAllClients(int fd, const Vector<String16>& args __unused) {
+    String8 result;
+
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "    Total num of Clients: %zu\n", mClientIdToClientInfoMap.size());
+    result.append(buffer);
+
+    if (mClientIdToClientInfoMap.size() > 0) {
+        snprintf(buffer, SIZE, "========== Dumping all clients =========\n");
+        result.append(buffer);
+    }
+
+    for (const auto& iter : mClientIdToClientInfoMap) {
+        const std::shared_ptr<ITranscodingServiceClient> client = iter.second->mClient;
+        std::string clientName;
+        Status status = client->getName(&clientName);
+        if (!status.isOk()) {
+            ALOGE("Failed to get client: %d information", iter.first);
+            continue;
+        }
+        snprintf(buffer, SIZE, "    -- Clients: %d  name: %s\n", iter.first, clientName.c_str());
+        result.append(buffer);
+    }
+
+    write(fd, result.string(), result.size());
+}
+
+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() ||
+        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.
+    if (mClientIdToClientInfoMap.count(client->mClientId) != 0) {
+        ALOGW("Client already exists.");
+        return ALREADY_EXISTS;
+    }
+
+    // Listen to the death of the client.
+    client->mDeathNotifier = new DeathNotifier();
+    AIBinder_linkToDeath(client->mClient->asBinder().get(), mDeathRecipient.get(),
+                         client->mDeathNotifier.get());
+
+    // Adds the new client to the map.
+    mClientIdToClientInfoMap[client->mClientId] = std::move(client);
+
+    return OK;
+}
+
+status_t TranscodingClientManager::removeClient(int32_t clientId) {
+    ALOGD("Removing client id %d", clientId);
+    std::scoped_lock lock{mLock};
+
+    // Checks if the client is valid.
+    auto it = mClientIdToClientInfoMap.find(clientId);
+    if (it == mClientIdToClientInfoMap.end()) {
+        ALOGE("Client id %d does not exist", clientId);
+        return INVALID_OPERATION;
+    }
+
+    std::shared_ptr<ITranscodingServiceClient> client = it->second->mClient;
+
+    // Check if the client still live. If alive, unlink the death.
+    if (client) {
+        AIBinder_unlinkToDeath(client->asBinder().get(), mDeathRecipient.get(),
+                               it->second->mDeathNotifier.get());
+    }
+
+    // Erase the entry.
+    mClientIdToClientInfoMap.erase(it);
+
+    return OK;
+}
+
+size_t TranscodingClientManager::getNumOfClients() const {
+    std::scoped_lock lock{mLock};
+    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
diff --git a/media/libmediatranscoding/include/media/TranscodingClientManager.h b/media/libmediatranscoding/include/media/TranscodingClientManager.h
new file mode 100644
index 0000000..dbf837c
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingClientManager.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 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_MEDIA_TRANSCODING_CLIENT_MANAGER_H
+#define ANDROID_MEDIA_TRANSCODING_CLIENT_MANAGER_H
+
+#include <aidl/android/media/BnTranscodingServiceClient.h>
+#include <android/binder_ibinder.h>
+#include <sys/types.h>
+#include <utils/Condition.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+using ::aidl::android::media::ITranscodingServiceClient;
+
+class MediaTranscodingService;
+
+/*
+ * TranscodingClientManager manages all the transcoding clients across different processes.
+ *
+ * TranscodingClientManager is a global singleton that could only acquired by
+ * MediaTranscodingService. It manages all the clients's registration/unregistration and clients'
+ * information. It also bookkeeps all the clients' information. It also monitors to the death of the
+ * clients. Upon client's death, it will remove the client from it.
+ *
+ * TODO(hkuang): Hook up with ResourceManager for resource management.
+ * 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();
+
+    /**
+     * ClientInfo contains a single client's information.
+     */
+    struct ClientInfo {
+        /* The remote client that this ClientInfo is associated with. */
+        std::shared_ptr<ITranscodingServiceClient> mClient;
+        /* A unique positive Id assigned to the client by the service. */
+        int32_t mClientId;
+        /* Process id of the client */
+        int32_t mClientPid;
+        /* User id of the client. */
+        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)
+            : mClient(client),
+              mClientId(clientId),
+              mClientPid(pid),
+              mClientUid(uid),
+              mClientOpPackageName(opPackageName),
+              mDeathNotifier(nullptr) {}
+    };
+
+    /**
+     * Adds a new client to the manager.
+     *
+     * The client must have valid clientId, pid, uid and opPackageName, otherwise, this will return
+     * a non-zero errorcode. If the client has already been added, it will also return non-zero
+     * errorcode.
+     *
+     * @param client to be added to the manager.
+     * @return 0 if client is added successfully, non-zero errorcode otherwise.
+     */
+    status_t addClient(std::unique_ptr<ClientInfo> client);
+
+    /**
+     * Removes an existing client from the manager.
+     *
+     * If the client does not exist, this will return non-zero errorcode.
+     *
+     * @param clientId id of the client to be removed..
+     * @return 0 if client is removed successfully, non-zero errorcode otherwise.
+     */
+    status_t removeClient(int32_t clientId);
+
+    /**
+     * Gets the number of clients.
+     */
+    size_t getNumOfClients() const;
+
+    /**
+     * Checks if a client with clientId is already registered.
+     */
+    bool isClientIdRegistered(int32_t clientId) const;
+
+    /**
+     * Dump all the client information to the fd.
+     */
+    void dumpAllClients(int fd, const Vector<String16>& args);
+
+   private:
+    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();
+
+    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;
+};
+
+}  // namespace android
+#endif  // ANDROID_MEDIA_TRANSCODING_SERVICE_H
diff --git a/media/libmediatranscoding/tests/Android.bp b/media/libmediatranscoding/tests/Android.bp
new file mode 100644
index 0000000..f3cc4c5
--- /dev/null
+++ b/media/libmediatranscoding/tests/Android.bp
@@ -0,0 +1,38 @@
+// Build the unit tests for libmediatranscoding.
+cc_defaults {
+    name: "libmediatranscoding_test_defaults",
+
+    header_libs: [
+        "libbase_headers",
+        "libmedia_headers",
+    ],
+
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libmediatranscoding"
+    ],
+
+    static_libs: [
+        "mediatranscoding_aidl_interface-ndk_platform",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+}
+
+//
+// TranscodingClientManager unit test
+//
+cc_test {
+    name: "TranscodingClientManager_tests",
+    defaults: ["libmediatranscoding_test_defaults"],
+
+    srcs: ["TranscodingClientManager_tests.cpp"],
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
new file mode 100644
index 0000000..97c8919
--- /dev/null
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// Unit Test for TranscodingClientManager
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingClientManagerTest"
+
+#include <aidl/android/media/BnTranscodingServiceClient.h>
+#include <aidl/android/media/IMediaTranscodingService.h>
+#include <aidl/android/media/ITranscodingServiceClient.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <media/TranscodingClientManager.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnTranscodingServiceClient;
+using aidl::android::media::IMediaTranscodingService;
+using aidl::android::media::ITranscodingServiceClient;
+
+constexpr int32_t kInvalidClientId = -1;
+constexpr int32_t kInvalidClientPid = -1;
+constexpr int32_t kInvalidClientUid = -1;
+constexpr const char* kInvalidClientOpPackageName = "";
+
+constexpr int32_t kClientId = 1;
+constexpr int32_t kClientPid = 2;
+constexpr int32_t kClientUid = 3;
+constexpr const char* kClientOpPackageName = "TestClient";
+
+struct TestClient : public BnTranscodingServiceClient {
+    TestClient(const std::shared_ptr<IMediaTranscodingService>& service) : mService(service) {
+        ALOGD("TestClient Created");
+    }
+
+    Status getName(std::string* _aidl_return) override {
+        *_aidl_return = "test_client";
+        return Status::ok();
+    }
+
+    Status onTranscodingFinished(
+            int32_t /* in_jobId */,
+            const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
+        return Status::ok();
+    }
+
+    Status onTranscodingFailed(
+            int32_t /* in_jobId */,
+            ::aidl::android::media::TranscodingErrorCode /*in_errorCode */) override {
+        return Status::ok();
+    }
+
+    Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
+                                      int32_t /* in_newAwaitNumber */) override {
+        return Status::ok();
+    }
+
+    Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
+        return Status::ok();
+    }
+
+    virtual ~TestClient() { ALOGI("TestClient destroyed"); };
+
+   private:
+    std::shared_ptr<IMediaTranscodingService> mService;
+    TestClient(const TestClient&) = delete;
+    TestClient& operator=(const TestClient&) = delete;
+};
+
+class TranscodingClientManagerTest : public ::testing::Test {
+   public:
+    TranscodingClientManagerTest() { ALOGD("TranscodingClientManagerTest created"); }
+
+    void SetUp() override {
+        mClientManager = TranscodingClientManager::getInstance();
+        if (mClientManager == nullptr) {
+            ALOGE("Failed to acquire TranscodingClientManager.");
+            return;
+        }
+
+        ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
+        mService = IMediaTranscodingService::fromBinder(binder);
+        if (mService == nullptr) {
+            ALOGE("Failed to connect to the media.trascoding service.");
+            return;
+        }
+
+        mTestClient = ::ndk::SharedRefBase::make<TestClient>(mService);
+    }
+
+    void TearDown() override {
+        ALOGI("TranscodingClientManagerTest tear down");
+        mClientManager = nullptr;
+        mService = nullptr;
+    }
+
+    ~TranscodingClientManagerTest() { ALOGD("TranscodingClientManagerTest destroyed"); }
+
+    sp<TranscodingClientManager> mClientManager = nullptr;
+    std::shared_ptr<ITranscodingServiceClient> mTestClient = nullptr;
+    std::shared_ptr<IMediaTranscodingService> mService = nullptr;
+};
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientId) {
+    std::shared_ptr<ITranscodingServiceClient> client =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    // Create a client with invalid client id.
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client, kInvalidClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+    // Add the client to the manager and expect failure.
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
+    std::shared_ptr<ITranscodingServiceClient> client =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    // Create a client with invalid Pid.
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client, kClientId, kInvalidClientPid, kClientUid, kClientOpPackageName);
+
+    // Add the client to the manager and expect failure.
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientUid) {
+    std::shared_ptr<ITranscodingServiceClient> client =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    // Create a client with invalid Uid.
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client, kClientId, kClientPid, kInvalidClientUid, kClientOpPackageName);
+
+    // Add the client to the manager and expect failure.
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPackageName) {
+    std::shared_ptr<ITranscodingServiceClient> client =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    // Create a client with invalid packagename.
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client, kClientId, kClientPid, kClientUid, kInvalidClientOpPackageName);
+
+    // Add the client to the manager and expect failure.
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingValidClient) {
+    std::shared_ptr<ITranscodingServiceClient> client1 =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client1, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err == OK);
+
+    size_t numOfClients = mClientManager->getNumOfClients();
+    EXPECT_EQ(numOfClients, 1);
+
+    err = mClientManager->removeClient(kClientId);
+    EXPECT_TRUE(err == OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingDupliacteClient) {
+    std::shared_ptr<ITranscodingServiceClient> client1 =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client1, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err == OK);
+
+    err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err != OK);
+
+    err = mClientManager->removeClient(kClientId);
+    EXPECT_TRUE(err == OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestAddingMultipleClient) {
+    std::shared_ptr<ITranscodingServiceClient> client1 =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo1 =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client1, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+    status_t err = mClientManager->addClient(std::move(clientInfo1));
+    EXPECT_TRUE(err == OK);
+
+    std::shared_ptr<ITranscodingServiceClient> client2 =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo2 =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client2, kClientId + 1, kClientPid, kClientUid, kClientOpPackageName);
+
+    err = mClientManager->addClient(std::move(clientInfo2));
+    EXPECT_TRUE(err == OK);
+
+    std::shared_ptr<ITranscodingServiceClient> client3 =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    // Create a client with invalid packagename.
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo3 =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client3, kClientId + 2, kClientPid, kClientUid, kClientOpPackageName);
+
+    err = mClientManager->addClient(std::move(clientInfo3));
+    EXPECT_TRUE(err == OK);
+
+    size_t numOfClients = mClientManager->getNumOfClients();
+    EXPECT_EQ(numOfClients, 3);
+
+    err = mClientManager->removeClient(kClientId);
+    EXPECT_TRUE(err == OK);
+
+    err = mClientManager->removeClient(kClientId + 1);
+    EXPECT_TRUE(err == OK);
+
+    err = mClientManager->removeClient(kClientId + 2);
+    EXPECT_TRUE(err == OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestRemovingNonExistClient) {
+    status_t err = mClientManager->removeClient(kInvalidClientId);
+    EXPECT_TRUE(err != OK);
+
+    err = mClientManager->removeClient(1000 /* clientId */);
+    EXPECT_TRUE(err != OK);
+}
+
+TEST_F(TranscodingClientManagerTest, TestCheckClientWithClientId) {
+    std::shared_ptr<ITranscodingServiceClient> client =
+            ::ndk::SharedRefBase::make<TestClient>(mService);
+
+    std::unique_ptr<TranscodingClientManager::ClientInfo> clientInfo =
+            std::make_unique<TranscodingClientManager::ClientInfo>(
+                    client, kClientId, kClientPid, kClientUid, kClientOpPackageName);
+
+    status_t err = mClientManager->addClient(std::move(clientInfo));
+    EXPECT_TRUE(err == OK);
+
+    bool res = mClientManager->isClientIdRegistered(kClientId);
+    EXPECT_TRUE(res);
+
+    res = mClientManager->isClientIdRegistered(kInvalidClientId);
+    EXPECT_FALSE(res);
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
new file mode 100644
index 0000000..9832696
--- /dev/null
+++ b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Android build environment not set"
+    exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount && adb sync
+
+echo "========================================"
+
+echo "testing TranscodingClientManager"
+adb shell /data/nativetest64/TranscodingClientManager_tests/TranscodingClientManager_tests