blob: d9f3f2883223e86d25b0175adbb63e298b848457 [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>
Chong Zhang3f23e982020-09-24 14:03:41 -070026#include <private/android_filesystem_config.h>
hkuang26587cb2020-01-16 10:36:08 -080027#include <utils/Log.h>
hkuang26587cb2020-01-16 10:36:08 -080028namespace android {
29
Chong Zhang15c192a2020-05-05 16:24:00 -070030static_assert(sizeof(ClientIdType) == sizeof(void*), "ClientIdType should be pointer-sized");
31
Chong Zhang8e062632020-03-31 10:56:37 -070032using ::aidl::android::media::BnTranscodingClient;
Chong Zhang15c192a2020-05-05 16:24:00 -070033using ::aidl::android::media::IMediaTranscodingService; // For service error codes
Chong Zhang8e062632020-03-31 10:56:37 -070034using ::aidl::android::media::TranscodingJobParcel;
35using ::aidl::android::media::TranscodingRequestParcel;
hkuang26587cb2020-01-16 10:36:08 -080036using Status = ::ndk::ScopedAStatus;
Chong Zhang8e062632020-03-31 10:56:37 -070037using ::ndk::SpAIBinder;
38
Chong Zhang3fa408f2020-04-30 11:04:28 -070039//static
40std::atomic<ClientIdType> TranscodingClientManager::sCookieCounter = 0;
41//static
42std::mutex TranscodingClientManager::sCookie2ClientLock;
43//static
44std::map<ClientIdType, std::shared_ptr<TranscodingClientManager::ClientImpl>>
45 TranscodingClientManager::sCookie2Client;
Chong Zhang8e062632020-03-31 10:56:37 -070046///////////////////////////////////////////////////////////////////////////////
47
Chong Zhang3f23e982020-09-24 14:03:41 -070048// Convenience methods for constructing binder::Status objects for error returns
49#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
50 Status::fromServiceSpecificErrorWithMessage( \
51 errorCode, \
52 String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
53
54// Can MediaTranscoding service trust the caller based on the calling UID?
55// TODO(hkuang): Add MediaProvider's UID.
56static bool isTrustedCallingUid(uid_t uid) {
57 switch (uid) {
58 case AID_ROOT: // root user
59 case AID_SYSTEM:
60 case AID_SHELL:
61 case AID_MEDIA: // mediaserver
62 return true;
63 default:
64 return false;
65 }
66}
67
Chong Zhang8e062632020-03-31 10:56:37 -070068/**
69 * ClientImpl implements a single client and contains all its information.
70 */
71struct TranscodingClientManager::ClientImpl : public BnTranscodingClient {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070072 /* The remote client callback that this ClientInfo is associated with.
Chong Zhang8e062632020-03-31 10:56:37 -070073 * Once the ClientInfo is created, we hold an SpAIBinder so that the binder
74 * object doesn't get created again, otherwise the binder object pointer
75 * may not be unique.
76 */
Chong Zhangacb33502020-04-20 11:04:48 -070077 SpAIBinder mClientBinder;
78 std::shared_ptr<ITranscodingClientCallback> mClientCallback;
Chong Zhang8e062632020-03-31 10:56:37 -070079 /* A unique id assigned to the client by the service. This number is used
80 * by the service for indexing. Here we use the binder object's pointer
81 * (casted to int64t_t) as the client id.
82 */
83 ClientIdType mClientId;
Chong Zhang8e062632020-03-31 10:56:37 -070084 std::string mClientName;
85 std::string mClientOpPackageName;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070086
Chong Zhang15c192a2020-05-05 16:24:00 -070087 // Next jobId to assign.
Chong Zhang3fa408f2020-04-30 11:04:28 -070088 std::atomic<int32_t> mNextJobId;
Chong Zhang15c192a2020-05-05 16:24:00 -070089 // Whether this client has been unregistered already.
90 std::atomic<bool> mAbandoned;
91 // Weak pointer to the client manager for this client.
92 std::weak_ptr<TranscodingClientManager> mOwner;
Chong Zhang8e062632020-03-31 10:56:37 -070093
Chong Zhang3f23e982020-09-24 14:03:41 -070094 ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback,
hkuang08b38d02020-04-17 14:29:33 -070095 const std::string& clientName, const std::string& opPackageName,
Chong Zhang15c192a2020-05-05 16:24:00 -070096 const std::weak_ptr<TranscodingClientManager>& owner);
Chong Zhang8e062632020-03-31 10:56:37 -070097
98 Status submitRequest(const TranscodingRequestParcel& /*in_request*/,
Chong Zhang6d58e4b2020-03-31 09:41:10 -070099 TranscodingJobParcel* /*out_job*/, bool* /*_aidl_return*/) override;
Chong Zhang8e062632020-03-31 10:56:37 -0700100
101 Status cancelJob(int32_t /*in_jobId*/, bool* /*_aidl_return*/) override;
102
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700103 Status getJobWithId(int32_t /*in_jobId*/, TranscodingJobParcel* /*out_job*/,
104 bool* /*_aidl_return*/) override;
Chong Zhang8e062632020-03-31 10:56:37 -0700105
106 Status unregister() override;
107};
108
109TranscodingClientManager::ClientImpl::ClientImpl(
Chong Zhang3f23e982020-09-24 14:03:41 -0700110 const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
111 const std::string& opPackageName, const std::weak_ptr<TranscodingClientManager>& owner)
Chong Zhangacb33502020-04-20 11:04:48 -0700112 : mClientBinder((callback != nullptr) ? callback->asBinder() : nullptr),
113 mClientCallback(callback),
Chong Zhang3fa408f2020-04-30 11:04:28 -0700114 mClientId(sCookieCounter.fetch_add(1, std::memory_order_relaxed)),
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700115 mClientName(clientName),
116 mClientOpPackageName(opPackageName),
117 mNextJobId(0),
Chong Zhang15c192a2020-05-05 16:24:00 -0700118 mAbandoned(false),
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700119 mOwner(owner) {}
Chong Zhang8e062632020-03-31 10:56:37 -0700120
121Status TranscodingClientManager::ClientImpl::submitRequest(
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700122 const TranscodingRequestParcel& in_request, TranscodingJobParcel* out_job,
123 bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700124 *_aidl_return = false;
125
126 std::shared_ptr<TranscodingClientManager> owner;
127 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
128 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
129 }
130
hkuang72d105f2020-05-21 10:48:55 -0700131 if (in_request.sourceFilePath.empty() || in_request.destinationFilePath.empty()) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700132 return Status::ok();
133 }
134
Chong Zhang3f23e982020-09-24 14:03:41 -0700135 int32_t callingPid = AIBinder_getCallingPid();
136 int32_t callingUid = AIBinder_getCallingUid();
137 int32_t in_clientUid = in_request.clientUid;
138 int32_t in_clientPid = in_request.clientPid;
139
140 // Check if we can trust clientUid. Only privilege caller could forward the
141 // uid on app client's behalf.
142 if (in_clientUid == IMediaTranscodingService::USE_CALLING_UID) {
143 in_clientUid = callingUid;
144 } else if (in_clientUid < 0) {
145 return Status::ok();
146 } else if (in_clientUid != callingUid && !isTrustedCallingUid(callingUid)) {
147 ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
148 "(don't trust callingUid %d)",
149 in_clientPid, in_clientUid, callingUid);
150 return STATUS_ERROR_FMT(
151 IMediaTranscodingService::ERROR_PERMISSION_DENIED,
152 "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
153 "(don't trust callingUid %d)",
154 in_clientPid, in_clientUid, callingUid);
155 }
156
157 // Check if we can trust clientPid. Only privilege caller could forward the
158 // pid on app client's behalf.
159 if (in_clientPid == IMediaTranscodingService::USE_CALLING_PID) {
160 in_clientPid = callingPid;
161 } else if (in_clientPid < 0) {
162 return Status::ok();
163 } else if (in_clientPid != callingPid && !isTrustedCallingUid(callingUid)) {
164 ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
165 "(don't trust callingUid %d)",
166 in_clientPid, in_clientUid, callingUid);
167 return STATUS_ERROR_FMT(
168 IMediaTranscodingService::ERROR_PERMISSION_DENIED,
169 "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
170 "(don't trust callingUid %d)",
171 in_clientPid, in_clientUid, callingUid);
172 }
173
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700174 int32_t jobId = mNextJobId.fetch_add(1);
175
Chong Zhang3f23e982020-09-24 14:03:41 -0700176 *_aidl_return = owner->mJobScheduler->submit(mClientId, jobId, in_clientUid, in_request,
177 mClientCallback);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700178
179 if (*_aidl_return) {
180 out_job->jobId = jobId;
181
182 // TODO(chz): is some of this coming from JobScheduler?
183 *(TranscodingRequest*)&out_job->request = in_request;
184 out_job->awaitNumberOfJobs = 0;
185 }
Chong Zhang15c192a2020-05-05 16:24:00 -0700186
Chong Zhang8e062632020-03-31 10:56:37 -0700187 return Status::ok();
188}
189
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700190Status TranscodingClientManager::ClientImpl::cancelJob(int32_t in_jobId, bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700191 *_aidl_return = false;
192
193 std::shared_ptr<TranscodingClientManager> owner;
194 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
195 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
196 }
197
198 if (in_jobId < 0) {
199 return Status::ok();
200 }
201
202 *_aidl_return = owner->mJobScheduler->cancel(mClientId, in_jobId);
Chong Zhang8e062632020-03-31 10:56:37 -0700203 return Status::ok();
204}
205
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700206Status TranscodingClientManager::ClientImpl::getJobWithId(int32_t in_jobId,
207 TranscodingJobParcel* out_job,
208 bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700209 *_aidl_return = false;
210
211 std::shared_ptr<TranscodingClientManager> owner;
212 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
213 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
214 }
215
216 if (in_jobId < 0) {
217 return Status::ok();
218 }
219
220 *_aidl_return = owner->mJobScheduler->getJob(mClientId, in_jobId, &out_job->request);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700221
222 if (*_aidl_return) {
223 out_job->jobId = in_jobId;
224 out_job->awaitNumberOfJobs = 0;
225 }
Chong Zhang8e062632020-03-31 10:56:37 -0700226 return Status::ok();
227}
228
229Status TranscodingClientManager::ClientImpl::unregister() {
Chong Zhang15c192a2020-05-05 16:24:00 -0700230 bool abandoned = mAbandoned.exchange(true);
231
232 std::shared_ptr<TranscodingClientManager> owner;
233 if (abandoned || (owner = mOwner.lock()) == nullptr) {
234 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
235 }
236
237 // Use jobId == -1 to cancel all realtime jobs for this client with the scheduler.
238 owner->mJobScheduler->cancel(mClientId, -1);
239 owner->removeClient(mClientId);
240
Chong Zhang8e062632020-03-31 10:56:37 -0700241 return Status::ok();
242}
243
244///////////////////////////////////////////////////////////////////////////////
hkuang26587cb2020-01-16 10:36:08 -0800245
246// static
hkuang9c04b8d2020-01-22 10:03:21 -0800247void TranscodingClientManager::BinderDiedCallback(void* cookie) {
Chong Zhang3fa408f2020-04-30 11:04:28 -0700248 ClientIdType clientId = reinterpret_cast<ClientIdType>(cookie);
249
250 ALOGD("Client %lld is dead", (long long)clientId);
251
252 std::shared_ptr<ClientImpl> client;
253
254 {
255 std::scoped_lock lock{sCookie2ClientLock};
256
257 auto it = sCookie2Client.find(clientId);
258 if (it != sCookie2Client.end()) {
259 client = it->second;
260 }
261 }
262
263 if (client != nullptr) {
264 client->unregister();
265 }
hkuang9c04b8d2020-01-22 10:03:21 -0800266}
267
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700268TranscodingClientManager::TranscodingClientManager(
269 const std::shared_ptr<SchedulerClientInterface>& scheduler)
270 : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)), mJobScheduler(scheduler) {
hkuang26587cb2020-01-16 10:36:08 -0800271 ALOGD("TranscodingClientManager started");
272}
273
274TranscodingClientManager::~TranscodingClientManager() {
275 ALOGD("TranscodingClientManager exited");
276}
277
hkuang26587cb2020-01-16 10:36:08 -0800278void TranscodingClientManager::dumpAllClients(int fd, const Vector<String16>& args __unused) {
279 String8 result;
280
281 const size_t SIZE = 256;
282 char buffer[SIZE];
hkuang08b38d02020-04-17 14:29:33 -0700283 std::scoped_lock lock{mLock};
hkuang26587cb2020-01-16 10:36:08 -0800284
Chong Zhang8e062632020-03-31 10:56:37 -0700285 snprintf(buffer, SIZE, " Total num of Clients: %zu\n", mClientIdToClientMap.size());
hkuang26587cb2020-01-16 10:36:08 -0800286 result.append(buffer);
287
Chong Zhang8e062632020-03-31 10:56:37 -0700288 if (mClientIdToClientMap.size() > 0) {
hkuang26587cb2020-01-16 10:36:08 -0800289 snprintf(buffer, SIZE, "========== Dumping all clients =========\n");
290 result.append(buffer);
291 }
292
Chong Zhang8e062632020-03-31 10:56:37 -0700293 for (const auto& iter : mClientIdToClientMap) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700294 snprintf(buffer, SIZE, " -- Client id: %lld name: %s\n", (long long)iter.first,
295 iter.second->mClientName.c_str());
hkuang26587cb2020-01-16 10:36:08 -0800296 result.append(buffer);
297 }
298
299 write(fd, result.string(), result.size());
300}
301
Chong Zhang8e062632020-03-31 10:56:37 -0700302status_t TranscodingClientManager::addClient(
Chong Zhang3f23e982020-09-24 14:03:41 -0700303 const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
304 const std::string& opPackageName, std::shared_ptr<ITranscodingClient>* outClient) {
hkuang26587cb2020-01-16 10:36:08 -0800305 // Validate the client.
Chong Zhang3f23e982020-09-24 14:03:41 -0700306 if (callback == nullptr || clientName.empty() || opPackageName.empty()) {
hkuang26587cb2020-01-16 10:36:08 -0800307 ALOGE("Invalid client");
Chong Zhang15c192a2020-05-05 16:24:00 -0700308 return IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT;
hkuang26587cb2020-01-16 10:36:08 -0800309 }
310
Chong Zhang3fa408f2020-04-30 11:04:28 -0700311 SpAIBinder binder = callback->asBinder();
Chong Zhang8e062632020-03-31 10:56:37 -0700312
hkuang26587cb2020-01-16 10:36:08 -0800313 std::scoped_lock lock{mLock};
314
Chong Zhang8e062632020-03-31 10:56:37 -0700315 // Checks if the client already registers.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700316 if (mRegisteredCallbacks.count((uintptr_t)binder.get()) > 0) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700317 return IMediaTranscodingService::ERROR_ALREADY_EXISTS;
hkuang26587cb2020-01-16 10:36:08 -0800318 }
319
Chong Zhang3f23e982020-09-24 14:03:41 -0700320 // Creates the client (with the id assigned by ClientImpl).
Chong Zhang3fa408f2020-04-30 11:04:28 -0700321 std::shared_ptr<ClientImpl> client = ::ndk::SharedRefBase::make<ClientImpl>(
Chong Zhang3f23e982020-09-24 14:03:41 -0700322 callback, clientName, opPackageName, shared_from_this());
Chong Zhang3fa408f2020-04-30 11:04:28 -0700323
Chong Zhang3f23e982020-09-24 14:03:41 -0700324 ALOGD("Adding client id %lld, name %s, package %s", (long long)client->mClientId,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700325 client->mClientName.c_str(), client->mClientOpPackageName.c_str());
hkuang9c04b8d2020-01-22 10:03:21 -0800326
Chong Zhang3fa408f2020-04-30 11:04:28 -0700327 {
328 std::scoped_lock lock{sCookie2ClientLock};
329 sCookie2Client.emplace(std::make_pair(client->mClientId, client));
330 }
331
332 AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(),
333 reinterpret_cast<void*>(client->mClientId));
hkuang26587cb2020-01-16 10:36:08 -0800334
335 // Adds the new client to the map.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700336 mRegisteredCallbacks.insert((uintptr_t)binder.get());
Chong Zhang8e062632020-03-31 10:56:37 -0700337 mClientIdToClientMap[client->mClientId] = client;
338
339 *outClient = client;
hkuang26587cb2020-01-16 10:36:08 -0800340
341 return OK;
342}
343
Chong Zhang8e062632020-03-31 10:56:37 -0700344status_t TranscodingClientManager::removeClient(ClientIdType clientId) {
345 ALOGD("Removing client id %lld", (long long)clientId);
hkuang26587cb2020-01-16 10:36:08 -0800346 std::scoped_lock lock{mLock};
347
348 // Checks if the client is valid.
Chong Zhang8e062632020-03-31 10:56:37 -0700349 auto it = mClientIdToClientMap.find(clientId);
350 if (it == mClientIdToClientMap.end()) {
351 ALOGE("Client id %lld does not exist", (long long)clientId);
Chong Zhang15c192a2020-05-05 16:24:00 -0700352 return IMediaTranscodingService::ERROR_INVALID_OPERATION;
hkuang26587cb2020-01-16 10:36:08 -0800353 }
354
Chong Zhang3fa408f2020-04-30 11:04:28 -0700355 SpAIBinder binder = it->second->mClientBinder;
hkuang26587cb2020-01-16 10:36:08 -0800356
357 // Check if the client still live. If alive, unlink the death.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700358 if (binder.get() != nullptr) {
359 AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(),
360 reinterpret_cast<void*>(it->second->mClientId));
361 }
362
363 {
364 std::scoped_lock lock{sCookie2ClientLock};
365 sCookie2Client.erase(it->second->mClientId);
hkuang26587cb2020-01-16 10:36:08 -0800366 }
367
368 // Erase the entry.
Chong Zhang8e062632020-03-31 10:56:37 -0700369 mClientIdToClientMap.erase(it);
Chong Zhang3fa408f2020-04-30 11:04:28 -0700370 mRegisteredCallbacks.erase((uintptr_t)binder.get());
hkuang26587cb2020-01-16 10:36:08 -0800371
372 return OK;
373}
374
375size_t TranscodingClientManager::getNumOfClients() const {
376 std::scoped_lock lock{mLock};
Chong Zhang8e062632020-03-31 10:56:37 -0700377 return mClientIdToClientMap.size();
hkuang26587cb2020-01-16 10:36:08 -0800378}
379
hkuang26587cb2020-01-16 10:36:08 -0800380} // namespace android