1 /*
2 * Copyright 2018 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 "Codec2Client"
19 #define ATRACE_TAG ATRACE_TAG_VIDEO
20 #include <android-base/logging.h>
21 #include <utils/Trace.h>
22
23 #include <android_media_codec.h>
24
25 #include <codec2/aidl/GraphicBufferAllocator.h>
26 #include <codec2/common/HalSelection.h>
27 #include <codec2/hidl/client.h>
28
29 #include <C2Debug.h>
30 #include <C2BufferPriv.h>
31 #include <C2Config.h> // for C2StreamUsageTuning
32 #include <C2PlatformSupport.h>
33
34 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
35 #include <android/hardware/media/c2/1.0/IComponent.h>
36 #include <android/hardware/media/c2/1.0/IComponentInterface.h>
37 #include <android/hardware/media/c2/1.0/IComponentListener.h>
38 #include <android/hardware/media/c2/1.0/IComponentStore.h>
39 #include <android/hardware/media/c2/1.0/IConfigurable.h>
40 #include <android/hidl/manager/1.2/IServiceManager.h>
41
42 #include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
43 #include <aidl/android/hardware/media/c2/BnComponentListener.h>
44 #include <aidl/android/hardware/media/c2/FieldSupportedValues.h>
45 #include <aidl/android/hardware/media/c2/FieldSupportedValuesQuery.h>
46 #include <aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.h>
47 #include <aidl/android/hardware/media/c2/IComponent.h>
48 #include <aidl/android/hardware/media/c2/IComponentInterface.h>
49 #include <aidl/android/hardware/media/c2/IComponentStore.h>
50 #include <aidl/android/hardware/media/c2/IConfigurable.h>
51 #include <aidl/android/hardware/media/c2/ParamDescriptor.h>
52 #include <aidl/android/hardware/media/c2/StructDescriptor.h>
53
54 #include <aidlcommonsupport/NativeHandle.h>
55 #include <android/api-level.h>
56 #include <android/binder_auto_utils.h>
57 #include <android/binder_ibinder.h>
58 #include <android/binder_manager.h>
59 #include <android-base/properties.h>
60 #include <android-base/scopeguard.h>
61 #include <android-base/stringprintf.h>
62 #include <apex/ApexCodecs.h>
63 #include <bufferpool/ClientManager.h>
64 #include <bufferpool2/ClientManager.h>
65 #include <codec2/aidl/BufferTypes.h>
66 #include <codec2/aidl/ParamTypes.h>
67 #include <codec2/hidl/1.0/types.h>
68 #include <codec2/hidl/1.1/types.h>
69 #include <codec2/hidl/1.2/types.h>
70 #include <codec2/hidl/output.h>
71 #include <cutils/native_handle.h>
72 #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
73 #include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
74 #include <hardware/gralloc.h> // for GRALLOC_USAGE_*
75 #include <hidl/HidlSupport.h>
76 #include <media/stagefright/foundation/ADebug.h> // for asString(status_t)
77 #include <private/android/AHardwareBufferHelpers.h>
78 #include <system/window.h> // for NATIVE_WINDOW_QUERY_*
79
80 #include <deque>
81 #include <iterator>
82 #include <limits>
83 #include <map>
84 #include <mutex>
85 #include <optional>
86 #include <sstream>
87 #include <thread>
88 #include <type_traits>
89 #include <vector>
90
91 namespace android {
92
93 using ::android::hardware::hidl_vec;
94 using ::android::hardware::hidl_string;
95 using ::android::hardware::Return;
96 using ::android::hardware::Void;
97
98 using HGraphicBufferProducer1 = ::android::hardware::graphics::bufferqueue::
99 V1_0::IGraphicBufferProducer;
100 using HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
101 V2_0::IGraphicBufferProducer;
102 using B2HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
103 V2_0::utils::B2HGraphicBufferProducer;
104 using H2BGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
105 V2_0::utils::H2BGraphicBufferProducer;
106 using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
107
108 using AidlGraphicBufferAllocator = ::aidl::android::hardware::media::c2::
109 implementation::GraphicBufferAllocator;
110
111 namespace bufferpool2_aidl = ::aidl::android::hardware::media::bufferpool2;
112 namespace bufferpool_hidl = ::android::hardware::media::bufferpool::V2_0;
113 namespace c2_aidl = ::aidl::android::hardware::media::c2;
114 namespace c2_hidl_base = ::android::hardware::media::c2;
115 namespace c2_hidl = ::android::hardware::media::c2::V1_2;
116
117 using c2_hidl::utils::operator<<;
118
119 namespace /* unnamed */ {
120
121 // c2_status_t value that corresponds to hwbinder transaction failure.
122 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
123
124 // By default prepare buffer to be displayed on any of the common surfaces
125 constexpr uint64_t kDefaultConsumerUsage =
126 (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER);
127
128 // Searches for a name in GetServiceNames() and returns the index found. If the
129 // name is not found, the returned index will be equal to
130 // GetServiceNames().size().
getServiceIndex(char const * name)131 size_t getServiceIndex(char const* name) {
132 std::vector<std::string> const& names = Codec2Client::GetServiceNames();
133 size_t i = 0;
134 for (; i < names.size(); ++i) {
135 if (name == names[i]) {
136 break;
137 }
138 }
139 return i;
140 }
141
142 class Client2Store : public C2ComponentStore {
143 std::shared_ptr<Codec2Client> mClient;
144
145 public:
Client2Store(std::shared_ptr<Codec2Client> const & client)146 Client2Store(std::shared_ptr<Codec2Client> const& client)
147 : mClient(client) { }
148
149 virtual ~Client2Store() = default;
150
config_sm(std::vector<C2Param * > const & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)151 virtual c2_status_t config_sm(
152 std::vector<C2Param*> const ¶ms,
153 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
154 return mClient->config(params, C2_MAY_BLOCK, failures);
155 };
156
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)157 virtual c2_status_t copyBuffer(
158 std::shared_ptr<C2GraphicBuffer>,
159 std::shared_ptr<C2GraphicBuffer>) {
160 return C2_OMITTED;
161 }
162
createComponent(C2String,std::shared_ptr<C2Component> * const component)163 virtual c2_status_t createComponent(
164 C2String, std::shared_ptr<C2Component>* const component) {
165 component->reset();
166 return C2_OMITTED;
167 }
168
createInterface(C2String,std::shared_ptr<C2ComponentInterface> * const interface)169 virtual c2_status_t createInterface(
170 C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
171 interface->reset();
172 return C2_OMITTED;
173 }
174
query_sm(std::vector<C2Param * > const & stackParams,std::vector<C2Param::Index> const & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const175 virtual c2_status_t query_sm(
176 std::vector<C2Param*> const& stackParams,
177 std::vector<C2Param::Index> const& heapParamIndices,
178 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
179 return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
180 }
181
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const182 virtual c2_status_t querySupportedParams_nb(
183 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
184 return mClient->querySupportedParams(params);
185 }
186
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const187 virtual c2_status_t querySupportedValues_sm(
188 std::vector<C2FieldSupportedValuesQuery>& fields) const {
189 return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
190 }
191
getName() const192 virtual C2String getName() const {
193 return mClient->getName();
194 }
195
getParamReflector() const196 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
197 return mClient->getParamReflector();
198 }
199
listComponents()200 virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
201 return std::vector<std::shared_ptr<C2Component::Traits const>>();
202 }
203 };
204
GetC2Status(const::ndk::ScopedAStatus & transStatus,const char * method)205 c2_status_t GetC2Status(const ::ndk::ScopedAStatus &transStatus, const char *method) {
206 if (!transStatus.isOk()) {
207 if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
208 c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
209 LOG(DEBUG) << method << " -- call failed: " << status << ".";
210 return status;
211 } else {
212 LOG(ERROR) << method << " -- transaction failed.";
213 return C2_TRANSACTION_FAILED;
214 }
215 }
216 return C2_OK;
217 }
218
219 } // unnamed namespace
220
221 // This class caches a Codec2Client object and its component traits. The client
222 // will be created the first time it is needed, and it can be refreshed if the
223 // service dies (by calling invalidate()). The first time listComponents() is
224 // called from the client, the result will be cached.
225 class Codec2Client::Cache {
226 // Cached client
227 std::shared_ptr<Codec2Client> mClient;
228 mutable std::mutex mClientMutex;
229
230 // Cached component traits
231 std::vector<C2Component::Traits> mTraits;
232 std::once_flag mTraitsInitializationFlag;
233
234 // The index of the service. This is based on GetServiceNames().
235 size_t mIndex;
236 // Called by s() exactly once to initialize the cache. The index must be a
237 // valid index into the vector returned by GetServiceNames(). Calling
238 // init(index) will associate the cache to the service with name
239 // GetServiceNames()[index].
init(size_t index)240 void init(size_t index) {
241 mIndex = index;
242 }
243
244 public:
245 Cache() = default;
246
247 // Initializes mClient if needed, then returns mClient.
248 // If the service is unavailable but listed in the manifest, this function
249 // will block indefinitely.
getClient()250 std::shared_ptr<Codec2Client> getClient() {
251 std::scoped_lock lock{mClientMutex};
252 if (!mClient) {
253 mClient = Codec2Client::_CreateFromIndex(mIndex);
254 }
255 CHECK(mClient) << "Failed to create Codec2Client to service \""
256 << GetServiceNames()[mIndex] << "\". (Index = "
257 << mIndex << ").";
258 return mClient;
259 }
260
261 // Causes a subsequent call to getClient() to create a new client. This
262 // function should be called after the service dies.
263 //
264 // Note: This function is called only by ForAllServices().
invalidate()265 void invalidate() {
266 std::scoped_lock lock{mClientMutex};
267 mClient = nullptr;
268 }
269
270 // Returns a list of traits for components supported by the service. This
271 // list is cached.
getTraits()272 std::vector<C2Component::Traits> const& getTraits() {
273 std::call_once(mTraitsInitializationFlag, [this]() {
274 bool success{false};
275 // Spin until _listComponents() is successful.
276 while (true) {
277 std::shared_ptr<Codec2Client> client = getClient();
278 mTraits = client->_listComponents(&success);
279 if (success) {
280 break;
281 }
282 invalidate();
283 using namespace std::chrono_literals;
284 static constexpr auto kServiceRetryPeriod = 5s;
285 LOG(INFO) << "Failed to retrieve component traits from service "
286 "\"" << GetServiceNames()[mIndex] << "\". "
287 "Retrying...";
288 std::this_thread::sleep_for(kServiceRetryPeriod);
289 }
290 });
291 return mTraits;
292 }
293
294 // List() returns the list of all caches.
List()295 static std::vector<Cache>& List() {
296 static std::vector<Cache> sCaches{[]() {
297 size_t numServices = GetServiceNames().size();
298 std::vector<Cache> caches(numServices);
299 for (size_t i = 0; i < numServices; ++i) {
300 caches[i].init(i);
301 }
302 return caches;
303 }()};
304 return sCaches;
305 }
306 };
307 // Codec2ConfigurableClient::HidlImpl
308
309 struct Codec2ConfigurableClient::HidlImpl : public Codec2ConfigurableClient::ImplBase {
310 typedef c2_hidl::IConfigurable Base;
311
312 // base cannot be null.
313 explicit HidlImpl(const sp<Base>& base);
314
getNameandroid::Codec2ConfigurableClient::HidlImpl315 const C2String& getName() const override {
316 return mName;
317 }
318
319 c2_status_t query(
320 const std::vector<C2Param*>& stackParams,
321 const std::vector<C2Param::Index> &heapParamIndices,
322 c2_blocking_t mayBlock,
323 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
324
325 c2_status_t config(
326 const std::vector<C2Param*> ¶ms,
327 c2_blocking_t mayBlock,
328 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
329
330 c2_status_t querySupportedParams(
331 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
332 ) const override;
333
334 c2_status_t querySupportedValues(
335 std::vector<C2FieldSupportedValuesQuery>& fields,
336 c2_blocking_t mayBlock) const override;
337
338 private:
339 sp<Base> mBase;
340 const C2String mName;
341 };
342
HidlImpl(const sp<Base> & base)343 Codec2ConfigurableClient::HidlImpl::HidlImpl(const sp<Base>& base)
344 : mBase{base},
__anon3331b31b0402() 345 mName{[base]() -> C2String {
346 C2String outName;
347 Return<void> transStatus = base->getName(
348 [&outName](const hidl_string& name) {
349 outName = name.c_str();
350 });
351 return transStatus.isOk() ? outName : "";
352 }()} {
353 }
354
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const355 c2_status_t Codec2ConfigurableClient::HidlImpl::query(
356 const std::vector<C2Param*> &stackParams,
357 const std::vector<C2Param::Index> &heapParamIndices,
358 c2_blocking_t mayBlock,
359 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
360 hidl_vec<c2_hidl::ParamIndex> indices(
361 stackParams.size() + heapParamIndices.size());
362 size_t numIndices = 0;
363 for (C2Param* const& stackParam : stackParams) {
364 if (!stackParam) {
365 LOG(WARNING) << "query -- null stack param encountered.";
366 continue;
367 }
368 indices[numIndices++] = static_cast<c2_hidl::ParamIndex>(stackParam->index());
369 }
370 size_t numStackIndices = numIndices;
371 for (const C2Param::Index& index : heapParamIndices) {
372 indices[numIndices++] =
373 static_cast<c2_hidl::ParamIndex>(static_cast<uint32_t>(index));
374 }
375 indices.resize(numIndices);
376 if (heapParams) {
377 heapParams->reserve(heapParams->size() + numIndices);
378 }
379 c2_status_t status;
380 Return<void> transStatus = mBase->query(
381 indices,
382 mayBlock == C2_MAY_BLOCK,
383 [&status, &numStackIndices, &stackParams, heapParams](
384 c2_hidl::Status s, const c2_hidl::Params& p) {
385 status = static_cast<c2_status_t>(s);
386 if (status != C2_OK && status != C2_BAD_INDEX) {
387 LOG(DEBUG) << "query -- call failed: "
388 << status << ".";
389 return;
390 }
391 std::vector<C2Param*> paramPointers;
392 if (!c2_hidl::utils::parseParamsBlob(¶mPointers, p)) {
393 LOG(ERROR) << "query -- error while parsing params.";
394 status = C2_CORRUPTED;
395 return;
396 }
397 size_t i = 0;
398 for (auto it = paramPointers.begin();
399 it != paramPointers.end(); ) {
400 C2Param* paramPointer = *it;
401 if (numStackIndices > 0) {
402 --numStackIndices;
403 if (!paramPointer) {
404 LOG(WARNING) << "query -- null stack param.";
405 ++it;
406 continue;
407 }
408 for (; i < stackParams.size() && !stackParams[i]; ) {
409 ++i;
410 }
411 if (i >= stackParams.size()) {
412 LOG(ERROR) << "query -- unexpected error.";
413 status = C2_CORRUPTED;
414 return;
415 }
416 if (stackParams[i]->index() != paramPointer->index()) {
417 LOG(WARNING) << "query -- param skipped: "
418 "index = "
419 << stackParams[i]->index() << ".";
420 stackParams[i++]->invalidate();
421 continue;
422 }
423 if (!stackParams[i++]->updateFrom(*paramPointer)) {
424 LOG(WARNING) << "query -- param update failed: "
425 "index = "
426 << paramPointer->index() << ".";
427 }
428 } else {
429 if (!paramPointer) {
430 LOG(WARNING) << "query -- null heap param.";
431 ++it;
432 continue;
433 }
434 if (!heapParams) {
435 LOG(WARNING) << "query -- "
436 "unexpected extra stack param.";
437 } else {
438 heapParams->emplace_back(
439 C2Param::Copy(*paramPointer));
440 }
441 }
442 ++it;
443 }
444 });
445 if (!transStatus.isOk()) {
446 LOG(ERROR) << "query -- transaction failed.";
447 return C2_TRANSACTION_FAILED;
448 }
449 return status;
450 }
451
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)452 c2_status_t Codec2ConfigurableClient::HidlImpl::config(
453 const std::vector<C2Param*> ¶ms,
454 c2_blocking_t mayBlock,
455 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
456 c2_hidl::Params hidlParams;
457 if (!c2_hidl::utils::createParamsBlob(&hidlParams, params)) {
458 LOG(ERROR) << "config -- bad input.";
459 return C2_TRANSACTION_FAILED;
460 }
461 c2_status_t status;
462 Return<void> transStatus = mBase->config(
463 hidlParams,
464 mayBlock == C2_MAY_BLOCK,
465 [&status, ¶ms, failures](
466 c2_hidl::Status s,
467 const hidl_vec<c2_hidl::SettingResult> f,
468 const c2_hidl::Params& o) {
469 status = static_cast<c2_status_t>(s);
470 if (status != C2_OK && status != C2_BAD_INDEX) {
471 LOG(DEBUG) << "config -- call failed: "
472 << status << ".";
473 }
474 size_t i = failures->size();
475 failures->resize(i + f.size());
476 for (const c2_hidl::SettingResult& sf : f) {
477 if (!c2_hidl::utils::objcpy(&(*failures)[i++], sf)) {
478 LOG(ERROR) << "config -- "
479 << "invalid SettingResult returned.";
480 return;
481 }
482 }
483 if (!c2_hidl::utils::updateParamsFromBlob(params, o)) {
484 LOG(ERROR) << "config -- "
485 << "failed to parse returned params.";
486 status = C2_CORRUPTED;
487 }
488 });
489 if (!transStatus.isOk()) {
490 LOG(ERROR) << "config -- transaction failed.";
491 return C2_TRANSACTION_FAILED;
492 }
493 return status;
494 }
495
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const496 c2_status_t Codec2ConfigurableClient::HidlImpl::querySupportedParams(
497 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
498 // TODO: Cache and query properly!
499 c2_status_t status;
500 Return<void> transStatus = mBase->querySupportedParams(
501 std::numeric_limits<uint32_t>::min(),
502 std::numeric_limits<uint32_t>::max(),
503 [&status, params](
504 c2_hidl::Status s,
505 const hidl_vec<c2_hidl::ParamDescriptor>& p) {
506 status = static_cast<c2_status_t>(s);
507 if (status != C2_OK) {
508 LOG(DEBUG) << "querySupportedParams -- call failed: "
509 << status << ".";
510 return;
511 }
512 size_t i = params->size();
513 params->resize(i + p.size());
514 for (const c2_hidl::ParamDescriptor& sp : p) {
515 if (!c2_hidl::utils::objcpy(&(*params)[i++], sp)) {
516 LOG(ERROR) << "querySupportedParams -- "
517 << "invalid returned ParamDescriptor.";
518 return;
519 }
520 }
521 });
522 if (!transStatus.isOk()) {
523 LOG(ERROR) << "querySupportedParams -- transaction failed.";
524 return C2_TRANSACTION_FAILED;
525 }
526 return status;
527 }
528
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const529 c2_status_t Codec2ConfigurableClient::HidlImpl::querySupportedValues(
530 std::vector<C2FieldSupportedValuesQuery>& fields,
531 c2_blocking_t mayBlock) const {
532 hidl_vec<c2_hidl::FieldSupportedValuesQuery> inFields(fields.size());
533 for (size_t i = 0; i < fields.size(); ++i) {
534 if (!c2_hidl::utils::objcpy(&inFields[i], fields[i])) {
535 LOG(ERROR) << "querySupportedValues -- bad input";
536 return C2_TRANSACTION_FAILED;
537 }
538 }
539
540 c2_status_t status;
541 Return<void> transStatus = mBase->querySupportedValues(
542 inFields,
543 mayBlock == C2_MAY_BLOCK,
544 [&status, &inFields, &fields](
545 c2_hidl::Status s,
546 const hidl_vec<c2_hidl::FieldSupportedValuesQueryResult>& r) {
547 status = static_cast<c2_status_t>(s);
548 if (status != C2_OK) {
549 LOG(DEBUG) << "querySupportedValues -- call failed: "
550 << status << ".";
551 return;
552 }
553 if (r.size() != fields.size()) {
554 LOG(ERROR) << "querySupportedValues -- "
555 "input and output lists "
556 "have different sizes.";
557 status = C2_CORRUPTED;
558 return;
559 }
560 for (size_t i = 0; i < fields.size(); ++i) {
561 if (!c2_hidl::utils::objcpy(&fields[i], inFields[i], r[i])) {
562 LOG(ERROR) << "querySupportedValues -- "
563 "invalid returned value.";
564 status = C2_CORRUPTED;
565 return;
566 }
567 }
568 });
569 if (!transStatus.isOk()) {
570 LOG(ERROR) << "querySupportedValues -- transaction failed.";
571 return C2_TRANSACTION_FAILED;
572 }
573 return status;
574 }
575
576 // Codec2ConfigurableClient::AidlImpl
577
578 struct Codec2ConfigurableClient::AidlImpl : public Codec2ConfigurableClient::ImplBase {
579 typedef c2_aidl::IConfigurable Base;
580
581 // base cannot be null.
582 explicit AidlImpl(const std::shared_ptr<Base>& base);
583
getNameandroid::Codec2ConfigurableClient::AidlImpl584 const C2String& getName() const override {
585 return mName;
586 }
587
588 c2_status_t query(
589 const std::vector<C2Param*>& stackParams,
590 const std::vector<C2Param::Index> &heapParamIndices,
591 c2_blocking_t mayBlock,
592 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
593
594 c2_status_t config(
595 const std::vector<C2Param*> ¶ms,
596 c2_blocking_t mayBlock,
597 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
598
599 c2_status_t querySupportedParams(
600 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
601 ) const override;
602
603 c2_status_t querySupportedValues(
604 std::vector<C2FieldSupportedValuesQuery>& fields,
605 c2_blocking_t mayBlock) const override;
606
607 private:
608 std::shared_ptr<Base> mBase;
609 const C2String mName;
610 };
611
AidlImpl(const std::shared_ptr<Base> & base)612 Codec2ConfigurableClient::AidlImpl::AidlImpl(const std::shared_ptr<Base>& base)
613 : mBase{base},
__anon3331b31b0a02() 614 mName{[base]() -> C2String {
615 std::string outName;
616 ndk::ScopedAStatus status = base->getName(&outName);
617 return status.isOk() ? outName : "";
618 }()} {
619 }
620
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const621 c2_status_t Codec2ConfigurableClient::AidlImpl::query(
622 const std::vector<C2Param*> &stackParams,
623 const std::vector<C2Param::Index> &heapParamIndices,
624 c2_blocking_t mayBlock,
625 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
626 std::vector<int> indices(
627 stackParams.size() + heapParamIndices.size());
628 size_t numIndices = 0;
629 for (C2Param* const& stackParam : stackParams) {
630 if (!stackParam) {
631 LOG(WARNING) << "query -- null stack param encountered.";
632 continue;
633 }
634 indices[numIndices++] = int(stackParam->index());
635 }
636 size_t numStackIndices = numIndices;
637 for (const C2Param::Index& index : heapParamIndices) {
638 indices[numIndices++] = int(static_cast<uint32_t>(index));
639 }
640 indices.resize(numIndices);
641 if (heapParams) {
642 heapParams->reserve(heapParams->size() + numIndices);
643 }
644 c2_aidl::IConfigurable::QueryResult result;
645 ndk::ScopedAStatus transStatus = mBase->query(indices, (mayBlock == C2_MAY_BLOCK), &result);
646 c2_status_t status = GetC2Status(transStatus, "query");
647 if (status != C2_OK) {
648 return status;
649 }
650 status = static_cast<c2_status_t>(result.status.status);
651
652 std::vector<C2Param*> paramPointers;
653 if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, result.params)) {
654 LOG(ERROR) << "query -- error while parsing params.";
655 return C2_CORRUPTED;
656 }
657 size_t i = 0;
658 size_t numQueried = 0;
659 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
660 C2Param* paramPointer = *it;
661 if (numStackIndices > 0) {
662 --numStackIndices;
663 if (!paramPointer) {
664 LOG(DEBUG) << "query -- null stack param.";
665 ++it;
666 continue;
667 }
668 for (; i < stackParams.size() && !stackParams[i]; ) {
669 ++i;
670 }
671 if (i >= stackParams.size()) {
672 LOG(ERROR) << "query -- unexpected error.";
673 status = C2_CORRUPTED;
674 break;
675 }
676 if (stackParams[i]->index() != paramPointer->index()) {
677 LOG(DEBUG) << "query -- param skipped: "
678 "index = "
679 << stackParams[i]->index() << ".";
680 stackParams[i++]->invalidate();
681 // this means that the param could not be queried.
682 // signalling C2_BAD_INDEX to the client.
683 status = C2_BAD_INDEX;
684 continue;
685 }
686 if (stackParams[i++]->updateFrom(*paramPointer)) {
687 ++numQueried;
688 } else {
689 LOG(WARNING) << "query -- param update failed: "
690 "index = "
691 << paramPointer->index() << ".";
692 }
693 } else {
694 if (!paramPointer) {
695 LOG(DEBUG) << "query -- null heap param.";
696 ++it;
697 continue;
698 }
699 if (!heapParams) {
700 LOG(WARNING) << "query -- "
701 "unexpected extra stack param.";
702 } else {
703 heapParams->emplace_back(C2Param::Copy(*paramPointer));
704 ++numQueried;
705 }
706 }
707 ++it;
708 }
709 if (status == C2_OK && indices.size() != numQueried) {
710 status = C2_BAD_INDEX;
711 }
712 return status;
713 }
714
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)715 c2_status_t Codec2ConfigurableClient::AidlImpl::config(
716 const std::vector<C2Param*> ¶ms,
717 c2_blocking_t mayBlock,
718 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
719 c2_aidl::Params aidlParams;
720 if (!c2_aidl::utils::CreateParamsBlob(&aidlParams, params)) {
721 LOG(ERROR) << "config -- bad input.";
722 return C2_TRANSACTION_FAILED;
723 }
724 c2_aidl::IConfigurable::ConfigResult result;
725 ndk::ScopedAStatus transStatus = mBase->config(aidlParams, (mayBlock == C2_MAY_BLOCK), &result);
726 c2_status_t status = GetC2Status(transStatus, "config");
727 if (status != C2_OK) {
728 return status;
729 }
730 status = static_cast<c2_status_t>(result.status.status);
731 size_t i = failures->size();
732 failures->resize(i + result.failures.size());
733 for (const c2_aidl::SettingResult& sf : result.failures) {
734 if (!c2_aidl::utils::FromAidl(&(*failures)[i++], sf)) {
735 LOG(ERROR) << "config -- invalid SettingResult returned.";
736 return C2_CORRUPTED;
737 }
738 }
739 if (!c2_aidl::utils::UpdateParamsFromBlob(params, result.params)) {
740 LOG(ERROR) << "config -- "
741 << "failed to parse returned params.";
742 status = C2_CORRUPTED;
743 }
744 return status;
745 }
746
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const747 c2_status_t Codec2ConfigurableClient::AidlImpl::querySupportedParams(
748 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
749 // TODO: Cache and query properly!
750 std::vector<c2_aidl::ParamDescriptor> result;
751 ndk::ScopedAStatus transStatus = mBase->querySupportedParams(
752 std::numeric_limits<uint32_t>::min(),
753 std::numeric_limits<uint32_t>::max(),
754 &result);
755 c2_status_t status = GetC2Status(transStatus, "querySupportedParams");
756 if (status != C2_OK) {
757 return status;
758 }
759 size_t i = params->size();
760 params->resize(i + result.size());
761 for (const c2_aidl::ParamDescriptor& sp : result) {
762 if (!c2_aidl::utils::FromAidl(&(*params)[i++], sp)) {
763 LOG(ERROR) << "querySupportedParams -- invalid returned ParamDescriptor.";
764 return C2_CORRUPTED;
765 }
766 }
767 return status;
768 }
769
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const770 c2_status_t Codec2ConfigurableClient::AidlImpl::querySupportedValues(
771 std::vector<C2FieldSupportedValuesQuery>& fields,
772 c2_blocking_t mayBlock) const {
773 std::vector<c2_aidl::FieldSupportedValuesQuery> inFields(fields.size());
774 for (size_t i = 0; i < fields.size(); ++i) {
775 if (!c2_aidl::utils::ToAidl(&inFields[i], fields[i])) {
776 LOG(ERROR) << "querySupportedValues -- bad input";
777 return C2_TRANSACTION_FAILED;
778 }
779 }
780
781 c2_aidl::IConfigurable::QuerySupportedValuesResult result;
782
783 ndk::ScopedAStatus transStatus = mBase->querySupportedValues(
784 inFields, (mayBlock == C2_MAY_BLOCK), &result);
785 c2_status_t status = GetC2Status(transStatus, "querySupportedValues");
786 if (status != C2_OK) {
787 return status;
788 }
789 status = static_cast<c2_status_t>(result.status.status);
790 if (result.values.size() != fields.size()) {
791 LOG(ERROR) << "querySupportedValues -- "
792 "input and output lists "
793 "have different sizes.";
794 return C2_CORRUPTED;
795 }
796 for (size_t i = 0; i < fields.size(); ++i) {
797 if (!c2_aidl::utils::FromAidl(&fields[i], inFields[i], result.values[i])) {
798 LOG(ERROR) << "querySupportedValues -- "
799 "invalid returned value.";
800 return C2_CORRUPTED;
801 }
802 }
803 return status;
804 }
805
806 // Codec2ConfigurableClient::ApexImpl
807
808 struct Codec2ConfigurableClient::ApexImpl : public Codec2ConfigurableClient::ImplBase {
809 ApexImpl(ApexCodec_Configurable *base, const C2String &name);
810
getNameandroid::Codec2ConfigurableClient::ApexImpl811 const C2String& getName() const override {
812 return mName;
813 }
814
815 c2_status_t query(
816 const std::vector<C2Param*>& stackParams,
817 const std::vector<C2Param::Index> &heapParamIndices,
818 c2_blocking_t mayBlock,
819 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
820
821 c2_status_t config(
822 const std::vector<C2Param*> ¶ms,
823 c2_blocking_t mayBlock,
824 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
825
826 c2_status_t querySupportedParams(
827 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
828 ) const override;
829
830 c2_status_t querySupportedValues(
831 std::vector<C2FieldSupportedValuesQuery>& fields,
832 c2_blocking_t mayBlock) const override;
833
834 private:
835 ApexCodec_Configurable* mBase;
836 const C2String mName;
837 };
838
ApexImpl(ApexCodec_Configurable * base,const C2String & name)839 Codec2ConfigurableClient::ApexImpl::ApexImpl(ApexCodec_Configurable *base, const C2String &name)
840 : mBase{base},
841 mName{name} {
842 }
843
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const844 c2_status_t Codec2ConfigurableClient::ApexImpl::query(
845 const std::vector<C2Param*> &stackParams,
846 const std::vector<C2Param::Index> &heapParamIndices,
847 [[maybe_unused]] c2_blocking_t mayBlock,
848 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
849 if (mBase == nullptr) {
850 return C2_OMITTED;
851 }
852
853 if (__builtin_available(android 36, *)) {
854 std::vector<uint32_t> indices(
855 stackParams.size() + heapParamIndices.size());
856 size_t numIndices = 0;
857 for (C2Param* const& stackParam : stackParams) {
858 if (!stackParam) {
859 LOG(WARNING) << "query -- null stack param encountered.";
860 continue;
861 }
862 indices[numIndices++] = uint32_t(stackParam->index());
863 }
864 size_t numStackIndices = numIndices;
865 for (const C2Param::Index& index : heapParamIndices) {
866 indices[numIndices++] = uint32_t(index);
867 }
868 indices.resize(numIndices);
869 if (heapParams) {
870 heapParams->reserve(heapParams->size() + numIndices);
871 }
872 if (numIndices == 0) {
873 return C2_OK;
874 }
875 thread_local std::vector<uint8_t> configBuffer(1024);
876 if (configBuffer.capacity() < numIndices * 16u) {
877 configBuffer.resize(numIndices * 16u);
878 }
879 ApexCodec_LinearBuffer config{configBuffer.data(), configBuffer.capacity()};
880 size_t writtenOrRequested = 0;
881 ApexCodec_Status status = ApexCodec_Configurable_query(
882 mBase, indices.data(), indices.size(), &config, &writtenOrRequested);
883 if (status == APEXCODEC_STATUS_NO_MEMORY) {
884 size_t requested = writtenOrRequested;
885 configBuffer.resize(align(requested, 1024));
886 config.data = configBuffer.data();
887 config.size = configBuffer.capacity();
888 status = ApexCodec_Configurable_query(
889 mBase, indices.data(), indices.size(), &config, &writtenOrRequested);
890 }
891 size_t written = writtenOrRequested;
892 if (status != APEXCODEC_STATUS_OK && status != APEXCODEC_STATUS_BAD_INDEX) {
893 written = 0;
894 }
895 configBuffer.resize(written);
896 std::vector<C2Param*> paramPointers;
897 if (!::android::parseParamsBlob(¶mPointers, configBuffer)) {
898 LOG(ERROR) << "query -- error while parsing params.";
899 return C2_CORRUPTED;
900 }
901 size_t i = 0;
902 size_t numQueried = 0;
903 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
904 C2Param* paramPointer = *it;
905 if (numStackIndices > 0) {
906 --numStackIndices;
907 if (!paramPointer) {
908 LOG(DEBUG) << "query -- null stack param.";
909 ++it;
910 continue;
911 }
912 for (; i < stackParams.size() && !stackParams[i]; ) {
913 ++i;
914 }
915 if (i >= stackParams.size()) {
916 LOG(ERROR) << "query -- unexpected error.";
917 status = APEXCODEC_STATUS_CORRUPTED;
918 break;
919 }
920 if (stackParams[i]->index() != paramPointer->index()) {
921 LOG(DEBUG) << "query -- param skipped: "
922 "index = "
923 << stackParams[i]->index() << ".";
924 stackParams[i++]->invalidate();
925 // this means that the param could not be queried.
926 // signalling C2_BAD_INDEX to the client.
927 status = APEXCODEC_STATUS_BAD_INDEX;
928 continue;
929 }
930 if (stackParams[i++]->updateFrom(*paramPointer)) {
931 ++numQueried;
932 } else {
933 LOG(WARNING) << "query -- param update failed: "
934 "index = "
935 << paramPointer->index() << ".";
936 }
937 } else {
938 if (!paramPointer) {
939 LOG(DEBUG) << "query -- null heap param.";
940 ++it;
941 continue;
942 }
943 if (!heapParams) {
944 LOG(WARNING) << "query -- "
945 "unexpected extra stack param.";
946 } else {
947 heapParams->emplace_back(C2Param::Copy(*paramPointer));
948 ++numQueried;
949 }
950 }
951 ++it;
952 }
953 if (status == APEXCODEC_STATUS_OK && indices.size() != numQueried) {
954 status = APEXCODEC_STATUS_BAD_INDEX;
955 }
956 return (c2_status_t)status;
957 } else {
958 return C2_OMITTED;
959 }
960 }
961
962 namespace {
963 struct ParamOrField : public C2ParamField {
ParamOrFieldandroid::__anon3331b31b0b11::ParamOrField964 explicit ParamOrField(const ApexCodec_ParamFieldValues& field)
965 : C2ParamField(field.index, field.offset, field.size) {}
966 };
967
FromApex(ApexCodec_SupportedValues * apexValues,C2FieldSupportedValues * c2Values)968 static bool FromApex(
969 ApexCodec_SupportedValues *apexValues,
970 C2FieldSupportedValues* c2Values) {
971 if (__builtin_available(android 36, *)) {
972 if (apexValues == nullptr) {
973 c2Values->type = C2FieldSupportedValues::EMPTY;
974 return true;
975 }
976 ApexCodec_SupportedValuesType type = APEXCODEC_SUPPORTED_VALUES_EMPTY;
977 ApexCodec_SupportedValuesNumberType numberType = APEXCODEC_SUPPORTED_VALUES_TYPE_NONE;
978 ApexCodec_Value* values = nullptr;
979 uint32_t numValues = 0;
980 ApexCodec_SupportedValues_getTypeAndValues(
981 apexValues, &type, &numberType, &values, &numValues);
982 c2Values->type = (C2FieldSupportedValues::type_t)type;
983 std::function<C2Value::Primitive(const ApexCodec_Value &)> getPrimitive;
984 switch (numberType) {
985 case APEXCODEC_SUPPORTED_VALUES_TYPE_NONE:
986 getPrimitive = [](const ApexCodec_Value &) -> C2Value::Primitive {
987 return C2Value::Primitive();
988 };
989 break;
990 case APEXCODEC_SUPPORTED_VALUES_TYPE_INT32:
991 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
992 return C2Value::Primitive(value.i32);
993 };
994 break;
995 case APEXCODEC_SUPPORTED_VALUES_TYPE_UINT32:
996 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
997 return C2Value::Primitive(value.u32);
998 };
999 break;
1000 case APEXCODEC_SUPPORTED_VALUES_TYPE_INT64:
1001 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
1002 return C2Value::Primitive(value.i64);
1003 };
1004 break;
1005 case APEXCODEC_SUPPORTED_VALUES_TYPE_UINT64:
1006 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
1007 return C2Value::Primitive(value.u64);
1008 };
1009 break;
1010 case APEXCODEC_SUPPORTED_VALUES_TYPE_FLOAT:
1011 getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
1012 return C2Value::Primitive(value.f);
1013 };
1014 break;
1015 default:
1016 LOG(ERROR) << "Unsupported number type: " << numberType;
1017 return false;
1018 }
1019 switch (type) {
1020 case APEXCODEC_SUPPORTED_VALUES_EMPTY:
1021 break;
1022 case APEXCODEC_SUPPORTED_VALUES_RANGE:
1023 c2Values->range.min = getPrimitive(values[0]);
1024 c2Values->range.max = getPrimitive(values[1]);
1025 c2Values->range.step = getPrimitive(values[2]);
1026 c2Values->range.num = getPrimitive(values[3]);
1027 c2Values->range.denom = getPrimitive(values[4]);
1028 break;
1029 case APEXCODEC_SUPPORTED_VALUES_VALUES:
1030 case APEXCODEC_SUPPORTED_VALUES_FLAGS:
1031 c2Values->values.clear();
1032 for (uint32_t i = 0; i < numValues; ++i) {
1033 c2Values->values.push_back(getPrimitive(values[i]));
1034 }
1035 break;
1036 default:
1037 LOG(ERROR) << "Unsupported supported values type: " << type;
1038 return false;
1039 }
1040 return true;
1041 } else {
1042 return false;
1043 }
1044 }
1045
1046 } // anonymous namespace
1047
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)1048 c2_status_t Codec2ConfigurableClient::ApexImpl::config(
1049 const std::vector<C2Param*> ¶ms,
1050 c2_blocking_t mayBlock,
1051 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
1052 (void)mayBlock;
1053 if (mBase == nullptr) {
1054 return C2_OMITTED;
1055 }
1056
1057 if (__builtin_available(android 36, *)) {
1058 std::vector<uint8_t> configBuffer;
1059 if (!::android::_createParamsBlob(&configBuffer, params)) {
1060 LOG(ERROR) << "config -- bad input.";
1061 return C2_TRANSACTION_FAILED;
1062 }
1063 ApexCodec_SettingResults* result = nullptr;
1064 ApexCodec_LinearBuffer config{configBuffer.data(), configBuffer.size()};
1065 ApexCodec_Status status = ApexCodec_Configurable_config(
1066 mBase, &config, &result);
1067 base::ScopeGuard guard([result] {
1068 if (result) {
1069 ApexCodec_SettingResults_release(result);
1070 }
1071 });
1072 size_t index = 0;
1073 ApexCodec_SettingResultFailure failure;
1074 ApexCodec_ParamFieldValues field;
1075 ApexCodec_ParamFieldValues* conflicts = nullptr;
1076 size_t numConflicts = 0;
1077 ApexCodec_Status getResultStatus = ApexCodec_SettingResults_getResultAtIndex(
1078 result, 0, &failure, &field, &conflicts, &numConflicts);
1079 while (getResultStatus == APEXCODEC_STATUS_OK) {
1080 std::unique_ptr<C2SettingResult> settingResult;
1081 settingResult.reset(new C2SettingResult{
1082 C2SettingResult::Failure(failure), C2ParamFieldValues(ParamOrField(field)), {}
1083 });
1084 // TODO: settingResult->field.values = ?
1085 for (size_t i = 0; i < numConflicts; ++i) {
1086 settingResult->conflicts.emplace_back(ParamOrField(conflicts[i]));
1087 C2ParamFieldValues& conflict = settingResult->conflicts.back();
1088 conflict.values = std::make_unique<C2FieldSupportedValues>();
1089 FromApex(conflicts[i].values, conflict.values.get());
1090 }
1091 failures->push_back(std::move(settingResult));
1092 getResultStatus = ApexCodec_SettingResults_getResultAtIndex(
1093 result, ++index, &failure, &field, &conflicts, &numConflicts);
1094 }
1095 if (!::android::updateParamsFromBlob(params, configBuffer)) {
1096 LOG(ERROR) << "config -- "
1097 << "failed to parse returned params.";
1098 status = APEXCODEC_STATUS_CORRUPTED;
1099 }
1100 return (c2_status_t)status;
1101 } else {
1102 return C2_OMITTED;
1103 }
1104 }
1105
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const1106 c2_status_t Codec2ConfigurableClient::ApexImpl::querySupportedParams(
1107 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
1108 if (mBase == nullptr) {
1109 return C2_OMITTED;
1110 }
1111
1112 if (__builtin_available(android 36, *)) {
1113 // TODO: Cache and query properly!
1114 ApexCodec_ParamDescriptors* paramDescs = nullptr;
1115 ApexCodec_Configurable_querySupportedParams(mBase, ¶mDescs);
1116 base::ScopeGuard guard([paramDescs] {
1117 if (paramDescs) {
1118 ApexCodec_ParamDescriptors_release(paramDescs);
1119 }
1120 });
1121 uint32_t *indices = nullptr;
1122 size_t numIndices = 0;
1123 ApexCodec_Status status = ApexCodec_ParamDescriptors_getIndices(
1124 paramDescs, &indices, &numIndices);
1125 if (status != APEXCODEC_STATUS_OK) {
1126 return (c2_status_t)status;
1127 }
1128 if (numIndices > 0) {
1129 for (int i = 0; i < numIndices; ++i) {
1130 uint32_t index = indices[i];
1131 ApexCodec_ParamAttribute attr = (ApexCodec_ParamAttribute)0;
1132 const char* name = nullptr;
1133 uint32_t* dependencies = nullptr;
1134 size_t numDependencies = 0;
1135 ApexCodec_Status status = ApexCodec_ParamDescriptors_getDescriptor(
1136 paramDescs, index, &attr, &name, &dependencies, &numDependencies);
1137 if (status != APEXCODEC_STATUS_OK) {
1138 LOG(WARNING) << "querySupportedParams -- "
1139 << "failed to get descriptor for index "
1140 << std::hex << index << std::dec << " with status " << status;
1141 continue;
1142 }
1143 params->push_back(std::make_shared<C2ParamDescriptor>(
1144 C2Param::Index(index), C2ParamDescriptor::attrib_t(attr), name,
1145 std::vector<C2Param::Index>(dependencies, dependencies + numDependencies)));
1146 }
1147 }
1148 return (c2_status_t)status;
1149 } else {
1150 return C2_OMITTED;
1151 }
1152 }
1153
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const1154 c2_status_t Codec2ConfigurableClient::ApexImpl::querySupportedValues(
1155 std::vector<C2FieldSupportedValuesQuery>& fields,
1156 [[maybe_unused]] c2_blocking_t mayBlock) const {
1157 if (mBase == nullptr) {
1158 return C2_OMITTED;
1159 }
1160
1161 if (__builtin_available(android 36, *)) {
1162 std::vector<ApexCodec_SupportedValuesQuery> queries(fields.size());
1163 for (size_t i = 0; i < fields.size(); ++i) {
1164 queries[i].index = _C2ParamInspector::GetIndex(fields[i].field());
1165 queries[i].offset = _C2ParamInspector::GetOffset(fields[i].field());
1166 queries[i].type = (ApexCodec_SupportedValuesQueryType)fields[i].type();
1167 queries[i].status = APEXCODEC_STATUS_OK;
1168 queries[i].values = nullptr;
1169 }
1170 ApexCodec_Status status = ApexCodec_Configurable_querySupportedValues(
1171 mBase, queries.data(), queries.size());
1172 for (size_t i = 0; i < fields.size(); ++i) {
1173 fields[i].status = (c2_status_t)queries[i].status;
1174 FromApex(queries[i].values, &fields[i].values);
1175 if (queries[i].values) {
1176 ApexCodec_SupportedValues_release(queries[i].values);
1177 queries[i].values = nullptr;
1178 }
1179 }
1180 return (c2_status_t)status;
1181 } else {
1182 return C2_OMITTED;
1183 }
1184 }
1185
1186 // Codec2ConfigurableClient
1187
Codec2ConfigurableClient(const sp<HidlBase> & hidlBase)1188 Codec2ConfigurableClient::Codec2ConfigurableClient(const sp<HidlBase> &hidlBase)
1189 : mImpl(new Codec2ConfigurableClient::HidlImpl(hidlBase)) {
1190 }
1191
Codec2ConfigurableClient(const std::shared_ptr<AidlBase> & aidlBase)1192 Codec2ConfigurableClient::Codec2ConfigurableClient(
1193 const std::shared_ptr<AidlBase> &aidlBase)
1194 : mImpl(new Codec2ConfigurableClient::AidlImpl(aidlBase)) {
1195 }
1196
Codec2ConfigurableClient(ApexCodec_Configurable * apexBase,const C2String & name)1197 Codec2ConfigurableClient::Codec2ConfigurableClient(
1198 ApexCodec_Configurable *apexBase, const C2String &name)
1199 : mImpl(new Codec2ConfigurableClient::ApexImpl(apexBase, name)) {
1200 }
1201
getName() const1202 const C2String& Codec2ConfigurableClient::getName() const {
1203 return mImpl->getName();
1204 }
1205
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const1206 c2_status_t Codec2ConfigurableClient::query(
1207 const std::vector<C2Param*>& stackParams,
1208 const std::vector<C2Param::Index> &heapParamIndices,
1209 c2_blocking_t mayBlock,
1210 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
1211 return mImpl->query(stackParams, heapParamIndices, mayBlock, heapParams);
1212 }
1213
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)1214 c2_status_t Codec2ConfigurableClient::config(
1215 const std::vector<C2Param*> ¶ms,
1216 c2_blocking_t mayBlock,
1217 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
1218 return mImpl->config(params, mayBlock, failures);
1219 }
1220
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const1221 c2_status_t Codec2ConfigurableClient::querySupportedParams(
1222 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
1223 return mImpl->querySupportedParams(params);
1224 }
1225
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const1226 c2_status_t Codec2ConfigurableClient::querySupportedValues(
1227 std::vector<C2FieldSupportedValuesQuery>& fields,
1228 c2_blocking_t mayBlock) const {
1229 return mImpl->querySupportedValues(fields, mayBlock);
1230 }
1231
1232
1233 // Codec2Client::Component::HidlListener
1234 struct Codec2Client::Component::HidlListener : public c2_hidl::IComponentListener {
1235 std::weak_ptr<Component> component;
1236 std::weak_ptr<Listener> base;
1237
onWorkDoneandroid::Codec2Client::Component::HidlListener1238 virtual Return<void> onWorkDone(const c2_hidl::WorkBundle& workBundle) override {
1239 std::list<std::unique_ptr<C2Work>> workItems;
1240 if (!c2_hidl::utils::objcpy(&workItems, workBundle)) {
1241 LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
1242 return Void();
1243 }
1244 // release input buffers potentially held by the component from queue
1245 std::shared_ptr<Codec2Client::Component> strongComponent =
1246 component.lock();
1247 if (strongComponent) {
1248 strongComponent->handleOnWorkDone(workItems);
1249 }
1250 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1251 listener->onWorkDone(component, workItems);
1252 } else {
1253 LOG(DEBUG) << "onWorkDone -- listener died.";
1254 }
1255 return Void();
1256 }
1257
onTrippedandroid::Codec2Client::Component::HidlListener1258 virtual Return<void> onTripped(
1259 const hidl_vec<c2_hidl::SettingResult>& settingResults) override {
1260 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
1261 settingResults.size());
1262 for (size_t i = 0; i < settingResults.size(); ++i) {
1263 std::unique_ptr<C2SettingResult> c2SettingResult;
1264 if (!c2_hidl::utils::objcpy(&c2SettingResult, settingResults[i])) {
1265 LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
1266 return Void();
1267 }
1268 c2SettingResults[i] = std::move(c2SettingResult);
1269 }
1270 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1271 listener->onTripped(component, c2SettingResults);
1272 } else {
1273 LOG(DEBUG) << "onTripped -- listener died.";
1274 }
1275 return Void();
1276 }
1277
onErrorandroid::Codec2Client::Component::HidlListener1278 virtual Return<void> onError(c2_hidl::Status s, uint32_t errorCode) override {
1279 LOG(DEBUG) << "onError --"
1280 << " status = " << s
1281 << ", errorCode = " << errorCode
1282 << ".";
1283 if (std::shared_ptr<Listener> listener = base.lock()) {
1284 listener->onError(component, s == c2_hidl::Status::OK ?
1285 errorCode : static_cast<c2_status_t>(s));
1286 } else {
1287 LOG(DEBUG) << "onError -- listener died.";
1288 }
1289 return Void();
1290 }
1291
onFramesRenderedandroid::Codec2Client::Component::HidlListener1292 virtual Return<void> onFramesRendered(
1293 const hidl_vec<RenderedFrame>& renderedFrames) override {
1294 std::shared_ptr<Listener> listener = base.lock();
1295 if (!listener) {
1296 LOG(DEBUG) << "onFramesRendered -- listener died.";
1297 return Void();
1298 }
1299 for (const RenderedFrame& renderedFrame : renderedFrames) {
1300 listener->onFrameRendered(
1301 renderedFrame.bufferQueueId,
1302 renderedFrame.slotId,
1303 renderedFrame.timestampNs);
1304 }
1305 return Void();
1306 }
1307
onInputBuffersReleasedandroid::Codec2Client::Component::HidlListener1308 virtual Return<void> onInputBuffersReleased(
1309 const hidl_vec<InputBuffer>& inputBuffers) override {
1310 std::shared_ptr<Listener> listener = base.lock();
1311 if (!listener) {
1312 LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
1313 return Void();
1314 }
1315 for (const InputBuffer& inputBuffer : inputBuffers) {
1316 LOG(VERBOSE) << "onInputBuffersReleased --"
1317 " received death notification of"
1318 " input buffer:"
1319 " frameIndex = " << inputBuffer.frameIndex
1320 << ", bufferIndex = " << inputBuffer.arrayIndex
1321 << ".";
1322 listener->onInputBufferDone(
1323 inputBuffer.frameIndex, inputBuffer.arrayIndex);
1324 }
1325 return Void();
1326 }
1327
1328 };
1329
1330 // Codec2Client::Component::AidlListener
1331 struct Codec2Client::Component::AidlListener : public c2_aidl::BnComponentListener {
1332 std::weak_ptr<Component> component;
1333 std::weak_ptr<Listener> base;
1334
onWorkDoneandroid::Codec2Client::Component::AidlListener1335 virtual ::ndk::ScopedAStatus onWorkDone(const c2_aidl::WorkBundle& workBundle) override {
1336 std::list<std::unique_ptr<C2Work>> workItems;
1337 if (!c2_aidl::utils::FromAidl(&workItems, workBundle)) {
1338 LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
1339 return ::ndk::ScopedAStatus::ok();
1340 }
1341 // release input buffers potentially held by the component from queue
1342 std::shared_ptr<Codec2Client::Component> strongComponent =
1343 component.lock();
1344 if (strongComponent) {
1345 strongComponent->handleOnWorkDone(workItems);
1346 }
1347 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1348 listener->onWorkDone(component, workItems);
1349 } else {
1350 LOG(DEBUG) << "onWorkDone -- listener died.";
1351 }
1352 return ::ndk::ScopedAStatus::ok();
1353 }
1354
onTrippedandroid::Codec2Client::Component::AidlListener1355 virtual ::ndk::ScopedAStatus onTripped(
1356 const std::vector<c2_aidl::SettingResult>& settingResults) override {
1357 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
1358 settingResults.size());
1359 for (size_t i = 0; i < settingResults.size(); ++i) {
1360 std::unique_ptr<C2SettingResult> c2SettingResult;
1361 if (!c2_aidl::utils::FromAidl(&c2SettingResult, settingResults[i])) {
1362 LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
1363 return ::ndk::ScopedAStatus::ok();
1364 }
1365 c2SettingResults[i] = std::move(c2SettingResult);
1366 }
1367 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1368 listener->onTripped(component, c2SettingResults);
1369 } else {
1370 LOG(DEBUG) << "onTripped -- listener died.";
1371 }
1372 return ::ndk::ScopedAStatus::ok();
1373 }
1374
onErrorandroid::Codec2Client::Component::AidlListener1375 virtual ::ndk::ScopedAStatus onError(const c2_aidl::Status &s, int32_t errorCode) override {
1376 LOG(DEBUG) << "onError --"
1377 << " status = " << s.status
1378 << ", errorCode = " << errorCode
1379 << ".";
1380 if (std::shared_ptr<Listener> listener = base.lock()) {
1381 listener->onError(component, s.status == c2_aidl::Status::OK ?
1382 errorCode : static_cast<c2_status_t>(s.status));
1383 } else {
1384 LOG(DEBUG) << "onError -- listener died.";
1385 }
1386 return ::ndk::ScopedAStatus::ok();
1387 }
1388
onFramesRenderedandroid::Codec2Client::Component::AidlListener1389 virtual ::ndk::ScopedAStatus onFramesRendered(
1390 const std::vector<RenderedFrame>& renderedFrames) override {
1391 std::shared_ptr<Listener> listener = base.lock();
1392 if (!listener) {
1393 LOG(DEBUG) << "onFramesRendered -- listener died.";
1394 return ::ndk::ScopedAStatus::ok();
1395 }
1396 for (const RenderedFrame& renderedFrame : renderedFrames) {
1397 listener->onFrameRendered(
1398 renderedFrame.bufferQueueId,
1399 renderedFrame.slotId,
1400 renderedFrame.timestampNs);
1401 }
1402 return ::ndk::ScopedAStatus::ok();
1403 }
1404
onInputBuffersReleasedandroid::Codec2Client::Component::AidlListener1405 virtual ::ndk::ScopedAStatus onInputBuffersReleased(
1406 const std::vector<InputBuffer>& inputBuffers) override {
1407 std::shared_ptr<Listener> listener = base.lock();
1408 if (!listener) {
1409 LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
1410 return ::ndk::ScopedAStatus::ok();
1411 }
1412 for (const InputBuffer& inputBuffer : inputBuffers) {
1413 LOG(VERBOSE) << "onInputBuffersReleased --"
1414 " received death notification of"
1415 " input buffer:"
1416 " frameIndex = " << inputBuffer.frameIndex
1417 << ", bufferIndex = " << inputBuffer.arrayIndex
1418 << ".";
1419 listener->onInputBufferDone(
1420 inputBuffer.frameIndex, inputBuffer.arrayIndex);
1421 }
1422 return ::ndk::ScopedAStatus::ok();
1423 }
1424
1425 };
1426
1427 // Codec2Client::Component::ApexHandler
1428 class Codec2Client::Component::ApexHandler {
1429 public:
ApexHandler(ApexCodec_Component * apexComponent,const std::shared_ptr<Listener> & listener,const std::shared_ptr<Component> & comp)1430 ApexHandler(ApexCodec_Component *apexComponent,
1431 const std::shared_ptr<Listener> &listener,
1432 const std::shared_ptr<Component> &comp)
1433 : mApexComponent(apexComponent),
1434 mListener(listener),
1435 mComponent(comp),
1436 mStopped(false),
1437 mOutputBufferType(APEXCODEC_BUFFER_TYPE_INVALID) {
1438 }
1439
start()1440 void start() {
1441 std::shared_ptr<Component> comp = mComponent.lock();
1442 if (!comp) {
1443 LOG(ERROR) << "ApexHandler::start -- component died.";
1444 return;
1445 }
1446 C2ComponentDomainSetting domain;
1447 C2ComponentKindSetting kind;
1448 c2_status_t status = comp->query({&domain, &kind}, {}, C2_MAY_BLOCK, {});
1449 if (status != C2_OK) {
1450 LOG(ERROR) << "ApexHandler::start -- failed to query component domain and kind";
1451 return;
1452 }
1453 if (kind.value != C2Component::KIND_DECODER
1454 && kind.value != C2Component::KIND_ENCODER) {
1455 LOG(ERROR) << "ApexHandler::start -- unrecognized component kind " << kind.value;
1456 return;
1457 }
1458 ApexCodec_BufferType outputBufferType = APEXCODEC_BUFFER_TYPE_INVALID;
1459 if (domain.value == C2Component::DOMAIN_AUDIO) {
1460 // For both encoders and decoders the output buffer type is linear.
1461 outputBufferType = APEXCODEC_BUFFER_TYPE_LINEAR;
1462 } else if (domain.value == C2Component::DOMAIN_VIDEO
1463 || domain.value == C2Component::DOMAIN_IMAGE) {
1464 // For video / image domain the decoder outputs a graphic buffer, and the encoder
1465 // outputs a linear buffer.
1466 outputBufferType = (kind.value == C2Component::KIND_DECODER)
1467 ? APEXCODEC_BUFFER_TYPE_GRAPHIC : APEXCODEC_BUFFER_TYPE_LINEAR;
1468 } else {
1469 LOG(ERROR) << "ApexHandler::start -- unrecognized component domain " << domain.value;
1470 return;
1471 }
1472 {
1473 std::unique_lock<std::mutex> l(mMutex);
1474 mStopped = false;
1475 mOutputBufferType = outputBufferType;
1476 }
1477 mThread = std::thread([this]() {
1478 run();
1479 });
1480 }
1481
queue(std::list<std::unique_ptr<C2Work>> & workItems)1482 void queue(std::list<std::unique_ptr<C2Work>>& workItems) {
1483 std::unique_lock<std::mutex> l(mMutex);
1484 mWorkQueue.splice(mWorkQueue.end(), workItems);
1485 mCondition.notify_all();
1486 }
1487
stop()1488 void stop() {
1489 std::unique_lock<std::mutex> l(mMutex);
1490 mStopped = true;
1491 mCondition.notify_all();
1492 l.unlock();
1493 mThread.join();
1494 }
1495
1496 private:
run()1497 void run() {
1498 while (true) {
1499 std::unique_lock<std::mutex> l(mMutex);
1500 mCondition.wait(l, [this]() {
1501 return !mWorkQueue.empty() || mStopped;
1502 });
1503 if (mStopped) {
1504 break;
1505 }
1506 if (mWorkQueue.empty()) {
1507 continue;
1508 }
1509 std::list<std::unique_ptr<C2Work>> workItems;
1510 mWorkQueue.swap(workItems);
1511 for (std::unique_ptr<C2Work>& workItem : workItems) {
1512 if (mStopped) {
1513 break;
1514 }
1515 l.unlock();
1516 handleWork(std::move(workItem));
1517 l.lock();
1518 }
1519 }
1520 mWorkQueue.clear();
1521 mWorkMap.clear();
1522 }
1523
handleWork(std::unique_ptr<C2Work> && workItem)1524 void handleWork(std::unique_ptr<C2Work> &&workItem) {
1525 if (__builtin_available(android 36, *)) {
1526 std::shared_ptr<Listener> listener = mListener.lock();
1527 if (!listener) {
1528 LOG(DEBUG) << "handleWork -- listener died.";
1529 return;
1530 }
1531 ApexCodec_Buffer input;
1532 input.flags = (ApexCodec_BufferFlags)workItem->input.flags;
1533 input.frameIndex = workItem->input.ordinal.frameIndex.peekll();
1534 input.timestampUs = workItem->input.ordinal.timestamp.peekll();
1535
1536 if (workItem->input.buffers.size() > 1) {
1537 LOG(ERROR) << "handleWork -- input buffer size is "
1538 << workItem->input.buffers.size();
1539 return;
1540 }
1541 std::shared_ptr<C2Buffer> buffer;
1542 std::optional<C2ReadView> linearView;
1543 if (!workItem->input.buffers.empty()) {
1544 buffer = workItem->input.buffers[0];
1545 }
1546 if (!FillMemory(buffer, &input, &linearView)) {
1547 LOG(ERROR) << "handleWork -- failed to map input";
1548 return;
1549 }
1550
1551 std::vector<uint8_t> configUpdatesVector;
1552 if (!_createParamsBlob(&configUpdatesVector, workItem->input.configUpdate)) {
1553 listener->onError(mComponent, C2_CORRUPTED);
1554 return;
1555 }
1556 input.configUpdates.data = configUpdatesVector.data();
1557 input.configUpdates.size = configUpdatesVector.size();
1558 mWorkMap.insert_or_assign(
1559 workItem->input.ordinal.frameIndex.peekll(), std::move(workItem));
1560
1561 std::list<std::unique_ptr<C2Work>> workItems;
1562 bool inputDrained = false;
1563 while (!inputDrained) {
1564 ApexCodec_Buffer output;
1565 std::shared_ptr<C2LinearBlock> linearBlock;
1566 std::optional<C2WriteView> linearView;
1567 std::shared_ptr<C2GraphicBlock> graphicBlock;
1568 allocOutputBuffer(&output, &linearBlock, &linearView, &graphicBlock);
1569 size_t consumed = 0;
1570 size_t produced = 0;
1571 ApexCodec_Status status = ApexCodec_Component_process(
1572 mApexComponent, &input, &output, &consumed, &produced);
1573 if (status == APEXCODEC_STATUS_NO_MEMORY) {
1574 continue;
1575 }
1576 if (produced > 0) {
1577 auto it = mWorkMap.find(output.frameIndex);
1578 std::unique_ptr<C2Work> outputWorkItem;
1579 if (it != mWorkMap.end()) {
1580 if (output.flags & APEXCODEC_FLAG_INCOMPLETE) {
1581 outputWorkItem = std::make_unique<C2Work>();
1582 outputWorkItem->input.ordinal = it->second->input.ordinal;
1583 outputWorkItem->input.flags = it->second->input.flags;
1584 } else {
1585 outputWorkItem = std::move(it->second);
1586 mWorkMap.erase(it);
1587 }
1588 } else {
1589 LOG(WARNING) << "handleWork -- no work item found for output frame index "
1590 << output.frameIndex;
1591 outputWorkItem = std::make_unique<C2Work>();
1592 outputWorkItem->input.ordinal.frameIndex = output.frameIndex;
1593 outputWorkItem->input.ordinal.timestamp = output.timestampUs;
1594 }
1595 outputWorkItem->worklets.emplace_back(new C2Worklet);
1596 const std::unique_ptr<C2Worklet> &worklet = outputWorkItem->worklets.front();
1597 if (worklet == nullptr) {
1598 LOG(ERROR) << "handleWork -- output work item has null worklet";
1599 return;
1600 }
1601 worklet->output.ordinal.frameIndex = output.frameIndex;
1602 worklet->output.ordinal.timestamp = output.timestampUs;
1603 // non-owning hidl_vec<> to wrap around the output config updates
1604 hidl_vec<uint8_t> outputConfigUpdates;
1605 outputConfigUpdates.setToExternal(
1606 output.configUpdates.data, output.configUpdates.size);
1607 std::vector<C2Param*> outputConfigUpdatePtrs;
1608 parseParamsBlob(&outputConfigUpdatePtrs, outputConfigUpdates);
1609 worklet->output.configUpdate.clear();
1610 std::ranges::transform(
1611 outputConfigUpdatePtrs,
1612 std::back_inserter(worklet->output.configUpdate),
1613 [](C2Param* param) { return C2Param::Copy(*param); });
1614 worklet->output.flags = (C2FrameData::flags_t)output.flags;
1615
1616 workItems.push_back(std::move(outputWorkItem));
1617 }
1618
1619 // determine whether the input buffer is drained
1620 if (input.type == APEXCODEC_BUFFER_TYPE_LINEAR) {
1621 if (input.memory.linear.size < consumed) {
1622 LOG(WARNING) << "handleWork -- component consumed more bytes "
1623 << "than the input buffer size";
1624 inputDrained = true;
1625 } else {
1626 input.memory.linear.data += consumed;
1627 input.memory.linear.size -= consumed;
1628 }
1629 } else if (input.type == APEXCODEC_BUFFER_TYPE_GRAPHIC) {
1630 inputDrained = (consumed > 0);
1631 }
1632 }
1633
1634 if (!workItems.empty()) {
1635 listener->onWorkDone(mComponent, workItems);
1636 }
1637 }
1638 }
1639
ensureBlockPool()1640 bool ensureBlockPool() {
1641 std::shared_ptr<Component> comp = mComponent.lock();
1642 if (!comp) {
1643 return false;
1644 }
1645 std::vector<std::unique_ptr<C2Param>> heapParams;
1646 comp->query({}, {C2PortBlockPoolsTuning::output::PARAM_TYPE}, C2_MAY_BLOCK, &heapParams);
1647 if (heapParams.size() != 1) {
1648 return false;
1649 }
1650 const C2Param* param = heapParams[0].get();
1651 if (param->type() != C2PortBlockPoolsTuning::output::PARAM_TYPE) {
1652 return false;
1653 }
1654 const C2PortBlockPoolsTuning::output *blockPools =
1655 static_cast<const C2PortBlockPoolsTuning::output *>(param);
1656 if (blockPools->flexCount() == 0) {
1657 return false;
1658 }
1659 C2BlockPool::local_id_t blockPoolId = blockPools->m.values[0];
1660 if (mBlockPool && mBlockPool->getLocalId() == blockPoolId) {
1661 // no need to update
1662 return true;
1663 }
1664 return C2_OK == GetCodec2BlockPool(blockPoolId, nullptr, &mBlockPool);
1665 }
1666
allocOutputBuffer(ApexCodec_Buffer * output,std::shared_ptr<C2LinearBlock> * linearBlock,std::optional<C2WriteView> * linearView,std::shared_ptr<C2GraphicBlock> * graphicBlock)1667 void allocOutputBuffer(
1668 ApexCodec_Buffer* output,
1669 std::shared_ptr<C2LinearBlock> *linearBlock,
1670 std::optional<C2WriteView> *linearView,
1671 std::shared_ptr<C2GraphicBlock> *graphicBlock) {
1672 if (mOutputBufferType == APEXCODEC_BUFFER_TYPE_LINEAR) {
1673 if (!ensureBlockPool()) {
1674 return;
1675 }
1676 {
1677 std::shared_ptr<Component> comp = mComponent.lock();
1678 if (!comp) {
1679 return;
1680 }
1681 C2StreamMaxBufferSizeInfo::output maxBufferSize(0u /* stream */);
1682 comp->query({&maxBufferSize}, {}, C2_MAY_BLOCK, {});
1683 mLinearBlockCapacity = maxBufferSize ? maxBufferSize.value : 1024 * 1024;
1684 }
1685 output->type = APEXCODEC_BUFFER_TYPE_LINEAR;
1686 c2_status_t status = mBlockPool->fetchLinearBlock(
1687 mLinearBlockCapacity,
1688 C2MemoryUsage(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
1689 linearBlock);
1690 if (!(*linearBlock)) {
1691 return;
1692 }
1693 linearView->emplace((*linearBlock)->map().get());
1694 if ((*linearView)->error() != C2_OK) {
1695 return;
1696 }
1697 output->memory.linear.data = (*linearView)->data();
1698 output->memory.linear.size = (*linearView)->capacity();
1699 } else if (mOutputBufferType == APEXCODEC_BUFFER_TYPE_GRAPHIC) {
1700 if (!ensureBlockPool()) {
1701 return;
1702 }
1703 {
1704 std::shared_ptr<Component> comp = mComponent.lock();
1705 if (!comp) {
1706 return;
1707 }
1708 C2StreamMaxPictureSizeTuning::output maxPictureSize(0u /* stream */);
1709 C2StreamPictureSizeInfo::output pictureSize(0u /* stream */);
1710 C2StreamPixelFormatInfo::output pixelFormat(0u /* stream */);
1711 comp->query({&maxPictureSize, &pictureSize, &pixelFormat}, {}, C2_MAY_BLOCK, {});
1712 mWidth = maxPictureSize ? maxPictureSize.width : pictureSize.width;
1713 mHeight = maxPictureSize ? maxPictureSize.height : pictureSize.height;
1714 mFormat = pixelFormat ? pixelFormat.value : HAL_PIXEL_FORMAT_YCBCR_420_888;
1715 }
1716 output->type = APEXCODEC_BUFFER_TYPE_GRAPHIC;
1717 c2_status_t status = mBlockPool->fetchGraphicBlock(
1718 mWidth, mHeight, mFormat,
1719 C2MemoryUsage(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
1720 graphicBlock);
1721 if (!(*graphicBlock)) {
1722 return;
1723 }
1724 const C2Handle *handle = (*graphicBlock)->handle();
1725 uint32_t width, height, format, stride, igbp_slot, generation;
1726 uint64_t usage, igbp_id;
1727 _UnwrapNativeCodec2GrallocMetadata(
1728 handle, &width, &height, &format, &usage, &stride, &generation,
1729 &igbp_id, &igbp_slot);
1730 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(handle);
1731 sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
1732 grallocHandle, GraphicBuffer::CLONE_HANDLE,
1733 width, height, format, 1, usage, stride);
1734 native_handle_delete(grallocHandle);
1735 AHardwareBuffer *hardwareBuffer =
1736 AHardwareBuffer_from_GraphicBuffer(graphicBuffer.get());
1737 AHardwareBuffer_acquire(hardwareBuffer);
1738 output->memory.graphic = hardwareBuffer;
1739 } else {
1740 LOG(ERROR) << "allocOutputBuffer -- unsupported output buffer type: "
1741 << mOutputBufferType;
1742 return;
1743 }
1744 }
1745
FillMemory(const std::shared_ptr<C2Buffer> & buffer,ApexCodec_Buffer * apexBuffer,std::optional<C2ReadView> * linearView)1746 static bool FillMemory(
1747 const std::shared_ptr<C2Buffer>& buffer,
1748 ApexCodec_Buffer* apexBuffer,
1749 std::optional<C2ReadView>* linearView) {
1750 if (buffer->data().type() == C2BufferData::LINEAR) {
1751 apexBuffer->type = APEXCODEC_BUFFER_TYPE_LINEAR;
1752 if (buffer->data().linearBlocks().empty()) {
1753 apexBuffer->memory.linear.data = nullptr;
1754 apexBuffer->memory.linear.size = 0;
1755 return true;
1756 } else if (buffer->data().linearBlocks().size() > 1) {
1757 return false;
1758 }
1759 linearView->emplace(buffer->data().linearBlocks().front().map().get());
1760 if ((*linearView)->error() != C2_OK) {
1761 return false;
1762 }
1763 apexBuffer->memory.linear.data = const_cast<uint8_t*>((*linearView)->data());
1764 apexBuffer->memory.linear.size = (*linearView)->capacity();
1765 return true;
1766 } else if (buffer->data().type() == C2BufferData::GRAPHIC) {
1767 apexBuffer->type = APEXCODEC_BUFFER_TYPE_GRAPHIC;
1768 if (buffer->data().graphicBlocks().empty()) {
1769 apexBuffer->memory.graphic = nullptr;
1770 return true;
1771 } else if (buffer->data().graphicBlocks().size() > 1) {
1772 return false;
1773 }
1774 const C2Handle *handle = buffer->data().graphicBlocks().front().handle();
1775 uint32_t width, height, format, stride, igbp_slot, generation;
1776 uint64_t usage, igbp_id;
1777 _UnwrapNativeCodec2GrallocMetadata(
1778 handle, &width, &height, &format, &usage, &stride, &generation,
1779 &igbp_id, &igbp_slot);
1780 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(handle);
1781 sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
1782 grallocHandle, GraphicBuffer::CLONE_HANDLE,
1783 width, height, format, 1, usage, stride);
1784 native_handle_delete(grallocHandle);
1785 AHardwareBuffer *hardwareBuffer =
1786 AHardwareBuffer_from_GraphicBuffer(graphicBuffer.get());
1787 AHardwareBuffer_acquire(hardwareBuffer);
1788 apexBuffer->memory.graphic = hardwareBuffer;
1789 return true;
1790 }
1791 return false;
1792 }
1793
1794 ApexCodec_Component *mApexComponent;
1795 std::weak_ptr<Listener> mListener;
1796 std::weak_ptr<Component> mComponent;
1797
1798 std::thread mThread;
1799 std::mutex mMutex;
1800 std::condition_variable mCondition;
1801 bool mStopped;
1802 ApexCodec_BufferType mOutputBufferType;
1803
1804 size_t mLinearBlockCapacity;
1805 uint32_t mWidth;
1806 uint32_t mHeight;
1807 uint32_t mFormat;
1808
1809 std::shared_ptr<C2BlockPool> mBlockPool;
1810 std::list<std::unique_ptr<C2Work>> mWorkQueue;
1811 std::map<uint64_t, std::unique_ptr<C2Work>> mWorkMap;
1812 };
1813
1814 // Codec2Client::Component::HidlBufferPoolSender
1815 struct Codec2Client::Component::HidlBufferPoolSender :
1816 hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
HidlBufferPoolSenderandroid::Codec2Client::Component::HidlBufferPoolSender1817 HidlBufferPoolSender()
1818 : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
1819 }
1820 };
1821
1822 // Codec2Client::Component::AidlBufferPoolSender
1823 struct Codec2Client::Component::AidlBufferPoolSender :
1824 c2_aidl::utils::DefaultBufferPoolSender {
AidlBufferPoolSenderandroid::Codec2Client::Component::AidlBufferPoolSender1825 AidlBufferPoolSender()
1826 : c2_aidl::utils::DefaultBufferPoolSender() {
1827 }
1828 };
1829
1830 // Codec2Client::Component::OutputBufferQueue
1831 struct Codec2Client::Component::OutputBufferQueue :
1832 hardware::media::c2::OutputBufferQueue {
OutputBufferQueueandroid::Codec2Client::Component::OutputBufferQueue1833 OutputBufferQueue()
1834 : hardware::media::c2::OutputBufferQueue() {
1835 }
1836 };
1837
1838 // The class holds GraphicBufferAllocator and the associated id of
1839 // HAL side BlockPool.
1840 // This is tightly coupled with BlockPool creation and destruction.
1841 // The life cycle inside class will be as follows.
1842 //
1843 // On createBlockPool client request.
1844 // 1. this::create() creates a GraphicBufferAllocator and set it as
1845 // the current.
1846 // 2. C2AIDL_HAL::createBlockPool() creates a C2BlockPool using
1847 // the GraphicBufferAllocator created in #1.
1848 // 3. this::setCurrentId() associates the id returned in #2 to the current
1849 //
1850 // On destroyBlockPool cliet request
1851 // 1. C2AIDL_HAL::destroyBlockPool() destroys the block pool
1852 // from HAL process.
1853 // 2. this::remove() destroys GraphicBufferAllocator which is associatted
1854 // with the C2BlockPool in #1.
1855 //
1856 struct Codec2Client::Component::GraphicBufferAllocators {
1857 private:
1858 std::optional<C2BlockPool::local_id_t> mCurrentId;
1859 std::shared_ptr<AidlGraphicBufferAllocator> mCurrent;
1860
1861 // A new BlockPool is created before the old BlockPool is destroyed.
1862 // This holds the reference of the old BlockPool when a new BlockPool is
1863 // created until the old BlockPool is explicitly requested for destruction.
1864 std::map<C2BlockPool::local_id_t, std::shared_ptr<AidlGraphicBufferAllocator>> mOlds;
1865 std::mutex mMutex;
1866
1867 public:
1868 // Creates a GraphicBufferAllocator which will be passed to HAL
1869 // for creating C2BlockPool. And the created GraphicBufferAllocator
1870 // will be used afterwards by current().
createandroid::Codec2Client::Component::GraphicBufferAllocators1871 std::shared_ptr<AidlGraphicBufferAllocator> create() {
1872 std::unique_lock<std::mutex> l(mMutex);
1873 if (mCurrent) {
1874 // If this is not stopped.
1875 mCurrent->reset();
1876 if (mCurrentId.has_value()) {
1877 mOlds.emplace(mCurrentId.value(), mCurrent);
1878 }
1879 mCurrentId.reset();
1880 mCurrent.reset();
1881 }
1882 // TODO: integrate initial value with CCodec/CCodecBufferChannel
1883 mCurrent =
1884 AidlGraphicBufferAllocator::CreateGraphicBufferAllocator(3 /* maxDequeueCount */);
1885 ALOGD("GraphicBufferAllocator created");
1886 return mCurrent;
1887 }
1888
1889 // Associates the blockpool Id returned from HAL to the
1890 // current GraphicBufferAllocator.
setCurrentIdandroid::Codec2Client::Component::GraphicBufferAllocators1891 void setCurrentId(C2BlockPool::local_id_t id) {
1892 std::unique_lock<std::mutex> l(mMutex);
1893 CHECK(!mCurrentId.has_value());
1894 mCurrentId = id;
1895 }
1896
1897 // Returns the current GraphicBufferAllocator.
currentandroid::Codec2Client::Component::GraphicBufferAllocators1898 std::shared_ptr<AidlGraphicBufferAllocator> current() {
1899 std::unique_lock<std::mutex> l(mMutex);
1900 return mCurrent;
1901 }
1902
1903 // Removes the GraphicBufferAllocator associated with given \p id.
removeandroid::Codec2Client::Component::GraphicBufferAllocators1904 void remove(C2BlockPool::local_id_t id) {
1905 std::unique_lock<std::mutex> l(mMutex);
1906 mOlds.erase(id);
1907 if (mCurrentId == id) {
1908 if (mCurrent) {
1909 mCurrent->reset();
1910 mCurrent.reset();
1911 }
1912 mCurrentId.reset();
1913 }
1914 }
1915 };
1916
1917 // Codec2Client
Codec2Client(sp<HidlBase> const & base,sp<c2_hidl::IConfigurable> const & configurable,size_t serviceIndex)1918 Codec2Client::Codec2Client(sp<HidlBase> const& base,
1919 sp<c2_hidl::IConfigurable> const& configurable,
1920 size_t serviceIndex)
1921 : Configurable{configurable},
1922 mHidlBase1_0{base},
1923 mHidlBase1_1{HidlBase1_1::castFrom(base)},
1924 mHidlBase1_2{HidlBase1_2::castFrom(base)},
1925 mServiceIndex{serviceIndex} {
1926 Return<sp<bufferpool_hidl::IClientManager>> transResult = base->getPoolClientManager();
1927 if (!transResult.isOk()) {
1928 LOG(ERROR) << "getPoolClientManager -- transaction failed.";
1929 } else {
1930 mHidlHostPoolManager = static_cast<sp<bufferpool_hidl::IClientManager>>(transResult);
1931 }
1932 }
1933
Codec2Client(std::shared_ptr<AidlBase> const & base,std::shared_ptr<c2_aidl::IConfigurable> const & configurable,size_t serviceIndex)1934 Codec2Client::Codec2Client(std::shared_ptr<AidlBase> const& base,
1935 std::shared_ptr<c2_aidl::IConfigurable> const& configurable,
1936 size_t serviceIndex)
1937 : Configurable{configurable},
1938 mAidlBase{base},
1939 mServiceIndex{serviceIndex} {
1940 ::ndk::ScopedAStatus transStatus = base->getPoolClientManager(&mAidlHostPoolManager);
1941 if (!transStatus.isOk()) {
1942 LOG(ERROR) << "getPoolClientManager -- transaction failed.";
1943 mAidlHostPoolManager.reset();
1944 }
1945 }
1946
Codec2Client(ApexCodec_ComponentStore * base,size_t serviceIndex)1947 Codec2Client::Codec2Client(ApexCodec_ComponentStore *base,
1948 size_t serviceIndex)
1949 : Configurable{nullptr, "android.componentStore.apexCodecs"},
1950 mApexBase{base},
1951 mServiceIndex{serviceIndex} {
1952 }
1953
getHidlBase() const1954 sp<Codec2Client::HidlBase> const& Codec2Client::getHidlBase() const {
1955 return mHidlBase1_0;
1956 }
1957
getHidlBase1_0() const1958 sp<Codec2Client::HidlBase1_0> const& Codec2Client::getHidlBase1_0() const {
1959 return mHidlBase1_0;
1960 }
1961
getHidlBase1_1() const1962 sp<Codec2Client::HidlBase1_1> const& Codec2Client::getHidlBase1_1() const {
1963 return mHidlBase1_1;
1964 }
1965
getHidlBase1_2() const1966 sp<Codec2Client::HidlBase1_2> const& Codec2Client::getHidlBase1_2() const {
1967 return mHidlBase1_2;
1968 }
1969
getAidlBase() const1970 ::ndk::SpAIBinder Codec2Client::getAidlBase() const {
1971 return mAidlBase ? mAidlBase->asBinder() : nullptr;
1972 }
1973
getServiceName() const1974 std::string const& Codec2Client::getServiceName() const {
1975 return GetServiceNames()[mServiceIndex];
1976 }
1977
createComponent(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)1978 c2_status_t Codec2Client::createComponent(
1979 const C2String& name,
1980 const std::shared_ptr<Codec2Client::Listener>& listener,
1981 std::shared_ptr<Codec2Client::Component>* const component) {
1982 if (mApexBase) {
1983 return createComponent_apex(name, listener, component);
1984 } else if (mAidlBase) {
1985 return createComponent_aidl(name, listener, component);
1986 } else {
1987 return createComponent_hidl(name, listener, component);
1988 }
1989 }
1990
createComponent_apex(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)1991 c2_status_t Codec2Client::createComponent_apex(
1992 const C2String& name,
1993 const std::shared_ptr<Codec2Client::Listener>& listener,
1994 std::shared_ptr<Codec2Client::Component>* const component) {
1995 if (__builtin_available(android 36, *)) {
1996 ApexCodec_Component *apexComponent = nullptr;
1997 ApexCodec_Status status = ApexCodec_Component_create(
1998 mApexBase, name.c_str(), &apexComponent);
1999 if (status != APEXCODEC_STATUS_OK) {
2000 return (c2_status_t)status;
2001 }
2002 *component = std::make_shared<Codec2Client::Component>(apexComponent, name);
2003 (*component)->initApexHandler(listener, *component);
2004 return C2_OK;
2005 } else {
2006 return C2_OMITTED;
2007 }
2008 }
2009
createComponent_aidl(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)2010 c2_status_t Codec2Client::createComponent_aidl(
2011 const C2String& name,
2012 const std::shared_ptr<Codec2Client::Listener>& listener,
2013 std::shared_ptr<Codec2Client::Component>* const component) {
2014 std::shared_ptr<Component::AidlListener> aidlListener =
2015 Component::AidlListener::make<Component::AidlListener>();
2016 aidlListener->base = listener;
2017 std::shared_ptr<c2_aidl::IComponent> aidlComponent;
2018 ::ndk::ScopedAStatus transStatus = mAidlBase->createComponent(
2019 name,
2020 aidlListener,
2021 bufferpool2_aidl::implementation::ClientManager::getInstance(),
2022 &aidlComponent);
2023 c2_status_t status = GetC2Status(transStatus, "createComponent");
2024 if (status != C2_OK) {
2025 return status;
2026 } else if (!aidlComponent) {
2027 LOG(ERROR) << "createComponent(" << name.c_str()
2028 << ") -- null component.";
2029 return C2_CORRUPTED;
2030 }
2031 *component = std::make_shared<Codec2Client::Component>(aidlComponent);
2032 status = (*component)->setDeathListener((*component), listener);
2033 if (status != C2_OK) {
2034 LOG(ERROR) << "createComponent(" << name.c_str()
2035 << ") -- failed to set up death listener: "
2036 << status << ".";
2037 }
2038 (*component)->mAidlBufferPoolSender->setReceiver(mAidlHostPoolManager);
2039 aidlListener->component = *component;
2040 return status;
2041 }
2042
createComponent_hidl(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)2043 c2_status_t Codec2Client::createComponent_hidl(
2044 const C2String& name,
2045 const std::shared_ptr<Codec2Client::Listener>& listener,
2046 std::shared_ptr<Codec2Client::Component>* const component) {
2047 c2_status_t status;
2048 sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
2049 hidlListener->base = listener;
2050 Return<void> transStatus;
2051 if (mHidlBase1_2) {
2052 transStatus = mHidlBase1_2->createComponent_1_2(
2053 name,
2054 hidlListener,
2055 bufferpool_hidl::implementation::ClientManager::getInstance(),
2056 [&status, component, hidlListener](
2057 c2_hidl::Status s,
2058 const sp<c2_hidl::IComponent>& c) {
2059 status = static_cast<c2_status_t>(s);
2060 if (status != C2_OK) {
2061 return;
2062 }
2063 *component = std::make_shared<Codec2Client::Component>(c);
2064 hidlListener->component = *component;
2065 });
2066 }
2067 else if (mHidlBase1_1) {
2068 transStatus = mHidlBase1_1->createComponent_1_1(
2069 name,
2070 hidlListener,
2071 bufferpool_hidl::implementation::ClientManager::getInstance(),
2072 [&status, component, hidlListener](
2073 c2_hidl::Status s,
2074 const sp<c2_hidl_base::V1_1::IComponent>& c) {
2075 status = static_cast<c2_status_t>(s);
2076 if (status != C2_OK) {
2077 return;
2078 }
2079 *component = std::make_shared<Codec2Client::Component>(c);
2080 hidlListener->component = *component;
2081 });
2082 } else if (mHidlBase1_0) { // ver1_0
2083 transStatus = mHidlBase1_0->createComponent(
2084 name,
2085 hidlListener,
2086 bufferpool_hidl::implementation::ClientManager::getInstance(),
2087 [&status, component, hidlListener](
2088 c2_hidl::Status s,
2089 const sp<c2_hidl_base::V1_0::IComponent>& c) {
2090 status = static_cast<c2_status_t>(s);
2091 if (status != C2_OK) {
2092 return;
2093 }
2094 *component = std::make_shared<Codec2Client::Component>(c);
2095 hidlListener->component = *component;
2096 });
2097 } else {
2098 status = C2_CORRUPTED;
2099 }
2100 if (!transStatus.isOk()) {
2101 LOG(ERROR) << "createComponent(" << name.c_str()
2102 << ") -- transaction failed.";
2103 return C2_TRANSACTION_FAILED;
2104 } else if (status != C2_OK) {
2105 if (status == C2_NOT_FOUND) {
2106 LOG(VERBOSE) << "createComponent(" << name.c_str()
2107 << ") -- component not found.";
2108 } else {
2109 LOG(ERROR) << "createComponent(" << name.c_str()
2110 << ") -- call failed: " << status << ".";
2111 }
2112 return status;
2113 } else if (!*component) {
2114 LOG(ERROR) << "createComponent(" << name.c_str()
2115 << ") -- null component.";
2116 return C2_CORRUPTED;
2117 }
2118
2119 status = (*component)->setDeathListener(*component, listener);
2120 if (status != C2_OK) {
2121 LOG(ERROR) << "createComponent(" << name.c_str()
2122 << ") -- failed to set up death listener: "
2123 << status << ".";
2124 }
2125
2126 (*component)->mHidlBufferPoolSender->setReceiver(mHidlHostPoolManager);
2127 return status;
2128 }
2129
createInterface(const C2String & name,std::shared_ptr<Codec2Client::Interface> * const interface)2130 c2_status_t Codec2Client::createInterface(
2131 const C2String& name,
2132 std::shared_ptr<Codec2Client::Interface>* const interface) {
2133 if (mAidlBase) {
2134 std::shared_ptr<c2_aidl::IComponentInterface> aidlInterface;
2135 ::ndk::ScopedAStatus transStatus = mAidlBase->createInterface(
2136 name,
2137 &aidlInterface);
2138 c2_status_t status = GetC2Status(transStatus, "createInterface");
2139 if (status != C2_OK) {
2140 return status;
2141 } else if (!aidlInterface) {
2142 LOG(ERROR) << "createInterface(" << name.c_str()
2143 << ") -- null interface.";
2144 return C2_CORRUPTED;
2145 }
2146 interface->reset(new Codec2Client::Interface(aidlInterface));
2147 return C2_OK;
2148 }
2149
2150 c2_status_t status;
2151 Return<void> transStatus = mHidlBase1_0->createInterface(
2152 name,
2153 [&status, interface](
2154 c2_hidl::Status s,
2155 const sp<c2_hidl::IComponentInterface>& i) {
2156 status = static_cast<c2_status_t>(s);
2157 if (status != C2_OK) {
2158 return;
2159 }
2160 *interface = std::make_shared<Interface>(i);
2161 });
2162 if (!transStatus.isOk()) {
2163 LOG(ERROR) << "createInterface(" << name.c_str()
2164 << ") -- transaction failed.";
2165 return C2_TRANSACTION_FAILED;
2166 } else if (status != C2_OK) {
2167 if (status == C2_NOT_FOUND) {
2168 LOG(VERBOSE) << "createInterface(" << name.c_str()
2169 << ") -- component not found.";
2170 } else {
2171 LOG(ERROR) << "createInterface(" << name.c_str()
2172 << ") -- call failed: " << status << ".";
2173 }
2174 return status;
2175 }
2176
2177 return status;
2178 }
2179
createInputSurface(std::shared_ptr<InputSurface> * const inputSurface)2180 c2_status_t Codec2Client::createInputSurface(
2181 std::shared_ptr<InputSurface>* const inputSurface) {
2182 if (mAidlBase) {
2183 // FIXME
2184 return C2_OMITTED;
2185 }
2186
2187 c2_status_t status;
2188 Return<void> transStatus = mHidlBase1_0->createInputSurface(
2189 [&status, inputSurface](
2190 c2_hidl::Status s,
2191 const sp<c2_hidl::IInputSurface>& i) {
2192 status = static_cast<c2_status_t>(s);
2193 if (status != C2_OK) {
2194 return;
2195 }
2196 *inputSurface = std::make_shared<InputSurface>(i);
2197 });
2198 if (!transStatus.isOk()) {
2199 LOG(ERROR) << "createInputSurface -- transaction failed.";
2200 return C2_TRANSACTION_FAILED;
2201 } else if (status != C2_OK) {
2202 LOG(DEBUG) << "createInputSurface -- call failed: "
2203 << status << ".";
2204 }
2205 return status;
2206 }
2207
listComponents() const2208 std::vector<C2Component::Traits> const& Codec2Client::listComponents() const {
2209 return Cache::List()[mServiceIndex].getTraits();
2210 }
2211
_listComponents(bool * success) const2212 std::vector<C2Component::Traits> Codec2Client::_listComponents(
2213 bool* success) const {
2214 std::vector<C2Component::Traits> traits;
2215 std::string const& serviceName = getServiceName();
2216
2217 if (mAidlBase) {
2218 std::vector<c2_aidl::IComponentStore::ComponentTraits> aidlTraits;
2219 ::ndk::ScopedAStatus transStatus = mAidlBase->listComponents(&aidlTraits);
2220 if (!transStatus.isOk()) {
2221 LOG(ERROR) << "_listComponents -- transaction failed.";
2222 *success = false;
2223 } else {
2224 traits.resize(aidlTraits.size());
2225 *success = true;
2226 for (size_t i = 0; i < aidlTraits.size(); ++i) {
2227 if (!c2_aidl::utils::FromAidl(&traits[i], aidlTraits[i])) {
2228 LOG(ERROR) << "_listComponents -- corrupted output.";
2229 *success = false;
2230 traits.clear();
2231 break;
2232 }
2233 traits[i].owner = serviceName;
2234 }
2235 }
2236 return traits;
2237 }
2238 Return<void> transStatus = mHidlBase1_0->listComponents(
2239 [&traits, &serviceName](c2_hidl::Status s,
2240 const hidl_vec<c2_hidl::IComponentStore::ComponentTraits>& t) {
2241 if (s != c2_hidl::Status::OK) {
2242 LOG(DEBUG) << "_listComponents -- call failed: "
2243 << static_cast<c2_status_t>(s) << ".";
2244 return;
2245 }
2246 traits.resize(t.size());
2247 for (size_t i = 0; i < t.size(); ++i) {
2248 if (!c2_hidl::utils::objcpy(&traits[i], t[i])) {
2249 LOG(ERROR) << "_listComponents -- corrupted output.";
2250 return;
2251 }
2252 traits[i].owner = serviceName;
2253 }
2254 });
2255 if (!transStatus.isOk()) {
2256 LOG(ERROR) << "_listComponents -- transaction failed.";
2257 *success = false;
2258 } else {
2259 *success = true;
2260 }
2261 return traits;
2262 }
2263
copyBuffer(const std::shared_ptr<C2Buffer> & src,const std::shared_ptr<C2Buffer> & dst)2264 c2_status_t Codec2Client::copyBuffer(
2265 const std::shared_ptr<C2Buffer>& src,
2266 const std::shared_ptr<C2Buffer>& dst) {
2267 // TODO: Implement?
2268 (void)src;
2269 (void)dst;
2270 LOG(ERROR) << "copyBuffer not implemented";
2271 return C2_OMITTED;
2272 }
2273
getParamReflector()2274 std::shared_ptr<C2ParamReflector> Codec2Client::getParamReflector() {
2275 // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
2276 // should reflect the HAL API.
2277 struct HidlSimpleParamReflector : public C2ParamReflector {
2278 std::unique_ptr<C2StructDescriptor> describe(
2279 C2Param::CoreIndex coreIndex) const override {
2280 hidl_vec<c2_hidl::ParamIndex> indices(1);
2281 indices[0] = static_cast<c2_hidl::ParamIndex>(coreIndex.coreIndex());
2282 std::unique_ptr<C2StructDescriptor> descriptor;
2283 Return<void> transStatus = mBase->getStructDescriptors(
2284 indices,
2285 [&descriptor](
2286 c2_hidl::Status s,
2287 const hidl_vec<c2_hidl::StructDescriptor>& sd) {
2288 c2_status_t status = static_cast<c2_status_t>(s);
2289 if (status != C2_OK) {
2290 LOG(DEBUG) << "SimpleParamReflector -- "
2291 "getStructDescriptors() failed: "
2292 << status << ".";
2293 descriptor.reset();
2294 return;
2295 }
2296 if (sd.size() != 1) {
2297 LOG(DEBUG) << "SimpleParamReflector -- "
2298 "getStructDescriptors() "
2299 "returned vector of size "
2300 << sd.size() << ". "
2301 "It should be 1.";
2302 descriptor.reset();
2303 return;
2304 }
2305 if (!c2_hidl::utils::objcpy(&descriptor, sd[0])) {
2306 LOG(DEBUG) << "SimpleParamReflector -- "
2307 "getStructDescriptors() returned "
2308 "corrupted data.";
2309 descriptor.reset();
2310 return;
2311 }
2312 });
2313 if (!transStatus.isOk()) {
2314 LOG(DEBUG) << "SimpleParamReflector -- transaction failed: "
2315 << transStatus.description();
2316 descriptor.reset();
2317 }
2318 return descriptor;
2319 }
2320
2321 HidlSimpleParamReflector(sp<HidlBase> base)
2322 : mBase(base) { }
2323
2324 sp<HidlBase> mBase;
2325 };
2326 struct AidlSimpleParamReflector : public C2ParamReflector {
2327 std::unique_ptr<C2StructDescriptor> describe(
2328 C2Param::CoreIndex coreIndex) const override {
2329 std::vector<c2_aidl::StructDescriptor> aidlDesc;
2330 std::unique_ptr<C2StructDescriptor> descriptor;
2331 ::ndk::ScopedAStatus transStatus = mBase->getStructDescriptors(
2332 {int32_t(coreIndex.coreIndex())},
2333 &aidlDesc);
2334 c2_status_t status = GetC2Status(transStatus, "describe");
2335 if (status != C2_OK) {
2336 descriptor.reset();
2337 } else if (!c2_aidl::utils::FromAidl(&descriptor, aidlDesc[0])) {
2338 LOG(ERROR) << "describe -- conversion failed.";
2339 descriptor.reset();
2340 }
2341 return descriptor;
2342 }
2343
2344 AidlSimpleParamReflector(const std::shared_ptr<AidlBase> &base)
2345 : mBase(base) { }
2346
2347 std::shared_ptr<AidlBase> mBase;
2348 };
2349
2350 if (mAidlBase) {
2351 return std::make_shared<AidlSimpleParamReflector>(mAidlBase);
2352 }
2353 return std::make_shared<HidlSimpleParamReflector>(mHidlBase1_0);
2354 };
2355
CacheServiceNames()2356 std::vector<std::string> Codec2Client::CacheServiceNames() {
2357 std::vector<std::string> names;
2358
2359 if (c2_aidl::utils::IsSelected()) {
2360 if (__builtin_available(android __ANDROID_API_S__, *)) {
2361 // Get AIDL service names
2362 AServiceManager_forEachDeclaredInstance(
2363 AidlBase::descriptor, &names, [](const char *name, void *context) {
2364 std::vector<std::string> *names = (std::vector<std::string> *)context;
2365 names->emplace_back(name);
2366 });
2367 } else {
2368 LOG(FATAL) << "C2 AIDL cannot be selected on Android version older than 35";
2369 }
2370 } else {
2371 // Get HIDL service names
2372 using ::android::hardware::media::c2::V1_0::IComponentStore;
2373 using ::android::hidl::manager::V1_2::IServiceManager;
2374 while (true) {
2375 sp<IServiceManager> serviceManager = IServiceManager::getService();
2376 CHECK(serviceManager) << "Hardware service manager is not running.";
2377
2378 Return<void> transResult;
2379 transResult = serviceManager->listManifestByInterface(
2380 IComponentStore::descriptor,
2381 [&names](
2382 hidl_vec<hidl_string> const& instanceNames) {
2383 names.insert(names.end(), instanceNames.begin(), instanceNames.end());
2384 });
2385 if (transResult.isOk()) {
2386 break;
2387 }
2388 LOG(ERROR) << "Could not retrieve the list of service instances of "
2389 << IComponentStore::descriptor
2390 << ". Retrying...";
2391 }
2392 }
2393 // Sort service names in each category.
2394 std::stable_sort(
2395 names.begin(), names.end(),
2396 [](const std::string &a, const std::string &b) {
2397 // First compare by prefix: default -> vendor -> {everything else}
2398 constexpr int DEFAULT = 1;
2399 constexpr int VENDOR = 2;
2400 constexpr int OTHER = 3;
2401 int aPrefix = ((a.compare(0, 7, "default") == 0) ? DEFAULT :
2402 (a.compare(0, 6, "vendor") == 0) ? VENDOR :
2403 OTHER);
2404 int bPrefix = ((b.compare(0, 7, "default") == 0) ? DEFAULT :
2405 (b.compare(0, 6, "vendor") == 0) ? VENDOR :
2406 OTHER);
2407 if (aPrefix != bPrefix) {
2408 return aPrefix < bPrefix;
2409 }
2410 // If the prefix is the same, compare alphabetically
2411 return a < b;
2412 });
2413
2414 if (__builtin_available(android 36, *)) {
2415 if (android::media::codec::provider_->in_process_sw_audio_codec_support()
2416 && nullptr != ApexCodec_GetComponentStore()) {
2417 names.push_back("__ApexCodecs__");
2418 }
2419 }
2420
2421 // Summarize to logcat.
2422 if (names.empty()) {
2423 LOG(INFO) << "No Codec2 services declared in the manifest.";
2424 } else {
2425 std::stringstream stringOutput;
2426 stringOutput << "Available Codec2 services:";
2427 for (std::string const& name : names) {
2428 stringOutput << " \"" << name << "\"";
2429 }
2430 LOG(INFO) << stringOutput.str();
2431 }
2432
2433 return names;
2434 }
2435
GetServiceNames()2436 std::vector<std::string> const& Codec2Client::GetServiceNames() {
2437 static std::vector<std::string> sServiceNames = CacheServiceNames();
2438 return sServiceNames;
2439 }
2440
CreateFromService(const char * name,bool setAsPreferredCodec2ComponentStore)2441 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
2442 const char* name,
2443 bool setAsPreferredCodec2ComponentStore) {
2444 size_t index = getServiceIndex(name);
2445 if (index == GetServiceNames().size()) {
2446 if (setAsPreferredCodec2ComponentStore) {
2447 LOG(WARNING) << "CreateFromService(" << name
2448 << ") -- preferred C2ComponentStore not set.";
2449 }
2450 return nullptr;
2451 }
2452 std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
2453 if (setAsPreferredCodec2ComponentStore) {
2454 SetPreferredCodec2ComponentStore(
2455 std::make_shared<Client2Store>(client));
2456 LOG(INFO) << "CreateFromService(" << name
2457 << ") -- service set as preferred C2ComponentStore.";
2458 }
2459 return client;
2460 }
2461
2462 std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
CreateFromAllServices()2463 CreateFromAllServices() {
2464 std::vector<std::shared_ptr<Codec2Client>> clients(
2465 GetServiceNames().size());
2466 for (size_t i = GetServiceNames().size(); i > 0; ) {
2467 --i;
2468 clients[i] = _CreateFromIndex(i);
2469 }
2470 return clients;
2471 }
2472
_CreateFromIndex(size_t index)2473 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
2474 std::string const& name = GetServiceNames()[index];
2475 LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
2476
2477 if (name == "__ApexCodecs__") {
2478 if (__builtin_available(android 36, *)) {
2479 return std::make_shared<Codec2Client>(ApexCodec_GetComponentStore(), index);
2480 } else {
2481 LOG(FATAL) << "ApexCodecs not supported on Android version older than 36";
2482 }
2483 } else if (c2_aidl::utils::IsSelected()) {
2484 if (__builtin_available(android __ANDROID_API_S__, *)) {
2485 std::string instanceName =
2486 ::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
2487 if (AServiceManager_isDeclared(instanceName.c_str())) {
2488 std::shared_ptr<AidlBase> baseStore = AidlBase::fromBinder(
2489 ::ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
2490 CHECK(baseStore) << "Codec2 AIDL service \"" << name << "\""
2491 " inaccessible for unknown reasons.";
2492 LOG(VERBOSE) << "Client to Codec2 AIDL service \"" << name << "\" created";
2493 std::shared_ptr<c2_aidl::IConfigurable> configurable;
2494 ::ndk::ScopedAStatus transStatus = baseStore->getConfigurable(&configurable);
2495 CHECK(transStatus.isOk()) << "Codec2 AIDL service \"" << name << "\""
2496 "does not have IConfigurable.";
2497 return std::make_shared<Codec2Client>(baseStore, configurable, index);
2498 } else {
2499 LOG(ERROR) << "Codec2 AIDL service \"" << name << "\" is not declared";
2500 }
2501 } else {
2502 LOG(FATAL) << "C2 AIDL cannot be selected on Android version older than 35";
2503 }
2504 } else {
2505 std::string instanceName = "android.hardware.media.c2/" + name;
2506 sp<HidlBase> baseStore = HidlBase::getService(name);
2507 CHECK(baseStore) << "Codec2 service \"" << name << "\""
2508 " inaccessible for unknown reasons.";
2509 LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
2510 Return<sp<c2_hidl::IConfigurable>> transResult = baseStore->getConfigurable();
2511 CHECK(transResult.isOk()) << "Codec2 service \"" << name << "\""
2512 "does not have IConfigurable.";
2513 sp<c2_hidl::IConfigurable> configurable =
2514 static_cast<sp<c2_hidl::IConfigurable>>(transResult);
2515 return std::make_shared<Codec2Client>(baseStore, configurable, index);
2516 }
2517 return nullptr;
2518 }
2519
ForAllServices(const std::string & key,size_t numberOfAttempts,std::function<c2_status_t (const std::shared_ptr<Codec2Client> &)> predicate)2520 c2_status_t Codec2Client::ForAllServices(
2521 const std::string &key,
2522 size_t numberOfAttempts,
2523 std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
2524 predicate) {
2525 c2_status_t status = C2_NO_INIT; // no IComponentStores present
2526
2527 // Cache the mapping key -> index of Codec2Client in Cache::List().
2528 static std::mutex key2IndexMutex;
2529 static std::map<std::string, size_t> key2Index;
2530
2531 // By default try all stores. However, try the last known client first. If
2532 // the last known client fails, retry once. We do this by pushing the last
2533 // known client in front of the list of all clients.
2534 std::deque<size_t> indices;
2535 for (size_t index = Cache::List().size(); index > 0; ) {
2536 indices.push_front(--index);
2537 }
2538
2539 bool wasMapped = false;
2540 {
2541 std::scoped_lock lock{key2IndexMutex};
2542 auto it = key2Index.find(key);
2543 if (it != key2Index.end()) {
2544 indices.push_front(it->second);
2545 wasMapped = true;
2546 }
2547 }
2548
2549 for (size_t index : indices) {
2550 Cache& cache = Cache::List()[index];
2551 for (size_t tries = numberOfAttempts; tries > 0; --tries) {
2552 std::shared_ptr<Codec2Client> client{cache.getClient()};
2553 status = predicate(client);
2554 if (status == C2_OK) {
2555 std::scoped_lock lock{key2IndexMutex};
2556 key2Index[key] = index; // update last known client index
2557 return C2_OK;
2558 } else if (status == C2_NO_MEMORY) {
2559 return C2_NO_MEMORY;
2560 } else if (status == C2_TRANSACTION_FAILED) {
2561 LOG(WARNING) << "\"" << key << "\" failed for service \""
2562 << client->getName()
2563 << "\" due to transaction failure. "
2564 << "(Service may have crashed.)"
2565 << (tries > 1 ? " Retrying..." : "");
2566 cache.invalidate();
2567 continue;
2568 }
2569 if (wasMapped) {
2570 LOG(INFO) << "\"" << key << "\" became invalid in service \""
2571 << client->getName() << "\". Retrying...";
2572 wasMapped = false;
2573 }
2574 break;
2575 }
2576 }
2577 return status; // return the last status from a valid client
2578 }
2579
CreateComponentByName(const char * componentName,const std::shared_ptr<Listener> & listener,std::shared_ptr<Component> * component,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)2580 c2_status_t Codec2Client::CreateComponentByName(
2581 const char* componentName,
2582 const std::shared_ptr<Listener>& listener,
2583 std::shared_ptr<Component>* component,
2584 std::shared_ptr<Codec2Client>* owner,
2585 size_t numberOfAttempts) {
2586 std::string key{"create:"};
2587 key.append(componentName);
2588 c2_status_t status = ForAllServices(
2589 key,
2590 numberOfAttempts,
2591 [owner, component, componentName, &listener](
2592 const std::shared_ptr<Codec2Client> &client)
2593 -> c2_status_t {
2594 c2_status_t status = client->createComponent(componentName,
2595 listener,
2596 component);
2597 if (status == C2_OK) {
2598 if (owner) {
2599 *owner = client;
2600 }
2601 } else if (status != C2_NOT_FOUND) {
2602 LOG(DEBUG) << "IComponentStore("
2603 << client->getServiceName()
2604 << ")::createComponent(\"" << componentName
2605 << "\") returned status = "
2606 << status << ".";
2607 }
2608 return status;
2609 });
2610 if (status != C2_OK) {
2611 LOG(DEBUG) << "Failed to create component \"" << componentName
2612 << "\" from all known services. "
2613 "Last returned status = " << status << ".";
2614 }
2615 return status;
2616 }
2617
CreateInterfaceByName(const char * interfaceName,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)2618 std::shared_ptr<Codec2Client::Interface> Codec2Client::CreateInterfaceByName(
2619 const char* interfaceName,
2620 std::shared_ptr<Codec2Client>* owner,
2621 size_t numberOfAttempts) {
2622 std::string key{"create:"};
2623 key.append(interfaceName);
2624 std::shared_ptr<Interface> interface;
2625 c2_status_t status = ForAllServices(
2626 key,
2627 numberOfAttempts,
2628 [owner, &interface, interfaceName](
2629 const std::shared_ptr<Codec2Client> &client)
2630 -> c2_status_t {
2631 c2_status_t status = client->createInterface(interfaceName,
2632 &interface);
2633 if (status == C2_OK) {
2634 if (owner) {
2635 *owner = client;
2636 }
2637 } else if (status != C2_NOT_FOUND) {
2638 LOG(DEBUG) << "IComponentStore("
2639 << client->getServiceName()
2640 << ")::createInterface(\"" << interfaceName
2641 << "\") returned status = "
2642 << status << ".";
2643 }
2644 return status;
2645 });
2646 if (status != C2_OK) {
2647 LOG(DEBUG) << "Failed to create interface \"" << interfaceName
2648 << "\" from all known services. "
2649 "Last returned status = " << status << ".";
2650 }
2651 return interface;
2652 }
2653
ListComponents()2654 std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
2655 static std::vector<C2Component::Traits> sList{[]() {
2656 std::vector<C2Component::Traits> list;
2657 for (Cache& cache : Cache::List()) {
2658 std::vector<C2Component::Traits> const& traits = cache.getTraits();
2659 list.insert(list.end(), traits.begin(), traits.end());
2660 }
2661 return list;
2662 }()};
2663 return sList;
2664 }
2665
CreateInputSurface(char const * serviceName)2666 std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface(
2667 char const* serviceName) {
2668 if (!IsCodec2AidlInputSurfaceSelected()) {
2669 return nullptr;
2670 }
2671 size_t index = GetServiceNames().size();
2672 if (serviceName) {
2673 index = getServiceIndex(serviceName);
2674 if (index == GetServiceNames().size()) {
2675 LOG(DEBUG) << "CreateInputSurface -- invalid service name: \""
2676 << serviceName << "\"";
2677 }
2678 }
2679
2680 std::shared_ptr<Codec2Client::InputSurface> inputSurface;
2681 if (index != GetServiceNames().size()) {
2682 std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient();
2683 if (client->createInputSurface(&inputSurface) == C2_OK) {
2684 return inputSurface;
2685 }
2686 }
2687 LOG(INFO) << "CreateInputSurface -- attempting to create an input surface "
2688 "from all services...";
2689 for (Cache& cache : Cache::List()) {
2690 std::shared_ptr<Codec2Client> client = cache.getClient();
2691 if (client->createInputSurface(&inputSurface) == C2_OK) {
2692 LOG(INFO) << "CreateInputSurface -- input surface obtained from "
2693 "service \"" << client->getServiceName() << "\"";
2694 return inputSurface;
2695 }
2696 }
2697 LOG(WARNING) << "CreateInputSurface -- failed to create an input surface "
2698 "from all services";
2699 return nullptr;
2700 }
2701
IsAidlSelected()2702 bool Codec2Client::IsAidlSelected() {
2703 return c2_aidl::utils::IsSelected();
2704 }
2705
2706 // Codec2Client::Interface
Interface(const sp<HidlBase> & base)2707 Codec2Client::Interface::Interface(const sp<HidlBase>& base)
2708 : Configurable{
2709 [base]() -> sp<c2_hidl::IConfigurable> {
2710 Return<sp<c2_hidl::IConfigurable>> transResult =
2711 base->getConfigurable();
2712 return transResult.isOk() ?
2713 static_cast<sp<c2_hidl::IConfigurable>>(transResult) :
2714 nullptr;
2715 }()
2716 },
2717 mHidlBase{base} {
2718 }
2719
Interface(const std::shared_ptr<AidlBase> & base)2720 Codec2Client::Interface::Interface(const std::shared_ptr<AidlBase>& base)
2721 : Configurable{
2722 [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
2723 std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
2724 ::ndk::ScopedAStatus transStatus =
2725 base->getConfigurable(&aidlConfigurable);
2726 return transStatus.isOk() ? aidlConfigurable : nullptr;
2727 }()
2728 },
2729 mAidlBase{base} {
2730 }
2731
2732 // Codec2Client::Component
2733
2734 class Codec2Client::Component::AidlDeathManager {
2735 public:
AidlDeathManager()2736 AidlDeathManager()
2737 : mSeq(0),
2738 mDeathRecipient(AIBinder_DeathRecipient_new(OnBinderDied)) {
2739 }
2740
2741 ~AidlDeathManager() = default;
2742
linkToDeath(const std::shared_ptr<Component> & comp,const std::shared_ptr<Listener> & listener,size_t * seqPtr)2743 bool linkToDeath(
2744 const std::shared_ptr<Component> &comp,
2745 const std::shared_ptr<Listener> &listener,
2746 size_t *seqPtr) {
2747 std::unique_lock lock(mMutex);
2748 size_t seq = mSeq++;
2749 if (!mMap.try_emplace(seq, comp, listener).second) {
2750 return false;
2751 }
2752 if (STATUS_OK != AIBinder_linkToDeath(
2753 comp->mAidlBase->asBinder().get(), mDeathRecipient.get(), (void *)seq)) {
2754 mMap.erase(seq);
2755 return false;
2756 }
2757 *seqPtr = seq;
2758 return true;
2759 }
2760
unlinkToDeath(size_t seq,const std::shared_ptr<AidlBase> & base)2761 void unlinkToDeath(size_t seq, const std::shared_ptr<AidlBase> &base) {
2762 std::unique_lock lock(mMutex);
2763 AIBinder_unlinkToDeath(base->asBinder().get(), mDeathRecipient.get(), (void *)seq);
2764 mMap.erase(seq);
2765 }
2766
2767 private:
2768 std::mutex mMutex;
2769 size_t mSeq;
2770 typedef std::tuple<std::weak_ptr<Component>, std::weak_ptr<Listener>> Context;
2771 std::map<size_t, Context> mMap;
2772 ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
2773
extractContext(size_t seq,Context * context)2774 bool extractContext(size_t seq, Context *context) {
2775 std::unique_lock lock(mMutex);
2776 auto node = mMap.extract(seq);
2777 if (!node) {
2778 return false;
2779 }
2780 *context = node.mapped();
2781 return true;
2782 }
2783
OnBinderDied(void * cookie)2784 static void OnBinderDied(void *cookie) {
2785 size_t seq = size_t(cookie);
2786 Context context;
2787 if (!Component::GetAidlDeathManager()->extractContext(seq, &context)) {
2788 return;
2789 }
2790 std::weak_ptr<Component> weakComponent;
2791 std::weak_ptr<Listener> weakListener;
2792 std::tie(weakComponent, weakListener) = context;
2793 if (std::shared_ptr<Listener> listener = weakListener.lock()) {
2794 listener->onDeath(weakComponent);
2795 } else {
2796 LOG(DEBUG) << "onDeath -- listener died.";
2797 }
2798 }
2799 };
2800
Component(const sp<HidlBase> & base)2801 Codec2Client::Component::Component(const sp<HidlBase>& base)
2802 : Configurable{
2803 [base]() -> sp<c2_hidl::IConfigurable> {
2804 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
2805 base->getInterface();
2806 if (!transResult1.isOk()) {
2807 return nullptr;
2808 }
2809 Return<sp<c2_hidl::IConfigurable>> transResult2 =
2810 static_cast<sp<c2_hidl::IComponentInterface>>(transResult1)->
2811 getConfigurable();
2812 return transResult2.isOk() ?
2813 static_cast<sp<c2_hidl::IConfigurable>>(transResult2) :
2814 nullptr;
2815 }()
2816 },
2817 mHidlBase1_0{base},
2818 mHidlBase1_1{HidlBase1_1::castFrom(base)},
2819 mHidlBase1_2{HidlBase1_2::castFrom(base)},
2820 mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
2821 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
2822 }
2823
Component(const sp<HidlBase1_1> & base)2824 Codec2Client::Component::Component(const sp<HidlBase1_1>& base)
2825 : Configurable{
2826 [base]() -> sp<c2_hidl::IConfigurable> {
2827 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
2828 base->getInterface();
2829 if (!transResult1.isOk()) {
2830 return nullptr;
2831 }
2832 Return<sp<c2_hidl::IConfigurable>> transResult2 =
2833 static_cast<sp<c2_hidl::IComponentInterface>>(transResult1)->
2834 getConfigurable();
2835 return transResult2.isOk() ?
2836 static_cast<sp<c2_hidl::IConfigurable>>(transResult2) :
2837 nullptr;
2838 }()
2839 },
2840 mHidlBase1_0{base},
2841 mHidlBase1_1{base},
2842 mHidlBase1_2{HidlBase1_2::castFrom(base)},
2843 mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
2844 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
2845 }
2846
Component(const sp<HidlBase1_2> & base)2847 Codec2Client::Component::Component(const sp<HidlBase1_2>& base)
2848 : Configurable{
2849 [base]() -> sp<c2_hidl::IConfigurable> {
2850 Return<sp<c2_hidl::IComponentInterface>> transResult1 =
2851 base->getInterface();
2852 if (!transResult1.isOk()) {
2853 return nullptr;
2854 }
2855 Return<sp<c2_hidl::IConfigurable>> transResult2 =
2856 static_cast<sp<c2_hidl::IComponentInterface>>(transResult1)->
2857 getConfigurable();
2858 return transResult2.isOk() ?
2859 static_cast<sp<c2_hidl::IConfigurable>>(transResult2) :
2860 nullptr;
2861 }()
2862 },
2863 mHidlBase1_0{base},
2864 mHidlBase1_1{base},
2865 mHidlBase1_2{base},
2866 mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
2867 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
2868 }
2869
Component(const std::shared_ptr<AidlBase> & base)2870 Codec2Client::Component::Component(const std::shared_ptr<AidlBase> &base)
2871 : Configurable{
2872 [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
2873 std::shared_ptr<c2_aidl::IComponentInterface> aidlIntf;
2874 ::ndk::ScopedAStatus transStatus = base->getInterface(&aidlIntf);
2875 if (!transStatus.isOk()) {
2876 return nullptr;
2877 }
2878 std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
2879 transStatus = aidlIntf->getConfigurable(&aidlConfigurable);
2880 return transStatus.isOk() ? aidlConfigurable : nullptr;
2881 }()
2882 },
2883 mAidlBase{base},
2884 mAidlBufferPoolSender{std::make_unique<AidlBufferPoolSender>()},
2885 mGraphicBufferAllocators{std::make_unique<GraphicBufferAllocators>()} {
2886 }
2887
Component(ApexCodec_Component * base,const C2String & name)2888 Codec2Client::Component::Component(ApexCodec_Component *base, const C2String &name)
2889 : Configurable{[base]() -> ApexCodec_Configurable * {
2890 if (__builtin_available(android 36, *)) {
2891 return ApexCodec_Component_getConfigurable(base);
2892 } else {
2893 return nullptr;
2894 }
2895 }(), name},
2896 mApexBase{base} {
2897 }
2898
~Component()2899 Codec2Client::Component::~Component() {
2900 if (mAidlDeathSeq) {
2901 GetAidlDeathManager()->unlinkToDeath(*mAidlDeathSeq, mAidlBase);
2902 }
2903 if (mApexBase) {
2904 if (__builtin_available(android 36, *)) {
2905 ApexCodec_Component_destroy(mApexBase);
2906 }
2907 mApexBase = nullptr;
2908 }
2909 }
2910
createBlockPool(C2Allocator::id_t id,C2BlockPool::local_id_t * blockPoolId,std::shared_ptr<Codec2Client::Configurable> * configurable)2911 c2_status_t Codec2Client::Component::createBlockPool(
2912 C2Allocator::id_t id,
2913 C2BlockPool::local_id_t* blockPoolId,
2914 std::shared_ptr<Codec2Client::Configurable>* configurable) {
2915 if (mApexBase) {
2916 std::shared_ptr<C2BlockPool> blockPool;
2917 CreateCodec2BlockPool(id, nullptr, &blockPool);
2918 *blockPoolId = blockPool->getLocalId();
2919 *configurable = nullptr;
2920 mBlockPools[*blockPoolId] = blockPool;
2921 return C2_OK;
2922 }
2923 if (mAidlBase) {
2924 c2_aidl::IComponent::BlockPool aidlBlockPool;
2925 c2_status_t status = C2_OK;
2926
2927 // TODO: Temporary mapping for the current CCodecBufferChannel.
2928 // Handle this properly and remove this temporary allocator mapping.
2929 id = id == C2PlatformAllocatorStore::BUFFERQUEUE ?
2930 C2PlatformAllocatorStore::IGBA : id;
2931
2932 c2_aidl::IComponent::BlockPoolAllocator allocator;
2933 allocator.allocatorId = id;
2934 if (id == C2PlatformAllocatorStore::IGBA) {
2935 std::shared_ptr<AidlGraphicBufferAllocator> gba =
2936 mGraphicBufferAllocators->create();
2937 ::ndk::ScopedFileDescriptor waitableFd;
2938 ::ndk::ScopedAStatus ret = gba->getWaitableFd(&waitableFd);
2939 status = GetC2Status(ret, "Gba::getWaitableFd");
2940 if (status != C2_OK) {
2941 return status;
2942 }
2943 c2_aidl::IComponent::GbAllocator gbAllocator;
2944 gbAllocator.waitableFd = std::move(waitableFd);
2945 gbAllocator.igba =
2946 c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
2947 allocator.gbAllocator = std::move(gbAllocator);
2948 ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
2949 allocator, &aidlBlockPool);
2950 status = GetC2Status(transStatus, "createBlockPool");
2951 if (status != C2_OK) {
2952 return status;
2953 }
2954 mGraphicBufferAllocators->setCurrentId(aidlBlockPool.blockPoolId);
2955 } else {
2956 ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
2957 allocator, &aidlBlockPool);
2958 status = GetC2Status(transStatus, "createBlockPool");
2959 if (status != C2_OK) {
2960 return status;
2961 }
2962 }
2963 *blockPoolId = aidlBlockPool.blockPoolId;
2964 *configurable = std::make_shared<Configurable>(aidlBlockPool.configurable);
2965 return C2_OK;
2966 }
2967 c2_status_t status;
2968 Return<void> transStatus = mHidlBase1_0->createBlockPool(
2969 static_cast<uint32_t>(id),
2970 [&status, blockPoolId, configurable](
2971 c2_hidl::Status s,
2972 uint64_t pId,
2973 const sp<c2_hidl::IConfigurable>& c) {
2974 status = static_cast<c2_status_t>(s);
2975 configurable->reset();
2976 if (status != C2_OK) {
2977 LOG(DEBUG) << "createBlockPool -- call failed: "
2978 << status << ".";
2979 return;
2980 }
2981 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
2982 *configurable = std::make_shared<Configurable>(c);
2983 });
2984 if (!transStatus.isOk()) {
2985 LOG(ERROR) << "createBlockPool -- transaction failed.";
2986 return C2_TRANSACTION_FAILED;
2987 }
2988 return status;
2989 }
2990
destroyBlockPool(C2BlockPool::local_id_t localId)2991 c2_status_t Codec2Client::Component::destroyBlockPool(
2992 C2BlockPool::local_id_t localId) {
2993 if (mApexBase) {
2994 mBlockPools.erase(localId);
2995 return C2_OK;
2996 }
2997 if (mAidlBase) {
2998 mGraphicBufferAllocators->remove(localId);
2999 ::ndk::ScopedAStatus transStatus = mAidlBase->destroyBlockPool(localId);
3000 return GetC2Status(transStatus, "destroyBlockPool");
3001 }
3002 Return<c2_hidl::Status> transResult = mHidlBase1_0->destroyBlockPool(
3003 static_cast<uint64_t>(localId));
3004 if (!transResult.isOk()) {
3005 LOG(ERROR) << "destroyBlockPool -- transaction failed.";
3006 return C2_TRANSACTION_FAILED;
3007 }
3008 return static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transResult));
3009 }
3010
handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> & workItems)3011 void Codec2Client::Component::handleOnWorkDone(
3012 const std::list<std::unique_ptr<C2Work>> &workItems) {
3013 if (mApexBase) {
3014 // no-op
3015 return;
3016 } else if (mAidlBase) {
3017 holdIgbaBlocks(workItems);
3018 } else {
3019 // Output bufferqueue-based blocks' lifetime management
3020 mOutputBufferQueue->holdBufferQueueBlocks(workItems);
3021 }
3022 }
3023
queue(std::list<std::unique_ptr<C2Work>> * const items)3024 c2_status_t Codec2Client::Component::queue(
3025 std::list<std::unique_ptr<C2Work>>* const items) {
3026 if (mApexBase) {
3027 mApexHandler->queue(*items);
3028 return C2_OK;
3029 }
3030 if (mAidlBase) {
3031 c2_aidl::WorkBundle workBundle;
3032 if (!c2_aidl::utils::ToAidl(&workBundle, *items, mAidlBufferPoolSender.get())) {
3033 LOG(ERROR) << "queue -- bad input.";
3034 return C2_TRANSACTION_FAILED;
3035 }
3036 ::ndk::ScopedAStatus transStatus = mAidlBase->queue(workBundle);
3037 return GetC2Status(transStatus, "queue");
3038 }
3039 c2_hidl::WorkBundle workBundle;
3040 if (!c2_hidl::utils::objcpy(&workBundle, *items, mHidlBufferPoolSender.get())) {
3041 LOG(ERROR) << "queue -- bad input.";
3042 return C2_TRANSACTION_FAILED;
3043 }
3044 Return<c2_hidl::Status> transStatus = mHidlBase1_0->queue(workBundle);
3045 if (!transStatus.isOk()) {
3046 LOG(ERROR) << "queue -- transaction failed.";
3047 return C2_TRANSACTION_FAILED;
3048 }
3049 c2_status_t status =
3050 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3051 if (status != C2_OK) {
3052 LOG(DEBUG) << "queue -- call failed: " << status << ".";
3053 }
3054 return status;
3055 }
3056
flush(C2Component::flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)3057 c2_status_t Codec2Client::Component::flush(
3058 C2Component::flush_mode_t mode,
3059 std::list<std::unique_ptr<C2Work>>* const flushedWork) {
3060 (void)mode; // Flush mode isn't supported in HIDL/AIDL yet.
3061 if (mApexBase) {
3062 if (__builtin_available(android 36, *)) {
3063 return (c2_status_t)ApexCodec_Component_flush(mApexBase);
3064 } else {
3065 return C2_OMITTED;
3066 }
3067 }
3068 c2_status_t status = C2_OK;
3069 if (mAidlBase) {
3070 c2_aidl::WorkBundle workBundle;
3071 ::ndk::ScopedAStatus transStatus = mAidlBase->flush(&workBundle);
3072 c2_status_t status = GetC2Status(transStatus, "flush");
3073 if (status != C2_OK) {
3074 return status;
3075 }
3076 if (!c2_aidl::utils::FromAidl(flushedWork, workBundle)) {
3077 LOG(DEBUG) << "flush -- flushedWork corrupted.";
3078 return C2_CORRUPTED;
3079 }
3080 } else {
3081 Return<void> transStatus = mHidlBase1_0->flush(
3082 [&status, flushedWork](
3083 c2_hidl::Status s, const c2_hidl::WorkBundle& wb) {
3084 status = static_cast<c2_status_t>(s);
3085 if (status != C2_OK) {
3086 LOG(DEBUG) << "flush -- call failed: " << status << ".";
3087 return;
3088 }
3089 if (!c2_hidl::utils::objcpy(flushedWork, wb)) {
3090 status = C2_CORRUPTED;
3091 } else {
3092 status = C2_OK;
3093 }
3094 });
3095 if (!transStatus.isOk()) {
3096 LOG(ERROR) << "flush -- transaction failed.";
3097 return C2_TRANSACTION_FAILED;
3098 }
3099 }
3100
3101 // Indices of flushed work items.
3102 std::vector<uint64_t> flushedIndices;
3103 for (const std::unique_ptr<C2Work> &work : *flushedWork) {
3104 if (work) {
3105 if (work->worklets.empty()
3106 || !work->worklets.back()
3107 || (work->worklets.back()->output.flags &
3108 C2FrameData::FLAG_INCOMPLETE) == 0) {
3109 // input is complete
3110 flushedIndices.emplace_back(
3111 work->input.ordinal.frameIndex.peeku());
3112 }
3113 }
3114 }
3115
3116 if (mAidlBase) {
3117 holdIgbaBlocks(*flushedWork);
3118 } else {
3119 // Output bufferqueue-based blocks' lifetime management
3120 mOutputBufferQueue->holdBufferQueueBlocks(*flushedWork);
3121 }
3122
3123 return status;
3124 }
3125
drain(C2Component::drain_mode_t mode)3126 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
3127 if (mApexBase) {
3128 return C2_OMITTED;
3129 }
3130 if (mAidlBase) {
3131 ::ndk::ScopedAStatus transStatus = mAidlBase->drain(
3132 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
3133 return GetC2Status(transStatus, "drain");
3134 }
3135 Return<c2_hidl::Status> transStatus = mHidlBase1_0->drain(
3136 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
3137 if (!transStatus.isOk()) {
3138 LOG(ERROR) << "drain -- transaction failed.";
3139 return C2_TRANSACTION_FAILED;
3140 }
3141 c2_status_t status =
3142 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3143 if (status != C2_OK) {
3144 LOG(DEBUG) << "drain -- call failed: " << status << ".";
3145 }
3146 return status;
3147 }
3148
start()3149 c2_status_t Codec2Client::Component::start() {
3150 if (mApexBase) {
3151 // no-op
3152 return C2_OK;
3153 }
3154 if (mAidlBase) {
3155 ::ndk::ScopedAStatus transStatus = mAidlBase->start();
3156 return GetC2Status(transStatus, "start");
3157 }
3158 Return<c2_hidl::Status> transStatus = mHidlBase1_0->start();
3159 if (!transStatus.isOk()) {
3160 LOG(ERROR) << "start -- transaction failed.";
3161 return C2_TRANSACTION_FAILED;
3162 }
3163 c2_status_t status =
3164 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3165 if (status != C2_OK) {
3166 LOG(DEBUG) << "start -- call failed: " << status << ".";
3167 }
3168 return status;
3169 }
3170
stop()3171 c2_status_t Codec2Client::Component::stop() {
3172 if (mAidlBase) {
3173 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3174 mGraphicBufferAllocators->current();
3175 if (gba) {
3176 gba->onRequestStop();
3177 }
3178 ::ndk::ScopedAStatus transStatus = mAidlBase->stop();
3179 return GetC2Status(transStatus, "stop");
3180 }
3181 Return<c2_hidl::Status> transStatus = mHidlBase1_0->stop();
3182 if (!transStatus.isOk()) {
3183 LOG(ERROR) << "stop -- transaction failed.";
3184 return C2_TRANSACTION_FAILED;
3185 }
3186 c2_status_t status =
3187 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3188 if (status != C2_OK) {
3189 LOG(DEBUG) << "stop -- call failed: " << status << ".";
3190 }
3191 return status;
3192 }
3193
reset()3194 c2_status_t Codec2Client::Component::reset() {
3195 if (mApexBase) {
3196 if (__builtin_available(android 36, *)) {
3197 return (c2_status_t)ApexCodec_Component_reset(mApexBase);
3198 } else {
3199 return C2_OMITTED;
3200 }
3201 }
3202 if (mAidlBase) {
3203 ::ndk::ScopedAStatus transStatus = mAidlBase->reset();
3204 return GetC2Status(transStatus, "reset");
3205 }
3206 Return<c2_hidl::Status> transStatus = mHidlBase1_0->reset();
3207 if (!transStatus.isOk()) {
3208 LOG(ERROR) << "reset -- transaction failed.";
3209 return C2_TRANSACTION_FAILED;
3210 }
3211 c2_status_t status =
3212 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3213 if (status != C2_OK) {
3214 LOG(DEBUG) << "reset -- call failed: " << status << ".";
3215 }
3216 return status;
3217 }
3218
release()3219 c2_status_t Codec2Client::Component::release() {
3220 if (mApexBase) {
3221 if (__builtin_available(android 36, *)) {
3222 return (c2_status_t)ApexCodec_Component_reset(mApexBase);
3223 } else {
3224 return C2_OMITTED;
3225 }
3226 }
3227 if (mAidlBase) {
3228 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3229 mGraphicBufferAllocators->current();
3230 if (gba) {
3231 gba->onRequestStop();
3232 }
3233 ::ndk::ScopedAStatus transStatus = mAidlBase->release();
3234 return GetC2Status(transStatus, "release");
3235 }
3236 Return<c2_hidl::Status> transStatus = mHidlBase1_0->release();
3237 if (!transStatus.isOk()) {
3238 LOG(ERROR) << "release -- transaction failed.";
3239 return C2_TRANSACTION_FAILED;
3240 }
3241 c2_status_t status =
3242 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3243 if (status != C2_OK) {
3244 LOG(DEBUG) << "release -- call failed: " << status << ".";
3245 }
3246 return status;
3247 }
3248
configureVideoTunnel(uint32_t avSyncHwId,native_handle_t ** sidebandHandle)3249 c2_status_t Codec2Client::Component::configureVideoTunnel(
3250 uint32_t avSyncHwId,
3251 native_handle_t** sidebandHandle) {
3252 *sidebandHandle = nullptr;
3253 if (mApexBase) {
3254 // tunneling is not supported in APEX
3255 return C2_OMITTED;
3256 }
3257 if (mAidlBase) {
3258 ::aidl::android::hardware::common::NativeHandle handle;
3259 ::ndk::ScopedAStatus transStatus = mAidlBase->configureVideoTunnel(avSyncHwId, &handle);
3260 c2_status_t status = GetC2Status(transStatus, "configureVideoTunnel");
3261 if (status != C2_OK) {
3262 return status;
3263 }
3264 if (isAidlNativeHandleEmpty(handle)) {
3265 LOG(DEBUG) << "configureVideoTunnel -- empty handle returned";
3266 } else {
3267 *sidebandHandle = dupFromAidl(handle);
3268 }
3269 return C2_OK;
3270 }
3271 if (!mHidlBase1_1) {
3272 return C2_OMITTED;
3273 }
3274 c2_status_t status{};
3275 Return<void> transStatus = mHidlBase1_1->configureVideoTunnel(avSyncHwId,
3276 [&status, sidebandHandle](
3277 c2_hidl::Status s, hardware::hidl_handle const& h) {
3278 status = static_cast<c2_status_t>(s);
3279 if (h.getNativeHandle()) {
3280 *sidebandHandle = native_handle_clone(h.getNativeHandle());
3281 }
3282 });
3283 if (!transStatus.isOk()) {
3284 LOG(ERROR) << "configureVideoTunnel -- transaction failed.";
3285 return C2_TRANSACTION_FAILED;
3286 }
3287 return status;
3288 }
3289
setOutputSurface(C2BlockPool::local_id_t blockPoolId,const sp<IGraphicBufferProducer> & surface,uint32_t generation,int maxDequeueCount)3290 c2_status_t Codec2Client::Component::setOutputSurface(
3291 C2BlockPool::local_id_t blockPoolId,
3292 const sp<IGraphicBufferProducer>& surface,
3293 uint32_t generation,
3294 int maxDequeueCount) {
3295 if (mAidlBase) {
3296 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3297 mGraphicBufferAllocators->current();
3298 if (!gba) {
3299 LOG(ERROR) << "setOutputSurface for AIDL -- "
3300 "GraphicBufferAllocator was not created.";
3301 return C2_CORRUPTED;
3302 }
3303 // Note: Consumer usage is set ahead of the HAL allocator(gba) being set.
3304 // This is same as HIDL.
3305 uint64_t consumerUsage = configConsumerUsage(surface);
3306 bool ret = gba->configure(surface, generation, maxDequeueCount);
3307 ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx",
3308 generation, (long long)consumerUsage);
3309 return ret ? C2_OK : C2_CORRUPTED;
3310 }
3311 uint64_t bqId = 0;
3312 sp<IGraphicBufferProducer> nullIgbp;
3313 sp<HGraphicBufferProducer2> nullHgbp;
3314
3315 sp<HGraphicBufferProducer2> igbp = surface ?
3316 surface->getHalInterface<HGraphicBufferProducer2>() : nullHgbp;
3317 if (surface && !igbp) {
3318 igbp = new B2HGraphicBufferProducer2(surface);
3319 }
3320
3321 std::scoped_lock lock(mOutputMutex);
3322 std::shared_ptr<SurfaceSyncObj> syncObj;
3323
3324 if (!surface) {
3325 mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
3326 } else if (surface->getUniqueId(&bqId) != OK) {
3327 LOG(ERROR) << "setOutputSurface -- "
3328 "cannot obtain bufferqueue id.";
3329 bqId = 0;
3330 mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
3331 } else {
3332 mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount,
3333 mHidlBase1_2 ? &syncObj : nullptr);
3334 }
3335
3336 uint64_t consumerUsage = configConsumerUsage(surface);
3337 ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx%s",
3338 generation, (long long)consumerUsage, syncObj ? " sync" : "");
3339
3340 Return<c2_hidl::Status> transStatus = syncObj ?
3341 mHidlBase1_2->setOutputSurfaceWithSyncObj(
3342 static_cast<uint64_t>(blockPoolId),
3343 bqId == 0 ? nullHgbp : igbp, *syncObj) :
3344 mHidlBase1_0->setOutputSurface(
3345 static_cast<uint64_t>(blockPoolId),
3346 bqId == 0 ? nullHgbp : igbp);
3347
3348 mOutputBufferQueue->expireOldWaiters();
3349
3350 if (!transStatus.isOk()) {
3351 LOG(ERROR) << "setOutputSurface -- transaction failed.";
3352 return C2_TRANSACTION_FAILED;
3353 }
3354 c2_status_t status =
3355 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3356 if (status != C2_OK) {
3357 LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
3358 }
3359 ALOGD("Surface configure completed");
3360 return status;
3361 }
3362
queueToOutputSurface(const C2ConstGraphicBlock & block,const QueueBufferInput & input,QueueBufferOutput * output)3363 status_t Codec2Client::Component::queueToOutputSurface(
3364 const C2ConstGraphicBlock& block,
3365 const QueueBufferInput& input,
3366 QueueBufferOutput* output) {
3367 ScopedTrace trace(ATRACE_TAG,"Codec2Client::Component::queueToOutputSurface");
3368 if (mAidlBase) {
3369 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3370 mGraphicBufferAllocators->current();
3371 if (gba) {
3372 return gba->displayBuffer(block, input, output);
3373 } else {
3374 return C2_NOT_FOUND;
3375 }
3376 }
3377 return mOutputBufferQueue->outputBuffer(block, input, output);
3378 }
3379
configConsumerUsage(const sp<IGraphicBufferProducer> & surface)3380 uint64_t Codec2Client::Component::configConsumerUsage(
3381 const sp<IGraphicBufferProducer>& surface) {
3382 // set consumer bits
3383 // TODO: should this get incorporated into setOutputSurface method so that consumer bits
3384 // can be set atomically?
3385 uint64_t consumerUsage = kDefaultConsumerUsage;
3386 {
3387 if (surface) {
3388 uint64_t usage = 0;
3389 status_t err = surface->getConsumerUsage(&usage);
3390 if (err != NO_ERROR) {
3391 ALOGD("setOutputSurface -- failed to get consumer usage bits (%d/%s). ignoring",
3392 err, asString(err));
3393 } else {
3394 // Note: we are adding the default usage because components must support
3395 // producing output frames that can be displayed an all output surfaces.
3396
3397 // TODO: do not set usage for tunneled scenario. It is unclear if consumer usage
3398 // is meaningful in a tunneled scenario; on one hand output buffers exist, but
3399 // they do not exist inside of C2 scope. Any buffer usage shall be communicated
3400 // through the sideband channel.
3401
3402 consumerUsage = usage | kDefaultConsumerUsage;
3403 }
3404 }
3405
3406 C2StreamUsageTuning::output outputUsage{
3407 0u, C2AndroidMemoryUsage::FromGrallocUsage(consumerUsage).expected};
3408 std::vector<std::unique_ptr<C2SettingResult>> failures;
3409 c2_status_t err = config({&outputUsage}, C2_MAY_BLOCK, &failures);
3410 if (err != C2_OK) {
3411 ALOGD("setOutputSurface -- failed to set consumer usage (%d/%s)",
3412 err, asString(err));
3413 }
3414 }
3415 return consumerUsage;
3416 }
3417
pollForRenderedFrames(FrameEventHistoryDelta * delta)3418 void Codec2Client::Component::pollForRenderedFrames(FrameEventHistoryDelta* delta) {
3419 if (mAidlBase) {
3420 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3421 mGraphicBufferAllocators->current();
3422 if (gba) {
3423 gba->pollForRenderedFrames(delta);
3424 }
3425 return;
3426 }
3427 mOutputBufferQueue->pollForRenderedFrames(delta);
3428 }
3429
setOutputSurfaceMaxDequeueCount(int maxDequeueCount)3430 void Codec2Client::Component::setOutputSurfaceMaxDequeueCount(
3431 int maxDequeueCount) {
3432 if (mAidlBase) {
3433 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3434 mGraphicBufferAllocators->current();
3435 if (gba) {
3436 gba->updateMaxDequeueBufferCount(maxDequeueCount);
3437 }
3438 return;
3439 }
3440 mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
3441 }
3442
stopUsingOutputSurface(C2BlockPool::local_id_t blockPoolId)3443 void Codec2Client::Component::stopUsingOutputSurface(
3444 C2BlockPool::local_id_t blockPoolId) {
3445 if (mAidlBase) {
3446 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3447 mGraphicBufferAllocators->current();
3448 if (gba) {
3449 gba->reset();
3450 }
3451 return;
3452 }
3453 std::scoped_lock lock(mOutputMutex);
3454 mOutputBufferQueue->stop();
3455 Return<c2_hidl::Status> transStatus = mHidlBase1_0->setOutputSurface(
3456 static_cast<uint64_t>(blockPoolId), nullptr);
3457 if (!transStatus.isOk()) {
3458 LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
3459 } else {
3460 c2_status_t status =
3461 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3462 if (status != C2_OK) {
3463 LOG(DEBUG) << "setOutputSurface(stopUsingOutputSurface) -- call failed: "
3464 << status << ".";
3465 }
3466 }
3467 mOutputBufferQueue->expireOldWaiters();
3468 }
3469
onBufferReleasedFromOutputSurface(uint32_t generation)3470 void Codec2Client::Component::onBufferReleasedFromOutputSurface(
3471 uint32_t generation) {
3472 if (mAidlBase) {
3473 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3474 mGraphicBufferAllocators->current();
3475 if (gba) {
3476 gba->onBufferReleased(generation);
3477 }
3478 return;
3479 }
3480 mOutputBufferQueue->onBufferReleased(generation);
3481 }
3482
onBufferAttachedToOutputSurface(uint32_t generation)3483 void Codec2Client::Component::onBufferAttachedToOutputSurface(
3484 uint32_t generation) {
3485 if (mAidlBase) {
3486 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3487 mGraphicBufferAllocators->current();
3488 if (gba) {
3489 gba->onBufferAttached(generation);
3490 }
3491 return;
3492 }
3493 mOutputBufferQueue->onBufferAttached(generation);
3494 }
3495
holdIgbaBlocks(const std::list<std::unique_ptr<C2Work>> & workList)3496 void Codec2Client::Component::holdIgbaBlocks(
3497 const std::list<std::unique_ptr<C2Work>>& workList) {
3498 if (!mAidlBase) {
3499 return;
3500 }
3501 std::shared_ptr<AidlGraphicBufferAllocator> gba =
3502 mGraphicBufferAllocators->current();
3503 if (!gba) {
3504 return;
3505 }
3506 std::shared_ptr<c2_aidl::IGraphicBufferAllocator> igba =
3507 c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
3508 for (const std::unique_ptr<C2Work>& work : workList) {
3509 if (!work) [[unlikely]] {
3510 continue;
3511 }
3512 for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
3513 if (!worklet) {
3514 continue;
3515 }
3516 for (const std::shared_ptr<C2Buffer>& buffer : worklet->output.buffers) {
3517 if (buffer) {
3518 for (const C2ConstGraphicBlock& block : buffer->data().graphicBlocks()) {
3519 std::shared_ptr<_C2BlockPoolData> poolData =
3520 _C2BlockFactory::GetGraphicBlockPoolData(block);
3521 _C2BlockFactory::RegisterIgba(poolData, igba);
3522 }
3523 }
3524 }
3525 }
3526 }
3527 }
3528
connectToInputSurface(const std::shared_ptr<InputSurface> & inputSurface,std::shared_ptr<InputSurfaceConnection> * connection)3529 c2_status_t Codec2Client::Component::connectToInputSurface(
3530 const std::shared_ptr<InputSurface>& inputSurface,
3531 std::shared_ptr<InputSurfaceConnection>* connection) {
3532 if (mApexBase) {
3533 // FIXME
3534 return C2_OMITTED;
3535 }
3536 if (mAidlBase) {
3537 // FIXME
3538 return C2_OMITTED;
3539 }
3540 c2_status_t status;
3541 Return<void> transStatus = mHidlBase1_0->connectToInputSurface(
3542 inputSurface->mBase,
3543 [&status, connection](
3544 c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
3545 status = static_cast<c2_status_t>(s);
3546 if (status != C2_OK) {
3547 LOG(DEBUG) << "connectToInputSurface -- call failed: "
3548 << status << ".";
3549 return;
3550 }
3551 *connection = std::make_shared<InputSurfaceConnection>(c);
3552 });
3553 if (!transStatus.isOk()) {
3554 LOG(ERROR) << "connectToInputSurface -- transaction failed";
3555 return C2_TRANSACTION_FAILED;
3556 }
3557 return status;
3558 }
3559
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<HGraphicBufferSource> & source,std::shared_ptr<InputSurfaceConnection> * connection)3560 c2_status_t Codec2Client::Component::connectToOmxInputSurface(
3561 const sp<HGraphicBufferProducer1>& producer,
3562 const sp<HGraphicBufferSource>& source,
3563 std::shared_ptr<InputSurfaceConnection>* connection) {
3564 if (mApexBase) {
3565 LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
3566 return C2_OMITTED;
3567 }
3568 if (mAidlBase) {
3569 LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
3570 return C2_OMITTED;
3571 }
3572 c2_status_t status;
3573 Return<void> transStatus = mHidlBase1_0->connectToOmxInputSurface(
3574 producer, source,
3575 [&status, connection](
3576 c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
3577 status = static_cast<c2_status_t>(s);
3578 if (status != C2_OK) {
3579 LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
3580 << status << ".";
3581 return;
3582 }
3583 *connection = std::make_shared<InputSurfaceConnection>(c);
3584 });
3585 if (!transStatus.isOk()) {
3586 LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
3587 return C2_TRANSACTION_FAILED;
3588 }
3589 return status;
3590 }
3591
disconnectFromInputSurface()3592 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
3593 if (mApexBase) {
3594 // FIXME
3595 return C2_OMITTED;
3596 }
3597 if (mAidlBase) {
3598 // FIXME
3599 return C2_OMITTED;
3600 }
3601 Return<c2_hidl::Status> transStatus = mHidlBase1_0->disconnectFromInputSurface();
3602 if (!transStatus.isOk()) {
3603 LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
3604 return C2_TRANSACTION_FAILED;
3605 }
3606 c2_status_t status =
3607 static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transStatus));
3608 if (status != C2_OK) {
3609 LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
3610 << status << ".";
3611 }
3612 return status;
3613 }
3614
GetAidlDeathManager()3615 Codec2Client::Component::AidlDeathManager *Codec2Client::Component::GetAidlDeathManager() {
3616 // This object never gets destructed
3617 static AidlDeathManager *sManager = new AidlDeathManager();
3618 return sManager;
3619 }
3620
initApexHandler(const std::shared_ptr<Listener> & listener,const std::shared_ptr<Component> & comp)3621 c2_status_t Codec2Client::Component::initApexHandler(
3622 const std::shared_ptr<Listener> &listener,
3623 const std::shared_ptr<Component> &comp) {
3624 if (!mApexBase) {
3625 return C2_BAD_STATE;
3626 }
3627 mApexHandler = std::make_unique<ApexHandler>(mApexBase, listener, comp);
3628 return C2_OK;
3629 }
3630
setDeathListener(const std::shared_ptr<Component> & component,const std::shared_ptr<Listener> & listener)3631 c2_status_t Codec2Client::Component::setDeathListener(
3632 const std::shared_ptr<Component>& component,
3633 const std::shared_ptr<Listener>& listener) {
3634
3635 struct HidlDeathRecipient : public hardware::hidl_death_recipient {
3636 std::weak_ptr<Component> component;
3637 std::weak_ptr<Listener> base;
3638
3639 virtual void serviceDied(
3640 uint64_t /* cookie */,
3641 const wp<::android::hidl::base::V1_0::IBase>& /* who */
3642 ) override {
3643 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
3644 listener->onDeath(component);
3645 } else {
3646 LOG(DEBUG) << "onDeath -- listener died.";
3647 }
3648 }
3649 };
3650
3651 if (component->mAidlBase) {
3652 size_t seq;
3653 if (GetAidlDeathManager()->linkToDeath(component, listener, &seq)) {
3654 component->mAidlDeathSeq = seq;
3655 }
3656 return C2_OK;
3657 }
3658
3659 sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
3660 deathRecipient->base = listener;
3661 deathRecipient->component = component;
3662
3663 component->mDeathRecipient = deathRecipient;
3664 Return<bool> transResult = component->mHidlBase1_0->linkToDeath(
3665 component->mDeathRecipient, 0);
3666 if (!transResult.isOk()) {
3667 LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
3668 return C2_TRANSACTION_FAILED;
3669 }
3670 if (!static_cast<bool>(transResult)) {
3671 LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
3672 return C2_CORRUPTED;
3673 }
3674 return C2_OK;
3675 }
3676
3677 // Codec2Client::InputSurface
InputSurface(const sp<c2_hidl::IInputSurface> & base)3678 Codec2Client::InputSurface::InputSurface(const sp<c2_hidl::IInputSurface>& base)
3679 : Configurable{
3680 [base]() -> sp<c2_hidl::IConfigurable> {
3681 Return<sp<c2_hidl::IConfigurable>> transResult =
3682 base->getConfigurable();
3683 return transResult.isOk() ?
3684 static_cast<sp<c2_hidl::IConfigurable>>(transResult) :
3685 nullptr;
3686 }()
3687 },
3688 mBase{base},
3689 mGraphicBufferProducer{new
__anon3331b31b3102() 3690 H2BGraphicBufferProducer2([base]() -> sp<HGraphicBufferProducer2> {
3691 Return<sp<HGraphicBufferProducer2>> transResult =
3692 base->getGraphicBufferProducer();
3693 return transResult.isOk() ?
3694 static_cast<sp<HGraphicBufferProducer2>>(transResult) :
3695 nullptr;
3696 }())} {
3697 }
3698
3699 sp<IGraphicBufferProducer>
getGraphicBufferProducer() const3700 Codec2Client::InputSurface::getGraphicBufferProducer() const {
3701 return mGraphicBufferProducer;
3702 }
3703
getHalInterface() const3704 sp<c2_hidl::IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
3705 return mBase;
3706 }
3707
3708 // Codec2Client::InputSurfaceConnection
InputSurfaceConnection(const sp<c2_hidl::IInputSurfaceConnection> & base)3709 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
3710 const sp<c2_hidl::IInputSurfaceConnection>& base)
3711 : Configurable{
3712 [base]() -> sp<c2_hidl::IConfigurable> {
3713 Return<sp<c2_hidl::IConfigurable>> transResult =
3714 base->getConfigurable();
3715 return transResult.isOk() ?
3716 static_cast<sp<c2_hidl::IConfigurable>>(transResult) :
3717 nullptr;
3718 }()
3719 },
3720 mBase{base} {
3721 }
3722
disconnect()3723 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
3724 Return<c2_hidl::Status> transResult = mBase->disconnect();
3725 return static_cast<c2_status_t>(static_cast<c2_hidl::Status>(transResult));
3726 }
3727
3728 } // namespace android
3729