|  | /* | 
|  | * Copyright (C) 2018 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | //#define LOG_NDEBUG 0 | 
|  | #define LOG_TAG "ReflectedParamUpdater" | 
|  | #include <utils/Log.h> | 
|  |  | 
|  | #include <iostream> | 
|  | #include <set> | 
|  | #include <sstream> | 
|  |  | 
|  | #include <C2Debug.h> | 
|  | #include <C2ParamInternal.h> | 
|  |  | 
|  | #include <media/stagefright/foundation/ABuffer.h> | 
|  | #include <media/stagefright/foundation/ADebug.h> | 
|  | #include <media/stagefright/foundation/AString.h> | 
|  | #include <media/stagefright/foundation/hexdump.h> | 
|  |  | 
|  | #include "ReflectedParamUpdater.h" | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | std::string ReflectedParamUpdater::Dict::debugString(size_t indent_) const { | 
|  | std::string indent(indent_, ' '); | 
|  | std::stringstream s; | 
|  | s << "Dict {" << std::endl; | 
|  |  | 
|  | for (const auto &it : *this) { | 
|  | s << indent << "  "; | 
|  |  | 
|  | C2Value c2Value; | 
|  | int32_t int32Value; | 
|  | uint32_t uint32Value; | 
|  | int64_t int64Value; | 
|  | uint64_t uint64Value; | 
|  | float floatValue; | 
|  | sp<ABuffer> bufValue; | 
|  | AString strValue; | 
|  | if (it.second.find(&c2Value)) { | 
|  | switch (c2Value.type()) { | 
|  | case C2Value::INT32: | 
|  | (void)c2Value.get(&int32Value); | 
|  | s << "c2::i32 " << it.first << " = " << int32Value; | 
|  | break; | 
|  | case C2Value::UINT32: | 
|  | (void)c2Value.get(&uint32Value); | 
|  | s << "c2::u32 " << it.first << " = " << uint32Value; | 
|  | break; | 
|  | case C2Value::CNTR32: | 
|  | // dump counter value as unsigned | 
|  | (void)c2Value.get((c2_cntr32_t*)&uint32Value); | 
|  | s << "c2::c32 " << it.first << " = " << uint32Value; | 
|  | break; | 
|  | case C2Value::INT64: | 
|  | (void)c2Value.get(&int64Value); | 
|  | s << "c2::i64 " << it.first << " = " << int64Value; | 
|  | break; | 
|  | case C2Value::UINT64: | 
|  | (void)c2Value.get(&uint64Value); | 
|  | s << "c2::u64 " << it.first << " = " << uint64Value; | 
|  | break; | 
|  | case C2Value::CNTR64: | 
|  | // dump counter value as unsigned | 
|  | (void)c2Value.get((c2_cntr64_t*)&uint64Value); | 
|  | s << "c2::c64 " << it.first << " = " << uint64Value; | 
|  | break; | 
|  | case C2Value::FLOAT: | 
|  | (void)c2Value.get(&floatValue); | 
|  | s << "c2::float " << it.first << " = " << floatValue; | 
|  | break; | 
|  | default: | 
|  | // dump unsupported values for debugging, these should not be used | 
|  | s << "c2::unsupported " << it.first; | 
|  | } | 
|  | } else if (it.second.find(&int32Value)) { | 
|  | s << "int32_t " << it.first << " = " << int32Value; | 
|  | } else if (it.second.find(&int64Value)) { | 
|  | s << "int64_t " << it.first << " = " << int64Value; | 
|  | } else if (it.second.find(&strValue)) { | 
|  | s << "string " << it.first << " = \"" << strValue.c_str() << "\""; | 
|  | } else if (it.second.find(&bufValue)) { | 
|  | s << "Buffer " << it.first << " = "; | 
|  | if (bufValue != nullptr && bufValue->data() != nullptr && bufValue->size() <= 64) { | 
|  | s << "{" << std::endl; | 
|  | AString tmp; | 
|  | hexdump(bufValue->data(), bufValue->size(), indent_ + 4, &tmp); | 
|  | s << tmp.c_str() << indent << "  }"; | 
|  | } else { | 
|  | s << (void*)bufValue.get(); | 
|  | } | 
|  | } else { | 
|  | // dump unsupported values for debugging, this should never happen. | 
|  | s << "unsupported " << it.first; | 
|  | } | 
|  | s << std::endl; | 
|  | } | 
|  | s << indent << "}"; | 
|  |  | 
|  | return s.str(); | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::addParamDesc( | 
|  | const std::shared_ptr<C2ParamReflector> &reflector, | 
|  | const std::vector<std::shared_ptr<C2ParamDescriptor>> ¶mDescs) { | 
|  | for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) { | 
|  | std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe( | 
|  | desc->index().coreIndex()); | 
|  | if (structDesc == nullptr) { | 
|  | ALOGD("Could not describe %s", desc->name().c_str()); | 
|  | continue; | 
|  | } | 
|  | addParamDesc(desc, *structDesc, reflector, true /* markVendor */); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::addParamStructDesc( | 
|  | std::shared_ptr<C2ParamDescriptor> desc, | 
|  | C2String path, | 
|  | size_t offset, | 
|  | const C2StructDescriptor &structDesc, | 
|  | const std::shared_ptr<C2ParamReflector> &reflector) { | 
|  | for (auto it = structDesc.begin(); it != structDesc.end(); ++it) { | 
|  | C2String fieldName = path + "." + it->name(); | 
|  | if (it->type() & C2FieldDescriptor::STRUCT_FLAG) { | 
|  | if (reflector == nullptr || it->extent() != 1) { | 
|  | ALOGD("ignored struct field %s", fieldName.c_str()); | 
|  | continue; | 
|  | } | 
|  | std::unique_ptr<C2StructDescriptor> structDesc_ = reflector->describe( | 
|  | C2Param::CoreIndex(it->type()).coreIndex()); | 
|  | if (structDesc_ == nullptr) { | 
|  | ALOGD("Could not describe structure of %s", fieldName.c_str()); | 
|  | continue; | 
|  | } | 
|  | addParamStructDesc(desc, fieldName, offset + _C2ParamInspector::GetOffset(*it), | 
|  | *structDesc_, reflector); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // verify extent and type | 
|  | switch (it->type()) { | 
|  | case C2FieldDescriptor::INT32: | 
|  | case C2FieldDescriptor::UINT32: | 
|  | case C2FieldDescriptor::CNTR32: | 
|  | case C2FieldDescriptor::INT64: | 
|  | case C2FieldDescriptor::UINT64: | 
|  | case C2FieldDescriptor::CNTR64: | 
|  | case C2FieldDescriptor::FLOAT: | 
|  | if (it->extent() != 1) { | 
|  | ALOGD("extent() != 1 for single value type: %s", fieldName.c_str()); | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::STRING: | 
|  | case C2FieldDescriptor::BLOB: | 
|  | break; | 
|  |  | 
|  | default: | 
|  | ALOGD("Unrecognized type: %s", fieldName.c_str()); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | ALOGV("%s registered", fieldName.c_str()); | 
|  | // TODO: get the proper size by iterating through the fields. | 
|  | // only insert fields the very first time | 
|  | mMap.emplace(fieldName, FieldDesc { | 
|  | desc, | 
|  | std::make_unique<C2FieldDescriptor>( | 
|  | it->type(), it->extent(), it->name(), | 
|  | _C2ParamInspector::GetOffset(*it), | 
|  | _C2ParamInspector::GetSize(*it)), | 
|  | offset, | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::addParamDesc( | 
|  | std::shared_ptr<C2ParamDescriptor> desc, const C2StructDescriptor &structDesc, | 
|  | const std::shared_ptr<C2ParamReflector> &reflector, bool markVendor) { | 
|  | C2String paramName = desc->name(); | 
|  |  | 
|  | // Do not reflect requested parameters | 
|  | // TODO: split these once aliases are introduced into '.actual' and '.requested' and alias | 
|  | // the name to '.actual'. | 
|  | if (desc->index() & C2Param::CoreIndex::IS_REQUEST_FLAG) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // prefix vendor parameters | 
|  | if (desc->index().isVendor() && markVendor) { | 
|  | paramName = "vendor." + paramName; | 
|  | } | 
|  | mParamNames.emplace(desc->index(), paramName); | 
|  |  | 
|  | // also allow setting whole parameters in a binary fashion via ByteBuffer | 
|  | // this is opt-in for now | 
|  | auto it = mWholeParams.find(paramName); | 
|  | if (it != mWholeParams.end() && it->second.coreIndex() == desc->index().coreIndex()) { | 
|  | mMap.emplace(paramName, FieldDesc{ desc, nullptr, 0 /* offset */ }); | 
|  | // don't add fields of whole parameters. | 
|  | return; | 
|  | } | 
|  |  | 
|  | addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector); | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::supportWholeParam(std::string name, C2Param::CoreIndex index) { | 
|  | mWholeParams.emplace(name, index); | 
|  | } | 
|  |  | 
|  | std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const { | 
|  | auto it = mParamNames.find(index); | 
|  | if (it != mParamNames.end()) { | 
|  | return it->second; | 
|  | } | 
|  |  | 
|  | std::stringstream ret; | 
|  | ret << "<unknown " << index << ">"; | 
|  | return ret.str(); | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::getParamIndicesFromMessage( | 
|  | const Dict ¶ms, | 
|  | std::vector<C2Param::Index> *vec /* nonnull */) const { | 
|  | CHECK(vec != nullptr); | 
|  | vec->clear(); | 
|  | std::set<C2Param::Index> indices; | 
|  | parseMessageAndDoWork( | 
|  | params, | 
|  | [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) { | 
|  | indices.insert(desc.paramDesc->index()); | 
|  | }); | 
|  | for (const C2Param::Index &index : indices) { | 
|  | vec->push_back(index); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::getParamIndicesForKeys( | 
|  | const std::vector<std::string> &keys, | 
|  | std::vector<C2Param::Index> *vec /* nonnull */) const { | 
|  | CHECK(vec != nullptr); | 
|  | vec->clear(); | 
|  | std::set<C2Param::Index> indices; | 
|  |  | 
|  | std::set<std::string> keyMap(keys.begin(), keys.end()); | 
|  |  | 
|  | ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries", | 
|  | keyMap.size(), mMap.size()); | 
|  | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | const std::string &name = kv.first; | 
|  | const FieldDesc &desc = kv.second; | 
|  | ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name)); | 
|  | if (keyMap.count(name) > 0) { | 
|  | indices.insert(desc.paramDesc->index()); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const C2Param::Index &index : indices) { | 
|  | vec->push_back(index); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::getKeysForParamIndex( | 
|  | const C2Param::Index &index, | 
|  | std::vector<std::string> *keys /* nonnull */) const { | 
|  | CHECK(keys != nullptr); | 
|  | keys->clear(); | 
|  | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | const std::string &name = kv.first; | 
|  | const FieldDesc &desc = kv.second; | 
|  | if (desc.paramDesc->index() == index) { | 
|  | keys->push_back(name); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | C2FieldDescriptor::type_t ReflectedParamUpdater::getTypeForKey( | 
|  | const std::string &key) const { | 
|  | auto it = mMap.find(key); | 
|  | if (it == mMap.end()) { | 
|  | return C2FieldDescriptor::type_t(~0); | 
|  | } | 
|  |  | 
|  | if (it->second.fieldDesc) { | 
|  | return it->second.fieldDesc->type(); | 
|  | } | 
|  | // whole param is exposed as a blob | 
|  | return C2FieldDescriptor::BLOB; | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::updateParamsFromMessage( | 
|  | const Dict ¶ms, | 
|  | std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const { | 
|  | CHECK(vec != nullptr); | 
|  |  | 
|  | std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap; | 
|  | for (std::unique_ptr<C2Param> ¶m : *vec) { | 
|  | if (param && *param) { | 
|  | paramsMap[param->index()] = ¶m; | 
|  | } | 
|  | } | 
|  |  | 
|  | parseMessageAndDoWork( | 
|  | params, | 
|  | [¶msMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) { | 
|  | std::unique_ptr<C2Param> *param = nullptr; | 
|  | auto paramIt = paramsMap.find(desc.paramDesc->index()); | 
|  | if (paramIt == paramsMap.end()) { | 
|  | ALOGD("%s found, but param #%d isn't present to update", | 
|  | name.c_str(), (int32_t)desc.paramDesc->index()); | 
|  | return; | 
|  | } | 
|  | param = paramIt->second; | 
|  |  | 
|  | struct _C2Param : public C2Param { | 
|  | using C2Param::C2Param; | 
|  | _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { } | 
|  | }; | 
|  |  | 
|  | // we will handle whole param updates as part of a flexible param update using | 
|  | // a zero offset. | 
|  | size_t offset = 0; | 
|  | size_t minOffset = 0; | 
|  |  | 
|  | // if this descriptor has a field, use the offset and size and ensure that offset | 
|  | // is not part of the header | 
|  | if (desc.fieldDesc) { | 
|  | minOffset = sizeof(C2Param); | 
|  | offset = sizeof(C2Param) + desc.offset | 
|  | + _C2ParamInspector::GetOffset(*desc.fieldDesc); | 
|  | } | 
|  |  | 
|  | // reallocate or trim flexible param (or whole param) as necessary | 
|  | if (!desc.fieldDesc /* whole param */ || desc.fieldDesc->extent() == 0) { | 
|  | // reallocate param if more space is needed | 
|  | if (param->get()->size() < offset + size) { | 
|  | if (size > INT32_MAX - offset || offset < minOffset) { | 
|  | // size too long or offset too early - abandon | 
|  | return; | 
|  | } | 
|  | C2Param *newParam = (C2Param *)::operator new(offset + size); | 
|  | new (newParam) _C2Param(offset + size, param->get()->index()); | 
|  | if (offset > sizeof(C2Param)) { | 
|  | memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param)); | 
|  | } | 
|  | param->reset(newParam); | 
|  | } else if (param->get()->size() > offset + size) { | 
|  | // trim parameter size | 
|  | _C2ParamInspector::TrimParam(param->get(), offset + size); | 
|  | } | 
|  | } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) { | 
|  | // zero fill blobs if updating with smaller blob | 
|  | if (desc.fieldDesc->extent() > size) { | 
|  | memset((uint8_t *)(param->get()) + offset + size, 0, | 
|  | desc.fieldDesc->extent() - size); | 
|  | } | 
|  | } | 
|  |  | 
|  | memcpy((uint8_t *)(param->get()) + offset, ptr, size); | 
|  | }); | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::parseMessageAndDoWork( | 
|  | const Dict ¶ms, | 
|  | std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const { | 
|  | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | const std::string &name = kv.first; | 
|  | const FieldDesc &desc = kv.second; | 
|  | auto param = params.find(name); | 
|  | if (param == params.end()) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // handle whole parameters | 
|  | if (!desc.fieldDesc) { | 
|  | sp<ABuffer> tmp; | 
|  | if (param->second.find(&tmp) && tmp != nullptr) { | 
|  | C2Param *tmpAsParam = C2Param::From(tmp->data(), tmp->size()); | 
|  | if (tmpAsParam && tmpAsParam->type().type() == desc.paramDesc->index().type()) { | 
|  | work(name, desc, tmp->data(), tmp->size()); | 
|  | } else { | 
|  | ALOGD("Param blob does not match param for '%s' (%p, %x vs %x)", | 
|  | name.c_str(), tmpAsParam, tmpAsParam ? tmpAsParam->type().type() : 0xDEADu, | 
|  | desc.paramDesc->index().type()); | 
|  | } | 
|  | } | 
|  | continue; | 
|  | } | 
|  |  | 
|  | int32_t int32Value; | 
|  | int64_t int64Value; | 
|  | C2Value c2Value; | 
|  |  | 
|  | C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type(); | 
|  | size_t fieldExtent = desc.fieldDesc->extent(); | 
|  | switch (fieldType) { | 
|  | case C2FieldDescriptor::INT32: | 
|  | if ((param->second.find(&c2Value) && c2Value.get(&int32Value)) | 
|  | || param->second.find(&int32Value)) { | 
|  | work(name, desc, &int32Value, sizeof(int32Value)); | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::UINT32: | 
|  | if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value)) | 
|  | || param->second.find(&int32Value)) { | 
|  | work(name, desc, &int32Value, sizeof(int32Value)); | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::CNTR32: | 
|  | if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value)) | 
|  | || param->second.find(&int32Value)) { | 
|  | work(name, desc, &int32Value, sizeof(int32Value)); | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::INT64: | 
|  | if ((param->second.find(&c2Value) && c2Value.get(&int64Value)) | 
|  | || param->second.find(&int64Value)) { | 
|  | work(name, desc, &int64Value, sizeof(int64Value)); | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::UINT64: | 
|  | if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value)) | 
|  | || param->second.find(&int64Value)) { | 
|  | work(name, desc, &int64Value, sizeof(int64Value)); | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::CNTR64: | 
|  | if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value)) | 
|  | || param->second.find(&int64Value)) { | 
|  | work(name, desc, &int64Value, sizeof(int64Value)); | 
|  | } | 
|  | break; | 
|  | case C2FieldDescriptor::FLOAT: { | 
|  | float tmp; | 
|  | if (param->second.find(&c2Value) && c2Value.get(&tmp)) { | 
|  | work(name, desc, &tmp, sizeof(tmp)); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case C2FieldDescriptor::STRING: { | 
|  | AString tmp; | 
|  | if (!param->second.find(&tmp)) { | 
|  | break; | 
|  | } | 
|  | if (fieldExtent > 0 && tmp.size() >= fieldExtent) { | 
|  | AString truncated(tmp, 0, fieldExtent - 1); | 
|  | ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"", | 
|  | tmp.c_str(), truncated.c_str()); | 
|  | tmp = truncated; | 
|  | } | 
|  | work(name, desc, tmp.c_str(), tmp.size() + 1); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case C2FieldDescriptor::BLOB: { | 
|  | sp<ABuffer> tmp; | 
|  | if (!param->second.find(&tmp) || tmp == nullptr) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (fieldExtent > 0 && tmp->size() > fieldExtent) { | 
|  | ALOGD("Blob value too long to fit. Truncating."); | 
|  | tmp->setRange(tmp->offset(), fieldExtent); | 
|  | } | 
|  | work(name, desc, tmp->data(), tmp->size()); | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | ALOGD("Unsupported data type for %s", name.c_str()); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ReflectedParamUpdater::Dict | 
|  | ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> ¶ms_) const { | 
|  | std::vector<C2Param*> params; | 
|  | params.resize(params_.size()); | 
|  | std::transform(params_.begin(), params_.end(), params.begin(), | 
|  | [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); }); | 
|  | return getParams(params); | 
|  | } | 
|  |  | 
|  | ReflectedParamUpdater::Dict | 
|  | ReflectedParamUpdater::getParams(const std::vector<C2Param*> ¶ms) const { | 
|  | Dict ret; | 
|  |  | 
|  | // convert vector to map | 
|  | std::map<C2Param::Index, C2Param *> paramsMap; | 
|  | for (C2Param *param : params) { | 
|  | if (param != nullptr && *param) { | 
|  | paramsMap[param->index()] = param; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const std::pair<const std::string, FieldDesc> &kv : mMap) { | 
|  | const std::string &name = kv.first; | 
|  | const FieldDesc &desc = kv.second; | 
|  | if (paramsMap.count(desc.paramDesc->index()) == 0) { | 
|  | continue; | 
|  | } | 
|  | C2Param *param = paramsMap[desc.paramDesc->index()]; | 
|  | Value value; | 
|  |  | 
|  | // handle whole params first | 
|  | if (!desc.fieldDesc) { | 
|  | sp<ABuffer> buf = ABuffer::CreateAsCopy(param, param->size()); | 
|  | value.set(buf); | 
|  | ret.emplace(name, value); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | size_t offset = sizeof(C2Param) + desc.offset | 
|  | + _C2ParamInspector::GetOffset(*desc.fieldDesc); | 
|  | uint8_t *data = (uint8_t *)param + offset; | 
|  | C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type(); | 
|  | switch (fieldType) { | 
|  | case C2FieldDescriptor::STRING: { | 
|  | size_t length = desc.fieldDesc->extent(); | 
|  | if (length == 0) { | 
|  | length = param->size() - offset; | 
|  | } | 
|  |  | 
|  | if (param->size() < length || param->size() - length < offset) { | 
|  | ALOGD("param too small for string: length %zu size %zu offset %zu", | 
|  | length, param->size(), offset); | 
|  | break; | 
|  | } | 
|  | value.set(AString((char *)data, strnlen((char *)data, length))); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case C2FieldDescriptor::BLOB: { | 
|  | size_t length = desc.fieldDesc->extent(); | 
|  | if (length == 0) { | 
|  | length = param->size() - offset; | 
|  | } | 
|  |  | 
|  | if (param->size() < length || param->size() - length < offset) { | 
|  | ALOGD("param too small for blob: length %zu size %zu offset %zu", | 
|  | length, param->size(), offset); | 
|  | break; | 
|  | } | 
|  |  | 
|  | sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length); | 
|  | value.set(buf); | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: { | 
|  | size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType); | 
|  | if (param->size() < valueSize || param->size() - valueSize < offset) { | 
|  | ALOGD("param too small for c2value: size %zu offset %zu", | 
|  | param->size(), offset); | 
|  | break; | 
|  | } | 
|  |  | 
|  | C2Value c2Value; | 
|  | switch (fieldType) { | 
|  | case C2FieldDescriptor::INT32:  c2Value = *((int32_t *)data); break; | 
|  | case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break; | 
|  | case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break; | 
|  | case C2FieldDescriptor::INT64:  c2Value = *((int64_t *)data); break; | 
|  | case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break; | 
|  | case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break; | 
|  | case C2FieldDescriptor::FLOAT:  c2Value = *((float *)data); break; | 
|  | default: | 
|  | ALOGD("Unsupported data type for %s", name.c_str()); | 
|  | continue; | 
|  | } | 
|  | value.set(c2Value); | 
|  | } | 
|  | } | 
|  | ret.emplace(name, value); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void ReflectedParamUpdater::clear() { | 
|  | mMap.clear(); | 
|  | } | 
|  |  | 
|  | }  // namespace android |