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 != NULL && bufValue->data() != NULL && 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     // prefix vendor parameters
209     if (desc->index().isVendor() && markVendor) {
210         paramName = "vendor." + paramName;
211     }
212     mParamNames.emplace(desc->index(), paramName);
213 
214     addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector);
215 }
216 
getParamName(C2Param::Index index) const217 std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const {
218     auto it = mParamNames.find(index);
219     if (it != mParamNames.end()) {
220         return it->second;
221     }
222 
223     std::stringstream ret;
224     ret << "<unknown " << index << ">";
225     return ret.str();
226 }
227 
getParamIndicesFromMessage(const Dict & params,std::vector<C2Param::Index> * vec) const228 void ReflectedParamUpdater::getParamIndicesFromMessage(
229         const Dict &params,
230         std::vector<C2Param::Index> *vec /* nonnull */) const {
231     CHECK(vec != nullptr);
232     vec->clear();
233     std::set<C2Param::Index> indices;
234     parseMessageAndDoWork(
235             params,
236             [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) {
237                 indices.insert(desc.paramDesc->index());
238             });
239     for (const C2Param::Index &index : indices) {
240         vec->push_back(index);
241     }
242 }
243 
getParamIndicesForKeys(const std::vector<std::string> & keys,std::vector<C2Param::Index> * vec) const244 void ReflectedParamUpdater::getParamIndicesForKeys(
245         const std::vector<std::string> &keys,
246         std::vector<C2Param::Index> *vec /* nonnull */) const {
247     CHECK(vec != nullptr);
248     vec->clear();
249     std::set<C2Param::Index> indices;
250 
251     std::set<std::string> keyMap(keys.begin(), keys.end());
252 
253     ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries",
254             keyMap.size(), mMap.size());
255     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
256         const std::string &name = kv.first;
257         const FieldDesc &desc = kv.second;
258         ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name));
259         if (keyMap.count(name) > 0) {
260             indices.insert(desc.paramDesc->index());
261         }
262     }
263 
264     for (const C2Param::Index &index : indices) {
265         vec->push_back(index);
266     }
267 }
268 
updateParamsFromMessage(const Dict & params,std::vector<std::unique_ptr<C2Param>> * vec) const269 void ReflectedParamUpdater::updateParamsFromMessage(
270         const Dict &params,
271         std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {
272     CHECK(vec != nullptr);
273 
274     std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap;
275     for (std::unique_ptr<C2Param> &param : *vec) {
276         if (param && *param) {
277             paramsMap[param->index()] = &param;
278         }
279     }
280 
281     parseMessageAndDoWork(
282             params,
283             [&paramsMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) {
284                 size_t offset = sizeof(C2Param) + desc.offset
285                         + _C2ParamInspector::GetOffset(*desc.fieldDesc);
286                 std::unique_ptr<C2Param> *param = nullptr;
287                 auto paramIt = paramsMap.find(desc.paramDesc->index());
288                 if (paramIt == paramsMap.end()) {
289                     ALOGD("%s found, but param #%d isn't present to update",
290                             name.c_str(), (int32_t)desc.paramDesc->index());
291                     return;
292                 }
293                 param = paramIt->second;
294 
295                 // reallocate or trim flexible param as necessary
296                 if (desc.fieldDesc->extent() == 0) {
297                     struct _C2Param : public C2Param {
298                         using C2Param::C2Param;
299                         _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { }
300                     };
301                     // reallocate param if more space is needed
302                     if (param->get()->size() < offset + size) {
303                         if (size > INT32_MAX - offset || offset < sizeof(C2Param)) {
304                             // size too long or offset too early - abandon
305                             return;
306                         }
307                         C2Param *newParam = (C2Param *)::operator new(offset + size);
308                         new (newParam) _C2Param(offset + size, param->get()->index());
309                         memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param));
310                         param->reset(newParam);
311                     } else if (param->get()->size() > offset + size) {
312                         // trim parameter size
313                         _C2ParamInspector::TrimParam(param->get(), offset + size);
314                     }
315                 } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) {
316                     // zero fill blobs if updating with smaller blob
317                     if (desc.fieldDesc->extent() > size) {
318                         memset((uint8_t *)(param->get()) + offset + size, 0,
319                                desc.fieldDesc->extent() - size);
320                     }
321                 }
322 
323                 memcpy((uint8_t *)(param->get()) + offset, ptr, size);
324             });
325 }
326 
parseMessageAndDoWork(const Dict & params,std::function<void (const std::string &,const FieldDesc &,const void *,size_t)> work) const327 void ReflectedParamUpdater::parseMessageAndDoWork(
328         const Dict &params,
329         std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const {
330     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
331         const std::string &name = kv.first;
332         const FieldDesc &desc = kv.second;
333         auto param = params.find(name);
334         if (param == params.end()) {
335             continue;
336         }
337 
338         int32_t int32Value;
339         int64_t int64Value;
340         C2Value c2Value;
341 
342         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
343         size_t fieldExtent = desc.fieldDesc->extent();
344         switch (fieldType) {
345             case C2FieldDescriptor::INT32:
346                 if ((param->second.find(&c2Value) && c2Value.get(&int32Value))
347                         || param->second.find(&int32Value)) {
348                     work(name, desc, &int32Value, sizeof(int32Value));
349                 }
350                 break;
351             case C2FieldDescriptor::UINT32:
352                 if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value))
353                         || param->second.find(&int32Value)) {
354                     work(name, desc, &int32Value, sizeof(int32Value));
355                 }
356                 break;
357             case C2FieldDescriptor::CNTR32:
358                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value))
359                         || param->second.find(&int32Value)) {
360                     work(name, desc, &int32Value, sizeof(int32Value));
361                 }
362                 break;
363             case C2FieldDescriptor::INT64:
364                 if ((param->second.find(&c2Value) && c2Value.get(&int64Value))
365                         || param->second.find(&int64Value)) {
366                     work(name, desc, &int64Value, sizeof(int64Value));
367                 }
368                 break;
369             case C2FieldDescriptor::UINT64:
370                 if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value))
371                         || param->second.find(&int64Value)) {
372                     work(name, desc, &int64Value, sizeof(int64Value));
373                 }
374                 break;
375             case C2FieldDescriptor::CNTR64:
376                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value))
377                         || param->second.find(&int64Value)) {
378                     work(name, desc, &int64Value, sizeof(int64Value));
379                 }
380                 break;
381             case C2FieldDescriptor::FLOAT: {
382                 float tmp;
383                 if (param->second.find(&c2Value) && c2Value.get(&tmp)) {
384                     work(name, desc, &tmp, sizeof(tmp));
385                 }
386                 break;
387             }
388             case C2FieldDescriptor::STRING: {
389                 AString tmp;
390                 if (!param->second.find(&tmp)) {
391                     break;
392                 }
393                 if (fieldExtent > 0 && tmp.size() >= fieldExtent) {
394                     AString truncated(tmp, 0, fieldExtent - 1);
395                     ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"",
396                             tmp.c_str(), truncated.c_str());
397                     tmp = truncated;
398                 }
399                 work(name, desc, tmp.c_str(), tmp.size() + 1);
400                 break;
401             }
402 
403             case C2FieldDescriptor::BLOB: {
404                 sp<ABuffer> tmp;
405                 if (!param->second.find(&tmp) || tmp == nullptr) {
406                     break;
407                 }
408 
409                 if (fieldExtent > 0 && tmp->size() > fieldExtent) {
410                     ALOGD("Blob value too long to fit. Truncating.");
411                     tmp->setRange(tmp->offset(), fieldExtent);
412                 }
413                 work(name, desc, tmp->data(), tmp->size());
414                 break;
415             }
416 
417             default:
418                 ALOGD("Unsupported data type for %s", name.c_str());
419                 break;
420         }
421     }
422 }
423 
424 ReflectedParamUpdater::Dict
getParams(const std::vector<std::unique_ptr<C2Param>> & params_) const425 ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> &params_) const {
426     std::vector<C2Param*> params;
427     params.resize(params_.size());
428     std::transform(params_.begin(), params_.end(), params.begin(),
429                    [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); });
430     return getParams(params);
431 }
432 
433 ReflectedParamUpdater::Dict
getParams(const std::vector<C2Param * > & params) const434 ReflectedParamUpdater::getParams(const std::vector<C2Param*> &params) const {
435     Dict ret;
436 
437     // convert vector to map
438     std::map<C2Param::Index, C2Param *> paramsMap;
439     for (C2Param *param : params) {
440         if (param != nullptr && *param) {
441             paramsMap[param->index()] = param;
442         }
443     }
444 
445     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
446         const std::string &name = kv.first;
447         const FieldDesc &desc = kv.second;
448         if (paramsMap.count(desc.paramDesc->index()) == 0) {
449             continue;
450         }
451         C2Param *param = paramsMap[desc.paramDesc->index()];
452         size_t offset = sizeof(C2Param) + desc.offset
453                 + _C2ParamInspector::GetOffset(*desc.fieldDesc);
454         uint8_t *data = (uint8_t *)param + offset;
455         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
456         Value value;
457         switch (fieldType) {
458             case C2FieldDescriptor::STRING: {
459                 size_t length = desc.fieldDesc->extent();
460                 if (length == 0) {
461                     length = param->size() - offset;
462                 }
463 
464                 if (param->size() < length || param->size() - length < offset) {
465                     ALOGD("param too small for string: length %zu size %zu offset %zu",
466                             length, param->size(), offset);
467                     break;
468                 }
469                 value.set(AString((char *)data, strnlen((char *)data, length)));
470                 break;
471             }
472 
473             case C2FieldDescriptor::BLOB: {
474                 size_t length = desc.fieldDesc->extent();
475                 if (length == 0) {
476                     length = param->size() - offset;
477                 }
478 
479                 if (param->size() < length || param->size() - length < offset) {
480                     ALOGD("param too small for blob: length %zu size %zu offset %zu",
481                             length, param->size(), offset);
482                     break;
483                 }
484 
485                 sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length);
486                 value.set(buf);
487                 break;
488             }
489 
490             default: {
491                 size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType);
492                 if (param->size() < valueSize || param->size() - valueSize < offset) {
493                     ALOGD("param too small for c2value: size %zu offset %zu",
494                             param->size(), offset);
495                     break;
496                 }
497 
498                 C2Value c2Value;
499                 switch (fieldType) {
500                     case C2FieldDescriptor::INT32:  c2Value = *((int32_t *)data); break;
501                     case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break;
502                     case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break;
503                     case C2FieldDescriptor::INT64:  c2Value = *((int64_t *)data); break;
504                     case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break;
505                     case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break;
506                     case C2FieldDescriptor::FLOAT:  c2Value = *((float *)data); break;
507                     default:
508                         ALOGD("Unsupported data type for %s", name.c_str());
509                         continue;
510                 }
511                 value.set(c2Value);
512             }
513         }
514         ret.emplace(name, value);
515     }
516     return ret;
517 }
518 
clear()519 void ReflectedParamUpdater::clear() {
520     mMap.clear();
521 }
522 
523 }  // namespace android
524