| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 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 |  | 
|  | 37 | 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 |  | 
|  | 116 | void ReflectedParamUpdater::addParamDesc( | 
|  | 117 | const std::shared_ptr<C2ParamReflector> &reflector, | 
|  | 118 | const std::vector<std::shared_ptr<C2ParamDescriptor>> ¶mDescs) { | 
|  | 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 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 128 | } | 
|  | 129 |  | 
|  | 130 | void ReflectedParamUpdater::addParamStructDesc( | 
|  | 131 | std::shared_ptr<C2ParamDescriptor> desc, | 
|  | 132 | C2String path, | 
|  | 133 | size_t offset, | 
|  | 134 | const C2StructDescriptor &structDesc, | 
|  | 135 | const std::shared_ptr<C2ParamReflector> &reflector) { | 
|  | 136 | for (auto it = structDesc.begin(); it != structDesc.end(); ++it) { | 
|  | 137 | C2String fieldName = path + "." + it->name(); | 
|  | 138 | if (it->type() & C2FieldDescriptor::STRUCT_FLAG) { | 
|  | 139 | if (reflector == nullptr || it->extent() != 1) { | 
|  | 140 | ALOGD("ignored struct field %s", fieldName.c_str()); | 
|  | 141 | continue; | 
|  | 142 | } | 
|  | 143 | std::unique_ptr<C2StructDescriptor> structDesc_ = reflector->describe( | 
|  | 144 | C2Param::CoreIndex(it->type()).coreIndex()); | 
|  | 145 | if (structDesc_ == nullptr) { | 
|  | 146 | ALOGD("Could not describe structure of %s", fieldName.c_str()); | 
|  | 147 | continue; | 
|  | 148 | } | 
|  | 149 | addParamStructDesc(desc, fieldName, offset + _C2ParamInspector::GetOffset(*it), | 
|  | 150 | *structDesc_, reflector); | 
|  | 151 | continue; | 
|  | 152 | } | 
|  | 153 |  | 
|  | 154 | // verify extent and type | 
|  | 155 | switch (it->type()) { | 
|  | 156 | case C2FieldDescriptor::INT32: | 
|  | 157 | case C2FieldDescriptor::UINT32: | 
|  | 158 | case C2FieldDescriptor::CNTR32: | 
|  | 159 | case C2FieldDescriptor::INT64: | 
|  | 160 | case C2FieldDescriptor::UINT64: | 
|  | 161 | case C2FieldDescriptor::CNTR64: | 
|  | 162 | case C2FieldDescriptor::FLOAT: | 
|  | 163 | if (it->extent() != 1) { | 
|  | 164 | ALOGD("extent() != 1 for single value type: %s", fieldName.c_str()); | 
|  | 165 | continue; | 
|  | 166 | } | 
|  | 167 | break; | 
|  | 168 | case C2FieldDescriptor::STRING: | 
|  | 169 | case C2FieldDescriptor::BLOB: | 
|  | 170 | break; | 
|  | 171 |  | 
|  | 172 | default: | 
|  | 173 | ALOGD("Unrecognized type: %s", fieldName.c_str()); | 
|  | 174 | continue; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | ALOGV("%s registered", fieldName.c_str()); | 
|  | 178 | // TODO: get the proper size by iterating through the fields. | 
|  | 179 | // only insert fields the very first time | 
|  | 180 | mMap.emplace(fieldName, FieldDesc { | 
|  | 181 | desc, | 
|  | 182 | std::make_unique<C2FieldDescriptor>( | 
|  | 183 | it->type(), it->extent(), it->name(), | 
|  | 184 | _C2ParamInspector::GetOffset(*it), | 
|  | 185 | _C2ParamInspector::GetSize(*it)), | 
|  | 186 | offset, | 
|  | 187 | }); | 
|  | 188 | } | 
|  | 189 | } | 
|  | 190 |  | 
|  | 191 | void ReflectedParamUpdater::addParamDesc( | 
|  | 192 | std::shared_ptr<C2ParamDescriptor> desc, const C2StructDescriptor &structDesc, | 
|  | 193 | const std::shared_ptr<C2ParamReflector> &reflector, bool markVendor) { | 
|  | 194 | C2String paramName = desc->name(); | 
|  | 195 |  | 
| Lajos Molnar | 02af5a1 | 2019-05-30 09:22:21 -0700 | [diff] [blame] | 196 | // Do not reflect requested parameters | 
|  | 197 | // TODO: split these once aliases are introduced into '.actual' and '.requested' and alias | 
|  | 198 | // the name to '.actual'. | 
|  | 199 | if (desc->index() & C2Param::CoreIndex::IS_REQUEST_FLAG) { | 
|  | 200 | return; | 
|  | 201 | } | 
|  | 202 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 203 | // prefix vendor parameters | 
|  | 204 | if (desc->index().isVendor() && markVendor) { | 
|  | 205 | paramName = "vendor." + paramName; | 
|  | 206 | } | 
|  | 207 | mParamNames.emplace(desc->index(), paramName); | 
|  | 208 |  | 
|  | 209 | // also allow setting whole parameters in a binary fashion via ByteBuffer | 
|  | 210 | // this is opt-in for now | 
|  | 211 | auto it = mWholeParams.find(paramName); | 
|  | 212 | if (it != mWholeParams.end() && it->second.coreIndex() == desc->index().coreIndex()) { | 
|  | 213 | mMap.emplace(paramName, FieldDesc{ desc, nullptr, 0 /* offset */ }); | 
|  | 214 | // don't add fields of whole parameters. | 
|  | 215 | return; | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector); | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | void ReflectedParamUpdater::supportWholeParam(std::string name, C2Param::CoreIndex index) { | 
|  | 222 | mWholeParams.emplace(name, index); | 
|  | 223 | } | 
|  | 224 |  | 
|  | 225 | std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const { | 
|  | 226 | auto it = mParamNames.find(index); | 
|  | 227 | if (it != mParamNames.end()) { | 
|  | 228 | return it->second; | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | std::stringstream ret; | 
|  | 232 | ret << "<unknown " << index << ">"; | 
|  | 233 | return ret.str(); | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | void ReflectedParamUpdater::getParamIndicesFromMessage( | 
|  | 237 | const Dict ¶ms, | 
|  | 238 | std::vector<C2Param::Index> *vec /* nonnull */) const { | 
|  | 239 | CHECK(vec != nullptr); | 
|  | 240 | vec->clear(); | 
|  | 241 | std::set<C2Param::Index> indices; | 
|  | 242 | parseMessageAndDoWork( | 
|  | 243 | params, | 
|  | 244 | [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) { | 
|  | 245 | indices.insert(desc.paramDesc->index()); | 
|  | 246 | }); | 
|  | 247 | for (const C2Param::Index &index : indices) { | 
|  | 248 | vec->push_back(index); | 
|  | 249 | } | 
|  | 250 | } | 
|  | 251 |  | 
|  | 252 | void ReflectedParamUpdater::getParamIndicesForKeys( | 
|  | 253 | const std::vector<std::string> &keys, | 
|  | 254 | std::vector<C2Param::Index> *vec /* nonnull */) const { | 
|  | 255 | CHECK(vec != nullptr); | 
|  | 256 | vec->clear(); | 
|  | 257 | std::set<C2Param::Index> indices; | 
|  | 258 |  | 
|  | 259 | std::set<std::string> keyMap(keys.begin(), keys.end()); | 
|  | 260 |  | 
|  | 261 | ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries", | 
|  | 262 | keyMap.size(), mMap.size()); | 
|  | 263 | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | 264 | const std::string &name = kv.first; | 
|  | 265 | const FieldDesc &desc = kv.second; | 
|  | 266 | ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name)); | 
|  | 267 | if (keyMap.count(name) > 0) { | 
|  | 268 | indices.insert(desc.paramDesc->index()); | 
|  | 269 | } | 
|  | 270 | } | 
|  | 271 |  | 
|  | 272 | for (const C2Param::Index &index : indices) { | 
|  | 273 | vec->push_back(index); | 
|  | 274 | } | 
|  | 275 | } | 
|  | 276 |  | 
| Wonsik Kim | 8a6ed37 | 2019-12-03 16:05:51 -0800 | [diff] [blame] | 277 | void ReflectedParamUpdater::getKeysForParamIndex( | 
|  | 278 | const C2Param::Index &index, | 
|  | 279 | std::vector<std::string> *keys /* nonnull */) const { | 
|  | 280 | CHECK(keys != nullptr); | 
|  | 281 | keys->clear(); | 
|  | 282 | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | 283 | const std::string &name = kv.first; | 
|  | 284 | const FieldDesc &desc = kv.second; | 
|  | 285 | if (desc.paramDesc->index() == index) { | 
|  | 286 | keys->push_back(name); | 
|  | 287 | } | 
|  | 288 | } | 
|  | 289 | } | 
|  | 290 |  | 
| Wonsik Kim | 874ad38 | 2021-03-12 09:59:36 -0800 | [diff] [blame] | 291 | C2FieldDescriptor::type_t ReflectedParamUpdater::getTypeForKey( | 
|  | 292 | const std::string &key) const { | 
|  | 293 | auto it = mMap.find(key); | 
|  | 294 | if (it == mMap.end()) { | 
|  | 295 | return C2FieldDescriptor::type_t(~0); | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | if (it->second.fieldDesc) { | 
|  | 299 | return it->second.fieldDesc->type(); | 
|  | 300 | } | 
|  | 301 | // whole param is exposed as a blob | 
|  | 302 | return C2FieldDescriptor::BLOB; | 
|  | 303 | } | 
|  | 304 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 305 | void ReflectedParamUpdater::updateParamsFromMessage( | 
|  | 306 | const Dict ¶ms, | 
|  | 307 | std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const { | 
|  | 308 | CHECK(vec != nullptr); | 
|  | 309 |  | 
|  | 310 | std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap; | 
|  | 311 | for (std::unique_ptr<C2Param> ¶m : *vec) { | 
|  | 312 | if (param && *param) { | 
|  | 313 | paramsMap[param->index()] = ¶m; | 
|  | 314 | } | 
|  | 315 | } | 
|  | 316 |  | 
|  | 317 | parseMessageAndDoWork( | 
|  | 318 | params, | 
|  | 319 | [¶msMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) { | 
|  | 320 | std::unique_ptr<C2Param> *param = nullptr; | 
|  | 321 | auto paramIt = paramsMap.find(desc.paramDesc->index()); | 
|  | 322 | if (paramIt == paramsMap.end()) { | 
|  | 323 | ALOGD("%s found, but param #%d isn't present to update", | 
|  | 324 | name.c_str(), (int32_t)desc.paramDesc->index()); | 
|  | 325 | return; | 
|  | 326 | } | 
|  | 327 | param = paramIt->second; | 
|  | 328 |  | 
|  | 329 | struct _C2Param : public C2Param { | 
|  | 330 | using C2Param::C2Param; | 
|  | 331 | _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { } | 
|  | 332 | }; | 
|  | 333 |  | 
|  | 334 | // we will handle whole param updates as part of a flexible param update using | 
|  | 335 | // a zero offset. | 
|  | 336 | size_t offset = 0; | 
|  | 337 | size_t minOffset = 0; | 
|  | 338 |  | 
|  | 339 | // if this descriptor has a field, use the offset and size and ensure that offset | 
|  | 340 | // is not part of the header | 
|  | 341 | if (desc.fieldDesc) { | 
|  | 342 | minOffset = sizeof(C2Param); | 
|  | 343 | offset = sizeof(C2Param) + desc.offset | 
|  | 344 | + _C2ParamInspector::GetOffset(*desc.fieldDesc); | 
|  | 345 | } | 
|  | 346 |  | 
|  | 347 | // reallocate or trim flexible param (or whole param) as necessary | 
|  | 348 | if (!desc.fieldDesc /* whole param */ || desc.fieldDesc->extent() == 0) { | 
|  | 349 | // reallocate param if more space is needed | 
|  | 350 | if (param->get()->size() < offset + size) { | 
|  | 351 | if (size > INT32_MAX - offset || offset < minOffset) { | 
|  | 352 | // size too long or offset too early - abandon | 
|  | 353 | return; | 
|  | 354 | } | 
|  | 355 | C2Param *newParam = (C2Param *)::operator new(offset + size); | 
|  | 356 | new (newParam) _C2Param(offset + size, param->get()->index()); | 
|  | 357 | if (offset > sizeof(C2Param)) { | 
|  | 358 | memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param)); | 
|  | 359 | } | 
|  | 360 | param->reset(newParam); | 
|  | 361 | } else if (param->get()->size() > offset + size) { | 
|  | 362 | // trim parameter size | 
|  | 363 | _C2ParamInspector::TrimParam(param->get(), offset + size); | 
|  | 364 | } | 
|  | 365 | } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) { | 
|  | 366 | // zero fill blobs if updating with smaller blob | 
|  | 367 | if (desc.fieldDesc->extent() > size) { | 
|  | 368 | memset((uint8_t *)(param->get()) + offset + size, 0, | 
|  | 369 | desc.fieldDesc->extent() - size); | 
|  | 370 | } | 
|  | 371 | } | 
|  | 372 |  | 
|  | 373 | memcpy((uint8_t *)(param->get()) + offset, ptr, size); | 
|  | 374 | }); | 
|  | 375 | } | 
|  | 376 |  | 
|  | 377 | void ReflectedParamUpdater::parseMessageAndDoWork( | 
|  | 378 | const Dict ¶ms, | 
|  | 379 | std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const { | 
|  | 380 | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | 381 | const std::string &name = kv.first; | 
|  | 382 | const FieldDesc &desc = kv.second; | 
|  | 383 | auto param = params.find(name); | 
|  | 384 | if (param == params.end()) { | 
|  | 385 | continue; | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | // handle whole parameters | 
|  | 389 | if (!desc.fieldDesc) { | 
|  | 390 | sp<ABuffer> tmp; | 
|  | 391 | if (param->second.find(&tmp) && tmp != nullptr) { | 
|  | 392 | C2Param *tmpAsParam = C2Param::From(tmp->data(), tmp->size()); | 
|  | 393 | if (tmpAsParam && tmpAsParam->type().type() == desc.paramDesc->index().type()) { | 
|  | 394 | work(name, desc, tmp->data(), tmp->size()); | 
|  | 395 | } else { | 
|  | 396 | ALOGD("Param blob does not match param for '%s' (%p, %x vs %x)", | 
|  | 397 | name.c_str(), tmpAsParam, tmpAsParam ? tmpAsParam->type().type() : 0xDEADu, | 
|  | 398 | desc.paramDesc->index().type()); | 
|  | 399 | } | 
|  | 400 | } | 
|  | 401 | continue; | 
|  | 402 | } | 
|  | 403 |  | 
|  | 404 | int32_t int32Value; | 
|  | 405 | int64_t int64Value; | 
|  | 406 | C2Value c2Value; | 
|  | 407 |  | 
|  | 408 | C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type(); | 
|  | 409 | size_t fieldExtent = desc.fieldDesc->extent(); | 
|  | 410 | switch (fieldType) { | 
|  | 411 | case C2FieldDescriptor::INT32: | 
|  | 412 | if ((param->second.find(&c2Value) && c2Value.get(&int32Value)) | 
|  | 413 | || param->second.find(&int32Value)) { | 
|  | 414 | work(name, desc, &int32Value, sizeof(int32Value)); | 
|  | 415 | } | 
|  | 416 | break; | 
|  | 417 | case C2FieldDescriptor::UINT32: | 
|  | 418 | if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value)) | 
|  | 419 | || param->second.find(&int32Value)) { | 
|  | 420 | work(name, desc, &int32Value, sizeof(int32Value)); | 
|  | 421 | } | 
|  | 422 | break; | 
|  | 423 | case C2FieldDescriptor::CNTR32: | 
|  | 424 | if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value)) | 
|  | 425 | || param->second.find(&int32Value)) { | 
|  | 426 | work(name, desc, &int32Value, sizeof(int32Value)); | 
|  | 427 | } | 
|  | 428 | break; | 
|  | 429 | case C2FieldDescriptor::INT64: | 
|  | 430 | if ((param->second.find(&c2Value) && c2Value.get(&int64Value)) | 
|  | 431 | || param->second.find(&int64Value)) { | 
|  | 432 | work(name, desc, &int64Value, sizeof(int64Value)); | 
|  | 433 | } | 
|  | 434 | break; | 
|  | 435 | case C2FieldDescriptor::UINT64: | 
|  | 436 | if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value)) | 
|  | 437 | || param->second.find(&int64Value)) { | 
|  | 438 | work(name, desc, &int64Value, sizeof(int64Value)); | 
|  | 439 | } | 
|  | 440 | break; | 
|  | 441 | case C2FieldDescriptor::CNTR64: | 
|  | 442 | if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value)) | 
|  | 443 | || param->second.find(&int64Value)) { | 
|  | 444 | work(name, desc, &int64Value, sizeof(int64Value)); | 
|  | 445 | } | 
|  | 446 | break; | 
|  | 447 | case C2FieldDescriptor::FLOAT: { | 
|  | 448 | float tmp; | 
|  | 449 | if (param->second.find(&c2Value) && c2Value.get(&tmp)) { | 
|  | 450 | work(name, desc, &tmp, sizeof(tmp)); | 
|  | 451 | } | 
|  | 452 | break; | 
|  | 453 | } | 
|  | 454 | case C2FieldDescriptor::STRING: { | 
|  | 455 | AString tmp; | 
|  | 456 | if (!param->second.find(&tmp)) { | 
|  | 457 | break; | 
|  | 458 | } | 
|  | 459 | if (fieldExtent > 0 && tmp.size() >= fieldExtent) { | 
|  | 460 | AString truncated(tmp, 0, fieldExtent - 1); | 
|  | 461 | ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"", | 
|  | 462 | tmp.c_str(), truncated.c_str()); | 
|  | 463 | tmp = truncated; | 
|  | 464 | } | 
|  | 465 | work(name, desc, tmp.c_str(), tmp.size() + 1); | 
|  | 466 | break; | 
|  | 467 | } | 
|  | 468 |  | 
|  | 469 | case C2FieldDescriptor::BLOB: { | 
|  | 470 | sp<ABuffer> tmp; | 
|  | 471 | if (!param->second.find(&tmp) || tmp == nullptr) { | 
|  | 472 | break; | 
|  | 473 | } | 
|  | 474 |  | 
|  | 475 | if (fieldExtent > 0 && tmp->size() > fieldExtent) { | 
|  | 476 | ALOGD("Blob value too long to fit. Truncating."); | 
|  | 477 | tmp->setRange(tmp->offset(), fieldExtent); | 
|  | 478 | } | 
|  | 479 | work(name, desc, tmp->data(), tmp->size()); | 
|  | 480 | break; | 
|  | 481 | } | 
|  | 482 |  | 
|  | 483 | default: | 
|  | 484 | ALOGD("Unsupported data type for %s", name.c_str()); | 
|  | 485 | break; | 
|  | 486 | } | 
|  | 487 | } | 
|  | 488 | } | 
|  | 489 |  | 
|  | 490 | ReflectedParamUpdater::Dict | 
|  | 491 | ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> ¶ms_) const { | 
|  | 492 | std::vector<C2Param*> params; | 
|  | 493 | params.resize(params_.size()); | 
|  | 494 | std::transform(params_.begin(), params_.end(), params.begin(), | 
|  | 495 | [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); }); | 
|  | 496 | return getParams(params); | 
|  | 497 | } | 
|  | 498 |  | 
|  | 499 | ReflectedParamUpdater::Dict | 
|  | 500 | ReflectedParamUpdater::getParams(const std::vector<C2Param*> ¶ms) const { | 
|  | 501 | Dict ret; | 
|  | 502 |  | 
|  | 503 | // convert vector to map | 
|  | 504 | std::map<C2Param::Index, C2Param *> paramsMap; | 
|  | 505 | for (C2Param *param : params) { | 
|  | 506 | if (param != nullptr && *param) { | 
|  | 507 | paramsMap[param->index()] = param; | 
|  | 508 | } | 
|  | 509 | } | 
|  | 510 |  | 
|  | 511 | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | 512 | const std::string &name = kv.first; | 
|  | 513 | const FieldDesc &desc = kv.second; | 
|  | 514 | if (paramsMap.count(desc.paramDesc->index()) == 0) { | 
|  | 515 | continue; | 
|  | 516 | } | 
|  | 517 | C2Param *param = paramsMap[desc.paramDesc->index()]; | 
|  | 518 | Value value; | 
|  | 519 |  | 
|  | 520 | // handle whole params first | 
|  | 521 | if (!desc.fieldDesc) { | 
|  | 522 | sp<ABuffer> buf = ABuffer::CreateAsCopy(param, param->size()); | 
|  | 523 | value.set(buf); | 
|  | 524 | ret.emplace(name, value); | 
|  | 525 | continue; | 
|  | 526 | } | 
|  | 527 |  | 
|  | 528 | size_t offset = sizeof(C2Param) + desc.offset | 
|  | 529 | + _C2ParamInspector::GetOffset(*desc.fieldDesc); | 
|  | 530 | uint8_t *data = (uint8_t *)param + offset; | 
|  | 531 | C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type(); | 
|  | 532 | switch (fieldType) { | 
|  | 533 | case C2FieldDescriptor::STRING: { | 
|  | 534 | size_t length = desc.fieldDesc->extent(); | 
|  | 535 | if (length == 0) { | 
|  | 536 | length = param->size() - offset; | 
|  | 537 | } | 
|  | 538 |  | 
|  | 539 | if (param->size() < length || param->size() - length < offset) { | 
|  | 540 | ALOGD("param too small for string: length %zu size %zu offset %zu", | 
|  | 541 | length, param->size(), offset); | 
|  | 542 | break; | 
|  | 543 | } | 
|  | 544 | value.set(AString((char *)data, strnlen((char *)data, length))); | 
|  | 545 | break; | 
|  | 546 | } | 
|  | 547 |  | 
|  | 548 | case C2FieldDescriptor::BLOB: { | 
|  | 549 | size_t length = desc.fieldDesc->extent(); | 
|  | 550 | if (length == 0) { | 
|  | 551 | length = param->size() - offset; | 
|  | 552 | } | 
|  | 553 |  | 
|  | 554 | if (param->size() < length || param->size() - length < offset) { | 
|  | 555 | ALOGD("param too small for blob: length %zu size %zu offset %zu", | 
|  | 556 | length, param->size(), offset); | 
|  | 557 | break; | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length); | 
|  | 561 | value.set(buf); | 
|  | 562 | break; | 
|  | 563 | } | 
|  | 564 |  | 
|  | 565 | default: { | 
|  | 566 | size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType); | 
|  | 567 | if (param->size() < valueSize || param->size() - valueSize < offset) { | 
|  | 568 | ALOGD("param too small for c2value: size %zu offset %zu", | 
|  | 569 | param->size(), offset); | 
|  | 570 | break; | 
|  | 571 | } | 
|  | 572 |  | 
|  | 573 | C2Value c2Value; | 
|  | 574 | switch (fieldType) { | 
|  | 575 | case C2FieldDescriptor::INT32:  c2Value = *((int32_t *)data); break; | 
|  | 576 | case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break; | 
|  | 577 | case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break; | 
|  | 578 | case C2FieldDescriptor::INT64:  c2Value = *((int64_t *)data); break; | 
|  | 579 | case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break; | 
|  | 580 | case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break; | 
|  | 581 | case C2FieldDescriptor::FLOAT:  c2Value = *((float *)data); break; | 
|  | 582 | default: | 
|  | 583 | ALOGD("Unsupported data type for %s", name.c_str()); | 
|  | 584 | continue; | 
|  | 585 | } | 
|  | 586 | value.set(c2Value); | 
|  | 587 | } | 
|  | 588 | } | 
|  | 589 | ret.emplace(name, value); | 
|  | 590 | } | 
|  | 591 | return ret; | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | void ReflectedParamUpdater::clear() { | 
|  | 595 | mMap.clear(); | 
|  | 596 | } | 
|  | 597 |  | 
|  | 598 | }  // namespace android |