• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <android-base/logging.h>
20 
21 #include <codec2/hidl/client.h>
22 #include <C2Debug.h>
23 #include <C2BufferPriv.h>
24 #include <C2Config.h> // for C2StreamUsageTuning
25 #include <C2PlatformSupport.h>
26 
27 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
28 #include <android/hardware/media/c2/1.0/IComponent.h>
29 #include <android/hardware/media/c2/1.0/IComponentInterface.h>
30 #include <android/hardware/media/c2/1.0/IComponentListener.h>
31 #include <android/hardware/media/c2/1.0/IComponentStore.h>
32 #include <android/hardware/media/c2/1.0/IConfigurable.h>
33 #include <android/hidl/manager/1.2/IServiceManager.h>
34 
35 #include <android-base/properties.h>
36 #include <bufferpool/ClientManager.h>
37 #include <codec2/hidl/1.0/types.h>
38 #include <codec2/hidl/1.1/types.h>
39 #include <codec2/hidl/1.2/types.h>
40 #include <codec2/hidl/output.h>
41 
42 #include <cutils/native_handle.h>
43 #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
44 #include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
45 #include <hardware/gralloc.h> // for GRALLOC_USAGE_*
46 #include <hidl/HidlSupport.h>
47 #include <system/window.h> // for NATIVE_WINDOW_QUERY_*
48 #include <media/stagefright/foundation/ADebug.h> // for asString(status_t)
49 
50 
51 #include <deque>
52 #include <iterator>
53 #include <limits>
54 #include <map>
55 #include <mutex>
56 #include <sstream>
57 #include <thread>
58 #include <type_traits>
59 #include <vector>
60 
61 namespace android {
62 
63 using ::android::hardware::hidl_vec;
64 using ::android::hardware::hidl_string;
65 using ::android::hardware::Return;
66 using ::android::hardware::Void;
67 
68 using namespace ::android::hardware::media::c2::V1_1;
69 using namespace ::android::hardware::media::c2::V1_1::utils;
70 using namespace ::android::hardware::media::bufferpool::V2_0;
71 using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
72 
73 using HGraphicBufferProducer1 = ::android::hardware::graphics::bufferqueue::
74         V1_0::IGraphicBufferProducer;
75 using HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
76         V2_0::IGraphicBufferProducer;
77 using B2HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
78         V2_0::utils::B2HGraphicBufferProducer;
79 using H2BGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
80         V2_0::utils::H2BGraphicBufferProducer;
81 using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
82 
83 namespace /* unnamed */ {
84 
85 // c2_status_t value that corresponds to hwbinder transaction failure.
86 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
87 
88 // By default prepare buffer to be displayed on any of the common surfaces
89 constexpr uint64_t kDefaultConsumerUsage =
90     (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER);
91 
92 // Searches for a name in GetServiceNames() and returns the index found. If the
93 // name is not found, the returned index will be equal to
94 // GetServiceNames().size().
getServiceIndex(char const * name)95 size_t getServiceIndex(char const* name) {
96     std::vector<std::string> const& names = Codec2Client::GetServiceNames();
97     size_t i = 0;
98     for (; i < names.size(); ++i) {
99         if (name == names[i]) {
100             break;
101         }
102     }
103     return i;
104 }
105 
106 class Client2Store : public C2ComponentStore {
107     std::shared_ptr<Codec2Client> mClient;
108 
109 public:
Client2Store(std::shared_ptr<Codec2Client> const & client)110     Client2Store(std::shared_ptr<Codec2Client> const& client)
111         : mClient(client) { }
112 
113     virtual ~Client2Store() = default;
114 
config_sm(std::vector<C2Param * > const & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)115     virtual c2_status_t config_sm(
116             std::vector<C2Param*> const &params,
117             std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
118         return mClient->config(params, C2_MAY_BLOCK, failures);
119     };
120 
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)121     virtual c2_status_t copyBuffer(
122             std::shared_ptr<C2GraphicBuffer>,
123             std::shared_ptr<C2GraphicBuffer>) {
124         return C2_OMITTED;
125     }
126 
createComponent(C2String,std::shared_ptr<C2Component> * const component)127     virtual c2_status_t createComponent(
128             C2String, std::shared_ptr<C2Component>* const component) {
129         component->reset();
130         return C2_OMITTED;
131     }
132 
createInterface(C2String,std::shared_ptr<C2ComponentInterface> * const interface)133     virtual c2_status_t createInterface(
134             C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
135         interface->reset();
136         return C2_OMITTED;
137     }
138 
query_sm(std::vector<C2Param * > const & stackParams,std::vector<C2Param::Index> const & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const139     virtual c2_status_t query_sm(
140             std::vector<C2Param*> const& stackParams,
141             std::vector<C2Param::Index> const& heapParamIndices,
142             std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
143         return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
144     }
145 
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const146     virtual c2_status_t querySupportedParams_nb(
147             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
148         return mClient->querySupportedParams(params);
149     }
150 
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const151     virtual c2_status_t querySupportedValues_sm(
152             std::vector<C2FieldSupportedValuesQuery>& fields) const {
153         return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
154     }
155 
getName() const156     virtual C2String getName() const {
157         return mClient->getName();
158     }
159 
getParamReflector() const160     virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
161         return mClient->getParamReflector();
162     }
163 
listComponents()164     virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
165         return std::vector<std::shared_ptr<C2Component::Traits const>>();
166     }
167 };
168 
169 }  // unnamed namespace
170 
171 // This class caches a Codec2Client object and its component traits. The client
172 // will be created the first time it is needed, and it can be refreshed if the
173 // service dies (by calling invalidate()). The first time listComponents() is
174 // called from the client, the result will be cached.
175 class Codec2Client::Cache {
176     // Cached client
177     std::shared_ptr<Codec2Client> mClient;
178     mutable std::mutex mClientMutex;
179 
180     // Cached component traits
181     std::vector<C2Component::Traits> mTraits;
182     std::once_flag mTraitsInitializationFlag;
183 
184     // The index of the service. This is based on GetServiceNames().
185     size_t mIndex;
186     // Called by s() exactly once to initialize the cache. The index must be a
187     // valid index into the vector returned by GetServiceNames(). Calling
188     // init(index) will associate the cache to the service with name
189     // GetServiceNames()[index].
init(size_t index)190     void init(size_t index) {
191         mIndex = index;
192     }
193 
194 public:
195     Cache() = default;
196 
197     // Initializes mClient if needed, then returns mClient.
198     // If the service is unavailable but listed in the manifest, this function
199     // will block indefinitely.
getClient()200     std::shared_ptr<Codec2Client> getClient() {
201         std::scoped_lock lock{mClientMutex};
202         if (!mClient) {
203             mClient = Codec2Client::_CreateFromIndex(mIndex);
204         }
205         CHECK(mClient) << "Failed to create Codec2Client to service \""
206                        << GetServiceNames()[mIndex] << "\". (Index = "
207                        << mIndex << ").";
208         return mClient;
209     }
210 
211     // Causes a subsequent call to getClient() to create a new client. This
212     // function should be called after the service dies.
213     //
214     // Note: This function is called only by ForAllServices().
invalidate()215     void invalidate() {
216         std::scoped_lock lock{mClientMutex};
217         mClient = nullptr;
218     }
219 
220     // Returns a list of traits for components supported by the service. This
221     // list is cached.
getTraits()222     std::vector<C2Component::Traits> const& getTraits() {
223         std::call_once(mTraitsInitializationFlag, [this]() {
224             bool success{false};
225             // Spin until _listComponents() is successful.
226             while (true) {
227                 std::shared_ptr<Codec2Client> client = getClient();
228                 mTraits = client->_listComponents(&success);
229                 if (success) {
230                     break;
231                 }
232                 invalidate();
233                 using namespace std::chrono_literals;
234                 static constexpr auto kServiceRetryPeriod = 5s;
235                 LOG(INFO) << "Failed to retrieve component traits from service "
236                              "\"" << GetServiceNames()[mIndex] << "\". "
237                              "Retrying...";
238                 std::this_thread::sleep_for(kServiceRetryPeriod);
239             }
240         });
241         return mTraits;
242     }
243 
244     // List() returns the list of all caches.
List()245     static std::vector<Cache>& List() {
246         static std::vector<Cache> sCaches{[]() {
247             size_t numServices = GetServiceNames().size();
248             std::vector<Cache> caches(numServices);
249             for (size_t i = 0; i < numServices; ++i) {
250                 caches[i].init(i);
251             }
252             return caches;
253         }()};
254         return sCaches;
255     }
256 };
257 
258 // Codec2ConfigurableClient
259 
getName() const260 const C2String& Codec2ConfigurableClient::getName() const {
261     return mName;
262 }
263 
Codec2ConfigurableClient(const sp<IConfigurable> & base)264 Codec2ConfigurableClient::Codec2ConfigurableClient(
265         const sp<IConfigurable>& base)
266       : mBase{base},
__anon4f0a646a0402() 267         mName{[base]() -> C2String {
268                 C2String outName;
269                 Return<void> transStatus = base->getName(
270                         [&outName](const hidl_string& name) {
271                             outName = name.c_str();
272                         });
273                 return transStatus.isOk() ? outName : "";
274             }()} {
275 }
276 
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const277 c2_status_t Codec2ConfigurableClient::query(
278         const std::vector<C2Param*> &stackParams,
279         const std::vector<C2Param::Index> &heapParamIndices,
280         c2_blocking_t mayBlock,
281         std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
282     hidl_vec<ParamIndex> indices(
283             stackParams.size() + heapParamIndices.size());
284     size_t numIndices = 0;
285     for (C2Param* const& stackParam : stackParams) {
286         if (!stackParam) {
287             LOG(WARNING) << "query -- null stack param encountered.";
288             continue;
289         }
290         indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
291     }
292     size_t numStackIndices = numIndices;
293     for (const C2Param::Index& index : heapParamIndices) {
294         indices[numIndices++] =
295                 static_cast<ParamIndex>(static_cast<uint32_t>(index));
296     }
297     indices.resize(numIndices);
298     if (heapParams) {
299         heapParams->reserve(heapParams->size() + numIndices);
300     }
301     c2_status_t status;
302     Return<void> transStatus = mBase->query(
303             indices,
304             mayBlock == C2_MAY_BLOCK,
305             [&status, &numStackIndices, &stackParams, heapParams](
306                     Status s, const Params& p) {
307                 status = static_cast<c2_status_t>(s);
308                 if (status != C2_OK && status != C2_BAD_INDEX) {
309                     LOG(DEBUG) << "query -- call failed: "
310                                << status << ".";
311                     return;
312                 }
313                 std::vector<C2Param*> paramPointers;
314                 if (!parseParamsBlob(&paramPointers, p)) {
315                     LOG(ERROR) << "query -- error while parsing params.";
316                     status = C2_CORRUPTED;
317                     return;
318                 }
319                 size_t i = 0;
320                 for (auto it = paramPointers.begin();
321                         it != paramPointers.end(); ) {
322                     C2Param* paramPointer = *it;
323                     if (numStackIndices > 0) {
324                         --numStackIndices;
325                         if (!paramPointer) {
326                             LOG(WARNING) << "query -- null stack param.";
327                             ++it;
328                             continue;
329                         }
330                         for (; i < stackParams.size() && !stackParams[i]; ) {
331                             ++i;
332                         }
333                         if (i >= stackParams.size()) {
334                             LOG(ERROR) << "query -- unexpected error.";
335                             status = C2_CORRUPTED;
336                             return;
337                         }
338                         if (stackParams[i]->index() != paramPointer->index()) {
339                             LOG(WARNING) << "query -- param skipped: "
340                                             "index = "
341                                          << stackParams[i]->index() << ".";
342                             stackParams[i++]->invalidate();
343                             continue;
344                         }
345                         if (!stackParams[i++]->updateFrom(*paramPointer)) {
346                             LOG(WARNING) << "query -- param update failed: "
347                                             "index = "
348                                          << paramPointer->index() << ".";
349                         }
350                     } else {
351                         if (!paramPointer) {
352                             LOG(WARNING) << "query -- null heap param.";
353                             ++it;
354                             continue;
355                         }
356                         if (!heapParams) {
357                             LOG(WARNING) << "query -- "
358                                             "unexpected extra stack param.";
359                         } else {
360                             heapParams->emplace_back(
361                                     C2Param::Copy(*paramPointer));
362                         }
363                     }
364                     ++it;
365                 }
366             });
367     if (!transStatus.isOk()) {
368         LOG(ERROR) << "query -- transaction failed.";
369         return C2_TRANSACTION_FAILED;
370     }
371     return status;
372 }
373 
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)374 c2_status_t Codec2ConfigurableClient::config(
375         const std::vector<C2Param*> &params,
376         c2_blocking_t mayBlock,
377         std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
378     Params hidlParams;
379     if (!createParamsBlob(&hidlParams, params)) {
380         LOG(ERROR) << "config -- bad input.";
381         return C2_TRANSACTION_FAILED;
382     }
383     c2_status_t status;
384     Return<void> transStatus = mBase->config(
385             hidlParams,
386             mayBlock == C2_MAY_BLOCK,
387             [&status, &params, failures](
388                     Status s,
389                     const hidl_vec<SettingResult> f,
390                     const Params& o) {
391                 status = static_cast<c2_status_t>(s);
392                 if (status != C2_OK && status != C2_BAD_INDEX) {
393                     LOG(DEBUG) << "config -- call failed: "
394                                << status << ".";
395                 }
396                 size_t i = failures->size();
397                 failures->resize(i + f.size());
398                 for (const SettingResult& sf : f) {
399                     if (!objcpy(&(*failures)[i++], sf)) {
400                         LOG(ERROR) << "config -- "
401                                    << "invalid SettingResult returned.";
402                         return;
403                     }
404                 }
405                 if (!updateParamsFromBlob(params, o)) {
406                     LOG(ERROR) << "config -- "
407                                << "failed to parse returned params.";
408                     status = C2_CORRUPTED;
409                 }
410             });
411     if (!transStatus.isOk()) {
412         LOG(ERROR) << "config -- transaction failed.";
413         return C2_TRANSACTION_FAILED;
414     }
415     return status;
416 }
417 
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const418 c2_status_t Codec2ConfigurableClient::querySupportedParams(
419         std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
420     // TODO: Cache and query properly!
421     c2_status_t status;
422     Return<void> transStatus = mBase->querySupportedParams(
423             std::numeric_limits<uint32_t>::min(),
424             std::numeric_limits<uint32_t>::max(),
425             [&status, params](
426                     Status s,
427                     const hidl_vec<ParamDescriptor>& p) {
428                 status = static_cast<c2_status_t>(s);
429                 if (status != C2_OK) {
430                     LOG(DEBUG) << "querySupportedParams -- call failed: "
431                                << status << ".";
432                     return;
433                 }
434                 size_t i = params->size();
435                 params->resize(i + p.size());
436                 for (const ParamDescriptor& sp : p) {
437                     if (!objcpy(&(*params)[i++], sp)) {
438                         LOG(ERROR) << "querySupportedParams -- "
439                                    << "invalid returned ParamDescriptor.";
440                         return;
441                     }
442                 }
443             });
444     if (!transStatus.isOk()) {
445         LOG(ERROR) << "querySupportedParams -- transaction failed.";
446         return C2_TRANSACTION_FAILED;
447     }
448     return status;
449 }
450 
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const451 c2_status_t Codec2ConfigurableClient::querySupportedValues(
452         std::vector<C2FieldSupportedValuesQuery>& fields,
453         c2_blocking_t mayBlock) const {
454     hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
455     for (size_t i = 0; i < fields.size(); ++i) {
456         if (!objcpy(&inFields[i], fields[i])) {
457             LOG(ERROR) << "querySupportedValues -- bad input";
458             return C2_TRANSACTION_FAILED;
459         }
460     }
461 
462     c2_status_t status;
463     Return<void> transStatus = mBase->querySupportedValues(
464             inFields,
465             mayBlock == C2_MAY_BLOCK,
466             [&status, &inFields, &fields](
467                     Status s,
468                     const hidl_vec<FieldSupportedValuesQueryResult>& r) {
469                 status = static_cast<c2_status_t>(s);
470                 if (status != C2_OK) {
471                     LOG(DEBUG) << "querySupportedValues -- call failed: "
472                                << status << ".";
473                     return;
474                 }
475                 if (r.size() != fields.size()) {
476                     LOG(ERROR) << "querySupportedValues -- "
477                                   "input and output lists "
478                                   "have different sizes.";
479                     status = C2_CORRUPTED;
480                     return;
481                 }
482                 for (size_t i = 0; i < fields.size(); ++i) {
483                     if (!objcpy(&fields[i], inFields[i], r[i])) {
484                         LOG(ERROR) << "querySupportedValues -- "
485                                       "invalid returned value.";
486                         status = C2_CORRUPTED;
487                         return;
488                     }
489                 }
490             });
491     if (!transStatus.isOk()) {
492         LOG(ERROR) << "querySupportedValues -- transaction failed.";
493         return C2_TRANSACTION_FAILED;
494     }
495     return status;
496 }
497 
498 // Codec2Client::Component::HidlListener
499 struct Codec2Client::Component::HidlListener : public IComponentListener {
500     std::weak_ptr<Component> component;
501     std::weak_ptr<Listener> base;
502 
onWorkDoneandroid::Codec2Client::Component::HidlListener503     virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
504         std::list<std::unique_ptr<C2Work>> workItems;
505         if (!objcpy(&workItems, workBundle)) {
506             LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
507             return Void();
508         }
509         // release input buffers potentially held by the component from queue
510         std::shared_ptr<Codec2Client::Component> strongComponent =
511                 component.lock();
512         if (strongComponent) {
513             strongComponent->handleOnWorkDone(workItems);
514         }
515         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
516             listener->onWorkDone(component, workItems);
517         } else {
518             LOG(DEBUG) << "onWorkDone -- listener died.";
519         }
520         return Void();
521     }
522 
onTrippedandroid::Codec2Client::Component::HidlListener523     virtual Return<void> onTripped(
524             const hidl_vec<SettingResult>& settingResults) override {
525         std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
526                 settingResults.size());
527         for (size_t i = 0; i < settingResults.size(); ++i) {
528             std::unique_ptr<C2SettingResult> c2SettingResult;
529             if (!objcpy(&c2SettingResult, settingResults[i])) {
530                 LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
531                 return Void();
532             }
533             c2SettingResults[i] = std::move(c2SettingResult);
534         }
535         if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
536             listener->onTripped(component, c2SettingResults);
537         } else {
538             LOG(DEBUG) << "onTripped -- listener died.";
539         }
540         return Void();
541     }
542 
onErrorandroid::Codec2Client::Component::HidlListener543     virtual Return<void> onError(Status s, uint32_t errorCode) override {
544         LOG(DEBUG) << "onError --"
545                    << " status = " << s
546                    << ", errorCode = " << errorCode
547                    << ".";
548         if (std::shared_ptr<Listener> listener = base.lock()) {
549             listener->onError(component, s == Status::OK ?
550                     errorCode : static_cast<c2_status_t>(s));
551         } else {
552             LOG(DEBUG) << "onError -- listener died.";
553         }
554         return Void();
555     }
556 
onFramesRenderedandroid::Codec2Client::Component::HidlListener557     virtual Return<void> onFramesRendered(
558             const hidl_vec<RenderedFrame>& renderedFrames) override {
559         std::shared_ptr<Listener> listener = base.lock();
560         if (!listener) {
561             LOG(DEBUG) << "onFramesRendered -- listener died.";
562             return Void();
563         }
564         for (const RenderedFrame& renderedFrame : renderedFrames) {
565             listener->onFrameRendered(
566                     renderedFrame.bufferQueueId,
567                     renderedFrame.slotId,
568                     renderedFrame.timestampNs);
569         }
570         return Void();
571     }
572 
onInputBuffersReleasedandroid::Codec2Client::Component::HidlListener573     virtual Return<void> onInputBuffersReleased(
574             const hidl_vec<InputBuffer>& inputBuffers) override {
575         std::shared_ptr<Listener> listener = base.lock();
576         if (!listener) {
577             LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
578             return Void();
579         }
580         for (const InputBuffer& inputBuffer : inputBuffers) {
581             LOG(VERBOSE) << "onInputBuffersReleased --"
582                             " received death notification of"
583                             " input buffer:"
584                             " frameIndex = " << inputBuffer.frameIndex
585                          << ", bufferIndex = " << inputBuffer.arrayIndex
586                          << ".";
587             listener->onInputBufferDone(
588                     inputBuffer.frameIndex, inputBuffer.arrayIndex);
589         }
590         return Void();
591     }
592 
593 };
594 
595 // Codec2Client::Component::BufferPoolSender
596 struct Codec2Client::Component::BufferPoolSender :
597         hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
BufferPoolSenderandroid::Codec2Client::Component::BufferPoolSender598     BufferPoolSender()
599           : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
600     }
601 };
602 
603 // Codec2Client::Component::OutputBufferQueue
604 struct Codec2Client::Component::OutputBufferQueue :
605         hardware::media::c2::OutputBufferQueue {
OutputBufferQueueandroid::Codec2Client::Component::OutputBufferQueue606     OutputBufferQueue()
607           : hardware::media::c2::OutputBufferQueue() {
608     }
609 };
610 
611 // Codec2Client
Codec2Client(sp<Base> const & base,sp<IConfigurable> const & configurable,size_t serviceIndex)612 Codec2Client::Codec2Client(sp<Base> const& base,
613                            sp<IConfigurable> const& configurable,
614                            size_t serviceIndex)
615       : Configurable{configurable},
616         mBase1_0{base},
617         mBase1_1{Base1_1::castFrom(base)},
618         mBase1_2{Base1_2::castFrom(base)},
619         mServiceIndex{serviceIndex} {
620     Return<sp<IClientManager>> transResult = base->getPoolClientManager();
621     if (!transResult.isOk()) {
622         LOG(ERROR) << "getPoolClientManager -- transaction failed.";
623     } else {
624         mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
625     }
626 }
627 
getBase() const628 sp<Codec2Client::Base> const& Codec2Client::getBase() const {
629     return mBase1_0;
630 }
631 
getBase1_0() const632 sp<Codec2Client::Base1_0> const& Codec2Client::getBase1_0() const {
633     return mBase1_0;
634 }
635 
getBase1_1() const636 sp<Codec2Client::Base1_1> const& Codec2Client::getBase1_1() const {
637     return mBase1_1;
638 }
639 
getBase1_2() const640 sp<Codec2Client::Base1_2> const& Codec2Client::getBase1_2() const {
641     return mBase1_2;
642 }
643 
getServiceName() const644 std::string const& Codec2Client::getServiceName() const {
645     return GetServiceNames()[mServiceIndex];
646 }
647 
createComponent(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)648 c2_status_t Codec2Client::createComponent(
649         const C2String& name,
650         const std::shared_ptr<Codec2Client::Listener>& listener,
651         std::shared_ptr<Codec2Client::Component>* const component) {
652 
653     c2_status_t status;
654     sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
655     hidlListener->base = listener;
656     Return<void> transStatus;
657     if (mBase1_2) {
658         transStatus = mBase1_2->createComponent_1_2(
659             name,
660             hidlListener,
661             ClientManager::getInstance(),
662             [&status, component, hidlListener](
663                     Status s,
664                     const sp<IComponent>& c) {
665                 status = static_cast<c2_status_t>(s);
666                 if (status != C2_OK) {
667                     return;
668                 }
669                 *component = std::make_shared<Codec2Client::Component>(c);
670                 hidlListener->component = *component;
671             });
672     }
673     else if (mBase1_1) {
674         transStatus = mBase1_1->createComponent_1_1(
675             name,
676             hidlListener,
677             ClientManager::getInstance(),
678             [&status, component, hidlListener](
679                     Status s,
680                     const sp<IComponent>& c) {
681                 status = static_cast<c2_status_t>(s);
682                 if (status != C2_OK) {
683                     return;
684                 }
685                 *component = std::make_shared<Codec2Client::Component>(c);
686                 hidlListener->component = *component;
687             });
688     } else if (mBase1_0) { // ver1_0
689         transStatus = mBase1_0->createComponent(
690             name,
691             hidlListener,
692             ClientManager::getInstance(),
693             [&status, component, hidlListener](
694                     Status s,
695                     const sp<hardware::media::c2::V1_0::IComponent>& c) {
696                 status = static_cast<c2_status_t>(s);
697                 if (status != C2_OK) {
698                     return;
699                 }
700                 *component = std::make_shared<Codec2Client::Component>(c);
701                 hidlListener->component = *component;
702             });
703     } else {
704         status = C2_CORRUPTED;
705     }
706     if (!transStatus.isOk()) {
707         LOG(ERROR) << "createComponent(" << name.c_str()
708                    << ") -- transaction failed.";
709         return C2_TRANSACTION_FAILED;
710     } else if (status != C2_OK) {
711         if (status == C2_NOT_FOUND) {
712             LOG(VERBOSE) << "createComponent(" << name.c_str()
713                          << ") -- component not found.";
714         } else {
715             LOG(ERROR) << "createComponent(" << name.c_str()
716                        << ") -- call failed: " << status << ".";
717         }
718         return status;
719     } else if (!*component) {
720         LOG(ERROR) << "createComponent(" << name.c_str()
721                    << ") -- null component.";
722         return C2_CORRUPTED;
723     }
724 
725     status = (*component)->setDeathListener(*component, listener);
726     if (status != C2_OK) {
727         LOG(ERROR) << "createComponent(" << name.c_str()
728                    << ") -- failed to set up death listener: "
729                    << status << ".";
730     }
731 
732     (*component)->mBufferPoolSender->setReceiver(mHostPoolManager);
733     return status;
734 }
735 
createInterface(const C2String & name,std::shared_ptr<Codec2Client::Interface> * const interface)736 c2_status_t Codec2Client::createInterface(
737         const C2String& name,
738         std::shared_ptr<Codec2Client::Interface>* const interface) {
739     c2_status_t status;
740     Return<void> transStatus = mBase1_0->createInterface(
741             name,
742             [&status, interface](
743                     Status s,
744                     const sp<IComponentInterface>& i) {
745                 status = static_cast<c2_status_t>(s);
746                 if (status != C2_OK) {
747                     return;
748                 }
749                 *interface = std::make_shared<Interface>(i);
750             });
751     if (!transStatus.isOk()) {
752         LOG(ERROR) << "createInterface(" << name.c_str()
753                    << ") -- transaction failed.";
754         return C2_TRANSACTION_FAILED;
755     } else if (status != C2_OK) {
756         if (status == C2_NOT_FOUND) {
757             LOG(VERBOSE) << "createInterface(" << name.c_str()
758                          << ") -- component not found.";
759         } else {
760             LOG(ERROR) << "createInterface(" << name.c_str()
761                        << ") -- call failed: " << status << ".";
762         }
763         return status;
764     }
765 
766     return status;
767 }
768 
createInputSurface(std::shared_ptr<InputSurface> * const inputSurface)769 c2_status_t Codec2Client::createInputSurface(
770         std::shared_ptr<InputSurface>* const inputSurface) {
771     c2_status_t status;
772     Return<void> transStatus = mBase1_0->createInputSurface(
773             [&status, inputSurface](
774                     Status s,
775                     const sp<IInputSurface>& i) {
776                 status = static_cast<c2_status_t>(s);
777                 if (status != C2_OK) {
778                     return;
779                 }
780                 *inputSurface = std::make_shared<InputSurface>(i);
781             });
782     if (!transStatus.isOk()) {
783         LOG(ERROR) << "createInputSurface -- transaction failed.";
784         return C2_TRANSACTION_FAILED;
785     } else if (status != C2_OK) {
786         LOG(DEBUG) << "createInputSurface -- call failed: "
787                    << status << ".";
788     }
789     return status;
790 }
791 
listComponents() const792 std::vector<C2Component::Traits> const& Codec2Client::listComponents() const {
793     return Cache::List()[mServiceIndex].getTraits();
794 }
795 
_listComponents(bool * success) const796 std::vector<C2Component::Traits> Codec2Client::_listComponents(
797         bool* success) const {
798     std::vector<C2Component::Traits> traits;
799     std::string const& serviceName = getServiceName();
800     Return<void> transStatus = mBase1_0->listComponents(
801             [&traits, &serviceName](Status s,
802                    const hidl_vec<IComponentStore::ComponentTraits>& t) {
803                 if (s != Status::OK) {
804                     LOG(DEBUG) << "_listComponents -- call failed: "
805                                << static_cast<c2_status_t>(s) << ".";
806                     return;
807                 }
808                 traits.resize(t.size());
809                 for (size_t i = 0; i < t.size(); ++i) {
810                     if (!objcpy(&traits[i], t[i])) {
811                         LOG(ERROR) << "_listComponents -- corrupted output.";
812                         return;
813                     }
814                     traits[i].owner = serviceName;
815                 }
816             });
817     if (!transStatus.isOk()) {
818         LOG(ERROR) << "_listComponents -- transaction failed.";
819         *success = false;
820     } else {
821         *success = true;
822     }
823     return traits;
824 }
825 
copyBuffer(const std::shared_ptr<C2Buffer> & src,const std::shared_ptr<C2Buffer> & dst)826 c2_status_t Codec2Client::copyBuffer(
827         const std::shared_ptr<C2Buffer>& src,
828         const std::shared_ptr<C2Buffer>& dst) {
829     // TODO: Implement?
830     (void)src;
831     (void)dst;
832     LOG(ERROR) << "copyBuffer not implemented";
833     return C2_OMITTED;
834 }
835 
836 std::shared_ptr<C2ParamReflector>
getParamReflector()837         Codec2Client::getParamReflector() {
838     // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
839     // should reflect the HAL API.
840     struct SimpleParamReflector : public C2ParamReflector {
841         virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
842             hidl_vec<ParamIndex> indices(1);
843             indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
844             std::unique_ptr<C2StructDescriptor> descriptor;
845             Return<void> transStatus = mBase->getStructDescriptors(
846                     indices,
847                     [&descriptor](
848                             Status s,
849                             const hidl_vec<StructDescriptor>& sd) {
850                         c2_status_t status = static_cast<c2_status_t>(s);
851                         if (status != C2_OK) {
852                             LOG(DEBUG) << "SimpleParamReflector -- "
853                                           "getStructDescriptors() failed: "
854                                        << status << ".";
855                             descriptor.reset();
856                             return;
857                         }
858                         if (sd.size() != 1) {
859                             LOG(DEBUG) << "SimpleParamReflector -- "
860                                           "getStructDescriptors() "
861                                           "returned vector of size "
862                                        << sd.size() << ". "
863                                           "It should be 1.";
864                             descriptor.reset();
865                             return;
866                         }
867                         if (!objcpy(&descriptor, sd[0])) {
868                             LOG(DEBUG) << "SimpleParamReflector -- "
869                                           "getStructDescriptors() returned "
870                                           "corrupted data.";
871                             descriptor.reset();
872                             return;
873                         }
874                     });
875             if (!transStatus.isOk()) {
876                 LOG(DEBUG) << "SimpleParamReflector -- transaction failed: "
877                            << transStatus.description();
878                 descriptor.reset();
879             }
880             return descriptor;
881         }
882 
883         SimpleParamReflector(sp<Base> base)
884             : mBase(base) { }
885 
886         sp<Base> mBase;
887     };
888 
889     return std::make_shared<SimpleParamReflector>(mBase1_0);
890 };
891 
GetServiceNames()892 std::vector<std::string> const& Codec2Client::GetServiceNames() {
893     static std::vector<std::string> sServiceNames{[]() {
894         using ::android::hardware::media::c2::V1_0::IComponentStore;
895         using ::android::hidl::manager::V1_2::IServiceManager;
896 
897         while (true) {
898             sp<IServiceManager> serviceManager = IServiceManager::getService();
899             CHECK(serviceManager) << "Hardware service manager is not running.";
900 
901             // There are three categories of services based on names.
902             std::vector<std::string> defaultNames; // Prefixed with "default"
903             std::vector<std::string> vendorNames;  // Prefixed with "vendor"
904             std::vector<std::string> otherNames;   // Others
905             Return<void> transResult;
906             transResult = serviceManager->listManifestByInterface(
907                     IComponentStore::descriptor,
908                     [&defaultNames, &vendorNames, &otherNames](
909                             hidl_vec<hidl_string> const& instanceNames) {
910                         for (hidl_string const& instanceName : instanceNames) {
911                             char const* name = instanceName.c_str();
912                             if (strncmp(name, "default", 7) == 0) {
913                                 defaultNames.emplace_back(name);
914                             } else if (strncmp(name, "vendor", 6) == 0) {
915                                 vendorNames.emplace_back(name);
916                             } else {
917                                 otherNames.emplace_back(name);
918                             }
919                         }
920                     });
921             if (transResult.isOk()) {
922                 // Sort service names in each category.
923                 std::sort(defaultNames.begin(), defaultNames.end());
924                 std::sort(vendorNames.begin(), vendorNames.end());
925                 std::sort(otherNames.begin(), otherNames.end());
926 
927                 // Concatenate the three lists in this order: default, vendor,
928                 // other.
929                 std::vector<std::string>& names = defaultNames;
930                 names.reserve(names.size() + vendorNames.size() + otherNames.size());
931                 names.insert(names.end(),
932                              std::make_move_iterator(vendorNames.begin()),
933                              std::make_move_iterator(vendorNames.end()));
934                 names.insert(names.end(),
935                              std::make_move_iterator(otherNames.begin()),
936                              std::make_move_iterator(otherNames.end()));
937 
938                 // Summarize to logcat.
939                 if (names.empty()) {
940                     LOG(INFO) << "No Codec2 services declared in the manifest.";
941                 } else {
942                     std::stringstream stringOutput;
943                     stringOutput << "Available Codec2 services:";
944                     for (std::string const& name : names) {
945                         stringOutput << " \"" << name << "\"";
946                     }
947                     LOG(INFO) << stringOutput.str();
948                 }
949 
950                 return names;
951             }
952             LOG(ERROR) << "Could not retrieve the list of service instances of "
953                        << IComponentStore::descriptor
954                        << ". Retrying...";
955         }
956     }()};
957     return sServiceNames;
958 }
959 
CreateFromService(const char * name,bool setAsPreferredCodec2ComponentStore)960 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
961         const char* name,
962         bool setAsPreferredCodec2ComponentStore) {
963     size_t index = getServiceIndex(name);
964     if (index == GetServiceNames().size()) {
965         if (setAsPreferredCodec2ComponentStore) {
966             LOG(WARNING) << "CreateFromService(" << name
967                          << ") -- preferred C2ComponentStore not set.";
968         }
969         return nullptr;
970     }
971     std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
972     if (setAsPreferredCodec2ComponentStore) {
973         SetPreferredCodec2ComponentStore(
974                 std::make_shared<Client2Store>(client));
975         LOG(INFO) << "CreateFromService(" << name
976                   << ") -- service set as preferred C2ComponentStore.";
977     }
978     return client;
979 }
980 
981 std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
CreateFromAllServices()982         CreateFromAllServices() {
983     std::vector<std::shared_ptr<Codec2Client>> clients(
984             GetServiceNames().size());
985     for (size_t i = GetServiceNames().size(); i > 0; ) {
986         --i;
987         clients[i] = _CreateFromIndex(i);
988     }
989     return clients;
990 }
991 
_CreateFromIndex(size_t index)992 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
993     std::string const& name = GetServiceNames()[index];
994     LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
995     sp<Base> baseStore = Base::getService(name);
996     CHECK(baseStore) << "Codec2 service \"" << name << "\""
997                         " inaccessible for unknown reasons.";
998     LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
999     Return<sp<IConfigurable>> transResult = baseStore->getConfigurable();
1000     CHECK(transResult.isOk()) << "Codec2 service \"" << name << "\""
1001                                 "does not have IConfigurable.";
1002     sp<IConfigurable> configurable = static_cast<sp<IConfigurable>>(transResult);
1003     return std::make_shared<Codec2Client>(baseStore, configurable, index);
1004 }
1005 
ForAllServices(const std::string & key,size_t numberOfAttempts,std::function<c2_status_t (const std::shared_ptr<Codec2Client> &)> predicate)1006 c2_status_t Codec2Client::ForAllServices(
1007         const std::string &key,
1008         size_t numberOfAttempts,
1009         std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
1010             predicate) {
1011     c2_status_t status = C2_NO_INIT;  // no IComponentStores present
1012 
1013     // Cache the mapping key -> index of Codec2Client in Cache::List().
1014     static std::mutex key2IndexMutex;
1015     static std::map<std::string, size_t> key2Index;
1016 
1017     // By default try all stores. However, try the last known client first. If
1018     // the last known client fails, retry once. We do this by pushing the last
1019     // known client in front of the list of all clients.
1020     std::deque<size_t> indices;
1021     for (size_t index = Cache::List().size(); index > 0; ) {
1022         indices.push_front(--index);
1023     }
1024 
1025     bool wasMapped = false;
1026     {
1027         std::scoped_lock lock{key2IndexMutex};
1028         auto it = key2Index.find(key);
1029         if (it != key2Index.end()) {
1030             indices.push_front(it->second);
1031             wasMapped = true;
1032         }
1033     }
1034 
1035     for (size_t index : indices) {
1036         Cache& cache = Cache::List()[index];
1037         for (size_t tries = numberOfAttempts; tries > 0; --tries) {
1038             std::shared_ptr<Codec2Client> client{cache.getClient()};
1039             status = predicate(client);
1040             if (status == C2_OK) {
1041                 std::scoped_lock lock{key2IndexMutex};
1042                 key2Index[key] = index; // update last known client index
1043                 return C2_OK;
1044             } else if (status == C2_NO_MEMORY) {
1045                 return C2_NO_MEMORY;
1046             } else if (status == C2_TRANSACTION_FAILED) {
1047                 LOG(WARNING) << "\"" << key << "\" failed for service \""
1048                              << client->getName()
1049                              << "\" due to transaction failure. "
1050                              << "(Service may have crashed.)"
1051                              << (tries > 1 ? " Retrying..." : "");
1052                 cache.invalidate();
1053                 continue;
1054             }
1055             if (wasMapped) {
1056                 LOG(INFO) << "\"" << key << "\" became invalid in service \""
1057                           << client->getName() << "\". Retrying...";
1058                 wasMapped = false;
1059             }
1060             break;
1061         }
1062     }
1063     return status; // return the last status from a valid client
1064 }
1065 
CreateComponentByName(const char * componentName,const std::shared_ptr<Listener> & listener,std::shared_ptr<Component> * component,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)1066 c2_status_t Codec2Client::CreateComponentByName(
1067         const char* componentName,
1068         const std::shared_ptr<Listener>& listener,
1069         std::shared_ptr<Component>* component,
1070         std::shared_ptr<Codec2Client>* owner,
1071         size_t numberOfAttempts) {
1072     std::string key{"create:"};
1073     key.append(componentName);
1074     c2_status_t status = ForAllServices(
1075             key,
1076             numberOfAttempts,
1077             [owner, component, componentName, &listener](
1078                     const std::shared_ptr<Codec2Client> &client)
1079                         -> c2_status_t {
1080                 c2_status_t status = client->createComponent(componentName,
1081                                                              listener,
1082                                                              component);
1083                 if (status == C2_OK) {
1084                     if (owner) {
1085                         *owner = client;
1086                     }
1087                 } else if (status != C2_NOT_FOUND) {
1088                     LOG(DEBUG) << "IComponentStore("
1089                                    << client->getServiceName()
1090                                << ")::createComponent(\"" << componentName
1091                                << "\") returned status = "
1092                                << status << ".";
1093                 }
1094                 return status;
1095             });
1096     if (status != C2_OK) {
1097         LOG(DEBUG) << "Failed to create component \"" << componentName
1098                    << "\" from all known services. "
1099                       "Last returned status = " << status << ".";
1100     }
1101     return status;
1102 }
1103 
1104 std::shared_ptr<Codec2Client::Interface>
CreateInterfaceByName(const char * interfaceName,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)1105         Codec2Client::CreateInterfaceByName(
1106         const char* interfaceName,
1107         std::shared_ptr<Codec2Client>* owner,
1108         size_t numberOfAttempts) {
1109     std::string key{"create:"};
1110     key.append(interfaceName);
1111     std::shared_ptr<Interface> interface;
1112     c2_status_t status = ForAllServices(
1113             key,
1114             numberOfAttempts,
1115             [owner, &interface, interfaceName](
1116                     const std::shared_ptr<Codec2Client> &client)
1117                         -> c2_status_t {
1118                 c2_status_t status = client->createInterface(interfaceName,
1119                                                              &interface);
1120                 if (status == C2_OK) {
1121                     if (owner) {
1122                         *owner = client;
1123                     }
1124                 } else if (status != C2_NOT_FOUND) {
1125                     LOG(DEBUG) << "IComponentStore("
1126                                    << client->getServiceName()
1127                                << ")::createInterface(\"" << interfaceName
1128                                << "\") returned status = "
1129                                << status << ".";
1130                 }
1131                 return status;
1132             });
1133     if (status != C2_OK) {
1134         LOG(DEBUG) << "Failed to create interface \"" << interfaceName
1135                    << "\" from all known services. "
1136                       "Last returned status = " << status << ".";
1137     }
1138     return interface;
1139 }
1140 
ListComponents()1141 std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
1142     static std::vector<C2Component::Traits> sList{[]() {
1143         std::vector<C2Component::Traits> list;
1144         for (Cache& cache : Cache::List()) {
1145             std::vector<C2Component::Traits> const& traits = cache.getTraits();
1146             list.insert(list.end(), traits.begin(), traits.end());
1147         }
1148         return list;
1149     }()};
1150     return sList;
1151 }
1152 
CreateInputSurface(char const * serviceName)1153 std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface(
1154         char const* serviceName) {
1155     int32_t inputSurfaceSetting = ::android::base::GetIntProperty(
1156             "debug.stagefright.c2inputsurface", int32_t(0));
1157     if (inputSurfaceSetting <= 0) {
1158         return nullptr;
1159     }
1160     size_t index = GetServiceNames().size();
1161     if (serviceName) {
1162         index = getServiceIndex(serviceName);
1163         if (index == GetServiceNames().size()) {
1164             LOG(DEBUG) << "CreateInputSurface -- invalid service name: \""
1165                        << serviceName << "\"";
1166         }
1167     }
1168 
1169     std::shared_ptr<Codec2Client::InputSurface> inputSurface;
1170     if (index != GetServiceNames().size()) {
1171         std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient();
1172         if (client->createInputSurface(&inputSurface) == C2_OK) {
1173             return inputSurface;
1174         }
1175     }
1176     LOG(INFO) << "CreateInputSurface -- attempting to create an input surface "
1177                  "from all services...";
1178     for (Cache& cache : Cache::List()) {
1179         std::shared_ptr<Codec2Client> client = cache.getClient();
1180         if (client->createInputSurface(&inputSurface) == C2_OK) {
1181             LOG(INFO) << "CreateInputSurface -- input surface obtained from "
1182                          "service \"" << client->getServiceName() << "\"";
1183             return inputSurface;
1184         }
1185     }
1186     LOG(WARNING) << "CreateInputSurface -- failed to create an input surface "
1187                     "from all services";
1188     return nullptr;
1189 }
1190 
1191 // Codec2Client::Listener
1192 
~Listener()1193 Codec2Client::Listener::~Listener() {
1194 }
1195 
1196 // Codec2Client::Interface
Interface(const sp<Base> & base)1197 Codec2Client::Interface::Interface(const sp<Base>& base)
1198       : Configurable{
1199             [base]() -> sp<IConfigurable> {
1200                 Return<sp<IConfigurable>> transResult =
1201                         base->getConfigurable();
1202                 return transResult.isOk() ?
1203                         static_cast<sp<IConfigurable>>(transResult) :
1204                         nullptr;
1205             }()
1206         },
1207         mBase{base} {
1208 }
1209 
1210 // Codec2Client::Component
Component(const sp<Base> & base)1211 Codec2Client::Component::Component(const sp<Base>& base)
1212       : Configurable{
1213             [base]() -> sp<IConfigurable> {
1214                 Return<sp<IComponentInterface>> transResult1 =
1215                         base->getInterface();
1216                 if (!transResult1.isOk()) {
1217                     return nullptr;
1218                 }
1219                 Return<sp<IConfigurable>> transResult2 =
1220                         static_cast<sp<IComponentInterface>>(transResult1)->
1221                         getConfigurable();
1222                 return transResult2.isOk() ?
1223                         static_cast<sp<IConfigurable>>(transResult2) :
1224                         nullptr;
1225             }()
1226         },
1227         mBase1_0{base},
1228         mBase1_1{Base1_1::castFrom(base)},
1229         mBase1_2{Base1_2::castFrom(base)},
1230         mBufferPoolSender{std::make_unique<BufferPoolSender>()},
1231         mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
1232 }
1233 
Component(const sp<Base1_1> & base)1234 Codec2Client::Component::Component(const sp<Base1_1>& base)
1235       : Configurable{
1236             [base]() -> sp<IConfigurable> {
1237                 Return<sp<IComponentInterface>> transResult1 =
1238                         base->getInterface();
1239                 if (!transResult1.isOk()) {
1240                     return nullptr;
1241                 }
1242                 Return<sp<IConfigurable>> transResult2 =
1243                         static_cast<sp<IComponentInterface>>(transResult1)->
1244                         getConfigurable();
1245                 return transResult2.isOk() ?
1246                         static_cast<sp<IConfigurable>>(transResult2) :
1247                         nullptr;
1248             }()
1249         },
1250         mBase1_0{base},
1251         mBase1_1{base},
1252         mBase1_2{Base1_2::castFrom(base)},
1253         mBufferPoolSender{std::make_unique<BufferPoolSender>()},
1254         mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
1255 }
1256 
Component(const sp<Base1_2> & base)1257 Codec2Client::Component::Component(const sp<Base1_2>& base)
1258       : Configurable{
1259             [base]() -> sp<IConfigurable> {
1260                 Return<sp<IComponentInterface>> transResult1 =
1261                         base->getInterface();
1262                 if (!transResult1.isOk()) {
1263                     return nullptr;
1264                 }
1265                 Return<sp<IConfigurable>> transResult2 =
1266                         static_cast<sp<IComponentInterface>>(transResult1)->
1267                         getConfigurable();
1268                 return transResult2.isOk() ?
1269                         static_cast<sp<IConfigurable>>(transResult2) :
1270                         nullptr;
1271             }()
1272         },
1273         mBase1_0{base},
1274         mBase1_1{base},
1275         mBase1_2{base},
1276         mBufferPoolSender{std::make_unique<BufferPoolSender>()},
1277         mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
1278 }
1279 
~Component()1280 Codec2Client::Component::~Component() {
1281 }
1282 
createBlockPool(C2Allocator::id_t id,C2BlockPool::local_id_t * blockPoolId,std::shared_ptr<Codec2Client::Configurable> * configurable)1283 c2_status_t Codec2Client::Component::createBlockPool(
1284         C2Allocator::id_t id,
1285         C2BlockPool::local_id_t* blockPoolId,
1286         std::shared_ptr<Codec2Client::Configurable>* configurable) {
1287     c2_status_t status;
1288     Return<void> transStatus = mBase1_0->createBlockPool(
1289             static_cast<uint32_t>(id),
1290             [&status, blockPoolId, configurable](
1291                     Status s,
1292                     uint64_t pId,
1293                     const sp<IConfigurable>& c) {
1294                 status = static_cast<c2_status_t>(s);
1295                 configurable->reset();
1296                 if (status != C2_OK) {
1297                     LOG(DEBUG) << "createBlockPool -- call failed: "
1298                                << status << ".";
1299                     return;
1300                 }
1301                 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
1302                 *configurable = std::make_shared<Configurable>(c);
1303             });
1304     if (!transStatus.isOk()) {
1305         LOG(ERROR) << "createBlockPool -- transaction failed.";
1306         return C2_TRANSACTION_FAILED;
1307     }
1308     return status;
1309 }
1310 
destroyBlockPool(C2BlockPool::local_id_t localId)1311 c2_status_t Codec2Client::Component::destroyBlockPool(
1312         C2BlockPool::local_id_t localId) {
1313     Return<Status> transResult = mBase1_0->destroyBlockPool(
1314             static_cast<uint64_t>(localId));
1315     if (!transResult.isOk()) {
1316         LOG(ERROR) << "destroyBlockPool -- transaction failed.";
1317         return C2_TRANSACTION_FAILED;
1318     }
1319     return static_cast<c2_status_t>(static_cast<Status>(transResult));
1320 }
1321 
handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> & workItems)1322 void Codec2Client::Component::handleOnWorkDone(
1323         const std::list<std::unique_ptr<C2Work>> &workItems) {
1324     // Output bufferqueue-based blocks' lifetime management
1325     mOutputBufferQueue->holdBufferQueueBlocks(workItems);
1326 }
1327 
queue(std::list<std::unique_ptr<C2Work>> * const items)1328 c2_status_t Codec2Client::Component::queue(
1329         std::list<std::unique_ptr<C2Work>>* const items) {
1330     WorkBundle workBundle;
1331     if (!objcpy(&workBundle, *items, mBufferPoolSender.get())) {
1332         LOG(ERROR) << "queue -- bad input.";
1333         return C2_TRANSACTION_FAILED;
1334     }
1335     Return<Status> transStatus = mBase1_0->queue(workBundle);
1336     if (!transStatus.isOk()) {
1337         LOG(ERROR) << "queue -- transaction failed.";
1338         return C2_TRANSACTION_FAILED;
1339     }
1340     c2_status_t status =
1341             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1342     if (status != C2_OK) {
1343         LOG(DEBUG) << "queue -- call failed: " << status << ".";
1344     }
1345     return status;
1346 }
1347 
flush(C2Component::flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)1348 c2_status_t Codec2Client::Component::flush(
1349         C2Component::flush_mode_t mode,
1350         std::list<std::unique_ptr<C2Work>>* const flushedWork) {
1351     (void)mode; // Flush mode isn't supported in HIDL yet.
1352     c2_status_t status;
1353     Return<void> transStatus = mBase1_0->flush(
1354             [&status, flushedWork](
1355                     Status s, const WorkBundle& wb) {
1356                 status = static_cast<c2_status_t>(s);
1357                 if (status != C2_OK) {
1358                     LOG(DEBUG) << "flush -- call failed: " << status << ".";
1359                     return;
1360                 }
1361                 if (!objcpy(flushedWork, wb)) {
1362                     status = C2_CORRUPTED;
1363                 } else {
1364                     status = C2_OK;
1365                 }
1366             });
1367     if (!transStatus.isOk()) {
1368         LOG(ERROR) << "flush -- transaction failed.";
1369         return C2_TRANSACTION_FAILED;
1370     }
1371 
1372     // Indices of flushed work items.
1373     std::vector<uint64_t> flushedIndices;
1374     for (const std::unique_ptr<C2Work> &work : *flushedWork) {
1375         if (work) {
1376             if (work->worklets.empty()
1377                     || !work->worklets.back()
1378                     || (work->worklets.back()->output.flags &
1379                         C2FrameData::FLAG_INCOMPLETE) == 0) {
1380                 // input is complete
1381                 flushedIndices.emplace_back(
1382                         work->input.ordinal.frameIndex.peeku());
1383             }
1384         }
1385     }
1386 
1387     // Output bufferqueue-based blocks' lifetime management
1388     mOutputBufferQueue->holdBufferQueueBlocks(*flushedWork);
1389 
1390     return status;
1391 }
1392 
drain(C2Component::drain_mode_t mode)1393 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
1394     Return<Status> transStatus = mBase1_0->drain(
1395             mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
1396     if (!transStatus.isOk()) {
1397         LOG(ERROR) << "drain -- transaction failed.";
1398         return C2_TRANSACTION_FAILED;
1399     }
1400     c2_status_t status =
1401             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1402     if (status != C2_OK) {
1403         LOG(DEBUG) << "drain -- call failed: " << status << ".";
1404     }
1405     return status;
1406 }
1407 
start()1408 c2_status_t Codec2Client::Component::start() {
1409     Return<Status> transStatus = mBase1_0->start();
1410     if (!transStatus.isOk()) {
1411         LOG(ERROR) << "start -- transaction failed.";
1412         return C2_TRANSACTION_FAILED;
1413     }
1414     c2_status_t status =
1415             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1416     if (status != C2_OK) {
1417         LOG(DEBUG) << "start -- call failed: " << status << ".";
1418     }
1419     return status;
1420 }
1421 
stop()1422 c2_status_t Codec2Client::Component::stop() {
1423     Return<Status> transStatus = mBase1_0->stop();
1424     if (!transStatus.isOk()) {
1425         LOG(ERROR) << "stop -- transaction failed.";
1426         return C2_TRANSACTION_FAILED;
1427     }
1428     c2_status_t status =
1429             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1430     if (status != C2_OK) {
1431         LOG(DEBUG) << "stop -- call failed: " << status << ".";
1432     }
1433     return status;
1434 }
1435 
reset()1436 c2_status_t Codec2Client::Component::reset() {
1437     Return<Status> transStatus = mBase1_0->reset();
1438     if (!transStatus.isOk()) {
1439         LOG(ERROR) << "reset -- transaction failed.";
1440         return C2_TRANSACTION_FAILED;
1441     }
1442     c2_status_t status =
1443             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1444     if (status != C2_OK) {
1445         LOG(DEBUG) << "reset -- call failed: " << status << ".";
1446     }
1447     return status;
1448 }
1449 
release()1450 c2_status_t Codec2Client::Component::release() {
1451     Return<Status> transStatus = mBase1_0->release();
1452     if (!transStatus.isOk()) {
1453         LOG(ERROR) << "release -- transaction failed.";
1454         return C2_TRANSACTION_FAILED;
1455     }
1456     c2_status_t status =
1457             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1458     if (status != C2_OK) {
1459         LOG(DEBUG) << "release -- call failed: " << status << ".";
1460     }
1461     return status;
1462 }
1463 
configureVideoTunnel(uint32_t avSyncHwId,native_handle_t ** sidebandHandle)1464 c2_status_t Codec2Client::Component::configureVideoTunnel(
1465         uint32_t avSyncHwId,
1466         native_handle_t** sidebandHandle) {
1467     *sidebandHandle = nullptr;
1468     if (!mBase1_1) {
1469         return C2_OMITTED;
1470     }
1471     c2_status_t status{};
1472     Return<void> transStatus = mBase1_1->configureVideoTunnel(avSyncHwId,
1473             [&status, sidebandHandle](
1474                     Status s, hardware::hidl_handle const& h) {
1475                 status = static_cast<c2_status_t>(s);
1476                 if (h.getNativeHandle()) {
1477                     *sidebandHandle = native_handle_clone(h.getNativeHandle());
1478                 }
1479             });
1480     if (!transStatus.isOk()) {
1481         LOG(ERROR) << "configureVideoTunnel -- transaction failed.";
1482         return C2_TRANSACTION_FAILED;
1483     }
1484     return status;
1485 }
1486 
setOutputSurface(C2BlockPool::local_id_t blockPoolId,const sp<IGraphicBufferProducer> & surface,uint32_t generation,int maxDequeueCount)1487 c2_status_t Codec2Client::Component::setOutputSurface(
1488         C2BlockPool::local_id_t blockPoolId,
1489         const sp<IGraphicBufferProducer>& surface,
1490         uint32_t generation,
1491         int maxDequeueCount) {
1492     uint64_t bqId = 0;
1493     sp<IGraphicBufferProducer> nullIgbp;
1494     sp<HGraphicBufferProducer2> nullHgbp;
1495 
1496     sp<HGraphicBufferProducer2> igbp = surface ?
1497             surface->getHalInterface<HGraphicBufferProducer2>() : nullHgbp;
1498     if (surface && !igbp) {
1499         igbp = new B2HGraphicBufferProducer2(surface);
1500     }
1501 
1502     std::scoped_lock lock(mOutputMutex);
1503     std::shared_ptr<SurfaceSyncObj> syncObj;
1504 
1505     if (!surface) {
1506         mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
1507     } else if (surface->getUniqueId(&bqId) != OK) {
1508         LOG(ERROR) << "setOutputSurface -- "
1509                    "cannot obtain bufferqueue id.";
1510         bqId = 0;
1511         mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
1512     } else {
1513         mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount, mBase1_2 ?
1514                                       &syncObj : nullptr);
1515     }
1516 
1517     // set consumer bits
1518     // TODO: should this get incorporated into setOutputSurface method so that consumer bits
1519     // can be set atomically?
1520     uint64_t consumerUsage = kDefaultConsumerUsage;
1521     {
1522         if (surface) {
1523             uint64_t usage = 0;
1524             status_t err = surface->getConsumerUsage(&usage);
1525             if (err != NO_ERROR) {
1526                 ALOGD("setOutputSurface -- failed to get consumer usage bits (%d/%s). ignoring",
1527                         err, asString(err));
1528             } else {
1529                 // Note: we are adding the default usage because components must support
1530                 // producing output frames that can be displayed an all output surfaces.
1531 
1532                 // TODO: do not set usage for tunneled scenario. It is unclear if consumer usage
1533                 // is meaningful in a tunneled scenario; on one hand output buffers exist, but
1534                 // they do not exist inside of C2 scope. Any buffer usage shall be communicated
1535                 // through the sideband channel.
1536 
1537                 consumerUsage = usage | kDefaultConsumerUsage;
1538             }
1539         }
1540 
1541         C2StreamUsageTuning::output outputUsage{
1542                 0u, C2AndroidMemoryUsage::FromGrallocUsage(consumerUsage).expected};
1543         std::vector<std::unique_ptr<C2SettingResult>> failures;
1544         c2_status_t err = config({&outputUsage}, C2_MAY_BLOCK, &failures);
1545         if (err != C2_OK) {
1546             ALOGD("setOutputSurface -- failed to set consumer usage (%d/%s)",
1547                     err, asString(err));
1548         }
1549     }
1550     ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx%s",
1551             generation, (long long)consumerUsage, syncObj ? " sync" : "");
1552 
1553     Return<Status> transStatus = syncObj ?
1554             mBase1_2->setOutputSurfaceWithSyncObj(
1555                     static_cast<uint64_t>(blockPoolId),
1556                     bqId == 0 ? nullHgbp : igbp, *syncObj) :
1557             mBase1_0->setOutputSurface(
1558                     static_cast<uint64_t>(blockPoolId),
1559                     bqId == 0 ? nullHgbp : igbp);
1560 
1561     mOutputBufferQueue->expireOldWaiters();
1562 
1563     if (!transStatus.isOk()) {
1564         LOG(ERROR) << "setOutputSurface -- transaction failed.";
1565         return C2_TRANSACTION_FAILED;
1566     }
1567     c2_status_t status =
1568             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1569     if (status != C2_OK) {
1570         LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
1571     }
1572     ALOGD("Surface configure completed");
1573     return status;
1574 }
1575 
queueToOutputSurface(const C2ConstGraphicBlock & block,const QueueBufferInput & input,QueueBufferOutput * output)1576 status_t Codec2Client::Component::queueToOutputSurface(
1577         const C2ConstGraphicBlock& block,
1578         const QueueBufferInput& input,
1579         QueueBufferOutput* output) {
1580     return mOutputBufferQueue->outputBuffer(block, input, output);
1581 }
1582 
pollForRenderedFrames(FrameEventHistoryDelta * delta)1583 void Codec2Client::Component::pollForRenderedFrames(FrameEventHistoryDelta* delta) {
1584     mOutputBufferQueue->pollForRenderedFrames(delta);
1585 }
1586 
setOutputSurfaceMaxDequeueCount(int maxDequeueCount)1587 void Codec2Client::Component::setOutputSurfaceMaxDequeueCount(
1588         int maxDequeueCount) {
1589     mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
1590 }
1591 
stopUsingOutputSurface(C2BlockPool::local_id_t blockPoolId)1592 void Codec2Client::Component::stopUsingOutputSurface(
1593         C2BlockPool::local_id_t blockPoolId) {
1594     std::scoped_lock lock(mOutputMutex);
1595     mOutputBufferQueue->stop();
1596     Return<Status> transStatus = mBase1_0->setOutputSurface(
1597             static_cast<uint64_t>(blockPoolId), nullptr);
1598     if (!transStatus.isOk()) {
1599         LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
1600     } else {
1601         c2_status_t status =
1602                 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1603         if (status != C2_OK) {
1604             LOG(DEBUG) << "setOutputSurface(stopUsingOutputSurface) -- call failed: "
1605                        << status << ".";
1606         }
1607     }
1608     mOutputBufferQueue->expireOldWaiters();
1609 }
1610 
connectToInputSurface(const std::shared_ptr<InputSurface> & inputSurface,std::shared_ptr<InputSurfaceConnection> * connection)1611 c2_status_t Codec2Client::Component::connectToInputSurface(
1612         const std::shared_ptr<InputSurface>& inputSurface,
1613         std::shared_ptr<InputSurfaceConnection>* connection) {
1614     c2_status_t status;
1615     Return<void> transStatus = mBase1_0->connectToInputSurface(
1616             inputSurface->mBase,
1617             [&status, connection](
1618                     Status s, const sp<IInputSurfaceConnection>& c) {
1619                 status = static_cast<c2_status_t>(s);
1620                 if (status != C2_OK) {
1621                     LOG(DEBUG) << "connectToInputSurface -- call failed: "
1622                                << status << ".";
1623                     return;
1624                 }
1625                 *connection = std::make_shared<InputSurfaceConnection>(c);
1626             });
1627     if (!transStatus.isOk()) {
1628         LOG(ERROR) << "connectToInputSurface -- transaction failed";
1629         return C2_TRANSACTION_FAILED;
1630     }
1631     return status;
1632 }
1633 
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<HGraphicBufferSource> & source,std::shared_ptr<InputSurfaceConnection> * connection)1634 c2_status_t Codec2Client::Component::connectToOmxInputSurface(
1635         const sp<HGraphicBufferProducer1>& producer,
1636         const sp<HGraphicBufferSource>& source,
1637         std::shared_ptr<InputSurfaceConnection>* connection) {
1638     c2_status_t status;
1639     Return<void> transStatus = mBase1_0->connectToOmxInputSurface(
1640             producer, source,
1641             [&status, connection](
1642                     Status s, const sp<IInputSurfaceConnection>& c) {
1643                 status = static_cast<c2_status_t>(s);
1644                 if (status != C2_OK) {
1645                     LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
1646                                << status << ".";
1647                     return;
1648                 }
1649                 *connection = std::make_shared<InputSurfaceConnection>(c);
1650             });
1651     if (!transStatus.isOk()) {
1652         LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
1653         return C2_TRANSACTION_FAILED;
1654     }
1655     return status;
1656 }
1657 
disconnectFromInputSurface()1658 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
1659     Return<Status> transStatus = mBase1_0->disconnectFromInputSurface();
1660     if (!transStatus.isOk()) {
1661         LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
1662         return C2_TRANSACTION_FAILED;
1663     }
1664     c2_status_t status =
1665             static_cast<c2_status_t>(static_cast<Status>(transStatus));
1666     if (status != C2_OK) {
1667         LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
1668                    << status << ".";
1669     }
1670     return status;
1671 }
1672 
setDeathListener(const std::shared_ptr<Component> & component,const std::shared_ptr<Listener> & listener)1673 c2_status_t Codec2Client::Component::setDeathListener(
1674         const std::shared_ptr<Component>& component,
1675         const std::shared_ptr<Listener>& listener) {
1676 
1677     struct HidlDeathRecipient : public hardware::hidl_death_recipient {
1678         std::weak_ptr<Component> component;
1679         std::weak_ptr<Listener> base;
1680 
1681         virtual void serviceDied(
1682                 uint64_t /* cookie */,
1683                 const wp<::android::hidl::base::V1_0::IBase>& /* who */
1684                 ) override {
1685             if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1686                 listener->onDeath(component);
1687             } else {
1688                 LOG(DEBUG) << "onDeath -- listener died.";
1689             }
1690         }
1691     };
1692 
1693     sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
1694     deathRecipient->base = listener;
1695     deathRecipient->component = component;
1696 
1697     component->mDeathRecipient = deathRecipient;
1698     Return<bool> transResult = component->mBase1_0->linkToDeath(
1699             component->mDeathRecipient, 0);
1700     if (!transResult.isOk()) {
1701         LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
1702         return C2_TRANSACTION_FAILED;
1703     }
1704     if (!static_cast<bool>(transResult)) {
1705         LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
1706         return C2_CORRUPTED;
1707     }
1708     return C2_OK;
1709 }
1710 
1711 // Codec2Client::InputSurface
InputSurface(const sp<IInputSurface> & base)1712 Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base)
1713       : Configurable{
1714             [base]() -> sp<IConfigurable> {
1715                 Return<sp<IConfigurable>> transResult =
1716                         base->getConfigurable();
1717                 return transResult.isOk() ?
1718                         static_cast<sp<IConfigurable>>(transResult) :
1719                         nullptr;
1720             }()
1721         },
1722         mBase{base},
1723         mGraphicBufferProducer{new
__anon4f0a646a2002() 1724             H2BGraphicBufferProducer2([base]() -> sp<HGraphicBufferProducer2> {
1725                 Return<sp<HGraphicBufferProducer2>> transResult =
1726                         base->getGraphicBufferProducer();
1727                 return transResult.isOk() ?
1728                         static_cast<sp<HGraphicBufferProducer2>>(transResult) :
1729                         nullptr;
1730             }())} {
1731 }
1732 
1733 sp<IGraphicBufferProducer>
getGraphicBufferProducer() const1734         Codec2Client::InputSurface::getGraphicBufferProducer() const {
1735     return mGraphicBufferProducer;
1736 }
1737 
getHalInterface() const1738 sp<IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
1739     return mBase;
1740 }
1741 
1742 // Codec2Client::InputSurfaceConnection
InputSurfaceConnection(const sp<IInputSurfaceConnection> & base)1743 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
1744         const sp<IInputSurfaceConnection>& base)
1745       : Configurable{
1746             [base]() -> sp<IConfigurable> {
1747                 Return<sp<IConfigurable>> transResult =
1748                         base->getConfigurable();
1749                 return transResult.isOk() ?
1750                         static_cast<sp<IConfigurable>>(transResult) :
1751                         nullptr;
1752             }()
1753         },
1754         mBase{base} {
1755 }
1756 
disconnect()1757 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
1758     Return<Status> transResult = mBase->disconnect();
1759     return static_cast<c2_status_t>(static_cast<Status>(transResult));
1760 }
1761 
1762 }  // namespace android
1763