blob: de9dd76b34b3844b60c551c0fa5e0cddc482da97 [file] [log] [blame]
hkuang26587cb2020-01-16 10:36:08 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// #define LOG_NDEBUG 0
18#define LOG_TAG "TranscodingClientManager"
19
Chong Zhang8e062632020-03-31 10:56:37 -070020#include <aidl/android/media/BnTranscodingClient.h>
Chong Zhang15c192a2020-05-05 16:24:00 -070021#include <aidl/android/media/IMediaTranscodingService.h>
Chong Zhang8e062632020-03-31 10:56:37 -070022#include <android/binder_ibinder.h>
hkuang9c04b8d2020-01-22 10:03:21 -080023#include <inttypes.h>
hkuang26587cb2020-01-16 10:36:08 -080024#include <media/TranscodingClientManager.h>
Chong Zhang6d58e4b2020-03-31 09:41:10 -070025#include <media/TranscodingRequest.h>
hkuang26587cb2020-01-16 10:36:08 -080026#include <utils/Log.h>
hkuang26587cb2020-01-16 10:36:08 -080027namespace android {
28
Chong Zhang15c192a2020-05-05 16:24:00 -070029static_assert(sizeof(ClientIdType) == sizeof(void*), "ClientIdType should be pointer-sized");
30
Chong Zhang8e062632020-03-31 10:56:37 -070031using ::aidl::android::media::BnTranscodingClient;
Chong Zhang15c192a2020-05-05 16:24:00 -070032using ::aidl::android::media::IMediaTranscodingService; // For service error codes
Chong Zhang8e062632020-03-31 10:56:37 -070033using ::aidl::android::media::TranscodingJobParcel;
34using ::aidl::android::media::TranscodingRequestParcel;
hkuang26587cb2020-01-16 10:36:08 -080035using Status = ::ndk::ScopedAStatus;
Chong Zhang8e062632020-03-31 10:56:37 -070036using ::ndk::SpAIBinder;
37
Chong Zhang3fa408f2020-04-30 11:04:28 -070038//static
39std::atomic<ClientIdType> TranscodingClientManager::sCookieCounter = 0;
40//static
41std::mutex TranscodingClientManager::sCookie2ClientLock;
42//static
43std::map<ClientIdType, std::shared_ptr<TranscodingClientManager::ClientImpl>>
44 TranscodingClientManager::sCookie2Client;
Chong Zhang8e062632020-03-31 10:56:37 -070045///////////////////////////////////////////////////////////////////////////////
46
47/**
48 * ClientImpl implements a single client and contains all its information.
49 */
50struct TranscodingClientManager::ClientImpl : public BnTranscodingClient {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070051 /* The remote client callback that this ClientInfo is associated with.
Chong Zhang8e062632020-03-31 10:56:37 -070052 * Once the ClientInfo is created, we hold an SpAIBinder so that the binder
53 * object doesn't get created again, otherwise the binder object pointer
54 * may not be unique.
55 */
Chong Zhangacb33502020-04-20 11:04:48 -070056 SpAIBinder mClientBinder;
57 std::shared_ptr<ITranscodingClientCallback> mClientCallback;
Chong Zhang8e062632020-03-31 10:56:37 -070058 /* A unique id assigned to the client by the service. This number is used
59 * by the service for indexing. Here we use the binder object's pointer
60 * (casted to int64t_t) as the client id.
61 */
62 ClientIdType mClientId;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070063 pid_t mClientPid;
64 uid_t mClientUid;
Chong Zhang8e062632020-03-31 10:56:37 -070065 std::string mClientName;
66 std::string mClientOpPackageName;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070067
Chong Zhang15c192a2020-05-05 16:24:00 -070068 // Next jobId to assign.
Chong Zhang3fa408f2020-04-30 11:04:28 -070069 std::atomic<int32_t> mNextJobId;
Chong Zhang15c192a2020-05-05 16:24:00 -070070 // Whether this client has been unregistered already.
71 std::atomic<bool> mAbandoned;
72 // Weak pointer to the client manager for this client.
73 std::weak_ptr<TranscodingClientManager> mOwner;
Chong Zhang8e062632020-03-31 10:56:37 -070074
hkuang08b38d02020-04-17 14:29:33 -070075 ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
76 const std::string& clientName, const std::string& opPackageName,
Chong Zhang15c192a2020-05-05 16:24:00 -070077 const std::weak_ptr<TranscodingClientManager>& owner);
Chong Zhang8e062632020-03-31 10:56:37 -070078
79 Status submitRequest(const TranscodingRequestParcel& /*in_request*/,
Chong Zhang6d58e4b2020-03-31 09:41:10 -070080 TranscodingJobParcel* /*out_job*/, bool* /*_aidl_return*/) override;
Chong Zhang8e062632020-03-31 10:56:37 -070081
82 Status cancelJob(int32_t /*in_jobId*/, bool* /*_aidl_return*/) override;
83
Chong Zhang6d58e4b2020-03-31 09:41:10 -070084 Status getJobWithId(int32_t /*in_jobId*/, TranscodingJobParcel* /*out_job*/,
85 bool* /*_aidl_return*/) override;
Chong Zhang8e062632020-03-31 10:56:37 -070086
87 Status unregister() override;
88};
89
90TranscodingClientManager::ClientImpl::ClientImpl(
Chong Zhang6d58e4b2020-03-31 09:41:10 -070091 const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
92 const std::string& clientName, const std::string& opPackageName,
Chong Zhang15c192a2020-05-05 16:24:00 -070093 const std::weak_ptr<TranscodingClientManager>& owner)
Chong Zhangacb33502020-04-20 11:04:48 -070094 : mClientBinder((callback != nullptr) ? callback->asBinder() : nullptr),
95 mClientCallback(callback),
Chong Zhang3fa408f2020-04-30 11:04:28 -070096 mClientId(sCookieCounter.fetch_add(1, std::memory_order_relaxed)),
Chong Zhang6d58e4b2020-03-31 09:41:10 -070097 mClientPid(pid),
98 mClientUid(uid),
99 mClientName(clientName),
100 mClientOpPackageName(opPackageName),
101 mNextJobId(0),
Chong Zhang15c192a2020-05-05 16:24:00 -0700102 mAbandoned(false),
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700103 mOwner(owner) {}
Chong Zhang8e062632020-03-31 10:56:37 -0700104
105Status TranscodingClientManager::ClientImpl::submitRequest(
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700106 const TranscodingRequestParcel& in_request, TranscodingJobParcel* out_job,
107 bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700108 *_aidl_return = false;
109
110 std::shared_ptr<TranscodingClientManager> owner;
111 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
112 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
113 }
114
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700115 if (in_request.fileName.empty()) {
116 // This is the only error we check for now.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700117 return Status::ok();
118 }
119
120 int32_t jobId = mNextJobId.fetch_add(1);
121
Chong Zhang15c192a2020-05-05 16:24:00 -0700122 *_aidl_return =
123 owner->mJobScheduler->submit(mClientId, jobId, mClientUid, in_request, mClientCallback);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700124
125 if (*_aidl_return) {
126 out_job->jobId = jobId;
127
128 // TODO(chz): is some of this coming from JobScheduler?
129 *(TranscodingRequest*)&out_job->request = in_request;
130 out_job->awaitNumberOfJobs = 0;
131 }
Chong Zhang15c192a2020-05-05 16:24:00 -0700132
Chong Zhang8e062632020-03-31 10:56:37 -0700133 return Status::ok();
134}
135
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700136Status TranscodingClientManager::ClientImpl::cancelJob(int32_t in_jobId, bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700137 *_aidl_return = false;
138
139 std::shared_ptr<TranscodingClientManager> owner;
140 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
141 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
142 }
143
144 if (in_jobId < 0) {
145 return Status::ok();
146 }
147
148 *_aidl_return = owner->mJobScheduler->cancel(mClientId, in_jobId);
Chong Zhang8e062632020-03-31 10:56:37 -0700149 return Status::ok();
150}
151
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700152Status TranscodingClientManager::ClientImpl::getJobWithId(int32_t in_jobId,
153 TranscodingJobParcel* out_job,
154 bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700155 *_aidl_return = false;
156
157 std::shared_ptr<TranscodingClientManager> owner;
158 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
159 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
160 }
161
162 if (in_jobId < 0) {
163 return Status::ok();
164 }
165
166 *_aidl_return = owner->mJobScheduler->getJob(mClientId, in_jobId, &out_job->request);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700167
168 if (*_aidl_return) {
169 out_job->jobId = in_jobId;
170 out_job->awaitNumberOfJobs = 0;
171 }
Chong Zhang8e062632020-03-31 10:56:37 -0700172 return Status::ok();
173}
174
175Status TranscodingClientManager::ClientImpl::unregister() {
Chong Zhang15c192a2020-05-05 16:24:00 -0700176 bool abandoned = mAbandoned.exchange(true);
177
178 std::shared_ptr<TranscodingClientManager> owner;
179 if (abandoned || (owner = mOwner.lock()) == nullptr) {
180 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
181 }
182
183 // Use jobId == -1 to cancel all realtime jobs for this client with the scheduler.
184 owner->mJobScheduler->cancel(mClientId, -1);
185 owner->removeClient(mClientId);
186
Chong Zhang8e062632020-03-31 10:56:37 -0700187 return Status::ok();
188}
189
190///////////////////////////////////////////////////////////////////////////////
hkuang26587cb2020-01-16 10:36:08 -0800191
192// static
hkuang9c04b8d2020-01-22 10:03:21 -0800193void TranscodingClientManager::BinderDiedCallback(void* cookie) {
Chong Zhang3fa408f2020-04-30 11:04:28 -0700194 ClientIdType clientId = reinterpret_cast<ClientIdType>(cookie);
195
196 ALOGD("Client %lld is dead", (long long)clientId);
197
198 std::shared_ptr<ClientImpl> client;
199
200 {
201 std::scoped_lock lock{sCookie2ClientLock};
202
203 auto it = sCookie2Client.find(clientId);
204 if (it != sCookie2Client.end()) {
205 client = it->second;
206 }
207 }
208
209 if (client != nullptr) {
210 client->unregister();
211 }
hkuang9c04b8d2020-01-22 10:03:21 -0800212}
213
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700214TranscodingClientManager::TranscodingClientManager(
215 const std::shared_ptr<SchedulerClientInterface>& scheduler)
216 : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)), mJobScheduler(scheduler) {
hkuang26587cb2020-01-16 10:36:08 -0800217 ALOGD("TranscodingClientManager started");
218}
219
220TranscodingClientManager::~TranscodingClientManager() {
221 ALOGD("TranscodingClientManager exited");
222}
223
hkuang26587cb2020-01-16 10:36:08 -0800224void TranscodingClientManager::dumpAllClients(int fd, const Vector<String16>& args __unused) {
225 String8 result;
226
227 const size_t SIZE = 256;
228 char buffer[SIZE];
hkuang08b38d02020-04-17 14:29:33 -0700229 std::scoped_lock lock{mLock};
hkuang26587cb2020-01-16 10:36:08 -0800230
Chong Zhang8e062632020-03-31 10:56:37 -0700231 snprintf(buffer, SIZE, " Total num of Clients: %zu\n", mClientIdToClientMap.size());
hkuang26587cb2020-01-16 10:36:08 -0800232 result.append(buffer);
233
Chong Zhang8e062632020-03-31 10:56:37 -0700234 if (mClientIdToClientMap.size() > 0) {
hkuang26587cb2020-01-16 10:36:08 -0800235 snprintf(buffer, SIZE, "========== Dumping all clients =========\n");
236 result.append(buffer);
237 }
238
Chong Zhang8e062632020-03-31 10:56:37 -0700239 for (const auto& iter : mClientIdToClientMap) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700240 snprintf(buffer, SIZE, " -- Client id: %lld name: %s\n", (long long)iter.first,
241 iter.second->mClientName.c_str());
hkuang26587cb2020-01-16 10:36:08 -0800242 result.append(buffer);
243 }
244
245 write(fd, result.string(), result.size());
246}
247
Chong Zhang8e062632020-03-31 10:56:37 -0700248status_t TranscodingClientManager::addClient(
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700249 const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
250 const std::string& clientName, const std::string& opPackageName,
Chong Zhang8e062632020-03-31 10:56:37 -0700251 std::shared_ptr<ITranscodingClient>* outClient) {
hkuang26587cb2020-01-16 10:36:08 -0800252 // Validate the client.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700253 if (callback == nullptr || pid < 0 || clientName.empty() || opPackageName.empty()) {
hkuang26587cb2020-01-16 10:36:08 -0800254 ALOGE("Invalid client");
Chong Zhang15c192a2020-05-05 16:24:00 -0700255 return IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT;
hkuang26587cb2020-01-16 10:36:08 -0800256 }
257
Chong Zhang3fa408f2020-04-30 11:04:28 -0700258 SpAIBinder binder = callback->asBinder();
Chong Zhang8e062632020-03-31 10:56:37 -0700259
hkuang26587cb2020-01-16 10:36:08 -0800260 std::scoped_lock lock{mLock};
261
Chong Zhang8e062632020-03-31 10:56:37 -0700262 // Checks if the client already registers.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700263 if (mRegisteredCallbacks.count((uintptr_t)binder.get()) > 0) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700264 return IMediaTranscodingService::ERROR_ALREADY_EXISTS;
hkuang26587cb2020-01-16 10:36:08 -0800265 }
266
Chong Zhang3fa408f2020-04-30 11:04:28 -0700267 // Creates the client and uses its process id as client id.
268 std::shared_ptr<ClientImpl> client = ::ndk::SharedRefBase::make<ClientImpl>(
Chong Zhang15c192a2020-05-05 16:24:00 -0700269 callback, pid, uid, clientName, opPackageName, shared_from_this());
Chong Zhang3fa408f2020-04-30 11:04:28 -0700270
Chong Zhang8e062632020-03-31 10:56:37 -0700271 ALOGD("Adding client id %lld, pid %d, uid %d, name %s, package %s",
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700272 (long long)client->mClientId, client->mClientPid, client->mClientUid,
273 client->mClientName.c_str(), client->mClientOpPackageName.c_str());
hkuang9c04b8d2020-01-22 10:03:21 -0800274
Chong Zhang3fa408f2020-04-30 11:04:28 -0700275 {
276 std::scoped_lock lock{sCookie2ClientLock};
277 sCookie2Client.emplace(std::make_pair(client->mClientId, client));
278 }
279
280 AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(),
281 reinterpret_cast<void*>(client->mClientId));
hkuang26587cb2020-01-16 10:36:08 -0800282
283 // Adds the new client to the map.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700284 mRegisteredCallbacks.insert((uintptr_t)binder.get());
Chong Zhang8e062632020-03-31 10:56:37 -0700285 mClientIdToClientMap[client->mClientId] = client;
286
287 *outClient = client;
hkuang26587cb2020-01-16 10:36:08 -0800288
289 return OK;
290}
291
Chong Zhang8e062632020-03-31 10:56:37 -0700292status_t TranscodingClientManager::removeClient(ClientIdType clientId) {
293 ALOGD("Removing client id %lld", (long long)clientId);
hkuang26587cb2020-01-16 10:36:08 -0800294 std::scoped_lock lock{mLock};
295
296 // Checks if the client is valid.
Chong Zhang8e062632020-03-31 10:56:37 -0700297 auto it = mClientIdToClientMap.find(clientId);
298 if (it == mClientIdToClientMap.end()) {
299 ALOGE("Client id %lld does not exist", (long long)clientId);
Chong Zhang15c192a2020-05-05 16:24:00 -0700300 return IMediaTranscodingService::ERROR_INVALID_OPERATION;
hkuang26587cb2020-01-16 10:36:08 -0800301 }
302
Chong Zhang3fa408f2020-04-30 11:04:28 -0700303 SpAIBinder binder = it->second->mClientBinder;
hkuang26587cb2020-01-16 10:36:08 -0800304
305 // Check if the client still live. If alive, unlink the death.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700306 if (binder.get() != nullptr) {
307 AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(),
308 reinterpret_cast<void*>(it->second->mClientId));
309 }
310
311 {
312 std::scoped_lock lock{sCookie2ClientLock};
313 sCookie2Client.erase(it->second->mClientId);
hkuang26587cb2020-01-16 10:36:08 -0800314 }
315
316 // Erase the entry.
Chong Zhang8e062632020-03-31 10:56:37 -0700317 mClientIdToClientMap.erase(it);
Chong Zhang3fa408f2020-04-30 11:04:28 -0700318 mRegisteredCallbacks.erase((uintptr_t)binder.get());
hkuang26587cb2020-01-16 10:36:08 -0800319
320 return OK;
321}
322
323size_t TranscodingClientManager::getNumOfClients() const {
324 std::scoped_lock lock{mLock};
Chong Zhang8e062632020-03-31 10:56:37 -0700325 return mClientIdToClientMap.size();
hkuang26587cb2020-01-16 10:36:08 -0800326}
327
hkuang26587cb2020-01-16 10:36:08 -0800328} // namespace android