1/*
2 * Copyright (C) 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 "Codec2-ComponentStore"
19#include <log/log.h>
20
21#include <codec2/hidl/1.0/ComponentStore.h>
22#include <codec2/hidl/1.0/InputSurface.h>
23#include <codec2/hidl/1.0/Component.h>
24#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
25#include <codec2/hidl/1.0/types.h>
26
27#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
28#include <media/stagefright/bqhelper/GraphicBufferSource.h>
29
30#include <C2PlatformSupport.h>
31
32#include <utils/Errors.h>
33
34#include <android-base/file.h>
35
36#ifdef LOG
37#undef LOG
38#endif
39
40#ifdef PLOG
41#undef PLOG
42#endif
43
44#include <android-base/logging.h>
45
46#include <ostream>
47#include <sstream>
48#include <iomanip>
49
50namespace hardware {
51namespace google {
52namespace media {
53namespace c2 {
54namespace V1_0 {
55namespace utils {
56
57using namespace ::android;
58using ::android::GraphicBufferSource;
59using namespace ::android::hardware::media::bufferpool::V1_0::implementation;
60
61namespace /* unnamed */ {
62
63struct StoreIntf : public ConfigurableC2Intf {
64    StoreIntf(const std::shared_ptr<C2ComponentStore>& store) :
65        ConfigurableC2Intf(store ? store->getName() : ""),
66        mStore(store) {
67    }
68
69    c2_status_t config(
70            const std::vector<C2Param*> &params,
71            c2_blocking_t mayBlock,
72            std::vector<std::unique_ptr<C2SettingResult>> *const failures
73            ) override {
74        // Assume all params are blocking
75        // TODO: Filter for supported params
76        if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
77            return C2_BLOCKING;
78        }
79        return mStore->config_sm(params, failures);
80    }
81
82    c2_status_t query(
83            const std::vector<C2Param::Index> &indices,
84            c2_blocking_t mayBlock,
85            std::vector<std::unique_ptr<C2Param>> *const params) const override {
86        // Assume all params are blocking
87        // TODO: Filter for supported params
88        if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
89            return C2_BLOCKING;
90        }
91        return mStore->query_sm({}, indices, params);
92    }
93
94    c2_status_t querySupportedParams(
95            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
96            ) const override {
97        return mStore->querySupportedParams_nb(params);
98    }
99
100    c2_status_t querySupportedValues(
101            std::vector<C2FieldSupportedValuesQuery> &fields,
102            c2_blocking_t mayBlock) const override {
103        // Assume all params are blocking
104        // TODO: Filter for supported params
105        if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
106            return C2_BLOCKING;
107        }
108        return mStore->querySupportedValues_sm(fields);
109    }
110
111protected:
112    std::shared_ptr<C2ComponentStore> mStore;
113};
114
115} // unnamed namespace
116
117ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) :
118    Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))),
119    mStore(store) {
120
121    std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
122    SetPreferredCodec2ComponentStore(store);
123
124    // Retrieve struct descriptors
125    mParamReflector = mStore->getParamReflector();
126
127    // Retrieve supported parameters from store
128    mInit = init(this);
129}
130
131c2_status_t ComponentStore::validateSupportedParams(
132        const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
133    c2_status_t res = C2_OK;
134
135    for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
136        if (!desc) {
137            // All descriptors should be valid
138            res = res ? res : C2_BAD_VALUE;
139            continue;
140        }
141        C2Param::CoreIndex coreIndex = desc->index().coreIndex();
142        std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
143        auto it = mStructDescriptors.find(coreIndex);
144        if (it == mStructDescriptors.end()) {
145            std::shared_ptr<C2StructDescriptor> structDesc =
146                    mParamReflector->describe(coreIndex);
147            if (!structDesc) {
148                // All supported params must be described
149                res = C2_BAD_INDEX;
150            }
151            mStructDescriptors.insert({ coreIndex, structDesc });
152        }
153    }
154    return res;
155}
156
157// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
158Return<void> ComponentStore::createComponent(
159        const hidl_string& name,
160        const sp<IComponentListener>& listener,
161        const sp<IClientManager>& pool,
162        createComponent_cb _hidl_cb) {
163
164    sp<Component> component;
165    std::shared_ptr<C2Component> c2component;
166    Status status = static_cast<Status>(
167            mStore->createComponent(name, &c2component));
168
169    if (status == Status::OK) {
170        onInterfaceLoaded(c2component->intf());
171        component = new Component(c2component, listener, this, pool);
172        if (!component) {
173            status = Status::CORRUPTED;
174        } else if (component->status() != C2_OK) {
175            status = static_cast<Status>(component->status());
176        } else {
177            component->initListener(component);
178            if (component->status() != C2_OK) {
179                status = static_cast<Status>(component->status());
180            } else {
181                std::lock_guard<std::mutex> lock(mComponentRosterMutex);
182                component->setLocalId(
183                        mComponentRoster.emplace(
184                            Component::InterfaceKey(component),
185                            c2component)
186                        .first);
187            }
188        }
189    }
190    _hidl_cb(status, component);
191    return Void();
192}
193
194Return<void> ComponentStore::createInterface(
195        const hidl_string& name,
196        createInterface_cb _hidl_cb) {
197    std::shared_ptr<C2ComponentInterface> c2interface;
198    c2_status_t res = mStore->createInterface(name, &c2interface);
199    sp<IComponentInterface> interface;
200    if (res == C2_OK) {
201        onInterfaceLoaded(c2interface);
202        interface = new ComponentInterface(c2interface, this);
203    }
204    _hidl_cb((Status)res, interface);
205    return Void();
206}
207
208Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
209    std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
210            mStore->listComponents();
211    hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
212    size_t ix = 0;
213    for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
214        if (c2trait) {
215            objcpy(&traits[ix++], *c2trait);
216        }
217    }
218    traits.resize(ix);
219    _hidl_cb(traits);
220    return Void();
221}
222
223Return<sp<IInputSurface>> ComponentStore::createInputSurface() {
224    sp<GraphicBufferSource> source = new GraphicBufferSource();
225    if (source->initCheck() != OK) {
226        return nullptr;
227    }
228    typedef ::android::hardware::graphics::bufferqueue::V1_0::
229            IGraphicBufferProducer HGBP;
230    typedef ::android::TWGraphicBufferProducer<HGBP> B2HGBP;
231    return new InputSurface(
232            this,
233            new B2HGBP(source->getIGraphicBufferProducer()),
234            source);
235}
236
237void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
238    // invalidate unsupported struct descriptors if a new interface is loaded as it may have
239    // exposed new descriptors
240    std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
241    if (!mLoadedInterfaces.count(intf->getName())) {
242        mUnsupportedStructDescriptors.clear();
243        mLoadedInterfaces.emplace(intf->getName());
244    }
245}
246
247Return<void> ComponentStore::getStructDescriptors(
248        const hidl_vec<uint32_t>& indices,
249        getStructDescriptors_cb _hidl_cb) {
250    hidl_vec<StructDescriptor> descriptors(indices.size());
251    size_t dstIx = 0;
252    Status res = Status::OK;
253    for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
254        std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
255        const C2Param::CoreIndex coreIndex = C2Param::CoreIndex(indices[srcIx]).coreIndex();
256        const auto item = mStructDescriptors.find(coreIndex);
257        if (item == mStructDescriptors.end()) {
258            // not in the cache, and not known to be unsupported, query local reflector
259            if (!mUnsupportedStructDescriptors.count(coreIndex)) {
260                std::shared_ptr<C2StructDescriptor> structDesc =
261                    mParamReflector->describe(coreIndex);
262                if (!structDesc) {
263                    mUnsupportedStructDescriptors.emplace(coreIndex);
264                } else {
265                    mStructDescriptors.insert({ coreIndex, structDesc });
266                    objcpy(&descriptors[dstIx++], *structDesc);
267                    continue;
268                }
269            }
270            res = Status::NOT_FOUND;
271        } else if (item->second) {
272            objcpy(&descriptors[dstIx++], *item->second);
273        } else {
274            res = Status::NO_MEMORY;
275        }
276    }
277    descriptors.resize(dstIx);
278    _hidl_cb(res, descriptors);
279    return Void();
280}
281
282Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
283    return ClientManager::getInstance();
284}
285
286Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
287    // TODO implement
288    (void)src;
289    (void)dst;
290    return Status::OMITTED;
291}
292
293void ComponentStore::reportComponentDeath(
294        const Component::LocalId& componentLocalId) {
295    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
296    mComponentRoster.erase(componentLocalId);
297}
298
299std::shared_ptr<C2Component> ComponentStore::findC2Component(
300        const sp<IComponent>& component) const {
301    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
302    Component::LocalId it = mComponentRoster.find(
303            Component::InterfaceKey(component));
304    if (it == mComponentRoster.end()) {
305        return std::shared_ptr<C2Component>();
306    }
307    return it->second.lock();
308}
309
310// Debug dump
311
312namespace /* unnamed */ {
313
314// Dump component traits
315std::ostream& dump(
316        std::ostream& out,
317        const std::shared_ptr<const C2Component::Traits>& comp) {
318
319    constexpr const char indent[] = "    ";
320
321    out << indent << "name: " << comp->name << std::endl;
322    out << indent << "domain: " << comp->domain << std::endl;
323    out << indent << "kind: " << comp->kind << std::endl;
324    out << indent << "rank: " << comp->rank << std::endl;
325    out << indent << "mediaType: " << comp->mediaType << std::endl;
326    out << indent << "aliases:";
327    for (const auto& alias : comp->aliases) {
328        out << ' ' << alias;
329    }
330    out << std::endl;
331
332    return out;
333}
334
335// Dump component
336std::ostream& dump(
337        std::ostream& out,
338        const std::shared_ptr<C2Component>& comp) {
339
340    constexpr const char indent[] = "    ";
341
342    std::shared_ptr<C2ComponentInterface> intf = comp->intf();
343    if (!intf) {
344        out << indent << "Unknown -- null interface" << std::endl;
345        return out;
346    }
347    out << indent << "name: " << intf->getName() << std::endl;
348    out << indent << "id: " << intf->getId() << std::endl;
349    return out;
350}
351
352} // unnamed namespace
353
354Return<void> ComponentStore::debug(
355        const hidl_handle& handle,
356        const hidl_vec<hidl_string>& /* args */) {
357   LOG(INFO) << "debug -- dumping...";
358   const native_handle_t *h = handle.getNativeHandle();
359   if (!h || h->numFds != 1) {
360      LOG(ERROR) << "debug -- dumping failed -- "
361              "invalid file descriptor to dump to";
362      return Void();
363   }
364   std::ostringstream out;
365
366   { // Populate "out".
367
368        constexpr const char indent[] = "  ";
369
370        // Show name.
371        out << "Beginning of dump -- C2ComponentStore: "
372                << mStore->getName() << std::endl << std::endl;
373
374        // Retrieve the list of supported components.
375        std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
376                mStore->listComponents();
377
378        // Dump the traits of supported components.
379        out << indent << "Supported components:" << std::endl << std::endl;
380        if (traitsList.size() == 0) {
381            out << indent << indent << "NONE" << std::endl << std::endl;
382        } else {
383            for (const auto& traits : traitsList) {
384                dump(out, traits) << std::endl;
385            }
386        }
387
388        // Retrieve the list of active components.
389        std::list<std::shared_ptr<C2Component>> activeComps;
390        {
391            std::lock_guard<std::mutex> lock(mComponentRosterMutex);
392            auto i = mComponentRoster.begin();
393            while (i != mComponentRoster.end()) {
394                std::shared_ptr<C2Component> c2comp = i->second.lock();
395                if (!c2comp) {
396                    auto j = i;
397                    ++i;
398                    mComponentRoster.erase(j);
399                } else {
400                    ++i;
401                    activeComps.emplace_back(c2comp);
402                }
403            }
404        }
405
406        // Dump active components.
407        out << indent << "Active components:" << std::endl << std::endl;
408        if (activeComps.size() == 0) {
409            out << indent << indent << "NONE" << std::endl << std::endl;
410        } else {
411            for (const std::shared_ptr<C2Component>& c2comp : activeComps) {
412                dump(out, c2comp) << std::endl;
413            }
414        }
415
416        out << "End of dump -- C2ComponentStore: "
417                << mStore->getName() << std::endl;
418   }
419
420   if (!android::base::WriteStringToFd(out.str(), h->data[0])) {
421       PLOG(WARNING) << "debug -- dumping failed -- write()";
422   } else {
423       LOG(INFO) << "debug -- dumping succeeded";
424   }
425   return Void();
426}
427
428
429}  // namespace utils
430}  // namespace V1_0
431}  // namespace c2
432}  // namespace media
433}  // namespace google
434}  // namespace hardware
435