/* * * Copyright (c) 2020-2021 Project CHIP Authors * All rights reserved. * * 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. */ /** * @file * Platform-specific implementation of KVS for android. */ #include #include #include #include #include #include #include #include namespace chip { namespace DeviceLayer { namespace PersistedStorage { namespace { constexpr size_t kMaxKvsValueBytes = 4096; constexpr size_t kMaxKvsValueEncodedChars = BASE64_ENCODED_LEN(kMaxKvsValueBytes) + 1; } // namespace KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; void KeyValueStoreManagerImpl::InitializeWithObject(jobject manager) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(DeviceLayer, "Failed to GetEnvForCurrentThread for KeyValueStoreManagerImpl")); VerifyOrReturn(mKeyValueStoreManagerObject.Init(manager) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to Init KeyValueStoreManager")); jclass KeyValueStoreManagerClass = env->GetObjectClass(manager); VerifyOrReturn(KeyValueStoreManagerClass != nullptr, ChipLogError(DeviceLayer, "Failed to get KeyValueStoreManager Java class")); mGetMethod = env->GetMethodID(KeyValueStoreManagerClass, "get", "(Ljava/lang/String;)Ljava/lang/String;"); if (mGetMethod == nullptr) { ChipLogError(DeviceLayer, "Failed to access KeyValueStoreManager 'get' method"); env->ExceptionClear(); } mSetMethod = env->GetMethodID(KeyValueStoreManagerClass, "set", "(Ljava/lang/String;Ljava/lang/String;)V"); if (mSetMethod == nullptr) { ChipLogError(DeviceLayer, "Failed to access KeyValueStoreManager 'set' method"); env->ExceptionClear(); } mDeleteMethod = env->GetMethodID(KeyValueStoreManagerClass, "delete", "(Ljava/lang/String;)V"); if (mDeleteMethod == nullptr) { ChipLogError(DeviceLayer, "Failed to access KeyValueStoreManager 'delete' method"); env->ExceptionClear(); } } CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, size_t offset_bytes) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrReturnError(mKeyValueStoreManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mGetMethod != nullptr, CHIP_ERROR_INCORRECT_STATE); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); chip::UtfString javaKey(env, key); jobject javaValue = env->CallObjectMethod(mKeyValueStoreManagerObject.ObjectRef(), mGetMethod, javaKey.jniValue()); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in KeyValueStoreManager::Get"); env->ExceptionDescribe(); env->ExceptionClear(); return CHIP_JNI_ERROR_EXCEPTION_THROWN; } if (javaValue == nullptr) { return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; } chip::JniUtfString utfValue(env, (jstring) javaValue); const size_t utfValueLen = strlen(utfValue.c_str()); if (utfValueLen > kMaxKvsValueEncodedChars) { ChipLogError(DeviceLayer, "Unexpected large value received from KeyValueStoreManager"); return CHIP_ERROR_NO_MEMORY; } std::unique_ptr buffer(new uint8_t[BASE64_MAX_DECODED_LEN(utfValueLen)]); uint16_t decodedLength = chip::Base64Decode(utfValue.c_str(), utfValueLen, buffer.get()); if (decodedLength == UINT16_MAX) { ChipLogError(DeviceLayer, "KeyValueStoreManager base64 decoding failed"); return CHIP_ERROR_INTEGRITY_CHECK_FAILED; } VerifyOrReturnError(offset_bytes == 0 || offset_bytes < decodedLength, CHIP_ERROR_INVALID_ARGUMENT); size_t read_size = std::min(value_size, decodedLength - offset_bytes); if (value_size + offset_bytes < decodedLength) { err = CHIP_ERROR_BUFFER_TOO_SMALL; } if (read_bytes_size != nullptr) { *read_bytes_size = read_size; } if (value != nullptr) { memcpy(value, buffer.get() + offset_bytes, read_size); } return err; } CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size) { VerifyOrReturnError(mKeyValueStoreManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mSetMethod != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(value_size <= kMaxKvsValueBytes, CHIP_ERROR_INVALID_ARGUMENT); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_ERROR_INTERNAL); std::unique_ptr buffer(new char[BASE64_ENCODED_LEN(value_size) + 1]); size_t length = chip::Base64Encode(static_cast(value), value_size, buffer.get()); buffer.get()[length] = 0; UtfString utfKey(env, key); UtfString utfBase64Value(env, buffer.get()); env->CallVoidMethod(mKeyValueStoreManagerObject.ObjectRef(), mSetMethod, utfKey.jniValue(), utfBase64Value.jniValue()); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in KeyValueStoreManager::Put"); env->ExceptionDescribe(); env->ExceptionClear(); return CHIP_JNI_ERROR_EXCEPTION_THROWN; } return CHIP_NO_ERROR; } CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) { VerifyOrReturnError(mKeyValueStoreManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mDeleteMethod != nullptr, CHIP_ERROR_INCORRECT_STATE); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_ERROR_INTERNAL); UtfString javaKey(env, key); env->CallVoidMethod(mKeyValueStoreManagerObject.ObjectRef(), mDeleteMethod, javaKey.jniValue()); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in KeyValueStoreManager::Delete"); env->ExceptionDescribe(); env->ExceptionClear(); return CHIP_JNI_ERROR_EXCEPTION_THROWN; } return CHIP_NO_ERROR; } } // namespace PersistedStorage } // namespace DeviceLayer } // namespace chip