/* * 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 #include "eco/ECODataKey.h" #include "eco/ECOUtils.h" namespace aidl { namespace android { namespace media { namespace eco { using namespace ::android; binder_status_t ECOData::readFromParcel(const AParcel* 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(AParcel_readInt32(parcel, &mDataType)); RETURN_STATUS_IF_ERROR(AParcel_readInt64(parcel, &mDataTimeUs)); // Reads the number of items. uint32_t numOfItems = 0; RETURN_STATUS_IF_ERROR(AParcel_readUint32(parcel, &numOfItems)); // Reads the key-value pairs one by one. for (size_t i = 0; i < numOfItems; ++i) { // Reads the name of the key. std::string name; AParcel_readString(parcel, &name, ndk::AParcel_stdStringAllocator); int32_t type; RETURN_STATUS_IF_ERROR(AParcel_readInt32(parcel, &type)); switch (static_cast(type)) { case kTypeInt32: { int32_t value32; RETURN_STATUS_IF_ERROR(AParcel_readInt32(parcel, &value32)); setInt32(name, value32); break; } case kTypeInt64: { int64_t value64; RETURN_STATUS_IF_ERROR(AParcel_readInt64(parcel, &value64)); setInt64(name, value64); break; } case kTypeSize: { int32_t valueSize; RETURN_STATUS_IF_ERROR(AParcel_readInt32(parcel, &valueSize)); setInt32(name, valueSize); break; } case kTypeFloat: { float valueFloat; RETURN_STATUS_IF_ERROR(AParcel_readFloat(parcel, &valueFloat)); setFloat(name, valueFloat); break; } case kTypeDouble: { double valueDouble; RETURN_STATUS_IF_ERROR(AParcel_readDouble(parcel, &valueDouble)); setDouble(name, valueDouble); break; } case kTypeString: { std::string valueString; AParcel_readString(parcel, &valueString, ndk::AParcel_stdStringAllocator); setString(name, valueString); break; } case kTypeInt8: { int8_t value8; RETURN_STATUS_IF_ERROR(AParcel_readByte(parcel, &value8)); setInt8(name, value8); break; } default: { return BAD_TYPE; } } } return NO_ERROR; } binder_status_t ECOData::writeToParcel(AParcel* 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(AParcel_writeInt32(parcel, mDataType)); RETURN_STATUS_IF_ERROR(AParcel_writeInt64(parcel, mDataTimeUs)); // Writes out number of items. RETURN_STATUS_IF_ERROR(AParcel_writeUint32(parcel, 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(AParcel_writeString(parcel, it.first.c_str(), static_cast(it.first.size()))); // Writes out the data type. const ECODataValueType& value = it.second; RETURN_STATUS_IF_ERROR(AParcel_writeInt32(parcel, static_cast(value.index()))); switch (static_cast(value.index())) { case kTypeInt32: RETURN_STATUS_IF_ERROR(AParcel_writeInt32(parcel, std::get(it.second))); break; case kTypeInt64: RETURN_STATUS_IF_ERROR(AParcel_writeInt64(parcel, std::get(it.second))); break; case kTypeSize: RETURN_STATUS_IF_ERROR(AParcel_writeUint32(parcel, std::get(it.second))); break; case kTypeFloat: RETURN_STATUS_IF_ERROR(AParcel_writeFloat(parcel, std::get(it.second))); break; case kTypeDouble: RETURN_STATUS_IF_ERROR(AParcel_writeDouble(parcel, std::get(it.second))); break; case kTypeString: RETURN_STATUS_IF_ERROR(AParcel_writeString( parcel, std::get(it.second).c_str(), static_cast(std::get(it.second).size()))); break; case kTypeInt8: RETURN_STATUS_IF_ERROR(AParcel_writeByte(parcel, 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; } std::string ECOData::toString() const { return debugString(); } } // namespace eco } // namespace media } // namespace android } // namespace aidl