Wonsik Kim | 5ec480f | 2023-07-11 14:25:55 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2021 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 "Codec2-Component@1.2" |
| 19 | #include <android-base/logging.h> |
| 20 | |
| 21 | #include <codec2/hidl/1.2/Component.h> |
| 22 | #include <codec2/hidl/1.2/ComponentStore.h> |
| 23 | #include <codec2/hidl/1.2/InputBufferManager.h> |
| 24 | |
| 25 | #ifndef __ANDROID_APEX__ |
| 26 | #include <FilterWrapper.h> |
| 27 | #endif |
| 28 | |
| 29 | #include <hidl/HidlBinderSupport.h> |
| 30 | #include <utils/Timers.h> |
| 31 | |
| 32 | #include <C2BqBufferPriv.h> |
| 33 | #include <C2Debug.h> |
| 34 | #include <C2PlatformSupport.h> |
| 35 | |
| 36 | #include <chrono> |
| 37 | #include <thread> |
| 38 | |
| 39 | namespace android { |
| 40 | namespace hardware { |
| 41 | namespace media { |
| 42 | namespace c2 { |
| 43 | namespace V1_2 { |
| 44 | namespace utils { |
| 45 | |
| 46 | using namespace ::android; |
| 47 | |
| 48 | // ComponentListener wrapper |
| 49 | struct Component::Listener : public C2Component::Listener { |
| 50 | |
| 51 | Listener(const sp<Component>& component) : |
| 52 | mComponent(component), |
| 53 | mListener(component->mListener) { |
| 54 | } |
| 55 | |
| 56 | virtual void onError_nb( |
| 57 | std::weak_ptr<C2Component> /* c2component */, |
| 58 | uint32_t errorCode) override { |
| 59 | sp<IComponentListener> listener = mListener.promote(); |
| 60 | if (listener) { |
| 61 | Return<void> transStatus = listener->onError(Status::OK, errorCode); |
| 62 | if (!transStatus.isOk()) { |
| 63 | LOG(ERROR) << "Component::Listener::onError_nb -- " |
| 64 | << "transaction failed."; |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | virtual void onTripped_nb( |
| 70 | std::weak_ptr<C2Component> /* c2component */, |
| 71 | std::vector<std::shared_ptr<C2SettingResult>> c2settingResult |
| 72 | ) override { |
| 73 | sp<IComponentListener> listener = mListener.promote(); |
| 74 | if (listener) { |
| 75 | hidl_vec<SettingResult> settingResults(c2settingResult.size()); |
| 76 | size_t ix = 0; |
| 77 | for (const std::shared_ptr<C2SettingResult> &c2result : |
| 78 | c2settingResult) { |
| 79 | if (c2result) { |
| 80 | if (!objcpy(&settingResults[ix++], *c2result)) { |
| 81 | break; |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | settingResults.resize(ix); |
| 86 | Return<void> transStatus = listener->onTripped(settingResults); |
| 87 | if (!transStatus.isOk()) { |
| 88 | LOG(ERROR) << "Component::Listener::onTripped_nb -- " |
| 89 | << "transaction failed."; |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | virtual void onWorkDone_nb( |
| 95 | std::weak_ptr<C2Component> /* c2component */, |
| 96 | std::list<std::unique_ptr<C2Work>> c2workItems) override { |
| 97 | for (const std::unique_ptr<C2Work>& work : c2workItems) { |
| 98 | if (work) { |
| 99 | if (work->worklets.empty() |
| 100 | || !work->worklets.back() |
| 101 | || (work->worklets.back()->output.flags & |
| 102 | C2FrameData::FLAG_INCOMPLETE) == 0) { |
| 103 | InputBufferManager:: |
| 104 | unregisterFrameData(mListener, work->input); |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | sp<IComponentListener> listener = mListener.promote(); |
| 110 | if (listener) { |
| 111 | WorkBundle workBundle; |
| 112 | |
| 113 | sp<Component> strongComponent = mComponent.promote(); |
| 114 | beginTransferBufferQueueBlocks(c2workItems, true); |
| 115 | if (!objcpy(&workBundle, c2workItems, strongComponent ? |
| 116 | &strongComponent->mBufferPoolSender : nullptr)) { |
| 117 | LOG(ERROR) << "Component::Listener::onWorkDone_nb -- " |
| 118 | << "received corrupted work items."; |
| 119 | endTransferBufferQueueBlocks(c2workItems, false, true); |
| 120 | return; |
| 121 | } |
| 122 | Return<void> transStatus = listener->onWorkDone(workBundle); |
| 123 | if (!transStatus.isOk()) { |
| 124 | LOG(ERROR) << "Component::Listener::onWorkDone_nb -- " |
| 125 | << "transaction failed."; |
| 126 | endTransferBufferQueueBlocks(c2workItems, false, true); |
| 127 | return; |
| 128 | } |
| 129 | endTransferBufferQueueBlocks(c2workItems, true, true); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | protected: |
| 134 | wp<Component> mComponent; |
| 135 | wp<IComponentListener> mListener; |
| 136 | }; |
| 137 | |
| 138 | // Component::Sink |
| 139 | struct Component::Sink : public IInputSink { |
| 140 | std::shared_ptr<Component> mComponent; |
| 141 | sp<IConfigurable> mConfigurable; |
| 142 | |
| 143 | virtual Return<Status> queue(const WorkBundle& workBundle) override { |
| 144 | return mComponent->queue(workBundle); |
| 145 | } |
| 146 | |
| 147 | virtual Return<sp<IConfigurable>> getConfigurable() override { |
| 148 | return mConfigurable; |
| 149 | } |
| 150 | |
| 151 | Sink(const std::shared_ptr<Component>& component); |
| 152 | virtual ~Sink() override; |
| 153 | |
| 154 | // Process-wide map: Component::Sink -> C2Component. |
| 155 | static std::mutex sSink2ComponentMutex; |
| 156 | static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component; |
| 157 | |
| 158 | static std::shared_ptr<C2Component> findLocalComponent( |
| 159 | const sp<IInputSink>& sink); |
| 160 | }; |
| 161 | |
| 162 | std::mutex |
| 163 | Component::Sink::sSink2ComponentMutex{}; |
| 164 | std::map<IInputSink*, std::weak_ptr<C2Component>> |
| 165 | Component::Sink::sSink2Component{}; |
| 166 | |
| 167 | Component::Sink::Sink(const std::shared_ptr<Component>& component) |
| 168 | : mComponent{component}, |
| 169 | mConfigurable{[&component]() -> sp<IConfigurable> { |
| 170 | Return<sp<IComponentInterface>> ret1 = component->getInterface(); |
| 171 | if (!ret1.isOk()) { |
| 172 | LOG(ERROR) << "Sink::Sink -- component's transaction failed."; |
| 173 | return nullptr; |
| 174 | } |
| 175 | Return<sp<IConfigurable>> ret2 = |
| 176 | static_cast<sp<IComponentInterface>>(ret1)-> |
| 177 | getConfigurable(); |
| 178 | if (!ret2.isOk()) { |
| 179 | LOG(ERROR) << "Sink::Sink -- interface's transaction failed."; |
| 180 | return nullptr; |
| 181 | } |
| 182 | return static_cast<sp<IConfigurable>>(ret2); |
| 183 | }()} { |
| 184 | std::lock_guard<std::mutex> lock(sSink2ComponentMutex); |
| 185 | sSink2Component.emplace(this, component->mComponent); |
| 186 | } |
| 187 | |
| 188 | Component::Sink::~Sink() { |
| 189 | std::lock_guard<std::mutex> lock(sSink2ComponentMutex); |
| 190 | sSink2Component.erase(this); |
| 191 | } |
| 192 | |
| 193 | std::shared_ptr<C2Component> Component::Sink::findLocalComponent( |
| 194 | const sp<IInputSink>& sink) { |
| 195 | std::lock_guard<std::mutex> lock(sSink2ComponentMutex); |
| 196 | auto i = sSink2Component.find(sink.get()); |
| 197 | if (i == sSink2Component.end()) { |
| 198 | return nullptr; |
| 199 | } |
| 200 | return i->second.lock(); |
| 201 | } |
| 202 | |
| 203 | // Component |
| 204 | Component::Component( |
| 205 | const std::shared_ptr<C2Component>& component, |
| 206 | const sp<IComponentListener>& listener, |
| 207 | const sp<ComponentStore>& store, |
| 208 | const sp<::android::hardware::media::bufferpool::V2_0:: |
| 209 | IClientManager>& clientPoolManager) |
| 210 | : mComponent{component}, |
| 211 | mInterface{new ComponentInterface(component->intf(), |
| 212 | store->getParameterCache())}, |
| 213 | mListener{listener}, |
| 214 | mStore{store}, |
| 215 | mBufferPoolSender{clientPoolManager} { |
| 216 | // Retrieve supported parameters from store |
| 217 | // TODO: We could cache this per component/interface type |
| 218 | mInit = mInterface->status(); |
| 219 | } |
| 220 | |
| 221 | c2_status_t Component::status() const { |
| 222 | return mInit; |
| 223 | } |
| 224 | |
| 225 | // Methods from ::android::hardware::media::c2::V1_1::IComponent |
| 226 | Return<Status> Component::queue(const WorkBundle& workBundle) { |
| 227 | std::list<std::unique_ptr<C2Work>> c2works; |
| 228 | |
| 229 | if (!objcpy(&c2works, workBundle)) { |
| 230 | return Status::CORRUPTED; |
| 231 | } |
| 232 | |
| 233 | // Register input buffers. |
| 234 | for (const std::unique_ptr<C2Work>& work : c2works) { |
| 235 | if (work) { |
| 236 | InputBufferManager:: |
| 237 | registerFrameData(mListener, work->input); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | return static_cast<Status>(mComponent->queue_nb(&c2works)); |
| 242 | } |
| 243 | |
| 244 | Return<void> Component::flush(flush_cb _hidl_cb) { |
| 245 | std::list<std::unique_ptr<C2Work>> c2flushedWorks; |
| 246 | c2_status_t c2res = mComponent->flush_sm( |
| 247 | C2Component::FLUSH_COMPONENT, |
| 248 | &c2flushedWorks); |
| 249 | |
| 250 | // Unregister input buffers. |
| 251 | for (const std::unique_ptr<C2Work>& work : c2flushedWorks) { |
| 252 | if (work) { |
| 253 | if (work->worklets.empty() |
| 254 | || !work->worklets.back() |
| 255 | || (work->worklets.back()->output.flags & |
| 256 | C2FrameData::FLAG_INCOMPLETE) == 0) { |
| 257 | InputBufferManager:: |
| 258 | unregisterFrameData(mListener, work->input); |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | WorkBundle flushedWorkBundle; |
| 264 | Status res = static_cast<Status>(c2res); |
| 265 | beginTransferBufferQueueBlocks(c2flushedWorks, true); |
| 266 | if (c2res == C2_OK) { |
| 267 | if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) { |
| 268 | res = Status::CORRUPTED; |
| 269 | } |
| 270 | } |
| 271 | _hidl_cb(res, flushedWorkBundle); |
| 272 | endTransferBufferQueueBlocks(c2flushedWorks, true, true); |
| 273 | return Void(); |
| 274 | } |
| 275 | |
| 276 | Return<Status> Component::drain(bool withEos) { |
| 277 | return static_cast<Status>(mComponent->drain_nb(withEos ? |
| 278 | C2Component::DRAIN_COMPONENT_WITH_EOS : |
| 279 | C2Component::DRAIN_COMPONENT_NO_EOS)); |
| 280 | } |
| 281 | |
| 282 | Return<Status> Component::setOutputSurface( |
| 283 | uint64_t blockPoolId, |
| 284 | const sp<HGraphicBufferProducer2>& surface) { |
| 285 | std::shared_ptr<C2BlockPool> pool; |
| 286 | GetCodec2BlockPool(blockPoolId, mComponent, &pool); |
| 287 | if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { |
| 288 | std::shared_ptr<C2BufferQueueBlockPool> bqPool = |
| 289 | std::static_pointer_cast<C2BufferQueueBlockPool>(pool); |
| 290 | C2BufferQueueBlockPool::OnRenderCallback cb = |
| 291 | [this](uint64_t producer, int32_t slot, int64_t nsecs) { |
| 292 | // TODO: batch this |
| 293 | hidl_vec<IComponentListener::RenderedFrame> rendered; |
| 294 | rendered.resize(1); |
| 295 | rendered[0] = { producer, slot, nsecs }; |
| 296 | (void)mListener->onFramesRendered(rendered).isOk(); |
| 297 | }; |
| 298 | if (bqPool) { |
| 299 | bqPool->setRenderCallback(cb); |
| 300 | bqPool->configureProducer(surface); |
| 301 | } |
| 302 | } |
| 303 | return Status::OK; |
| 304 | } |
| 305 | |
| 306 | Return<void> Component::connectToInputSurface( |
| 307 | const sp<IInputSurface>& inputSurface, |
| 308 | connectToInputSurface_cb _hidl_cb) { |
| 309 | Status status; |
| 310 | sp<IInputSurfaceConnection> connection; |
| 311 | auto transStatus = inputSurface->connect( |
| 312 | asInputSink(), |
| 313 | [&status, &connection]( |
| 314 | Status s, const sp<IInputSurfaceConnection>& c) { |
| 315 | status = s; |
| 316 | connection = c; |
| 317 | } |
| 318 | ); |
| 319 | _hidl_cb(status, connection); |
| 320 | return Void(); |
| 321 | } |
| 322 | |
| 323 | Return<void> Component::connectToOmxInputSurface( |
| 324 | const sp<HGraphicBufferProducer1>& producer, |
| 325 | const sp<::android::hardware::media::omx::V1_0:: |
| 326 | IGraphicBufferSource>& source, |
| 327 | connectToOmxInputSurface_cb _hidl_cb) { |
| 328 | (void)producer; |
| 329 | (void)source; |
| 330 | (void)_hidl_cb; |
| 331 | return Void(); |
| 332 | } |
| 333 | |
| 334 | Return<Status> Component::disconnectFromInputSurface() { |
| 335 | // TODO implement |
| 336 | return Status::OK; |
| 337 | } |
| 338 | |
| 339 | namespace /* unnamed */ { |
| 340 | |
| 341 | struct BlockPoolIntf : public ConfigurableC2Intf { |
| 342 | BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) |
| 343 | : ConfigurableC2Intf{ |
| 344 | "C2BlockPool:" + |
| 345 | (pool ? std::to_string(pool->getLocalId()) : "null"), |
| 346 | 0}, |
| 347 | mPool{pool} { |
| 348 | } |
| 349 | |
| 350 | virtual c2_status_t config( |
| 351 | const std::vector<C2Param*>& params, |
| 352 | c2_blocking_t mayBlock, |
| 353 | std::vector<std::unique_ptr<C2SettingResult>>* const failures |
| 354 | ) override { |
| 355 | (void)params; |
| 356 | (void)mayBlock; |
| 357 | (void)failures; |
| 358 | return C2_OK; |
| 359 | } |
| 360 | |
| 361 | virtual c2_status_t query( |
| 362 | const std::vector<C2Param::Index>& indices, |
| 363 | c2_blocking_t mayBlock, |
| 364 | std::vector<std::unique_ptr<C2Param>>* const params |
| 365 | ) const override { |
| 366 | (void)indices; |
| 367 | (void)mayBlock; |
| 368 | (void)params; |
| 369 | return C2_OK; |
| 370 | } |
| 371 | |
| 372 | virtual c2_status_t querySupportedParams( |
| 373 | std::vector<std::shared_ptr<C2ParamDescriptor>>* const params |
| 374 | ) const override { |
| 375 | (void)params; |
| 376 | return C2_OK; |
| 377 | } |
| 378 | |
| 379 | virtual c2_status_t querySupportedValues( |
| 380 | std::vector<C2FieldSupportedValuesQuery>& fields, |
| 381 | c2_blocking_t mayBlock) const override { |
| 382 | (void)fields; |
| 383 | (void)mayBlock; |
| 384 | return C2_OK; |
| 385 | } |
| 386 | |
| 387 | protected: |
| 388 | std::shared_ptr<C2BlockPool> mPool; |
| 389 | }; |
| 390 | |
| 391 | } // unnamed namespace |
| 392 | |
| 393 | Return<void> Component::createBlockPool( |
| 394 | uint32_t allocatorId, |
| 395 | createBlockPool_cb _hidl_cb) { |
| 396 | std::shared_ptr<C2BlockPool> blockPool; |
| 397 | #ifdef __ANDROID_APEX__ |
| 398 | c2_status_t status = CreateCodec2BlockPool( |
| 399 | static_cast<C2PlatformAllocatorStore::id_t>(allocatorId), |
| 400 | mComponent, |
| 401 | &blockPool); |
| 402 | #else |
| 403 | c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool( |
| 404 | static_cast<C2PlatformAllocatorStore::id_t>(allocatorId), |
| 405 | mComponent, |
| 406 | &blockPool); |
| 407 | #endif |
| 408 | if (status != C2_OK) { |
| 409 | blockPool = nullptr; |
| 410 | } |
| 411 | if (blockPool) { |
| 412 | mBlockPoolsMutex.lock(); |
| 413 | mBlockPools.emplace(blockPool->getLocalId(), blockPool); |
| 414 | mBlockPoolsMutex.unlock(); |
| 415 | } else if (status == C2_OK) { |
| 416 | status = C2_CORRUPTED; |
| 417 | } |
| 418 | |
| 419 | _hidl_cb(static_cast<Status>(status), |
| 420 | blockPool ? blockPool->getLocalId() : 0, |
| 421 | new CachedConfigurable( |
| 422 | std::make_unique<BlockPoolIntf>(blockPool))); |
| 423 | return Void(); |
| 424 | } |
| 425 | |
| 426 | Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) { |
| 427 | std::lock_guard<std::mutex> lock(mBlockPoolsMutex); |
| 428 | return mBlockPools.erase(blockPoolId) == 1 ? |
| 429 | Status::OK : Status::CORRUPTED; |
| 430 | } |
| 431 | |
| 432 | Return<Status> Component::start() { |
| 433 | return static_cast<Status>(mComponent->start()); |
| 434 | } |
| 435 | |
| 436 | Return<Status> Component::stop() { |
| 437 | InputBufferManager::unregisterFrameData(mListener); |
| 438 | return static_cast<Status>(mComponent->stop()); |
| 439 | } |
| 440 | |
| 441 | Return<Status> Component::reset() { |
| 442 | Status status = static_cast<Status>(mComponent->reset()); |
| 443 | { |
| 444 | std::lock_guard<std::mutex> lock(mBlockPoolsMutex); |
| 445 | mBlockPools.clear(); |
| 446 | } |
| 447 | InputBufferManager::unregisterFrameData(mListener); |
| 448 | return status; |
| 449 | } |
| 450 | |
| 451 | Return<Status> Component::release() { |
| 452 | Status status = static_cast<Status>(mComponent->release()); |
| 453 | { |
| 454 | std::lock_guard<std::mutex> lock(mBlockPoolsMutex); |
| 455 | mBlockPools.clear(); |
| 456 | } |
| 457 | InputBufferManager::unregisterFrameData(mListener); |
| 458 | return status; |
| 459 | } |
| 460 | |
| 461 | Return<sp<IComponentInterface>> Component::getInterface() { |
| 462 | return sp<IComponentInterface>(mInterface); |
| 463 | } |
| 464 | |
| 465 | Return<sp<IInputSink>> Component::asInputSink() { |
| 466 | std::lock_guard<std::mutex> lock(mSinkMutex); |
| 467 | if (!mSink) { |
| 468 | mSink = new Sink(shared_from_this()); |
| 469 | } |
| 470 | return {mSink}; |
| 471 | } |
| 472 | |
| 473 | Return<void> Component::configureVideoTunnel( |
| 474 | uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) { |
| 475 | (void)avSyncHwId; |
| 476 | _hidl_cb(Status::OMITTED, hidl_handle{}); |
| 477 | return Void(); |
| 478 | } |
| 479 | |
| 480 | Return<Status> Component::setOutputSurfaceWithSyncObj( |
| 481 | uint64_t blockPoolId, const sp<HGraphicBufferProducer2>& surface, |
| 482 | const SurfaceSyncObj& syncObject) { |
| 483 | std::shared_ptr<C2BlockPool> pool; |
| 484 | GetCodec2BlockPool(blockPoolId, mComponent, &pool); |
| 485 | if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { |
| 486 | std::shared_ptr<C2BufferQueueBlockPool> bqPool = |
| 487 | std::static_pointer_cast<C2BufferQueueBlockPool>(pool); |
| 488 | C2BufferQueueBlockPool::OnRenderCallback cb = |
| 489 | [this](uint64_t producer, int32_t slot, int64_t nsecs) { |
| 490 | // TODO: batch this |
| 491 | hidl_vec<IComponentListener::RenderedFrame> rendered; |
| 492 | rendered.resize(1); |
| 493 | rendered[0] = { producer, slot, nsecs }; |
| 494 | (void)mListener->onFramesRendered(rendered).isOk(); |
| 495 | }; |
| 496 | if (bqPool) { |
| 497 | const native_handle_t *h = syncObject.syncMemory; |
| 498 | native_handle_t *syncMemory = h ? native_handle_clone(h) : nullptr; |
| 499 | uint64_t bqId = syncObject.bqId; |
| 500 | uint32_t generationId = syncObject.generationId; |
| 501 | uint64_t consumerUsage = syncObject.consumerUsage; |
| 502 | |
| 503 | bqPool->setRenderCallback(cb); |
| 504 | bqPool->configureProducer(surface, syncMemory, bqId, |
| 505 | generationId, consumerUsage); |
| 506 | } |
| 507 | } |
| 508 | return Status::OK; |
| 509 | } |
| 510 | |
| 511 | std::shared_ptr<C2Component> Component::findLocalComponent( |
| 512 | const sp<IInputSink>& sink) { |
| 513 | return Component::Sink::findLocalComponent(sink); |
| 514 | } |
| 515 | |
| 516 | void Component::initListener(const sp<Component>& self) { |
| 517 | std::shared_ptr<C2Component::Listener> c2listener = |
| 518 | std::make_shared<Listener>(self); |
| 519 | c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK); |
| 520 | if (res != C2_OK) { |
| 521 | mInit = res; |
| 522 | } |
| 523 | |
| 524 | struct ListenerDeathRecipient : public HwDeathRecipient { |
| 525 | ListenerDeathRecipient(const wp<Component>& comp) |
| 526 | : component{comp} { |
| 527 | } |
| 528 | |
| 529 | virtual void serviceDied( |
| 530 | uint64_t /* cookie */, |
| 531 | const wp<::android::hidl::base::V1_0::IBase>& /* who */ |
| 532 | ) override { |
| 533 | auto strongComponent = component.promote(); |
| 534 | if (strongComponent) { |
| 535 | LOG(INFO) << "Client died ! release the component !!"; |
| 536 | strongComponent->release(); |
| 537 | } else { |
| 538 | LOG(ERROR) << "Client died ! no component to release !!"; |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | wp<Component> component; |
| 543 | }; |
| 544 | |
| 545 | mDeathRecipient = new ListenerDeathRecipient(self); |
| 546 | Return<bool> transStatus = mListener->linkToDeath( |
| 547 | mDeathRecipient, 0); |
| 548 | if (!transStatus.isOk()) { |
| 549 | LOG(ERROR) << "Listener linkToDeath() transaction failed."; |
| 550 | } |
| 551 | if (!static_cast<bool>(transStatus)) { |
| 552 | LOG(DEBUG) << "Listener linkToDeath() call failed."; |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | Component::~Component() { |
| 557 | InputBufferManager::unregisterFrameData(mListener); |
| 558 | mStore->reportComponentDeath(this); |
| 559 | } |
| 560 | |
| 561 | } // namespace utils |
| 562 | } // namespace V1_2 |
| 563 | } // namespace c2 |
| 564 | } // namespace media |
| 565 | } // namespace hardware |
| 566 | } // namespace android |