blob: 82a6dde08c51bb2c11096e32b75371e2a3157937 [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 Zhangc37bdfe2020-10-06 13:54:09 -070026#include <media/TranscodingUidPolicy.h>
Chong Zhang3f23e982020-09-24 14:03:41 -070027#include <private/android_filesystem_config.h>
hkuang26587cb2020-01-16 10:36:08 -080028#include <utils/Log.h>
Chong Zhangc37bdfe2020-10-06 13:54:09 -070029#include <utils/String16.h>
hkuang26587cb2020-01-16 10:36:08 -080030namespace android {
31
Chong Zhang15c192a2020-05-05 16:24:00 -070032static_assert(sizeof(ClientIdType) == sizeof(void*), "ClientIdType should be pointer-sized");
33
Chong Zhangc37bdfe2020-10-06 13:54:09 -070034static constexpr const char* MEDIA_PROVIDER_PKG_NAME = "com.google.android.providers.media.module";
35
Chong Zhang8e062632020-03-31 10:56:37 -070036using ::aidl::android::media::BnTranscodingClient;
Chong Zhang15c192a2020-05-05 16:24:00 -070037using ::aidl::android::media::IMediaTranscodingService; // For service error codes
Chong Zhang8e062632020-03-31 10:56:37 -070038using ::aidl::android::media::TranscodingJobParcel;
39using ::aidl::android::media::TranscodingRequestParcel;
hkuang26587cb2020-01-16 10:36:08 -080040using Status = ::ndk::ScopedAStatus;
Chong Zhang8e062632020-03-31 10:56:37 -070041using ::ndk::SpAIBinder;
42
Chong Zhang3fa408f2020-04-30 11:04:28 -070043//static
44std::atomic<ClientIdType> TranscodingClientManager::sCookieCounter = 0;
45//static
46std::mutex TranscodingClientManager::sCookie2ClientLock;
47//static
48std::map<ClientIdType, std::shared_ptr<TranscodingClientManager::ClientImpl>>
49 TranscodingClientManager::sCookie2Client;
Chong Zhang8e062632020-03-31 10:56:37 -070050///////////////////////////////////////////////////////////////////////////////
51
Chong Zhang3f23e982020-09-24 14:03:41 -070052// Convenience methods for constructing binder::Status objects for error returns
53#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
54 Status::fromServiceSpecificErrorWithMessage( \
55 errorCode, \
56 String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
57
Chong Zhang8e062632020-03-31 10:56:37 -070058/**
59 * ClientImpl implements a single client and contains all its information.
60 */
61struct TranscodingClientManager::ClientImpl : public BnTranscodingClient {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070062 /* The remote client callback that this ClientInfo is associated with.
Chong Zhang8e062632020-03-31 10:56:37 -070063 * Once the ClientInfo is created, we hold an SpAIBinder so that the binder
64 * object doesn't get created again, otherwise the binder object pointer
65 * may not be unique.
66 */
Chong Zhangacb33502020-04-20 11:04:48 -070067 SpAIBinder mClientBinder;
68 std::shared_ptr<ITranscodingClientCallback> mClientCallback;
Chong Zhang8e062632020-03-31 10:56:37 -070069 /* A unique id assigned to the client by the service. This number is used
70 * by the service for indexing. Here we use the binder object's pointer
71 * (casted to int64t_t) as the client id.
72 */
73 ClientIdType mClientId;
Chong Zhang8e062632020-03-31 10:56:37 -070074 std::string mClientName;
75 std::string mClientOpPackageName;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070076
Chong Zhang15c192a2020-05-05 16:24:00 -070077 // Next jobId to assign.
Chong Zhang3fa408f2020-04-30 11:04:28 -070078 std::atomic<int32_t> mNextJobId;
Chong Zhang15c192a2020-05-05 16:24:00 -070079 // Whether this client has been unregistered already.
80 std::atomic<bool> mAbandoned;
81 // Weak pointer to the client manager for this client.
82 std::weak_ptr<TranscodingClientManager> mOwner;
Chong Zhang8e062632020-03-31 10:56:37 -070083
Chong Zhang3f23e982020-09-24 14:03:41 -070084 ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback,
hkuang08b38d02020-04-17 14:29:33 -070085 const std::string& clientName, const std::string& opPackageName,
Chong Zhang15c192a2020-05-05 16:24:00 -070086 const std::weak_ptr<TranscodingClientManager>& owner);
Chong Zhang8e062632020-03-31 10:56:37 -070087
88 Status submitRequest(const TranscodingRequestParcel& /*in_request*/,
Chong Zhang6d58e4b2020-03-31 09:41:10 -070089 TranscodingJobParcel* /*out_job*/, bool* /*_aidl_return*/) override;
Chong Zhang8e062632020-03-31 10:56:37 -070090
91 Status cancelJob(int32_t /*in_jobId*/, bool* /*_aidl_return*/) override;
92
Chong Zhang6d58e4b2020-03-31 09:41:10 -070093 Status getJobWithId(int32_t /*in_jobId*/, TranscodingJobParcel* /*out_job*/,
94 bool* /*_aidl_return*/) override;
Chong Zhang8e062632020-03-31 10:56:37 -070095
96 Status unregister() override;
97};
98
99TranscodingClientManager::ClientImpl::ClientImpl(
Chong Zhang3f23e982020-09-24 14:03:41 -0700100 const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
101 const std::string& opPackageName, const std::weak_ptr<TranscodingClientManager>& owner)
Chong Zhangacb33502020-04-20 11:04:48 -0700102 : mClientBinder((callback != nullptr) ? callback->asBinder() : nullptr),
103 mClientCallback(callback),
Chong Zhang3fa408f2020-04-30 11:04:28 -0700104 mClientId(sCookieCounter.fetch_add(1, std::memory_order_relaxed)),
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700105 mClientName(clientName),
106 mClientOpPackageName(opPackageName),
107 mNextJobId(0),
Chong Zhang15c192a2020-05-05 16:24:00 -0700108 mAbandoned(false),
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700109 mOwner(owner) {}
Chong Zhang8e062632020-03-31 10:56:37 -0700110
111Status TranscodingClientManager::ClientImpl::submitRequest(
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700112 const TranscodingRequestParcel& in_request, TranscodingJobParcel* out_job,
113 bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700114 *_aidl_return = false;
115
116 std::shared_ptr<TranscodingClientManager> owner;
117 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
118 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
119 }
120
hkuang72d105f2020-05-21 10:48:55 -0700121 if (in_request.sourceFilePath.empty() || in_request.destinationFilePath.empty()) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700122 return Status::ok();
123 }
124
Chong Zhang3f23e982020-09-24 14:03:41 -0700125 int32_t callingPid = AIBinder_getCallingPid();
126 int32_t callingUid = AIBinder_getCallingUid();
127 int32_t in_clientUid = in_request.clientUid;
128 int32_t in_clientPid = in_request.clientPid;
129
130 // Check if we can trust clientUid. Only privilege caller could forward the
131 // uid on app client's behalf.
132 if (in_clientUid == IMediaTranscodingService::USE_CALLING_UID) {
133 in_clientUid = callingUid;
134 } else if (in_clientUid < 0) {
135 return Status::ok();
Chong Zhangc37bdfe2020-10-06 13:54:09 -0700136 } else if (in_clientUid != callingUid && !owner->isTrustedCallingUid(callingUid)) {
Chong Zhang3f23e982020-09-24 14:03:41 -0700137 ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
138 "(don't trust callingUid %d)",
139 in_clientPid, in_clientUid, callingUid);
140 return STATUS_ERROR_FMT(
141 IMediaTranscodingService::ERROR_PERMISSION_DENIED,
142 "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
143 "(don't trust callingUid %d)",
144 in_clientPid, in_clientUid, callingUid);
145 }
146
147 // Check if we can trust clientPid. Only privilege caller could forward the
148 // pid on app client's behalf.
149 if (in_clientPid == IMediaTranscodingService::USE_CALLING_PID) {
150 in_clientPid = callingPid;
151 } else if (in_clientPid < 0) {
152 return Status::ok();
Chong Zhangc37bdfe2020-10-06 13:54:09 -0700153 } else if (in_clientPid != callingPid && !owner->isTrustedCallingUid(callingUid)) {
Chong Zhang3f23e982020-09-24 14:03:41 -0700154 ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
155 "(don't trust callingUid %d)",
156 in_clientPid, in_clientUid, callingUid);
157 return STATUS_ERROR_FMT(
158 IMediaTranscodingService::ERROR_PERMISSION_DENIED,
159 "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
160 "(don't trust callingUid %d)",
161 in_clientPid, in_clientUid, callingUid);
162 }
163
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700164 int32_t jobId = mNextJobId.fetch_add(1);
165
Chong Zhang3f23e982020-09-24 14:03:41 -0700166 *_aidl_return = owner->mJobScheduler->submit(mClientId, jobId, in_clientUid, in_request,
167 mClientCallback);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700168
169 if (*_aidl_return) {
170 out_job->jobId = jobId;
171
172 // TODO(chz): is some of this coming from JobScheduler?
173 *(TranscodingRequest*)&out_job->request = in_request;
174 out_job->awaitNumberOfJobs = 0;
175 }
Chong Zhang15c192a2020-05-05 16:24:00 -0700176
Chong Zhang8e062632020-03-31 10:56:37 -0700177 return Status::ok();
178}
179
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700180Status TranscodingClientManager::ClientImpl::cancelJob(int32_t in_jobId, bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700181 *_aidl_return = false;
182
183 std::shared_ptr<TranscodingClientManager> owner;
184 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
185 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
186 }
187
188 if (in_jobId < 0) {
189 return Status::ok();
190 }
191
192 *_aidl_return = owner->mJobScheduler->cancel(mClientId, in_jobId);
Chong Zhang8e062632020-03-31 10:56:37 -0700193 return Status::ok();
194}
195
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700196Status TranscodingClientManager::ClientImpl::getJobWithId(int32_t in_jobId,
197 TranscodingJobParcel* out_job,
198 bool* _aidl_return) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700199 *_aidl_return = false;
200
201 std::shared_ptr<TranscodingClientManager> owner;
202 if (mAbandoned || (owner = mOwner.lock()) == nullptr) {
203 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
204 }
205
206 if (in_jobId < 0) {
207 return Status::ok();
208 }
209
210 *_aidl_return = owner->mJobScheduler->getJob(mClientId, in_jobId, &out_job->request);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700211
212 if (*_aidl_return) {
213 out_job->jobId = in_jobId;
214 out_job->awaitNumberOfJobs = 0;
215 }
Chong Zhang8e062632020-03-31 10:56:37 -0700216 return Status::ok();
217}
218
219Status TranscodingClientManager::ClientImpl::unregister() {
Chong Zhang15c192a2020-05-05 16:24:00 -0700220 bool abandoned = mAbandoned.exchange(true);
221
222 std::shared_ptr<TranscodingClientManager> owner;
223 if (abandoned || (owner = mOwner.lock()) == nullptr) {
224 return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
225 }
226
227 // Use jobId == -1 to cancel all realtime jobs for this client with the scheduler.
228 owner->mJobScheduler->cancel(mClientId, -1);
229 owner->removeClient(mClientId);
230
Chong Zhang8e062632020-03-31 10:56:37 -0700231 return Status::ok();
232}
233
234///////////////////////////////////////////////////////////////////////////////
hkuang26587cb2020-01-16 10:36:08 -0800235
236// static
hkuang9c04b8d2020-01-22 10:03:21 -0800237void TranscodingClientManager::BinderDiedCallback(void* cookie) {
Chong Zhang3fa408f2020-04-30 11:04:28 -0700238 ClientIdType clientId = reinterpret_cast<ClientIdType>(cookie);
239
240 ALOGD("Client %lld is dead", (long long)clientId);
241
242 std::shared_ptr<ClientImpl> client;
243
244 {
245 std::scoped_lock lock{sCookie2ClientLock};
246
247 auto it = sCookie2Client.find(clientId);
248 if (it != sCookie2Client.end()) {
249 client = it->second;
250 }
251 }
252
253 if (client != nullptr) {
254 client->unregister();
255 }
hkuang9c04b8d2020-01-22 10:03:21 -0800256}
257
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700258TranscodingClientManager::TranscodingClientManager(
259 const std::shared_ptr<SchedulerClientInterface>& scheduler)
Chong Zhangc37bdfe2020-10-06 13:54:09 -0700260 : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)),
261 mJobScheduler(scheduler),
262 mMediaProviderUid(-1) {
hkuang26587cb2020-01-16 10:36:08 -0800263 ALOGD("TranscodingClientManager started");
Chong Zhangc37bdfe2020-10-06 13:54:09 -0700264 uid_t mpuid;
265 if (TranscodingUidPolicy::getUidForPackage(String16(MEDIA_PROVIDER_PKG_NAME), mpuid) ==
266 NO_ERROR) {
267 ALOGI("Found MediaProvider uid: %d", mpuid);
268 mMediaProviderUid = mpuid;
269 } else {
270 ALOGW("Couldn't get uid for MediaProvider.");
271 }
hkuang26587cb2020-01-16 10:36:08 -0800272}
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 if (mClientIdToClientMap.size() > 0) {
Chong Zhang0579c6f2020-10-05 12:03:34 -0700286 snprintf(buffer, SIZE, "\n========== Dumping all clients =========\n");
hkuang26587cb2020-01-16 10:36:08 -0800287 result.append(buffer);
288 }
289
Chong Zhang0579c6f2020-10-05 12:03:34 -0700290 snprintf(buffer, SIZE, " Total num of Clients: %zu\n", mClientIdToClientMap.size());
291 result.append(buffer);
292
Chong Zhang8e062632020-03-31 10:56:37 -0700293 for (const auto& iter : mClientIdToClientMap) {
Chong Zhang0579c6f2020-10-05 12:03:34 -0700294 snprintf(buffer, SIZE, " Client %lld: pkg: %s\n", (long long)iter.first,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700295 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 Zhangc37bdfe2020-10-06 13:54:09 -0700302bool TranscodingClientManager::isTrustedCallingUid(uid_t uid) {
303 if (uid > 0 && uid == mMediaProviderUid) {
304 return true;
305 }
306
307 switch (uid) {
308 case AID_ROOT: // root user
309 case AID_SYSTEM:
310 case AID_SHELL:
311 case AID_MEDIA: // mediaserver
312 return true;
313 default:
314 return false;
315 }
316}
317
Chong Zhang8e062632020-03-31 10:56:37 -0700318status_t TranscodingClientManager::addClient(
Chong Zhang3f23e982020-09-24 14:03:41 -0700319 const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
320 const std::string& opPackageName, std::shared_ptr<ITranscodingClient>* outClient) {
hkuang26587cb2020-01-16 10:36:08 -0800321 // Validate the client.
Chong Zhang3f23e982020-09-24 14:03:41 -0700322 if (callback == nullptr || clientName.empty() || opPackageName.empty()) {
hkuang26587cb2020-01-16 10:36:08 -0800323 ALOGE("Invalid client");
Chong Zhang15c192a2020-05-05 16:24:00 -0700324 return IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT;
hkuang26587cb2020-01-16 10:36:08 -0800325 }
326
Chong Zhang3fa408f2020-04-30 11:04:28 -0700327 SpAIBinder binder = callback->asBinder();
Chong Zhang8e062632020-03-31 10:56:37 -0700328
hkuang26587cb2020-01-16 10:36:08 -0800329 std::scoped_lock lock{mLock};
330
Chong Zhang8e062632020-03-31 10:56:37 -0700331 // Checks if the client already registers.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700332 if (mRegisteredCallbacks.count((uintptr_t)binder.get()) > 0) {
Chong Zhang15c192a2020-05-05 16:24:00 -0700333 return IMediaTranscodingService::ERROR_ALREADY_EXISTS;
hkuang26587cb2020-01-16 10:36:08 -0800334 }
335
Chong Zhang3f23e982020-09-24 14:03:41 -0700336 // Creates the client (with the id assigned by ClientImpl).
Chong Zhang3fa408f2020-04-30 11:04:28 -0700337 std::shared_ptr<ClientImpl> client = ::ndk::SharedRefBase::make<ClientImpl>(
Chong Zhang3f23e982020-09-24 14:03:41 -0700338 callback, clientName, opPackageName, shared_from_this());
Chong Zhang3fa408f2020-04-30 11:04:28 -0700339
Chong Zhang3f23e982020-09-24 14:03:41 -0700340 ALOGD("Adding client id %lld, name %s, package %s", (long long)client->mClientId,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700341 client->mClientName.c_str(), client->mClientOpPackageName.c_str());
hkuang9c04b8d2020-01-22 10:03:21 -0800342
Chong Zhang3fa408f2020-04-30 11:04:28 -0700343 {
344 std::scoped_lock lock{sCookie2ClientLock};
345 sCookie2Client.emplace(std::make_pair(client->mClientId, client));
346 }
347
348 AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(),
349 reinterpret_cast<void*>(client->mClientId));
hkuang26587cb2020-01-16 10:36:08 -0800350
351 // Adds the new client to the map.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700352 mRegisteredCallbacks.insert((uintptr_t)binder.get());
Chong Zhang8e062632020-03-31 10:56:37 -0700353 mClientIdToClientMap[client->mClientId] = client;
354
355 *outClient = client;
hkuang26587cb2020-01-16 10:36:08 -0800356
357 return OK;
358}
359
Chong Zhang8e062632020-03-31 10:56:37 -0700360status_t TranscodingClientManager::removeClient(ClientIdType clientId) {
361 ALOGD("Removing client id %lld", (long long)clientId);
hkuang26587cb2020-01-16 10:36:08 -0800362 std::scoped_lock lock{mLock};
363
364 // Checks if the client is valid.
Chong Zhang8e062632020-03-31 10:56:37 -0700365 auto it = mClientIdToClientMap.find(clientId);
366 if (it == mClientIdToClientMap.end()) {
367 ALOGE("Client id %lld does not exist", (long long)clientId);
Chong Zhang15c192a2020-05-05 16:24:00 -0700368 return IMediaTranscodingService::ERROR_INVALID_OPERATION;
hkuang26587cb2020-01-16 10:36:08 -0800369 }
370
Chong Zhang3fa408f2020-04-30 11:04:28 -0700371 SpAIBinder binder = it->second->mClientBinder;
hkuang26587cb2020-01-16 10:36:08 -0800372
373 // Check if the client still live. If alive, unlink the death.
Chong Zhang3fa408f2020-04-30 11:04:28 -0700374 if (binder.get() != nullptr) {
375 AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(),
376 reinterpret_cast<void*>(it->second->mClientId));
377 }
378
379 {
380 std::scoped_lock lock{sCookie2ClientLock};
381 sCookie2Client.erase(it->second->mClientId);
hkuang26587cb2020-01-16 10:36:08 -0800382 }
383
384 // Erase the entry.
Chong Zhang8e062632020-03-31 10:56:37 -0700385 mClientIdToClientMap.erase(it);
Chong Zhang3fa408f2020-04-30 11:04:28 -0700386 mRegisteredCallbacks.erase((uintptr_t)binder.get());
hkuang26587cb2020-01-16 10:36:08 -0800387
388 return OK;
389}
390
391size_t TranscodingClientManager::getNumOfClients() const {
392 std::scoped_lock lock{mLock};
Chong Zhang8e062632020-03-31 10:56:37 -0700393 return mClientIdToClientMap.size();
hkuang26587cb2020-01-16 10:36:08 -0800394}
395
hkuang26587cb2020-01-16 10:36:08 -0800396} // namespace android