/* * Copyright (C) 2015 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_TAG "PersistableBundle" #include #include #include #include #include #include using android::BAD_TYPE; using android::BAD_VALUE; using android::NO_ERROR; using android::Parcel; using android::sp; using android::status_t; using android::UNEXPECTED_NULL; enum { // Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java. BUNDLE_MAGIC = 0x4C444E42, }; enum { // Keep in sync with frameworks/base/core/java/android/os/Parcel.java. VAL_STRING = 0, VAL_INTEGER = 1, VAL_LONG = 6, VAL_DOUBLE = 8, VAL_BOOLEAN = 9, VAL_STRINGARRAY = 14, VAL_INTARRAY = 18, VAL_LONGARRAY = 19, VAL_BOOLEANARRAY = 23, VAL_PERSISTABLEBUNDLE = 25, VAL_DOUBLEARRAY = 28, }; namespace { template bool getValue(const android::String16& key, T* out, const std::map& map) { const auto& it = map.find(key); if (it == map.end()) return false; *out = it->second; return true; } } // namespace namespace android { namespace os { #define RETURN_IF_FAILED(calledOnce) \ { \ status_t returnStatus = calledOnce; \ if (returnStatus) { \ ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ return returnStatus; \ } \ } #define RETURN_IF_ENTRY_ERASED(map, key) \ { \ size_t num_erased = map.erase(key); \ if (num_erased) { \ ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ return num_erased; \ } \ } status_t PersistableBundle::writeToParcel(Parcel* parcel) const { /* * Keep implementation in sync with writeToParcelInner() in * frameworks/base/core/java/android/os/BaseBundle.java. */ // Special case for empty bundles. if (empty()) { RETURN_IF_FAILED(parcel->writeInt32(0)); return NO_ERROR; } size_t length_pos = parcel->dataPosition(); RETURN_IF_FAILED(parcel->writeInt32(1)); // dummy, will hold length RETURN_IF_FAILED(parcel->writeInt32(BUNDLE_MAGIC)); size_t start_pos = parcel->dataPosition(); RETURN_IF_FAILED(writeToParcelInner(parcel)); size_t end_pos = parcel->dataPosition(); // Backpatch length. This length value includes the length header. parcel->setDataPosition(length_pos); size_t length = end_pos - start_pos; if (length > std::numeric_limits::max()) { ALOGE("Parcel length (%zu) too large to store in 32-bit signed int", length); return BAD_VALUE; } RETURN_IF_FAILED(parcel->writeInt32(static_cast(length))); parcel->setDataPosition(end_pos); return NO_ERROR; } status_t PersistableBundle::readFromParcel(const Parcel* parcel) { /* * Keep implementation in sync with readFromParcelInner() in * frameworks/base/core/java/android/os/BaseBundle.java. */ int32_t length = parcel->readInt32(); if (length < 0) { ALOGE("Bad length in parcel: %d", length); return UNEXPECTED_NULL; } return readFromParcelInner(parcel, static_cast(length)); } bool PersistableBundle::empty() const { return size() == 0u; } size_t PersistableBundle::size() const { return (mBoolMap.size() + mIntMap.size() + mLongMap.size() + mDoubleMap.size() + mStringMap.size() + mBoolVectorMap.size() + mIntVectorMap.size() + mLongVectorMap.size() + mDoubleVectorMap.size() + mStringVectorMap.size() + mPersistableBundleMap.size()); } size_t PersistableBundle::erase(const String16& key) { RETURN_IF_ENTRY_ERASED(mBoolMap, key); RETURN_IF_ENTRY_ERASED(mIntMap, key); RETURN_IF_ENTRY_ERASED(mLongMap, key); RETURN_IF_ENTRY_ERASED(mDoubleMap, key); RETURN_IF_ENTRY_ERASED(mStringMap, key); RETURN_IF_ENTRY_ERASED(mBoolVectorMap, key); RETURN_IF_ENTRY_ERASED(mIntVectorMap, key); RETURN_IF_ENTRY_ERASED(mLongVectorMap, key); RETURN_IF_ENTRY_ERASED(mDoubleVectorMap, key); RETURN_IF_ENTRY_ERASED(mStringVectorMap, key); return mPersistableBundleMap.erase(key); } void PersistableBundle::putBoolean(const String16& key, bool value) { erase(key); mBoolMap[key] = value; } void PersistableBundle::putInt(const String16& key, int32_t value) { erase(key); mIntMap[key] = value; } void PersistableBundle::putLong(const String16& key, int64_t value) { erase(key); mLongMap[key] = value; } void PersistableBundle::putDouble(const String16& key, double value) { erase(key); mDoubleMap[key] = value; } void PersistableBundle::putString(const String16& key, const String16& value) { erase(key); mStringMap[key] = value; } void PersistableBundle::putBooleanVector(const String16& key, const std::vector& value) { erase(key); mBoolVectorMap[key] = value; } void PersistableBundle::putIntVector(const String16& key, const std::vector& value) { erase(key); mIntVectorMap[key] = value; } void PersistableBundle::putLongVector(const String16& key, const std::vector& value) { erase(key); mLongVectorMap[key] = value; } void PersistableBundle::putDoubleVector(const String16& key, const std::vector& value) { erase(key); mDoubleVectorMap[key] = value; } void PersistableBundle::putStringVector(const String16& key, const std::vector& value) { erase(key); mStringVectorMap[key] = value; } void PersistableBundle::putPersistableBundle(const String16& key, const PersistableBundle& value) { erase(key); mPersistableBundleMap[key] = value; } bool PersistableBundle::getBoolean(const String16& key, bool* out) const { return getValue(key, out, mBoolMap); } bool PersistableBundle::getInt(const String16& key, int32_t* out) const { return getValue(key, out, mIntMap); } bool PersistableBundle::getLong(const String16& key, int64_t* out) const { return getValue(key, out, mLongMap); } bool PersistableBundle::getDouble(const String16& key, double* out) const { return getValue(key, out, mDoubleMap); } bool PersistableBundle::getString(const String16& key, String16* out) const { return getValue(key, out, mStringMap); } bool PersistableBundle::getBooleanVector(const String16& key, std::vector* out) const { return getValue(key, out, mBoolVectorMap); } bool PersistableBundle::getIntVector(const String16& key, std::vector* out) const { return getValue(key, out, mIntVectorMap); } bool PersistableBundle::getLongVector(const String16& key, std::vector* out) const { return getValue(key, out, mLongVectorMap); } bool PersistableBundle::getDoubleVector(const String16& key, std::vector* out) const { return getValue(key, out, mDoubleVectorMap); } bool PersistableBundle::getStringVector(const String16& key, std::vector* out) const { return getValue(key, out, mStringVectorMap); } bool PersistableBundle::getPersistableBundle(const String16& key, PersistableBundle* out) const { return getValue(key, out, mPersistableBundleMap); } status_t PersistableBundle::writeToParcelInner(Parcel* parcel) const { /* * To keep this implementation in sync with writeArrayMapInternal() in * frameworks/base/core/java/android/os/Parcel.java, the number of key * value pairs must be written into the parcel before writing the key-value * pairs themselves. */ size_t num_entries = size(); if (num_entries > std::numeric_limits::max()) { ALOGE("The size of this PersistableBundle (%zu) too large to store in 32-bit signed int", num_entries); return BAD_VALUE; } RETURN_IF_FAILED(parcel->writeInt32(static_cast(num_entries))); for (const auto& key_val_pair : mBoolMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_BOOLEAN)); RETURN_IF_FAILED(parcel->writeBool(key_val_pair.second)); } for (const auto& key_val_pair : mIntMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_INTEGER)); RETURN_IF_FAILED(parcel->writeInt32(key_val_pair.second)); } for (const auto& key_val_pair : mLongMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_LONG)); RETURN_IF_FAILED(parcel->writeInt64(key_val_pair.second)); } for (const auto& key_val_pair : mDoubleMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_DOUBLE)); RETURN_IF_FAILED(parcel->writeDouble(key_val_pair.second)); } for (const auto& key_val_pair : mStringMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_STRING)); RETURN_IF_FAILED(parcel->writeString16(key_val_pair.second)); } for (const auto& key_val_pair : mBoolVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_BOOLEANARRAY)); RETURN_IF_FAILED(parcel->writeBoolVector(key_val_pair.second)); } for (const auto& key_val_pair : mIntVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_INTARRAY)); RETURN_IF_FAILED(parcel->writeInt32Vector(key_val_pair.second)); } for (const auto& key_val_pair : mLongVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_LONGARRAY)); RETURN_IF_FAILED(parcel->writeInt64Vector(key_val_pair.second)); } for (const auto& key_val_pair : mDoubleVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_DOUBLEARRAY)); RETURN_IF_FAILED(parcel->writeDoubleVector(key_val_pair.second)); } for (const auto& key_val_pair : mStringVectorMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_STRINGARRAY)); RETURN_IF_FAILED(parcel->writeString16Vector(key_val_pair.second)); } for (const auto& key_val_pair : mPersistableBundleMap) { RETURN_IF_FAILED(parcel->writeString16(key_val_pair.first)); RETURN_IF_FAILED(parcel->writeInt32(VAL_PERSISTABLEBUNDLE)); RETURN_IF_FAILED(key_val_pair.second.writeToParcel(parcel)); } return NO_ERROR; } status_t PersistableBundle::readFromParcelInner(const Parcel* parcel, size_t length) { /* * Note: we don't actually use length for anything other than an empty PersistableBundle * check, since we do not actually need to copy in an entire Parcel, unlike in the Java * implementation. */ if (length == 0) { // Empty PersistableBundle or end of data. return NO_ERROR; } int32_t magic; RETURN_IF_FAILED(parcel->readInt32(&magic)); if (magic != BUNDLE_MAGIC) { ALOGE("Bad magic number for PersistableBundle: 0x%08x", magic); return BAD_VALUE; } /* * To keep this implementation in sync with unparcel() in * frameworks/base/core/java/android/os/BaseBundle.java, the number of * key-value pairs must be read from the parcel before reading the key-value * pairs themselves. */ int32_t num_entries; RETURN_IF_FAILED(parcel->readInt32(&num_entries)); for (; num_entries > 0; --num_entries) { size_t start_pos = parcel->dataPosition(); String16 key; int32_t value_type; RETURN_IF_FAILED(parcel->readString16(&key)); RETURN_IF_FAILED(parcel->readInt32(&value_type)); /* * We assume that both the C++ and Java APIs ensure that all keys in a PersistableBundle * are unique. */ switch (value_type) { case VAL_STRING: { RETURN_IF_FAILED(parcel->readString16(&mStringMap[key])); break; } case VAL_INTEGER: { RETURN_IF_FAILED(parcel->readInt32(&mIntMap[key])); break; } case VAL_LONG: { RETURN_IF_FAILED(parcel->readInt64(&mLongMap[key])); break; } case VAL_DOUBLE: { RETURN_IF_FAILED(parcel->readDouble(&mDoubleMap[key])); break; } case VAL_BOOLEAN: { RETURN_IF_FAILED(parcel->readBool(&mBoolMap[key])); break; } case VAL_STRINGARRAY: { RETURN_IF_FAILED(parcel->readString16Vector(&mStringVectorMap[key])); break; } case VAL_INTARRAY: { RETURN_IF_FAILED(parcel->readInt32Vector(&mIntVectorMap[key])); break; } case VAL_LONGARRAY: { RETURN_IF_FAILED(parcel->readInt64Vector(&mLongVectorMap[key])); break; } case VAL_BOOLEANARRAY: { RETURN_IF_FAILED(parcel->readBoolVector(&mBoolVectorMap[key])); break; } case VAL_PERSISTABLEBUNDLE: { RETURN_IF_FAILED(mPersistableBundleMap[key].readFromParcel(parcel)); break; } case VAL_DOUBLEARRAY: { RETURN_IF_FAILED(parcel->readDoubleVector(&mDoubleVectorMap[key])); break; } default: { ALOGE("Unrecognized type: %d", value_type); return BAD_TYPE; break; } } } return NO_ERROR; } } // namespace os } // namespace android