diff --git a/native/android/app/src/cpp/CommMMKV.cpp b/native/android/app/src/cpp/CommMMKV.cpp --- a/native/android/app/src/cpp/CommMMKV.cpp +++ b/native/android/app/src/cpp/CommMMKV.cpp @@ -14,6 +14,18 @@ method(cls); } + static void lock() { + static const auto cls = javaClassStatic(); + static auto method = cls->getStaticMethod("lock"); + method(cls); + } + + static void unlock() { + static const auto cls = javaClassStatic(); + static auto method = cls->getStaticMethod("unlock"); + method(cls); + } + static void clearSensitiveData() { static const auto cls = javaClassStatic(); static auto method = cls->getStaticMethod("clearSensitiveData"); @@ -93,6 +105,14 @@ []() { CommMMKVJavaClass::initialize(); }); } +CommMMKV::ScopedCommMMKVLock::ScopedCommMMKVLock() { + NativeAndroidAccessProvider::runTask([]() { CommMMKVJavaClass::lock(); }); +} + +CommMMKV::ScopedCommMMKVLock::~ScopedCommMMKVLock() { + NativeAndroidAccessProvider::runTask([]() { CommMMKVJavaClass::unlock(); }); +} + void CommMMKV::clearSensitiveData() { NativeAndroidAccessProvider::runTask( []() { CommMMKVJavaClass::clearSensitiveData(); }); diff --git a/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java b/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java --- a/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java +++ b/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java @@ -75,6 +75,15 @@ } } + public static void lock() { + initialize(); + getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey).lock(); + } + + public static void unlock() { + getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey).unlock(); + } + public static void clearSensitiveData() { initialize(); synchronized (mmkvEncryptionKey) { diff --git a/native/cpp/CommonCpp/Tools/CommMMKV.h b/native/cpp/CommonCpp/Tools/CommMMKV.h --- a/native/cpp/CommonCpp/Tools/CommMMKV.h +++ b/native/cpp/CommonCpp/Tools/CommMMKV.h @@ -31,5 +31,11 @@ public: using std::runtime_error::runtime_error; }; + + class ScopedCommMMKVLock { + public: + ScopedCommMMKVLock(); + ~ScopedCommMMKVLock(); + }; }; } // namespace comm diff --git a/native/ios/Comm/CommMMKV.mm b/native/ios/Comm/CommMMKV.mm --- a/native/ios/Comm/CommMMKV.mm +++ b/native/ios/Comm/CommMMKV.mm @@ -6,6 +6,18 @@ #import #import +#import + +// Core MMKV C++ implementation and Android wrapper have public `lock` and +// `unlock` methods while Obj-C wrapper doesn't. However Obj-C wrapper has +// private instance variable of type `mmkv::MMKV *`. Interface redeclaration +// below lets us access it. This pattern is hacky but it is well known in +// Obj-C and used in our codebase in CommSecureStore. +@interface MMKV () { +@public + mmkv::MMKV *m_mmkv; +} +@end namespace comm { @@ -29,6 +41,17 @@ return mmkv; } +CommMMKV::ScopedCommMMKVLock::ScopedCommMMKVLock() { + CommMMKV::initialize(); + MMKV *mmkv = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey); + mmkv->m_mmkv->lock(); +} + +CommMMKV::ScopedCommMMKVLock::~ScopedCommMMKVLock() { + MMKV *mmkv = getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey); + mmkv->m_mmkv->unlock(); +} + void assignInitializationData() { std::string encryptionKey = crypto::Tools::generateRandomString(mmkvEncryptionKeySize);