1/*
2 * Copyright 2016, 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#include <ios>
18#include <list>
19
20#include <android-base/logging.h>
21#include <gui/IGraphicBufferProducer.h>
22#include <OMX_Core.h>
23#include <OMX_AsString.h>
24
25#include "../OMXUtils.h"
26#include "../OMXMaster.h"
27#include "../GraphicBufferSource.h"
28
29#include "WOmxNode.h"
30#include "WOmxObserver.h"
31#include "WGraphicBufferProducer.h"
32#include "WGraphicBufferSource.h"
33#include "Conversion.h"
34
35#include "Omx.h"
36
37namespace android {
38namespace hardware {
39namespace media {
40namespace omx {
41namespace V1_0 {
42namespace implementation {
43
44constexpr size_t kMaxNodeInstances = (1 << 16);
45
46Omx::Omx() :
47    mMaster(new OMXMaster()),
48    mParser() {
49}
50
51Omx::~Omx() {
52    delete mMaster;
53}
54
55Return<void> Omx::listNodes(listNodes_cb _hidl_cb) {
56    std::list<::android::IOMX::ComponentInfo> list;
57    char componentName[256];
58    for (OMX_U32 index = 0;
59            mMaster->enumerateComponents(
60            componentName, sizeof(componentName), index) == OMX_ErrorNone;
61            ++index) {
62        list.push_back(::android::IOMX::ComponentInfo());
63        ::android::IOMX::ComponentInfo& info = list.back();
64        info.mName = componentName;
65        ::android::Vector<::android::String8> roles;
66        OMX_ERRORTYPE err =
67                mMaster->getRolesOfComponent(componentName, &roles);
68        if (err == OMX_ErrorNone) {
69            for (OMX_U32 i = 0; i < roles.size(); ++i) {
70                info.mRoles.push_back(roles[i]);
71            }
72        }
73    }
74
75    hidl_vec<ComponentInfo> tList;
76    tList.resize(list.size());
77    size_t i = 0;
78    for (auto const& info : list) {
79        convertTo(&(tList[i++]), info);
80    }
81    _hidl_cb(toStatus(OK), tList);
82    return Void();
83}
84
85Return<void> Omx::allocateNode(
86        const hidl_string& name,
87        const sp<IOmxObserver>& observer,
88        allocateNode_cb _hidl_cb) {
89
90    using ::android::IOMXNode;
91    using ::android::IOMXObserver;
92
93    Mutex::Autolock autoLock(mLock);
94    if (mLiveNodes.size() == kMaxNodeInstances) {
95        _hidl_cb(toStatus(NO_MEMORY), nullptr);
96        return Void();
97    }
98
99    sp<OMXNodeInstance> instance = new OMXNodeInstance(
100            this, new LWOmxObserver(observer), name.c_str());
101
102    OMX_COMPONENTTYPE *handle;
103    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
104            name.c_str(), &OMXNodeInstance::kCallbacks,
105            instance.get(), &handle);
106
107    if (err != OMX_ErrorNone) {
108        LOG(ERROR) << "Failed to allocate omx component "
109                "'" << name.c_str() << "' "
110                " err=" << asString(err) <<
111                "(0x" << std::hex << unsigned(err) << ")";
112        _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
113        return Void();
114    }
115    instance->setHandle(handle);
116    std::vector<AString> quirkVector;
117    if (mParser.getQuirks(name.c_str(), &quirkVector) == OK) {
118        uint32_t quirks = 0;
119        for (const AString quirk : quirkVector) {
120            if (quirk == "requires-allocate-on-input-ports") {
121                quirks |= kRequiresAllocateBufferOnInputPorts;
122            }
123            if (quirk == "requires-allocate-on-output-ports") {
124                quirks |= kRequiresAllocateBufferOnOutputPorts;
125            }
126        }
127        instance->setQuirks(quirks);
128    }
129
130    mLiveNodes.add(observer.get(), instance);
131    observer->linkToDeath(this, 0);
132    mNode2Observer.add(instance.get(), observer.get());
133
134    _hidl_cb(toStatus(OK), new TWOmxNode(instance));
135    return Void();
136}
137
138Return<void> Omx::createInputSurface(createInputSurface_cb _hidl_cb) {
139    sp<::android::IGraphicBufferProducer> bufferProducer;
140
141    sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
142    status_t err = graphicBufferSource->initCheck();
143    if (err != OK) {
144        LOG(ERROR) << "Failed to create persistent input surface: "
145                << strerror(-err) << " "
146                "(" << int(err) << ")";
147        _hidl_cb(toStatus(err), nullptr, nullptr);
148        return Void();
149    }
150    bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
151
152    _hidl_cb(toStatus(OK),
153            new TWGraphicBufferProducer(bufferProducer),
154            new TWGraphicBufferSource(graphicBufferSource));
155    return Void();
156}
157
158void Omx::serviceDied(uint64_t /* cookie */, wp<IBase> const& who) {
159    sp<OMXNodeInstance> instance;
160    {
161        Mutex::Autolock autoLock(mLock);
162
163        ssize_t index = mLiveNodes.indexOfKey(who);
164
165        if (index < 0) {
166            LOG(ERROR) << "b/27597103, nonexistent observer on serviceDied";
167            android_errorWriteLog(0x534e4554, "27597103");
168            return;
169        }
170
171        instance = mLiveNodes.editValueAt(index);
172        mLiveNodes.removeItemsAt(index);
173        mNode2Observer.removeItem(instance.get());
174    }
175    instance->onObserverDied();
176}
177
178status_t Omx::freeNode(sp<OMXNodeInstance> const& instance) {
179    if (instance == NULL) {
180        return OK;
181    }
182
183    {
184        Mutex::Autolock autoLock(mLock);
185        ssize_t observerIndex = mNode2Observer.indexOfKey(instance.get());
186        if (observerIndex >= 0) {
187            wp<IBase> observer = mNode2Observer.valueAt(observerIndex);
188            ssize_t nodeIndex = mLiveNodes.indexOfKey(observer);
189            if (nodeIndex >= 0) {
190                mNode2Observer.removeItemsAt(observerIndex);
191                mLiveNodes.removeItemsAt(nodeIndex);
192                sp<IBase> sObserver = observer.promote();
193                if (sObserver != nullptr) {
194                    sObserver->unlinkToDeath(this);
195                }
196            } else {
197                LOG(WARNING) << "Inconsistent observer record";
198            }
199        }
200    }
201
202    OMX_ERRORTYPE err = OMX_ErrorNone;
203    if (instance->handle() != NULL) {
204        err = mMaster->destroyComponentInstance(
205                static_cast<OMX_COMPONENTTYPE*>(instance->handle()));
206    }
207    return StatusFromOMXError(err);
208}
209
210// Methods from ::android::hidl::base::V1_0::IBase follow.
211
212IOmx* HIDL_FETCH_IOmx(const char* /* name */) {
213    return new Omx();
214}
215
216}  // namespace implementation
217}  // namespace V1_0
218}  // namespace omx
219}  // namespace media
220}  // namespace hardware
221}  // namespace android
222