/* * Copyright (C) 2019 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 "ECOData" #include "eco/ECOData.h" #include #include #include #include #include #include "eco/ECODataKey.h" #include "eco/ECOUtils.h" namespace android { namespace media { namespace eco { using namespace ::android; status_t ECOData::readFromParcel(const Parcel* parcel) { if (parcel == nullptr) { ALOGE("readFromParcel failed. Parcel pointer can not be null"); return BAD_VALUE; } // Reads the data type and time. RETURN_STATUS_IF_ERROR(parcel->readInt32(&mDataType)); RETURN_STATUS_IF_ERROR(parcel->readInt64(&mDataTimeUs)); // Reads the number of items. uint32_t numOfItems = 0; RETURN_STATUS_IF_ERROR(parcel->readUint32(&numOfItems)); // Reads the key-value pairs one by one. for (size_t i = 0; i < numOfItems; ++i) { // Reads the name of the key. const char* name = parcel->readCString(); if (name == NULL) { ALOGE("Failed reading name for the key. Parsing aborted."); return NAME_NOT_FOUND; } int32_t type; RETURN_STATUS_IF_ERROR(parcel->readInt32(&type)); switch (static_cast(type)) { case kTypeInt32: { int32_t value32; RETURN_STATUS_IF_ERROR(parcel->readInt32(&value32)); setInt32(std::string(name), value32); break; } case kTypeInt64: { int64_t value64; RETURN_STATUS_IF_ERROR(parcel->readInt64(&value64)); setInt64(std::string(name), value64); break; } case kTypeSize: { int32_t valueSize; RETURN_STATUS_IF_ERROR(parcel->readInt32(&valueSize)); setInt32(std::string(name), valueSize); break; } case kTypeFloat: { float valueFloat; RETURN_STATUS_IF_ERROR(parcel->readFloat(&valueFloat)); setFloat(std::string(name), valueFloat); break; } case kTypeDouble: { double valueDouble; RETURN_STATUS_IF_ERROR(parcel->readDouble(&valueDouble)); setDouble(std::string(name), valueDouble); break; } case kTypeString: { const char* valueStr = parcel->readCString(); if (valueStr == NULL) { ALOGE("Failed reading name for the key. Parsing aborted."); return NAME_NOT_FOUND; } setString(std::string(name), valueStr); break; } case kTypeInt8: { int8_t value8; RETURN_STATUS_IF_ERROR(parcel->readByte(&value8)); setInt8(std::string(name), value8); break; } default: { return BAD_TYPE; } } } return NO_ERROR; } status_t ECOData::writeToParcel(Parcel* parcel) const { if (parcel == nullptr) { ALOGE("writeToParcel failed. Parcel pointer can not be null"); return BAD_VALUE; } // Writes out the data type and time. RETURN_STATUS_IF_ERROR(parcel->writeInt32(mDataType)); RETURN_STATUS_IF_ERROR(parcel->writeInt64(mDataTimeUs)); // Writes out number of items. RETURN_STATUS_IF_ERROR(parcel->writeUint32(int32_t(mKeyValueStore.size()))); // Writes out the key-value pairs one by one. for (const auto& it : mKeyValueStore) { // Writes out the key. RETURN_STATUS_IF_ERROR(parcel->writeCString(it.first.c_str())); // Writes out the data type. const ECODataValueType& value = it.second; RETURN_STATUS_IF_ERROR(parcel->writeInt32(static_cast(value.index()))); switch (static_cast(value.index())) { case kTypeInt32: RETURN_STATUS_IF_ERROR(parcel->writeInt32(std::get(it.second))); break; case kTypeInt64: RETURN_STATUS_IF_ERROR(parcel->writeInt64(std::get(it.second))); break; case kTypeSize: RETURN_STATUS_IF_ERROR(parcel->writeUint32(std::get(it.second))); break; case kTypeFloat: RETURN_STATUS_IF_ERROR(parcel->writeFloat(std::get(it.second))); break; case kTypeDouble: RETURN_STATUS_IF_ERROR(parcel->writeDouble(std::get(it.second))); break; case kTypeString: RETURN_STATUS_IF_ERROR(parcel->writeCString(std::get(it.second).c_str())); break; case kTypeInt8: RETURN_STATUS_IF_ERROR(parcel->writeByte(std::get(it.second))); break; default: return BAD_TYPE; } } return NO_ERROR; } int32_t ECOData::getDataType() const { return mDataType; } int64_t ECOData::getDataTimeUs() const { return mDataTimeUs; } // Inserts a new key into store if the key does not exist yet. Otherwise, this will override the // existing key's value. ECODataStatus ECOData::setString(const std::string& key, const std::string& value) { if (key.empty() || value.empty()) { return ECODataStatus::INVALID_ARGUMENT; } mKeyValueStore[key] = value; // TODO(hkuang): Check the valueType is valid for the key. return ECODataStatus::OK; } ECODataStatus ECOData::findString(const std::string& key, std::string* value) const { if (key.empty()) { return ECODataStatus::INVALID_ARGUMENT; } // Check if the key exists. if (mKeyValueStore.find(key) == mKeyValueStore.end()) { return ECODataStatus::KEY_NOT_EXIST; } // Safely access the value. const std::string& entryValue = std::get(mKeyValueStore.at(key)); value->assign(entryValue); return ECODataStatus::OK; } // Inserts a new key into store if the key does not exist yet. Otherwise, this will override the // existing key's value. template ECODataStatus ECOData::setValue(const std::string& key, T value) { if (key.empty()) { return ECODataStatus::INVALID_ARGUMENT; } mKeyValueStore[key] = value; return ECODataStatus::OK; } template ECODataStatus ECOData::findValue(const std::string& key, T* out) const { if (key.empty() || out == nullptr) { return ECODataStatus::INVALID_ARGUMENT; } if (mKeyValueStore.find(key) == mKeyValueStore.end()) { return ECODataStatus::KEY_NOT_EXIST; } // Safely access the value. *out = std::get(mKeyValueStore.at(key)); return ECODataStatus::OK; } ECODataStatus ECOData::setInt32(const std::string& key, int32_t value) { return setValue(key, value); } ECODataStatus ECOData::findInt32(const std::string& key, int32_t* out) const { return findValue(key, out); } ECODataStatus ECOData::setInt64(const std::string& key, int64_t value) { return setValue(key, value); } ECODataStatus ECOData::findInt64(const std::string& key, int64_t* out) const { return findValue(key, out); } ECODataStatus ECOData::setDouble(const std::string& key, double value) { return setValue(key, value); } ECODataStatus ECOData::findDouble(const std::string& key, double* out) const { return findValue(key, out); } ECODataStatus ECOData::setSize(const std::string& key, size_t value) { return setValue(key, value); } ECODataStatus ECOData::findSize(const std::string& key, size_t* out) const { return findValue(key, out); } ECODataStatus ECOData::setFloat(const std::string& key, float value) { return setValue(key, value); } ECODataStatus ECOData::findFloat(const std::string& key, float* out) const { return findValue(key, out); } ECODataStatus ECOData::setInt8(const std::string& key, int8_t value) { return setValue(key, value); } ECODataStatus ECOData::findInt8(const std::string& key, int8_t* out) const { return findValue(key, out); } ECODataStatus ECOData::set(const std::string& key, const ECOData::ECODataValueType& value) { if (key.empty()) { return ECODataStatus::INVALID_ARGUMENT; } mKeyValueStore[key] = value; return ECODataStatus::OK; } ECODataStatus ECOData::find(const std::string& key, ECOData::ECODataValueType* out) const { if (key.empty() || out == nullptr) { return ECODataStatus::INVALID_ARGUMENT; } if (mKeyValueStore.find(key) == mKeyValueStore.end()) { return ECODataStatus::KEY_NOT_EXIST; } // Safely access the value. *out = mKeyValueStore.at(key); return ECODataStatus::OK; } std::string ECOData::getDataTypeString() const { switch (mDataType) { case DATA_TYPE_UNKNOWN: return "DATA_TYPE_UNKNOWN"; case DATA_TYPE_STATS: return "DATA_TYPE_STATS"; case DATA_TYPE_INFO: return "DATA_TYPE_INFO"; case DATA_TYPE_STATS_PROVIDER_CONFIG: return "DATA_TYPE_STATS_PROVIDER_CONFIG"; case DATA_TYPE_INFO_LISTENER_CONFIG: return "DATA_TYPE_INFO_LISTENER_CONFIG"; } return {}; } // TODO(hkuang): Add test for this. bool ECODataKeyValueIterator::hasNext() { if (mIterator == mKeyValueStore.end()) return false; if (!mBeginReturned) { // mIterator has been initialized to the beginning and // hasn't been returned. Do not advance: mBeginReturned = true; } else { std::advance(mIterator, 1); } return mIterator != mKeyValueStore.end(); } // TODO(hkuang): Add test for this. ECOData::ECODataKeyValuePair ECODataKeyValueIterator::next() const { return ECOData::ECODataKeyValuePair(mIterator->first, mIterator->second); } std::string ECOData::debugString() const { std::string s = "ECOData(type = "; std::string tmp; switch (mDataType) { case DATA_TYPE_UNKNOWN: tmp = "Unknown"; break; case DATA_TYPE_STATS: tmp = "Stats"; break; case DATA_TYPE_INFO: tmp = "Info"; break; case DATA_TYPE_STATS_PROVIDER_CONFIG: tmp = "Stats provider config"; break; case DATA_TYPE_INFO_LISTENER_CONFIG: tmp = "Info listener config"; break; default: break; } s.append(tmp); s.append(") = {\n "); // Writes out the key-value pairs one by one. for (const auto& it : mKeyValueStore) { const size_t SIZE = 100; char keyValue[SIZE]; const ECODataValueType& value = it.second; switch (static_cast(value.index())) { case kTypeInt32: snprintf(keyValue, SIZE, "int32_t %s = %d, ", it.first.c_str(), std::get(it.second)); break; case kTypeInt64: snprintf(keyValue, SIZE, "int64_t %s = %" PRId64 ", ", it.first.c_str(), std::get(it.second)); break; case kTypeSize: snprintf(keyValue, SIZE, "size_t %s = %zu, ", it.first.c_str(), std::get(it.second)); break; case kTypeFloat: snprintf(keyValue, SIZE, "float %s = %f, ", it.first.c_str(), std::get(it.second)); break; case kTypeDouble: snprintf(keyValue, SIZE, "double %s = %f, ", it.first.c_str(), std::get(it.second)); break; case kTypeString: snprintf(keyValue, SIZE, "string %s = %s, ", it.first.c_str(), std::get(it.second).c_str()); break; case kTypeInt8: snprintf(keyValue, SIZE, "int8_t %s = %d, ", it.first.c_str(), std::get(it.second)); break; default: break; } s.append(keyValue); } s.append("\n }"); return s; } } // namespace eco } // namespace media } // namespace android