blob: d806eaf6b6b00aaae7b257e229cc7979be0e0978 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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.
*/
#include <platform/KeyValueStoreManager.h>
#include <algorithm>
#include <string.h>
#include "CHIPJNIError.h"
#include "JniReferences.h"
#include "JniTypeWrappers.h"
#include <support/Base64.h>
#include <support/CodeUtils.h>
#include <support/logging/CHIPLogging.h>
namespace chip {
namespace DeviceLayer {
namespace PersistedStorage {
namespace {
constexpr size_t kMaxKvsValueBytes = 1024;
constexpr size_t kMaxKvsValueEncodedChars = BASE64_ENCODED_LEN(kMaxKvsValueBytes) + 1;
} // namespace
KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance;
CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size,
size_t offset)
{
ReturnErrorCodeIf(mEnv == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(mKeyValueStoreManagerClass == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(mGetMethod == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(offset != 0, CHIP_ERROR_INVALID_ARGUMENT);
UtfString javaKey(mEnv, key);
jobject javaValue = mEnv->CallStaticObjectMethod(mKeyValueStoreManagerClass, mGetMethod, javaKey.jniValue());
if (mEnv->ExceptionCheck())
{
ChipLogError(DeviceLayer, "Java exception in KVS::Get");
mEnv->ExceptionDescribe();
return CHIP_JNI_ERROR_EXCEPTION_THROWN;
}
if (javaValue == nullptr)
{
return CHIP_ERROR_KEY_NOT_FOUND;
}
JniUtfString utfValue(mEnv, (jstring) javaValue);
if (strlen(utfValue.c_str()) > kMaxKvsValueEncodedChars)
{
ChipLogError(DeviceLayer, "Unexpected large value received from KVS");
return CHIP_ERROR_NO_MEMORY;
}
uint8_t buffer[kMaxKvsValueBytes];
uint16_t decodedLength = chip::Base64Decode(utfValue.c_str(), strlen(utfValue.c_str()), buffer);
if (decodedLength == UINT16_MAX)
{
ChipLogError(DeviceLayer, "KVS base64 decoding failed");
return CHIP_ERROR_INTEGRITY_CHECK_FAILED;
}
if (read_bytes_size != nullptr)
{
*read_bytes_size = decodedLength;
}
if (value != nullptr)
{
memcpy(value, buffer, std::min<size_t>(value_size, decodedLength));
}
return CHIP_NO_ERROR;
}
CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key)
{
ReturnErrorCodeIf(mEnv == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(mKeyValueStoreManagerClass == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(mDeleteMethod == nullptr, CHIP_ERROR_INCORRECT_STATE);
UtfString javaKey(mEnv, key);
mEnv->CallStaticVoidMethod(mKeyValueStoreManagerClass, mDeleteMethod, javaKey.jniValue());
if (mEnv->ExceptionCheck())
{
ChipLogError(DeviceLayer, "Java exception in KVS::Delete");
mEnv->ExceptionDescribe();
mEnv->ExceptionClear();
return CHIP_JNI_ERROR_EXCEPTION_THROWN;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size)
{
ReturnErrorCodeIf(mEnv == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(mKeyValueStoreManagerClass == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(mSetMethod == nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorCodeIf(value_size > kMaxKvsValueBytes, CHIP_ERROR_INVALID_ARGUMENT);
char base64Buffer[kMaxKvsValueEncodedChars];
size_t length = chip::Base64Encode(static_cast<const uint8_t *>(value), value_size, base64Buffer);
base64Buffer[length] = 0;
UtfString utfKey(mEnv, key);
UtfString utfBase64Value(mEnv, base64Buffer);
mEnv->CallStaticVoidMethod(mKeyValueStoreManagerClass, mSetMethod, utfKey.jniValue(), utfBase64Value.jniValue());
if (mEnv->ExceptionCheck())
{
ChipLogError(DeviceLayer, "Java exception in KVS::Delete");
mEnv->ExceptionDescribe();
mEnv->ExceptionClear();
return CHIP_JNI_ERROR_EXCEPTION_THROWN;
}
return CHIP_NO_ERROR;
}
void KeyValueStoreManagerImpl::InitializeMethodForward(JNIEnv * env)
{
mEnv = env;
CHIP_ERROR err = GetClassRef(env, "chip/devicecontroller/KeyValueStoreManager", mKeyValueStoreManagerClass);
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Failed to get reference to KeyValueStoreManager");
return;
}
mGetMethod = env->GetStaticMethodID(mKeyValueStoreManagerClass, "get", "(Ljava/lang/String;)Ljava/lang/String;");
if (mGetMethod == nullptr)
{
ChipLogError(DeviceLayer, "Failed to access KVS 'get' method");
env->ExceptionClear();
}
mSetMethod = env->GetStaticMethodID(mKeyValueStoreManagerClass, "set", "(Ljava/lang/String;Ljava/lang/String;)V");
if (mSetMethod == nullptr)
{
ChipLogError(DeviceLayer, "Failed to access KVS 'set' method");
env->ExceptionClear();
}
mDeleteMethod = env->GetStaticMethodID(mKeyValueStoreManagerClass, "delete", "(Ljava/lang/String;)V");
if (mDeleteMethod == nullptr)
{
ChipLogError(DeviceLayer, "Failed to access KVS 'delete' method");
env->ExceptionClear();
}
}
} // namespace PersistedStorage
} // namespace DeviceLayer
} // namespace chip