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 "ReflectedParamUpdater"
19 #include <utils/Log.h>
20 
21 #include <iostream>
22 #include <set>
23 #include <sstream>
24 
25 #include <C2Debug.h>
26 #include <C2ParamInternal.h>
27 
28 #include <media/stagefright/foundation/ABuffer.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/AString.h>
31 #include <media/stagefright/foundation/hexdump.h>
32 
33 #include "ReflectedParamUpdater.h"
34 
35 namespace android {
36 
debugString(size_t indent_) const37 std::string ReflectedParamUpdater::Dict::debugString(size_t indent_) const {
38     std::string indent(indent_, ' ');
39     std::stringstream s;
40     s << "Dict {" << std::endl;
41 
42     for (const auto &it : *this) {
43         s << indent << "  ";
44 
45         C2Value c2Value;
46         int32_t int32Value;
47         uint32_t uint32Value;
48         int64_t int64Value;
49         uint64_t uint64Value;
50         float floatValue;
51         sp<ABuffer> bufValue;
52         AString strValue;
53         if (it.second.find(&c2Value)) {
54             switch (c2Value.type()) {
55                 case C2Value::INT32:
56                     (void)c2Value.get(&int32Value);
57                     s << "c2::i32 " << it.first << " = " << int32Value;
58                     break;
59                 case C2Value::UINT32:
60                     (void)c2Value.get(&uint32Value);
61                     s << "c2::u32 " << it.first << " = " << uint32Value;
62                     break;
63                 case C2Value::CNTR32:
64                     // dump counter value as unsigned
65                     (void)c2Value.get((c2_cntr32_t*)&uint32Value);
66                     s << "c2::c32 " << it.first << " = " << uint32Value;
67                     break;
68                 case C2Value::INT64:
69                     (void)c2Value.get(&int64Value);
70                     s << "c2::i64 " << it.first << " = " << int64Value;
71                     break;
72                 case C2Value::UINT64:
73                     (void)c2Value.get(&uint64Value);
74                     s << "c2::u64 " << it.first << " = " << uint64Value;
75                     break;
76                 case C2Value::CNTR64:
77                     // dump counter value as unsigned
78                     (void)c2Value.get((c2_cntr64_t*)&uint64Value);
79                     s << "c2::c64 " << it.first << " = " << uint64Value;
80                     break;
81                 case C2Value::FLOAT:
82                     (void)c2Value.get(&floatValue);
83                     s << "c2::float " << it.first << " = " << floatValue;
84                     break;
85                 default:
86                     // dump unsupported values for debugging, these should not be used
87                     s << "c2::unsupported " << it.first;
88             }
89         } else if (it.second.find(&int32Value)) {
90             s << "int32_t " << it.first << " = " << int32Value;
91         } else if (it.second.find(&int64Value)) {
92             s << "int64_t " << it.first << " = " << int64Value;
93         } else if (it.second.find(&strValue)) {
94             s << "string " << it.first << " = \"" << strValue.c_str() << "\"";
95         } else if (it.second.find(&bufValue)) {
96             s << "Buffer " << it.first << " = ";
97             if (bufValue != nullptr && bufValue->data() != nullptr && bufValue->size() <= 64) {
98                 s << "{" << std::endl;
99                 AString tmp;
100                 hexdump(bufValue->data(), bufValue->size(), indent_ + 4, &tmp);
101                 s << tmp.c_str() << indent << "  }";
102             } else {
103                 s << (void*)bufValue.get();
104             }
105         } else {
106             // dump unsupported values for debugging, this should never happen.
107             s << "unsupported " << it.first;
108         }
109         s << std::endl;
110     }
111     s << indent << "}";
112 
113     return s.str();
114 }
115 
addParamDesc(const std::shared_ptr<C2ParamReflector> & reflector,const std::vector<std::shared_ptr<C2ParamDescriptor>> & paramDescs)116 void ReflectedParamUpdater::addParamDesc(
117         const std::shared_ptr<C2ParamReflector> &reflector,
118         const std::vector<std::shared_ptr<C2ParamDescriptor>> &paramDescs) {
119     for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
120         std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe(
121                 desc->index().coreIndex());
122         if (structDesc == nullptr) {
123             ALOGD("Could not describe %s", desc->name().c_str());
124             continue;
125         }
126         addParamDesc(desc, *structDesc, reflector, true /* markVendor */);
127     }
128 
129     // TEMP: also add vendor parameters as non-vendor
130     for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
131         if (!desc->index().isVendor()) {
132             continue;
133         }
134         std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe(
135                 desc->index().coreIndex());
136         if (structDesc) {
137             addParamDesc(desc, *structDesc, reflector, false /* markVendor */);
138         }
139     }
140 }
141 
addParamStructDesc(std::shared_ptr<C2ParamDescriptor> desc,C2String path,size_t offset,const C2StructDescriptor & structDesc,const std::shared_ptr<C2ParamReflector> & reflector)142 void ReflectedParamUpdater::addParamStructDesc(
143         std::shared_ptr<C2ParamDescriptor> desc,
144         C2String path,
145         size_t offset,
146         const C2StructDescriptor &structDesc,
147         const std::shared_ptr<C2ParamReflector> &reflector) {
148     for (auto it = structDesc.begin(); it != structDesc.end(); ++it) {
149         C2String fieldName = path + "." + it->name();
150         if (it->type() & C2FieldDescriptor::STRUCT_FLAG) {
151             if (reflector == nullptr || it->extent() != 1) {
152                 ALOGD("ignored struct field %s", fieldName.c_str());
153                 continue;
154             }
155             std::unique_ptr<C2StructDescriptor> structDesc_ = reflector->describe(
156                     C2Param::CoreIndex(it->type()).coreIndex());
157             if (structDesc_ == nullptr) {
158                 ALOGD("Could not describe structure of %s", fieldName.c_str());
159                 continue;
160             }
161             addParamStructDesc(desc, fieldName, offset + _C2ParamInspector::GetOffset(*it),
162                                *structDesc_, reflector);
163             continue;
164         }
165 
166         // verify extent and type
167         switch (it->type()) {
168             case C2FieldDescriptor::INT32:
169             case C2FieldDescriptor::UINT32:
170             case C2FieldDescriptor::CNTR32:
171             case C2FieldDescriptor::INT64:
172             case C2FieldDescriptor::UINT64:
173             case C2FieldDescriptor::CNTR64:
174             case C2FieldDescriptor::FLOAT:
175                 if (it->extent() != 1) {
176                     ALOGD("extent() != 1 for single value type: %s", fieldName.c_str());
177                     continue;
178                 }
179                 break;
180             case C2FieldDescriptor::STRING:
181             case C2FieldDescriptor::BLOB:
182                 break;
183 
184             default:
185                 ALOGD("Unrecognized type: %s", fieldName.c_str());
186                 continue;
187         }
188 
189         ALOGV("%s registered", fieldName.c_str());
190         // TODO: get the proper size by iterating through the fields.
191         // only insert fields the very first time
192         mMap.emplace(fieldName, FieldDesc {
193             desc,
194             std::make_unique<C2FieldDescriptor>(
195                     it->type(), it->extent(), it->name(),
196                     _C2ParamInspector::GetOffset(*it),
197                     _C2ParamInspector::GetSize(*it)),
198             offset,
199         });
200     }
201 }
202 
addParamDesc(std::shared_ptr<C2ParamDescriptor> desc,const C2StructDescriptor & structDesc,const std::shared_ptr<C2ParamReflector> & reflector,bool markVendor)203 void ReflectedParamUpdater::addParamDesc(
204         std::shared_ptr<C2ParamDescriptor> desc, const C2StructDescriptor &structDesc,
205         const std::shared_ptr<C2ParamReflector> &reflector, bool markVendor) {
206     C2String paramName = desc->name();
207 
208     // Do not reflect requested parameters
209     // TODO: split these once aliases are introduced into '.actual' and '.requested' and alias
210     // the name to '.actual'.
211     if (desc->index() & C2Param::CoreIndex::IS_REQUEST_FLAG) {
212         return;
213     }
214 
215     // prefix vendor parameters
216     if (desc->index().isVendor() && markVendor) {
217         paramName = "vendor." + paramName;
218     }
219     mParamNames.emplace(desc->index(), paramName);
220 
221     // also allow setting whole parameters in a binary fashion via ByteBuffer
222     // this is opt-in for now
223     auto it = mWholeParams.find(paramName);
224     if (it != mWholeParams.end() && it->second.coreIndex() == desc->index().coreIndex()) {
225         mMap.emplace(paramName, FieldDesc{ desc, nullptr, 0 /* offset */ });
226         // don't add fields of whole parameters.
227         return;
228     }
229 
230     addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector);
231 }
232 
supportWholeParam(std::string name,C2Param::CoreIndex index)233 void ReflectedParamUpdater::supportWholeParam(std::string name, C2Param::CoreIndex index) {
234     mWholeParams.emplace(name, index);
235 }
236 
getParamName(C2Param::Index index) const237 std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const {
238     auto it = mParamNames.find(index);
239     if (it != mParamNames.end()) {
240         return it->second;
241     }
242 
243     std::stringstream ret;
244     ret << "<unknown " << index << ">";
245     return ret.str();
246 }
247 
getParamIndicesFromMessage(const Dict & params,std::vector<C2Param::Index> * vec) const248 void ReflectedParamUpdater::getParamIndicesFromMessage(
249         const Dict &params,
250         std::vector<C2Param::Index> *vec /* nonnull */) const {
251     CHECK(vec != nullptr);
252     vec->clear();
253     std::set<C2Param::Index> indices;
254     parseMessageAndDoWork(
255             params,
256             [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) {
257                 indices.insert(desc.paramDesc->index());
258             });
259     for (const C2Param::Index &index : indices) {
260         vec->push_back(index);
261     }
262 }
263 
getParamIndicesForKeys(const std::vector<std::string> & keys,std::vector<C2Param::Index> * vec) const264 void ReflectedParamUpdater::getParamIndicesForKeys(
265         const std::vector<std::string> &keys,
266         std::vector<C2Param::Index> *vec /* nonnull */) const {
267     CHECK(vec != nullptr);
268     vec->clear();
269     std::set<C2Param::Index> indices;
270 
271     std::set<std::string> keyMap(keys.begin(), keys.end());
272 
273     ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries",
274             keyMap.size(), mMap.size());
275     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
276         const std::string &name = kv.first;
277         const FieldDesc &desc = kv.second;
278         ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name));
279         if (keyMap.count(name) > 0) {
280             indices.insert(desc.paramDesc->index());
281         }
282     }
283 
284     for (const C2Param::Index &index : indices) {
285         vec->push_back(index);
286     }
287 }
288 
updateParamsFromMessage(const Dict & params,std::vector<std::unique_ptr<C2Param>> * vec) const289 void ReflectedParamUpdater::updateParamsFromMessage(
290         const Dict &params,
291         std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {
292     CHECK(vec != nullptr);
293 
294     std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap;
295     for (std::unique_ptr<C2Param> &param : *vec) {
296         if (param && *param) {
297             paramsMap[param->index()] = &param;
298         }
299     }
300 
301     parseMessageAndDoWork(
302             params,
303             [&paramsMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) {
304                 std::unique_ptr<C2Param> *param = nullptr;
305                 auto paramIt = paramsMap.find(desc.paramDesc->index());
306                 if (paramIt == paramsMap.end()) {
307                     ALOGD("%s found, but param #%d isn't present to update",
308                             name.c_str(), (int32_t)desc.paramDesc->index());
309                     return;
310                 }
311                 param = paramIt->second;
312 
313                 struct _C2Param : public C2Param {
314                     using C2Param::C2Param;
315                     _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { }
316                 };
317 
318                 // we will handle whole param updates as part of a flexible param update using
319                 // a zero offset.
320                 size_t offset = 0;
321                 size_t minOffset = 0;
322 
323                 // if this descriptor has a field, use the offset and size and ensure that offset
324                 // is not part of the header
325                 if (desc.fieldDesc) {
326                     minOffset = sizeof(C2Param);
327                     offset = sizeof(C2Param) + desc.offset
328                             + _C2ParamInspector::GetOffset(*desc.fieldDesc);
329                 }
330 
331                 // reallocate or trim flexible param (or whole param) as necessary
332                 if (!desc.fieldDesc /* whole param */ || desc.fieldDesc->extent() == 0) {
333                     // reallocate param if more space is needed
334                     if (param->get()->size() < offset + size) {
335                         if (size > INT32_MAX - offset || offset < minOffset) {
336                             // size too long or offset too early - abandon
337                             return;
338                         }
339                         C2Param *newParam = (C2Param *)::operator new(offset + size);
340                         new (newParam) _C2Param(offset + size, param->get()->index());
341                         if (offset > sizeof(C2Param)) {
342                             memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param));
343                         }
344                         param->reset(newParam);
345                     } else if (param->get()->size() > offset + size) {
346                         // trim parameter size
347                         _C2ParamInspector::TrimParam(param->get(), offset + size);
348                     }
349                 } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) {
350                     // zero fill blobs if updating with smaller blob
351                     if (desc.fieldDesc->extent() > size) {
352                         memset((uint8_t *)(param->get()) + offset + size, 0,
353                                desc.fieldDesc->extent() - size);
354                     }
355                 }
356 
357                 memcpy((uint8_t *)(param->get()) + offset, ptr, size);
358             });
359 }
360 
parseMessageAndDoWork(const Dict & params,std::function<void (const std::string &,const FieldDesc &,const void *,size_t)> work) const361 void ReflectedParamUpdater::parseMessageAndDoWork(
362         const Dict &params,
363         std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const {
364     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
365         const std::string &name = kv.first;
366         const FieldDesc &desc = kv.second;
367         auto param = params.find(name);
368         if (param == params.end()) {
369             continue;
370         }
371 
372         // handle whole parameters
373         if (!desc.fieldDesc) {
374             sp<ABuffer> tmp;
375             if (param->second.find(&tmp) && tmp != nullptr) {
376                 C2Param *tmpAsParam = C2Param::From(tmp->data(), tmp->size());
377                 if (tmpAsParam && tmpAsParam->type().type() == desc.paramDesc->index().type()) {
378                     work(name, desc, tmp->data(), tmp->size());
379                 } else {
380                     ALOGD("Param blob does not match param for '%s' (%p, %x vs %x)",
381                             name.c_str(), tmpAsParam, tmpAsParam ? tmpAsParam->type().type() : 0xDEADu,
382                             desc.paramDesc->index().type());
383                 }
384             }
385             continue;
386         }
387 
388         int32_t int32Value;
389         int64_t int64Value;
390         C2Value c2Value;
391 
392         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
393         size_t fieldExtent = desc.fieldDesc->extent();
394         switch (fieldType) {
395             case C2FieldDescriptor::INT32:
396                 if ((param->second.find(&c2Value) && c2Value.get(&int32Value))
397                         || param->second.find(&int32Value)) {
398                     work(name, desc, &int32Value, sizeof(int32Value));
399                 }
400                 break;
401             case C2FieldDescriptor::UINT32:
402                 if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value))
403                         || param->second.find(&int32Value)) {
404                     work(name, desc, &int32Value, sizeof(int32Value));
405                 }
406                 break;
407             case C2FieldDescriptor::CNTR32:
408                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value))
409                         || param->second.find(&int32Value)) {
410                     work(name, desc, &int32Value, sizeof(int32Value));
411                 }
412                 break;
413             case C2FieldDescriptor::INT64:
414                 if ((param->second.find(&c2Value) && c2Value.get(&int64Value))
415                         || param->second.find(&int64Value)) {
416                     work(name, desc, &int64Value, sizeof(int64Value));
417                 }
418                 break;
419             case C2FieldDescriptor::UINT64:
420                 if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value))
421                         || param->second.find(&int64Value)) {
422                     work(name, desc, &int64Value, sizeof(int64Value));
423                 }
424                 break;
425             case C2FieldDescriptor::CNTR64:
426                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value))
427                         || param->second.find(&int64Value)) {
428                     work(name, desc, &int64Value, sizeof(int64Value));
429                 }
430                 break;
431             case C2FieldDescriptor::FLOAT: {
432                 float tmp;
433                 if (param->second.find(&c2Value) && c2Value.get(&tmp)) {
434                     work(name, desc, &tmp, sizeof(tmp));
435                 }
436                 break;
437             }
438             case C2FieldDescriptor::STRING: {
439                 AString tmp;
440                 if (!param->second.find(&tmp)) {
441                     break;
442                 }
443                 if (fieldExtent > 0 && tmp.size() >= fieldExtent) {
444                     AString truncated(tmp, 0, fieldExtent - 1);
445                     ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"",
446                             tmp.c_str(), truncated.c_str());
447                     tmp = truncated;
448                 }
449                 work(name, desc, tmp.c_str(), tmp.size() + 1);
450                 break;
451             }
452 
453             case C2FieldDescriptor::BLOB: {
454                 sp<ABuffer> tmp;
455                 if (!param->second.find(&tmp) || tmp == nullptr) {
456                     break;
457                 }
458 
459                 if (fieldExtent > 0 && tmp->size() > fieldExtent) {
460                     ALOGD("Blob value too long to fit. Truncating.");
461                     tmp->setRange(tmp->offset(), fieldExtent);
462                 }
463                 work(name, desc, tmp->data(), tmp->size());
464                 break;
465             }
466 
467             default:
468                 ALOGD("Unsupported data type for %s", name.c_str());
469                 break;
470         }
471     }
472 }
473 
474 ReflectedParamUpdater::Dict
getParams(const std::vector<std::unique_ptr<C2Param>> & params_) const475 ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> &params_) const {
476     std::vector<C2Param*> params;
477     params.resize(params_.size());
478     std::transform(params_.begin(), params_.end(), params.begin(),
479                    [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); });
480     return getParams(params);
481 }
482 
483 ReflectedParamUpdater::Dict
getParams(const std::vector<C2Param * > & params) const484 ReflectedParamUpdater::getParams(const std::vector<C2Param*> &params) const {
485     Dict ret;
486 
487     // convert vector to map
488     std::map<C2Param::Index, C2Param *> paramsMap;
489     for (C2Param *param : params) {
490         if (param != nullptr && *param) {
491             paramsMap[param->index()] = param;
492         }
493     }
494 
495     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
496         const std::string &name = kv.first;
497         const FieldDesc &desc = kv.second;
498         if (paramsMap.count(desc.paramDesc->index()) == 0) {
499             continue;
500         }
501         C2Param *param = paramsMap[desc.paramDesc->index()];
502         Value value;
503 
504         // handle whole params first
505         if (!desc.fieldDesc) {
506             sp<ABuffer> buf = ABuffer::CreateAsCopy(param, param->size());
507             value.set(buf);
508             ret.emplace(name, value);
509             continue;
510         }
511 
512         size_t offset = sizeof(C2Param) + desc.offset
513                 + _C2ParamInspector::GetOffset(*desc.fieldDesc);
514         uint8_t *data = (uint8_t *)param + offset;
515         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
516         switch (fieldType) {
517             case C2FieldDescriptor::STRING: {
518                 size_t length = desc.fieldDesc->extent();
519                 if (length == 0) {
520                     length = param->size() - offset;
521                 }
522 
523                 if (param->size() < length || param->size() - length < offset) {
524                     ALOGD("param too small for string: length %zu size %zu offset %zu",
525                             length, param->size(), offset);
526                     break;
527                 }
528                 value.set(AString((char *)data, strnlen((char *)data, length)));
529                 break;
530             }
531 
532             case C2FieldDescriptor::BLOB: {
533                 size_t length = desc.fieldDesc->extent();
534                 if (length == 0) {
535                     length = param->size() - offset;
536                 }
537 
538                 if (param->size() < length || param->size() - length < offset) {
539                     ALOGD("param too small for blob: length %zu size %zu offset %zu",
540                             length, param->size(), offset);
541                     break;
542                 }
543 
544                 sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length);
545                 value.set(buf);
546                 break;
547             }
548 
549             default: {
550                 size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType);
551                 if (param->size() < valueSize || param->size() - valueSize < offset) {
552                     ALOGD("param too small for c2value: size %zu offset %zu",
553                             param->size(), offset);
554                     break;
555                 }
556 
557                 C2Value c2Value;
558                 switch (fieldType) {
559                     case C2FieldDescriptor::INT32:  c2Value = *((int32_t *)data); break;
560                     case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break;
561                     case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break;
562                     case C2FieldDescriptor::INT64:  c2Value = *((int64_t *)data); break;
563                     case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break;
564                     case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break;
565                     case C2FieldDescriptor::FLOAT:  c2Value = *((float *)data); break;
566                     default:
567                         ALOGD("Unsupported data type for %s", name.c_str());
568                         continue;
569                 }
570                 value.set(c2Value);
571             }
572         }
573         ret.emplace(name, value);
574     }
575     return ret;
576 }
577 
clear()578 void ReflectedParamUpdater::clear() {
579     mMap.clear();
580 }
581 
582 }  // namespace android
583