| /* | 
 |  * 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 <aidl/android/media/BnTranscodingClient.h> | 
 | #include <android/binder_ibinder.h> | 
 | #include <inttypes.h> | 
 | #include <media/TranscodingClientManager.h> | 
 | #include <utils/Log.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | using ::aidl::android::media::BnTranscodingClient; | 
 | using ::aidl::android::media::TranscodingJobParcel; | 
 | using ::aidl::android::media::TranscodingRequestParcel; | 
 | using Status = ::ndk::ScopedAStatus; | 
 | using ::ndk::SpAIBinder; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /** | 
 |  * ClientImpl implements a single client and contains all its information. | 
 |  */ | 
 | struct TranscodingClientManager::ClientImpl : public BnTranscodingClient { | 
 |     /* The remote client listener that this ClientInfo is associated with. | 
 |      * Once the ClientInfo is created, we hold an SpAIBinder so that the binder | 
 |      * object doesn't get created again, otherwise the binder object pointer | 
 |      * may not be unique. | 
 |      */ | 
 |     SpAIBinder mClientListener; | 
 |     /* A unique id assigned to the client by the service. This number is used | 
 |      * by the service for indexing. Here we use the binder object's pointer | 
 |      * (casted to int64t_t) as the client id. | 
 |      */ | 
 |     ClientIdType mClientId; | 
 |     int32_t mClientPid; | 
 |     int32_t mClientUid; | 
 |     std::string mClientName; | 
 |     std::string mClientOpPackageName; | 
 |     TranscodingClientManager* mOwner; | 
 |  | 
 |     ClientImpl(const std::shared_ptr<ITranscodingClientListener>& listener, | 
 |                int32_t pid, int32_t uid, | 
 |                const std::string& clientName, | 
 |                const std::string& opPackageName, | 
 |                TranscodingClientManager* owner); | 
 |  | 
 |     Status submitRequest(const TranscodingRequestParcel& /*in_request*/, | 
 |             TranscodingJobParcel* /*out_job*/, int32_t* /*_aidl_return*/) override; | 
 |  | 
 |     Status cancelJob(int32_t /*in_jobId*/, bool* /*_aidl_return*/) override; | 
 |  | 
 |     Status getJobWithId(int32_t /*in_jobId*/, | 
 |             TranscodingJobParcel* /*out_job*/, bool* /*_aidl_return*/) override; | 
 |  | 
 |     Status unregister() override; | 
 | }; | 
 |  | 
 | TranscodingClientManager::ClientImpl::ClientImpl( | 
 |         const std::shared_ptr<ITranscodingClientListener>& listener, | 
 |         int32_t pid, int32_t uid, | 
 |         const std::string& clientName, | 
 |         const std::string& opPackageName, | 
 |         TranscodingClientManager* owner) | 
 | : mClientListener((listener != nullptr) ? listener->asBinder() : nullptr), | 
 |   mClientId((int64_t)mClientListener.get()), | 
 |   mClientPid(pid), | 
 |   mClientUid(uid), | 
 |   mClientName(clientName), | 
 |   mClientOpPackageName(opPackageName), | 
 |   mOwner(owner) {} | 
 |  | 
 | Status TranscodingClientManager::ClientImpl::submitRequest( | 
 |         const TranscodingRequestParcel& /*in_request*/, | 
 |         TranscodingJobParcel* /*out_job*/, int32_t* /*_aidl_return*/) { | 
 |     return Status::ok(); | 
 | } | 
 |  | 
 | Status TranscodingClientManager::ClientImpl::cancelJob( | 
 |         int32_t /*in_jobId*/, bool* /*_aidl_return*/) { | 
 |     return Status::ok(); | 
 | } | 
 |  | 
 | Status TranscodingClientManager::ClientImpl::getJobWithId(int32_t /*in_jobId*/, | 
 |         TranscodingJobParcel* /*out_job*/, bool* /*_aidl_return*/) { | 
 |     return Status::ok(); | 
 | } | 
 |  | 
 | Status TranscodingClientManager::ClientImpl::unregister() { | 
 |     mOwner->removeClient(mClientId); | 
 |     return Status::ok(); | 
 | } | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | // static | 
 | TranscodingClientManager& TranscodingClientManager::getInstance() { | 
 |     static TranscodingClientManager gInstance{}; | 
 |     return gInstance; | 
 | } | 
 |  | 
 | // static | 
 | void TranscodingClientManager::BinderDiedCallback(void* cookie) { | 
 |     ClientIdType clientId = static_cast<ClientIdType>(reinterpret_cast<intptr_t>(cookie)); | 
 |     ALOGD("Client %lld is dead", (long long) clientId); | 
 |     // Don't check for pid validity since we know it's already dead. | 
 |     TranscodingClientManager& manager = TranscodingClientManager::getInstance(); | 
 |     manager.removeClient(clientId); | 
 | } | 
 |  | 
 | TranscodingClientManager::TranscodingClientManager() | 
 |     : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) { | 
 |     ALOGD("TranscodingClientManager started"); | 
 | } | 
 |  | 
 | TranscodingClientManager::~TranscodingClientManager() { | 
 |     ALOGD("TranscodingClientManager exited"); | 
 | } | 
 |  | 
 | bool TranscodingClientManager::isClientIdRegistered(ClientIdType clientId) const { | 
 |     return mClientIdToClientMap.find(clientId) != mClientIdToClientMap.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", mClientIdToClientMap.size()); | 
 |     result.append(buffer); | 
 |  | 
 |     if (mClientIdToClientMap.size() > 0) { | 
 |         snprintf(buffer, SIZE, "========== Dumping all clients =========\n"); | 
 |         result.append(buffer); | 
 |     } | 
 |  | 
 |     for (const auto& iter : mClientIdToClientMap) { | 
 |         snprintf(buffer, SIZE, "    -- Client id: %lld  name: %s\n", | 
 |                 (long long)iter.first, iter.second->mClientName.c_str()); | 
 |         result.append(buffer); | 
 |     } | 
 |  | 
 |     write(fd, result.string(), result.size()); | 
 | } | 
 |  | 
 | status_t TranscodingClientManager::addClient( | 
 |         const std::shared_ptr<ITranscodingClientListener>& listener, | 
 |         int32_t pid, int32_t uid, | 
 |         const std::string& clientName, | 
 |         const std::string& opPackageName, | 
 |         std::shared_ptr<ITranscodingClient>* outClient) { | 
 |     // Validate the client. | 
 |     if (listener == nullptr || pid < 0 || uid < 0 || | 
 |             clientName.empty() || opPackageName.empty()) { | 
 |         ALOGE("Invalid client"); | 
 |         return BAD_VALUE; | 
 |     } | 
 |  | 
 |     // Creates the client and uses its process id as client id. | 
 |     std::shared_ptr<ClientImpl> client = | 
 |             ::ndk::SharedRefBase::make<ClientImpl>( | 
 |                     listener, pid, uid, clientName, opPackageName, this); | 
 |  | 
 |     std::scoped_lock lock{mLock}; | 
 |  | 
 |     // Checks if the client already registers. | 
 |     if (isClientIdRegistered(client->mClientId)) { | 
 |         return ALREADY_EXISTS; | 
 |     } | 
 |  | 
 |     ALOGD("Adding client id %lld, pid %d, uid %d, name %s, package %s", | 
 |             (long long)client->mClientId, | 
 |             client->mClientPid, | 
 |             client->mClientUid, | 
 |             client->mClientName.c_str(), | 
 |             client->mClientOpPackageName.c_str()); | 
 |  | 
 |     AIBinder_linkToDeath(client->mClientListener.get(), mDeathRecipient.get(), | 
 |                          reinterpret_cast<void*>(client->mClientId)); | 
 |  | 
 |     // Adds the new client to the map. | 
 |     mClientIdToClientMap[client->mClientId] = client; | 
 |  | 
 |     *outClient = client; | 
 |  | 
 |     return OK; | 
 | } | 
 |  | 
 |  | 
 | status_t TranscodingClientManager::removeClient(ClientIdType clientId) { | 
 |     ALOGD("Removing client id %lld", (long long)clientId); | 
 |     std::scoped_lock lock{mLock}; | 
 |  | 
 |     // Checks if the client is valid. | 
 |     auto it = mClientIdToClientMap.find(clientId); | 
 |     if (it == mClientIdToClientMap.end()) { | 
 |         ALOGE("Client id %lld does not exist", (long long)clientId); | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |  | 
 |     SpAIBinder listener = it->second->mClientListener; | 
 |  | 
 |     // Check if the client still live. If alive, unlink the death. | 
 |     if (listener.get() != nullptr) { | 
 |         AIBinder_unlinkToDeath(listener.get(), mDeathRecipient.get(), | 
 |                                reinterpret_cast<void*>(clientId)); | 
 |     } | 
 |  | 
 |     // Erase the entry. | 
 |     mClientIdToClientMap.erase(it); | 
 |  | 
 |     return OK; | 
 | } | 
 |  | 
 | size_t TranscodingClientManager::getNumOfClients() const { | 
 |     std::scoped_lock lock{mLock}; | 
 |     return mClientIdToClientMap.size(); | 
 | } | 
 |  | 
 | }  // namespace android |