diff --git a/Android/MMKV/gradle.properties b/Android/MMKV/gradle.properties index 30da076e..3238487e 100644 --- a/Android/MMKV/gradle.properties +++ b/Android/MMKV/gradle.properties @@ -14,7 +14,7 @@ org.gradle.jvmargs=-Xmx1536m # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -VERSION_NAME_PREFIX=2.0.1 +VERSION_NAME_PREFIX=2.0.2 #VERSION_NAME_SUFFIX=-SNAPSHOT VERSION_NAME_SUFFIX= diff --git a/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKV.java b/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKV.java index 14b85e93..45e44114 100644 --- a/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKV.java +++ b/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKV.java @@ -190,6 +190,9 @@ public static String initialize(Context context, String rootDir, LibLoader loade } public static String initialize(@NonNull Context context, String rootDir, LibLoader loader, MMKVLogLevel logLevel, MMKVHandler handler) { + if (!android.os.Process.is64Bit()) { + throw new UnsupportedArchitectureException("MMKV 2.0+ requires 64-bit App, use 1.3.x instead."); + } // disable process mode in release build // FIXME: Find a better way to getApplicationInfo() without using context. // If any one knows how, you're welcome to make a contribution. diff --git a/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/UnsupportedArchitectureException.java b/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/UnsupportedArchitectureException.java new file mode 100644 index 00000000..2ae95eac --- /dev/null +++ b/Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/UnsupportedArchitectureException.java @@ -0,0 +1,27 @@ +/* + * Tencent is pleased to support the open source community by making + * MMKV available. + * + * Copyright (C) 2018 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ + +package com.tencent.mmkv; + +public class UnsupportedArchitectureException extends RuntimeException { + public UnsupportedArchitectureException(String message) { + super(message); + } +} diff --git a/Android/MMKV/mmkvdemo/build.gradle b/Android/MMKV/mmkvdemo/build.gradle index 4df3aa16..77c93af6 100644 --- a/Android/MMKV/mmkvdemo/build.gradle +++ b/Android/MMKV/mmkvdemo/build.gradle @@ -77,9 +77,9 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':mmkv') -// implementation 'com.tencent:mmkv:2.0.1' -// implementation 'com.tencent:mmkv-static:2.0.1' // this is identical to 'com.tencent:mmkv' -// implementation 'com.tencent:mmkv-shared:2.0.1' +// implementation 'com.tencent:mmkv:2.0.2' +// implementation 'com.tencent:mmkv-static:2.0.2' // this is identical to 'com.tencent:mmkv' +// implementation 'com.tencent:mmkv-shared:2.0.2' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' testImplementation 'junit:junit:4.13.2' diff --git a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/MainActivity.java b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/MainActivity.java index 859ab889..118a4948 100644 --- a/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/MainActivity.java +++ b/Android/MMKV/mmkvdemo/src/main/java/com/tencent/mmkvdemo/MainActivity.java @@ -105,6 +105,10 @@ public void onClick(View v) { kv.checkContentChangedByOuterProcess(); kv.close(); + // prepare for backup customize root path + kv = testMMKV("test_backup", "MMKV Backup", false, otherDir); + kv.close(); + testAshmem(); testReKey(); @@ -564,6 +568,15 @@ private void testBackup() { Log.i("MMKV", "check on backup file[" + mmkv.mmapID() + "] allKeys: " + Arrays.toString(mmkv.allKeys())); } + // test backup a normal mmkv from custom root path + mmapID = "test_backup"; + ret = MMKV.backupOneToDirectory(mmapID, backupRootDir, otherDir); + Log.i("MMKV", "backup one [" + mmapID + "] ret = " + ret); + if (ret) { + MMKV mmkv = MMKV.backedUpMMKVWithID(mmapID, MMKV.SINGLE_PROCESS_MODE, "MMKV Backup", backupRootDir); + Log.i("MMKV", "check on backup file[" + mmkv.mmapID() + "] allKeys: " + Arrays.toString(mmkv.allKeys())); + } + /*{ MMKV mmkv = MMKV.mmkvWithID("imported"); mmkv.close(); @@ -603,6 +616,17 @@ private void testRestore() { Log.i("MMKV", "after restore [" + mmkv.mmapID() + "] allKeys: " + Arrays.toString(mmkv.allKeys())); } + // test backup a normal mmkv from custom root path + mmapID = "test_backup"; + mmkv = MMKV.mmkvWithID(mmapID, MMKV.SINGLE_PROCESS_MODE, "MMKV Backup", otherDir); + mmkv.encode("test_restore", 1024); + Log.i("MMKV", "before restore [" + mmkv.mmapID() + "] allKeys: " + Arrays.toString(mmkv.allKeys())); + ret = MMKV.restoreOneMMKVFromDirectory(mmapID, backupRootDir, otherDir); + Log.i("MMKV", "backup one [" + mmapID + "] ret = " + ret); + if (ret) { + Log.i("MMKV", "check on backup file[" + mmkv.mmapID() + "] allKeys: " + Arrays.toString(mmkv.allKeys())); + } + /*{ mmkv = MMKV.mmkvWithID("imported"); mmkv.close(); diff --git a/CHANGELOG.md b/CHANGELOG.md index cd89fb83..2df3cee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,22 @@ # MMKV Change Log +## v2.0.2 / 2024-12-27 +Mary holiday and a happy new year! +### Changes for All platforms +* Fix a bug that MMKV might fail to backup/restore across different filesystems. +* Add protection from invalid value size of auto-key-expire mmkv. + +### Android +* If the running App is 32-bit only, warn about it (by throwing `UnsupportedArchitectureException`) before trying to load native lib. +* Add forward support for the correct filename with a custom root path. + +### HarmonyOS NEXT +* Obfuscation fully supported. +* Use atomic file rename on OHOS. +* Add forward support for the correct filename with a custom root path. + +### Win32 +* Only `mmap()` on `ftruncate()`/`zeroFillFile()` failure iff we have a valid file mapping before. + ## v2.0.1 / 2024-11-12 **This is a hotfix release.** ### Changes for All platforms diff --git a/Core/MMKV.cpp b/Core/MMKV.cpp index ccc730f4..62e0b525 100644 --- a/Core/MMKV.cpp +++ b/Core/MMKV.cpp @@ -343,11 +343,7 @@ void MMKV::close() { SCOPED_LOCK(g_instanceLock); m_lock->lock(); -#ifndef MMKV_ANDROID auto itr = g_instanceDic->find(m_mmapKey); -#else - auto itr = g_instanceDic->find(m_mmapID); -#endif if (itr != g_instanceDic->end()) { g_instanceDic->erase(itr); } @@ -1308,8 +1304,14 @@ bool MMKV::backupOneToDirectory(const string &mmapID, const MMKVPath_t &dstDir, auto dstPath = dstDir + MMKV_PATH_SLASH + encodePath; auto mmapKey = mmapedKVKey(mmapID, rootPath); #ifdef MMKV_ANDROID - // historically Android mistakenly use mmapKey as mmapID - auto srcPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath); + string srcPath; + auto correctPath = *rootPath + MMKV_PATH_SLASH + encodePath; + if (srcDir && isFileExist(correctPath)) { + srcPath = correctPath; + } else { + // historically Android mistakenly use mmapKey as mmapID + srcPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath); + } #else auto srcPath = *rootPath + MMKV_PATH_SLASH + encodePath; #endif @@ -1491,8 +1493,14 @@ bool MMKV::restoreOneFromDirectory(const string &mmapID, const MMKVPath_t &srcDi auto srcPath = srcDir + MMKV_PATH_SLASH + encodePath; auto mmapKey = mmapedKVKey(mmapID, rootPath); #ifdef MMKV_ANDROID - // historically Android mistakenly use mmapKey as mmapID - auto dstPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath); + string dstPath; + auto correctPath = *rootPath + MMKV_PATH_SLASH + encodePath; + if (dstDir && isFileExist(correctPath)) { + dstPath = correctPath; + } else { + // historically Android mistakenly use mmapKey as mmapID + dstPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath); + } #else auto dstPath = *rootPath + MMKV_PATH_SLASH + encodePath; #endif diff --git a/Core/MMKV.h b/Core/MMKV.h index c031fec8..68ac866e 100644 --- a/Core/MMKV.h +++ b/Core/MMKV.h @@ -95,20 +95,20 @@ concept MMKV_SUPPORTED_VALUE_TYPE = MMKV_SUPPORTED_PRIMITIVE_VALUE_TYPE || MM class MMKV { #ifndef MMKV_ANDROID - std::string m_mmapKey; MMKV(const std::string &mmapID, MMKVMode mode, std::string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity = 0); #else // defined(MMKV_ANDROID) mmkv::FileLock *m_fileModeLock; mmkv::InterProcessLock *m_sharedProcessModeLock; mmkv::InterProcessLock *m_exclusiveProcessModeLock; - MMKV(const std::string &mmapID, int size, MMKVMode mode, std::string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity = 0); + MMKV(const std::string &mmapID, int size, MMKVMode mode, const std::string *cryptKey, const MMKVPath_t *rootPath, size_t expectedCapacity = 0); - MMKV(const std::string &mmapID, int ashmemFD, int ashmemMetaFd, std::string *cryptKey = nullptr); + MMKV(const std::string &mmapID, int ashmemFD, int ashmemMetaFd, const std::string *cryptKey = nullptr); #endif ~MMKV(); + std::string m_mmapKey; std::string m_mmapID; const MMKVMode m_mode; MMKVPath_t m_path; @@ -226,7 +226,7 @@ class MMKV { void notifyContentChanged(); #if defined(MMKV_ANDROID) && !defined(MMKV_DISABLE_CRYPT) - void checkReSetCryptKey(int fd, int metaFD, std::string *cryptKey); + void checkReSetCryptKey(int fd, int metaFD, const std::string *cryptKey); #endif static bool backupOneToDirectory(const std::string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath); static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir); @@ -270,11 +270,11 @@ class MMKV { static MMKV *mmkvWithID(const std::string &mmapID, int size = mmkv::DEFAULT_MMAP_SIZE, MMKVMode mode = MMKV_SINGLE_PROCESS, - std::string *cryptKey = nullptr, - MMKVPath_t *rootPath = nullptr, + const std::string *cryptKey = nullptr, + const MMKVPath_t *rootPath = nullptr, size_t expectedCapacity = 0); - static MMKV *mmkvWithAshmemFD(const std::string &mmapID, int fd, int metaFD, std::string *cryptKey = nullptr); + static MMKV *mmkvWithAshmemFD(const std::string &mmapID, int fd, int metaFD, const std::string *cryptKey = nullptr); int ashmemFD(); @@ -591,5 +591,5 @@ bool MMKV::getVector(MMKVKey_t key, T &result) { MMKV_NAMESPACE_END -#endif +#endif // __cplusplus #endif // MMKV_MMKV_H diff --git a/Core/MMKVPredef.h b/Core/MMKVPredef.h index e9b0acf1..ab9cd95e 100755 --- a/Core/MMKVPredef.h +++ b/Core/MMKVPredef.h @@ -34,7 +34,7 @@ #include #include -constexpr auto MMKV_VERSION = "v2.0.1"; +constexpr auto MMKV_VERSION = "v2.0.2"; #ifdef DEBUG # define MMKV_DEBUG diff --git a/Core/MMKV_Android.cpp b/Core/MMKV_Android.cpp index 344a6a5c..905d86ec 100644 --- a/Core/MMKV_Android.cpp +++ b/Core/MMKV_Android.cpp @@ -39,8 +39,8 @@ using namespace mmkv; extern unordered_map *g_instanceDic; extern ThreadLock *g_instanceLock; -MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath, size_t expectedCapacity) - : m_mmapID((mode & MMKV_BACKUP) ? mmapID : mmapedKVKey(mmapID, rootPath)) // historically Android mistakenly use mmapKey as mmapID +MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, const string *cryptKey, const string *rootPath, size_t expectedCapacity) + : m_mmapID(mmapID) , m_mode(mode) , m_path(mappedKVPathWithID(m_mmapID, mode, rootPath)) , m_crcPath(crcPathWithID(m_mmapID, mode, rootPath)) @@ -88,7 +88,7 @@ MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, stri }*/ } -MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKey) +MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, const string *cryptKey) : m_mmapID(mmapID) , m_mode(MMKV_ASHMEM) , m_path(mappedKVPathWithID(m_mmapID, MMKV_ASHMEM, nullptr)) @@ -137,7 +137,7 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe }*/ } -MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath, size_t expectedCapacity) { +MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, const string *cryptKey, const string *rootPath, size_t expectedCapacity) { if (mmapID.empty() || !g_instanceLock) { return nullptr; } @@ -157,12 +157,23 @@ MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cr } MMKVInfo("prepare to load %s (id %s) from rootPath %s", mmapID.c_str(), mmapKey.c_str(), rootPath->c_str()); } - auto kv = new MMKV(mmapID, size, mode, cryptKey, rootPath, expectedCapacity); + + string realID; + auto correctPath = mappedKVPathWithID(mmapID, mode, rootPath); + if ((mode & MMKV_BACKUP) || (rootPath && isFileExist(correctPath))) { + // it's successfully migrated to the correct path by newer version of MMKV + realID = mmapID; + } else { + // historically Android mistakenly use mmapKey as mmapID + realID = mmapKey; + } + auto kv = new MMKV(realID, size, mode, cryptKey, rootPath, expectedCapacity); + kv->m_mmapKey = mmapKey; (*g_instanceDic)[mmapKey] = kv; return kv; } -MMKV *MMKV::mmkvWithAshmemFD(const string &mmapID, int fd, int metaFD, string *cryptKey) { +MMKV *MMKV::mmkvWithAshmemFD(const string &mmapID, int fd, int metaFD, const string *cryptKey) { if (fd < 0 || !g_instanceLock) { return nullptr; @@ -178,6 +189,7 @@ MMKV *MMKV::mmkvWithAshmemFD(const string &mmapID, int fd, int metaFD, string *c return kv; } auto kv = new MMKV(mmapID, fd, metaFD, cryptKey); + kv->m_mmapKey = mmapID; (*g_instanceDic)[mmapID] = kv; return kv; } @@ -191,7 +203,7 @@ int MMKV::ashmemMetaFD() { } # ifndef MMKV_DISABLE_CRYPT -void MMKV::checkReSetCryptKey(int fd, int metaFD, string *cryptKey) { +void MMKV::checkReSetCryptKey(int fd, int metaFD, const string *cryptKey) { SCOPED_LOCK(m_lock); checkReSetCryptKey(cryptKey); diff --git a/Core/MMKV_IO.cpp b/Core/MMKV_IO.cpp index bb1f302a..d347624a 100755 --- a/Core/MMKV_IO.cpp +++ b/Core/MMKV_IO.cpp @@ -1549,7 +1549,15 @@ bool MMKV::removeStorage(const std::string &mmapID, MMKVPath_t *relatePath) { } auto mmapKey = mmapedKVKey(mmapID, relatePath); #ifdef MMKV_ANDROID - auto &realID = mmapKey; // historically Android mistakenly use mmapKey as mmapID + std::string realID; + auto correctPath = mappedKVPathWithID(mmapID, MMKV_SINGLE_PROCESS, relatePath); + if (relatePath && isFileExist(correctPath)) { + // it's successfully migrated to the correct path by newer version of MMKV + realID = mmapID; + } else { + // historically Android mistakenly use mmapKey as mmapID + realID = mmapKey; + } #else auto &realID = mmapID; #endif @@ -1731,6 +1739,14 @@ bool MMKV::disableAutoKeyExpire() { MMKVVector vec; auto packKeyValue = [&](const MMKVKey_t &key, const MMBuffer &value) { assert(value.length() >= Fixed32Size); + if (value.length() < Fixed32Size) { +#ifdef MMKV_APPLE + MMKVWarning("key [%@] has invalid value size %u", key, value.length()); +#else + MMKVWarning("key [%s] has invalid value size %u", key.data(), value.length()); +#endif + return; + } MMBuffer data(value.length() - Fixed32Size); auto ptr = (uint8_t *) data.getPtr(); memcpy(ptr, value.getPtr(), value.length() - Fixed32Size); @@ -1771,6 +1787,13 @@ uint32_t MMKV::getExpireTimeForKey(MMKVKey_t key) { auto raw = getRawDataForKey(key); assert(raw.length() == 0 || raw.length() >= Fixed32Size); if (raw.length() < Fixed32Size) { + if (raw.length() != 0) { +#ifdef MMKV_APPLE + MMKVWarning("key [%@] has invalid value size %u", key, raw.length()); +#else + MMKVWarning("key [%s] has invalid value size %u", key.data(), raw.length()); +#endif + } return 0; } auto ptr = (const uint8_t *) raw.getPtr() + raw.length() - Fixed32Size; @@ -1786,6 +1809,13 @@ mmkv::MMBuffer MMKV::getDataWithoutMTimeForKey(MMKVKey_t key) { auto raw = getRawDataForKey(key); assert(raw.length() == 0 || raw.length() >= Fixed32Size); if (raw.length() < Fixed32Size) { + if (raw.length() != 0) { +#ifdef MMKV_APPLE + MMKVWarning("key [%@] has invalid value size %u", key, raw.length()); +#else + MMKVWarning("key [%s] has invalid value size %u", key.data(), raw.length()); +#endif + } return raw; } auto newLength = raw.length() - Fixed32Size; @@ -1824,6 +1854,15 @@ size_t MMKV::filterExpiredKeys() { for (auto itr = m_dicCrypt->begin(); itr != m_dicCrypt->end(); NOOP) { auto &kvHolder = itr->second; assert(kvHolder.realValueSize() >= Fixed32Size); + if (kvHolder.realValueSize() < Fixed32Size) { +#ifdef MMKV_APPLE + MMKVWarning("key [%@] has invalid value size %u", itr->first, kvHolder.realValueSize()); +#else + MMKVWarning("key [%s] has invalid value size %u", itr->first.c_str(), kvHolder.realValueSize()); +#endif + itr++; + continue; + } auto buffer = kvHolder.toMMBuffer(basePtr, m_crypter); auto ptr = (uint8_t *) buffer.getPtr(); ptr += buffer.length() - Fixed32Size; @@ -1848,6 +1887,15 @@ size_t MMKV::filterExpiredKeys() { for (auto itr = m_dic->begin(); itr != m_dic->end(); NOOP) { auto &kvHolder = itr->second; assert(kvHolder.valueSize >= Fixed32Size); + if (kvHolder.valueSize < Fixed32Size) { +#ifdef MMKV_APPLE + MMKVWarning("key [%@] has invalid value size %u", itr->first, kvHolder.valueSize); +#else + MMKVWarning("key [%s] has invalid value size %u", itr->first.c_str(), kvHolder.valueSize); +#endif + itr++; + continue; + } auto ptr = basePtr + kvHolder.offset + kvHolder.computedKVSize; ptr += kvHolder.valueSize - Fixed32Size; auto time = *(const uint32_t *) ptr; diff --git a/Core/MemoryFile.cpp b/Core/MemoryFile.cpp index 2e705e6a..808da7dc 100644 --- a/Core/MemoryFile.cpp +++ b/Core/MemoryFile.cpp @@ -520,6 +520,13 @@ bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { if (copyFileContent(srcPath, tmpFD, false)) { MMKVInfo("copyfile [%s] to [%s]", srcPath.c_str(), tmpPath.c_str()); renamed = tryAtomicRename(tmpPath, dstPath); + if (!renamed) { + MMKVInfo("rename fail, try copy file content instead."); + if (copyFileContent(tmpPath, dstPath)) { + renamed = true; + ::unlink(tmpPath.c_str()); + } + } if (renamed) { MMKVInfo("copyfile [%s] to [%s] finish.", srcPath.c_str(), dstPath.c_str()); } diff --git a/Core/MemoryFile_Linux.cpp b/Core/MemoryFile_Linux.cpp index 843b41a2..d9254216 100644 --- a/Core/MemoryFile_Linux.cpp +++ b/Core/MemoryFile_Linux.cpp @@ -54,7 +54,7 @@ bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { bool renamed = false; // try renameat2() first -#if defined(SYS_renameat2) && !defined(MMKV_OHOS) +#if defined(SYS_renameat2) #ifdef MMKV_ANDROID static auto g_renameat2 = (renameat2_t) dlsym(RTLD_DEFAULT, "renameat2"); if (g_renameat2) { @@ -72,7 +72,11 @@ bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { MMKVWarning("fail on syscall(SYS_renameat2) [%s] to [%s], %d(%s)", srcPath.c_str(), dstPath.c_str(), errno, strerror(errno)); } -#endif // SYS_renameat2 && !MMKV_OHOS + + if (renamed && (srcPath != dstPath)) { + ::unlink(srcPath.c_str()); + } +#endif // SYS_renameat2 if (!renamed) { if (::rename(srcPath.c_str(), dstPath.c_str()) != 0) { @@ -81,7 +85,6 @@ bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { } } - ::unlink(srcPath.c_str()); return true; } diff --git a/Core/MemoryFile_OSX.cpp b/Core/MemoryFile_OSX.cpp index fa65b0e7..21d56e38 100644 --- a/Core/MemoryFile_OSX.cpp +++ b/Core/MemoryFile_OSX.cpp @@ -58,6 +58,9 @@ void tryResetFileProtection(const string &path) { namespace mmkv { bool tryAtomicRename(const char *src, const char *dst) { + if (!src || !dst) { + return false; + } bool renamed = false; // try atomic swap first @@ -65,6 +68,9 @@ bool tryAtomicRename(const char *src, const char *dst) { // renameat2() equivalent if (renamex_np(src, dst, RENAME_SWAP) == 0) { renamed = true; + if (strcmp(src, dst) != 0) { + ::unlink(src); + } } else if (errno != ENOENT) { MMKVError("fail to renamex_np %s to %s, %s", src, dst, strerror(errno)); } @@ -78,8 +84,6 @@ bool tryAtomicRename(const char *src, const char *dst) { } } - ::unlink(src); - return true; } @@ -97,8 +101,12 @@ bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { MMKVInfo("copyfile [%s] to [%s] finish.", srcPath.c_str(), dstPath.c_str()); return true; } + + MMKVInfo("rename fail, try copy file content instead."); + auto ret = copyFileContent(tmpFile.UTF8String, dstPath); + unlink(tmpFile.UTF8String); - return false; + return ret; } bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) { diff --git a/Core/MemoryFile_Win32.cpp b/Core/MemoryFile_Win32.cpp index 8bec794b..7ada2d87 100755 --- a/Core/MemoryFile_Win32.cpp +++ b/Core/MemoryFile_Win32.cpp @@ -122,7 +122,11 @@ bool MemoryFile::truncate(size_t size) { m_size = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE; } + // Win32 won't ftruncate a file if there's active file mmapping/handle, we have to unmmap/close ahead + bool needMMapOnFailure = false; if (m_ptr) { + // if we have a valid file mapping before, we should restore it regardless + needMMapOnFailure = true; if (!UnmapViewOfFile(m_ptr)) { MMKVError("fail to munmap [%ls], %d", m_diskFile.m_path.c_str(), GetLastError()); } @@ -136,14 +140,18 @@ bool MemoryFile::truncate(size_t size) { if (!ftruncate(m_diskFile.getFd(), m_size)) { MMKVError("fail to truncate [%ls] to size %zu", m_diskFile.m_path.c_str(), m_size); m_size = oldSize; - mmap(); + if (needMMapOnFailure) { + mmap(); + } return false; } if (m_size > oldSize) { if (!zeroFillFile(m_diskFile.getFd(), oldSize, m_size - oldSize)) { MMKVError("fail to zeroFile [%ls] to size %zu", m_diskFile.m_path.c_str(), m_size); m_size = oldSize; - mmap(); + if (needMMapOnFailure) { + mmap(); + } return false; } } diff --git a/OpenHarmony/MMKV/BuildProfile.ets b/OpenHarmony/MMKV/BuildProfile.ets index 96577cf1..b82de3d4 100644 --- a/OpenHarmony/MMKV/BuildProfile.ets +++ b/OpenHarmony/MMKV/BuildProfile.ets @@ -2,8 +2,8 @@ * Use these variables when you tailor your ArkTS code. They must be of the const type. */ export const HAR_VERSION = '2.0.1'; -export const BUILD_MODE_NAME = 'release'; -export const DEBUG = false; +export const BUILD_MODE_NAME = 'debug'; +export const DEBUG = true; export const TARGET_NAME = 'default'; /** diff --git a/OpenHarmony/MMKV/CHANGELOG.md b/OpenHarmony/MMKV/CHANGELOG.md index 3e6080e8..7415c634 100644 --- a/OpenHarmony/MMKV/CHANGELOG.md +++ b/OpenHarmony/MMKV/CHANGELOG.md @@ -1,4 +1,9 @@ # MMKV for HarmonyOS NEXT Change Log +## v2.0.2 / 2024-12-27 +* Obfuscation fully supported. +* Use atomic file rename on OHOS. +* Add forward support for the correct filename with a custom root path. + ## v2.0.1 / 2024-11-12 * Fix a bug that MMKV might become dead-locked for other threads after `decodeStringSet()` / `decodeNumberSet` / `decodeBoolSet` or decoding `TypedArray`. diff --git a/OpenHarmony/MMKV/README.md b/OpenHarmony/MMKV/README.md index e037e334..a80202a0 100644 --- a/OpenHarmony/MMKV/README.md +++ b/OpenHarmony/MMKV/README.md @@ -1,6 +1,6 @@ [![license](https://img.shields.io/badge/license-BSD_3-brightgreen.svg?style=flat)](https://github.com/Tencent/MMKV/blob/master/LICENSE.TXT) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/MMKV/pulls) -[![Release Version](https://img.shields.io/badge/release-2.0.1-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) +[![Release Version](https://img.shields.io/badge/release-2.0.2-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) [![Platform](https://img.shields.io/badge/Platform-%20HarmonyOS%20NEXT-brightgreen.svg)](https://github.com/Tencent/MMKV/wiki/home) MMKV is an **efficient**, **small**, **easy-to-use** mobile key-value storage framework used in the WeChat application. It's now available on **HarmonyOS NEXT**. @@ -37,7 +37,7 @@ Or, you can add it to your project manually. ```json "dependencies": { - "@tencent/mmkv": "^2.0.1", + "@tencent/mmkv": "~2.0.2", } ``` * Then run @@ -89,6 +89,11 @@ export default class EntryAbility extends UIAbility { mmkv.encodeBytes('bytes', arrayBuffer); let bytes = mmkv.decodeBytes('bytes'); console.info('bytes = ', ArrayBufferToString(bytes)); + + let arr = new Uint8Array([0, 255, 1, 255]); + mmkv.encodeTypedArray('uint8-array', arr); + let newUI8Arr = kv.decodeUint8Array('uint8-array'); + console.info('uint8-array = ', newUI8Arr); ``` As you can see, MMKV is quite easy to use. diff --git a/OpenHarmony/MMKV/consumer-rules.txt b/OpenHarmony/MMKV/consumer-rules.txt index e02e7bb9..7f036af1 100644 --- a/OpenHarmony/MMKV/consumer-rules.txt +++ b/OpenHarmony/MMKV/consumer-rules.txt @@ -17,16 +17,44 @@ # -keep-property-name: specifies property names that you want to keep # -keep-global-name: specifies names that you want to keep in the global scope --keep -./src/main/ets/utils/MMKV.ets -./src/main/ets/utils/MMKVHandler.ets -./src/main/ets/utils/MMKVLogLevel.ets -./src/main/ets/utils/NativeBuffer.ets -./src/main/ets/utils/Util.ts - --keep-file-name +-keep-global-name MMKV MMKVHandler +MMKVRecoverStrategic MMKVLogLevel NativeBuffer -Util +getObjKeys + +-keep-property-name +*_MODE +initializeWithPath +defaultMMKV +initData +wantLogRedirect +mmkvLog +onMMKV* +wantContentChangeNotification +onContentChangedByOuterProcess +Level* +pointer +size +backedUpMMKVWithID +decodeFloat32Array +decodeFloat64Array +decodeInt16Array +decodeInt8Array +decodeUint16Array +decodeUint32Array +decodeUint64Array +decodeUint8Array +decodeUint8ClampedArray +defaultMMKV +encodeBytesPart +encodeTypedArray +importFromPreferences +mmkvWithAshmemID +rootDir + +-keep-dts +/Users/lingol/Developer/mmkv/OpenHarmony/MMKV/src/main/cpp/types/libmmkv/ + diff --git a/OpenHarmony/MMKV/obfuscation-rules.txt b/OpenHarmony/MMKV/obfuscation-rules.txt index d4c3b4d2..51021121 100644 --- a/OpenHarmony/MMKV/obfuscation-rules.txt +++ b/OpenHarmony/MMKV/obfuscation-rules.txt @@ -16,17 +16,3 @@ # Keep options: # -keep-property-name: specifies property names that you want to keep # -keep-global-name: specifies names that you want to keep in the global scope - --keep -./src/main/ets/utils/MMKV.ets -./src/main/ets/utils/MMKVHandler.ets -./src/main/ets/utils/MMKVLogLevel.ets -./src/main/ets/utils/NativeBuffer.ets -./src/main/ets/utils/Util.ts - --keep-file-name -MMKV -MMKVHandler -MMKVLogLevel -NativeBuffer -Util \ No newline at end of file diff --git a/OpenHarmony/MMKV/oh-package.json5 b/OpenHarmony/MMKV/oh-package.json5 index 3e8fcb15..25dd6379 100644 --- a/OpenHarmony/MMKV/oh-package.json5 +++ b/OpenHarmony/MMKV/oh-package.json5 @@ -1,6 +1,6 @@ { "name": "@tencent/mmkv", - "version": "2.0.1", + "version": "2.0.2", "description": "The official OpenHarmony package of MMKV. An efficient, small mobile key-value storage framework developed by WeChat.", "main": "Index.ets", "author": "guoling", diff --git a/OpenHarmony/entry/oh-package-lock.json5 b/OpenHarmony/entry/oh-package-lock.json5 index 2f2ec6bb..4e3f869a 100644 --- a/OpenHarmony/entry/oh-package-lock.json5 +++ b/OpenHarmony/entry/oh-package-lock.json5 @@ -5,25 +5,19 @@ "lockfileVersion": 3, "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", "specifiers": { - "@tencent/mmkv@../MMKV": "@tencent/mmkv@../MMKV", - "libmmkv.so@../MMKV/src/main/cpp/types/libmmkv": "libmmkv.so@../MMKV/src/main/cpp/types/libmmkv" + "@tencent/mmkv@~2.0.0": "@tencent/mmkv@2.0.1" }, "packages": { - "@tencent/mmkv@../MMKV": { + "@tencent/mmkv@2.0.1": { "name": "@tencent/mmkv", "version": "2.0.1", - "resolved": "../MMKV", - "registryType": "local", + "integrity": "sha512-UlIzMArUoQaEFASFxLSIg0Q/LHY1K3mqv/XdCXdgzz9Pb1VS7AS2o5LwUrkY/O8iuT8Rr1SxGmp98xKRE4e8yg==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@tencent/mmkv/-/mmkv-2.0.1.har", + "registryType": "ohpm", "dependencies": { "libmmkv.so": "file:./src/main/cpp/types/libmmkv" }, "packageType": "InterfaceHar" - }, - "libmmkv.so@../MMKV/src/main/cpp/types/libmmkv": { - "name": "libmmkv.so", - "version": "0.0.0", - "resolved": "../MMKV/src/main/cpp/types/libmmkv", - "registryType": "local" } } } \ No newline at end of file diff --git a/OpenHarmony/entry/oh-package.json5 b/OpenHarmony/entry/oh-package.json5 index b373db08..136d433f 100644 --- a/OpenHarmony/entry/oh-package.json5 +++ b/OpenHarmony/entry/oh-package.json5 @@ -6,8 +6,8 @@ "author": "guoling", "license": "BSD 3-Clause", "dependencies": { - "@tencent/mmkv": "file:../MMKV" -// "@tencent/mmkv": "2.0.0", + "@tencent/mmkv": "file:../MMKV", +// "@tencent/mmkv": "~2.0.2", } } diff --git a/README.md b/README.md index b746ab91..5e8401bf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![license](https://img.shields.io/badge/license-BSD_3-brightgreen.svg?style=flat)](https://github.com/Tencent/MMKV/blob/master/LICENSE.TXT) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/MMKV/pulls) -[![Release Version](https://img.shields.io/badge/release-2.0.1-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) +[![Release Version](https://img.shields.io/badge/release-2.0.2-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) [![Platform](https://img.shields.io/badge/Platform-%20Android%20%7C%20iOS%2FmacOS%20%7C%20Windows%20%7C%20POSIX%20%7C%20HarmonyOS%20NEXT-brightgreen.svg)](https://github.com/Tencent/MMKV/wiki/home) 中文版本请参看[这里](./README_CN.md) @@ -28,8 +28,8 @@ Add the following lines to `build.gradle` on your app module: ```gradle dependencies { - implementation 'com.tencent:mmkv:2.0.1' - // replace "2.0.1" with any available version + implementation 'com.tencent:mmkv:2.0.2' + // replace "2.0.2" with any available version } ``` diff --git a/README_CN.md b/README_CN.md index 0fc4a122..1ec6890e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -22,8 +22,8 @@ MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列 ```gradle dependencies { - implementation 'com.tencent:mmkv:2.0.1' - // replace "2.0.1" with any available version + implementation 'com.tencent:mmkv:2.0.2' + // replace "2.0.2" with any available version } ``` 从 v2.0.0 起, MMKV **去掉了 32-bit 架构的支持**、API level 22 及以下的支持, 如有这类需求,请使用 v1.3.x LTS 版本。 diff --git a/flutter/mmkv/CHANGELOG.md b/flutter/mmkv/CHANGELOG.md index 78b8f5b3..ba919e32 100644 --- a/flutter/mmkv/CHANGELOG.md +++ b/flutter/mmkv/CHANGELOG.md @@ -1,4 +1,7 @@ # MMKV for Flutter Change Log +## v2.0.2 / 2024-12-27 +* Add version limitation of < v2.1.0 on MMKV platform plugins. + ## v2.0.1 / 2024-10-25 * Fix breaking changes on platform interface package. diff --git a/flutter/mmkv/README.md b/flutter/mmkv/README.md index 3d1414b3..5d93157c 100644 --- a/flutter/mmkv/README.md +++ b/flutter/mmkv/README.md @@ -1,6 +1,6 @@ [![license](https://img.shields.io/badge/license-BSD_3-brightgreen.svg?style=flat)](https://github.com/Tencent/MMKV/blob/master/LICENSE.TXT) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/MMKV/pulls) -[![Release Version](https://img.shields.io/badge/release-2.0.1-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) +[![Release Version](https://img.shields.io/badge/release-2.0.2-brightgreen.svg)](https://github.com/Tencent/MMKV/releases) [![Platform](https://img.shields.io/badge/Platform-%20Android%20%7C%20iOS-brightgreen.svg)](https://github.com/Tencent/MMKV/wiki/home) MMKV is an **efficient**, **small**, **easy-to-use** mobile key-value storage framework used in the WeChat application. It's currently available on **Android** and **iOS**. @@ -26,7 +26,7 @@ Add the following lines to `pubspec.yaml` on your app module. Then run `flutter ```yaml dependencies: - mmkv: "^2.0.1" + mmkv: "^2.0.2" ``` If you already include MMKV native lib in your App, you need to upgrade to version newer than v2.0.0. diff --git a/flutter/mmkv/pubspec.yaml b/flutter/mmkv/pubspec.yaml index 2575dd14..cd7e8642 100644 --- a/flutter/mmkv/pubspec.yaml +++ b/flutter/mmkv/pubspec.yaml @@ -1,6 +1,6 @@ name: mmkv description: An efficient, small mobile key-value storage framework developed by WeChat. Works on Android & iOS. -version: 2.0.1 +version: 2.0.2 homepage: https://github.com/Tencent/mmkv repository: https://github.com/Tencent/MMKV/tree/master/flutter/mmkv @@ -13,16 +13,16 @@ dependencies: sdk: flutter ffi: ^2.0.0 mmkv_ios: - ^2.0.0 + '>=2.0.0 <2.1.0' # path: ../mmkv_ios mmkv_android: - ^2.0.0 + '>=2.0.0 <2.1.0' # path: ../mmkv_android mmkv_ohos: - ^2.0.0 + '>=2.0.2 <2.1.0' # path: ../mmkv_ohos mmkv_platform_interface: - ^2.0.0 + '>=2.0.0 <2.1.0' # path: ../mmkv_platform_interface dev_dependencies: diff --git a/flutter/mmkv_ohos/CHANGELOG.md b/flutter/mmkv_ohos/CHANGELOG.md index c7db7dbb..8ba69ac8 100644 --- a/flutter/mmkv_ohos/CHANGELOG.md +++ b/flutter/mmkv_ohos/CHANGELOG.md @@ -1,4 +1,7 @@ # MMKV Platform OHOS Change Log +## v2.0.2 / 2024-12-27 +Keep up with native lib v2.0.2. And add limitation of < v2.1. + ## v2.0.1 / 2024-10-25 Keep up with native lib v2.0.1. diff --git a/flutter/mmkv_ohos/ohos/oh-package.json5 b/flutter/mmkv_ohos/ohos/oh-package.json5 index 601aa441..343b4606 100644 --- a/flutter/mmkv_ohos/ohos/oh-package.json5 +++ b/flutter/mmkv_ohos/ohos/oh-package.json5 @@ -7,7 +7,7 @@ "license": "Apache-2.0", "dependencies": { "@ohos/flutter_ohos": "file:./har/flutter.har", - "@tencent/mmkv": "^2.0.1" + "@tencent/mmkv": ">=2.0.2 <2.1" // "@tencent/mmkv": "file:/Users/lingol/Developer/mmkv/OpenHarmony/MMKV/build/default/outputs/default/MMKV.har" }, "devDependencies": {}, diff --git a/flutter/mmkv_ohos/pubspec.yaml b/flutter/mmkv_ohos/pubspec.yaml index 8a2ac82f..479cdbbf 100644 --- a/flutter/mmkv_ohos/pubspec.yaml +++ b/flutter/mmkv_ohos/pubspec.yaml @@ -1,7 +1,7 @@ name: mmkv_ohos description: OHOS platform implementation of MMKV. repository: https://github.com/Tencent/MMKV/tree/master/flutter/mmkv_ohos -version: 2.0.1 +version: 2.0.2 homepage: https://github.com/Tencent/mmkv environment: diff --git a/iOS/MMKV.podspec b/iOS/MMKV.podspec index b8807307..c70e44d6 100644 --- a/iOS/MMKV.podspec +++ b/iOS/MMKV.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKV" - s.version = "2.0.0" + s.version = "2.0.2" s.summary = "MMKV is a cross-platform key-value storage framework developed by WeChat." s.description = <<-DESC @@ -33,7 +33,7 @@ Pod::Spec.new do |s| "CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF" => "NO", } - s.dependency 'MMKVCore', '~> 2.0.0' + s.dependency 'MMKVCore', '~> 2.0.2' end diff --git a/iOS/MMKV/MMKV.xcodeproj/project.pbxproj b/iOS/MMKV/MMKV.xcodeproj/project.pbxproj index c9596622..6a54d113 100644 --- a/iOS/MMKV/MMKV.xcodeproj/project.pbxproj +++ b/iOS/MMKV/MMKV.xcodeproj/project.pbxproj @@ -493,7 +493,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - MARKETING_VERSION = 2.0.0; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17"; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", @@ -539,7 +538,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - MARKETING_VERSION = 2.0.0; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17"; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", @@ -749,7 +747,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - MARKETING_VERSION = 2.0.0; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17"; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", @@ -794,7 +791,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - MARKETING_VERSION = 2.0.0; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17"; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", @@ -843,7 +839,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - MARKETING_VERSION = 2.0.0; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17"; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", @@ -891,7 +886,6 @@ "@loader_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - MARKETING_VERSION = 2.0.0; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17"; "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-framework", diff --git a/iOS/MMKVAppExtension.podspec b/iOS/MMKVAppExtension.podspec index 33040d09..bacd23ce 100644 --- a/iOS/MMKVAppExtension.podspec +++ b/iOS/MMKVAppExtension.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKVAppExtension" - s.version = "2.0.0" + s.version = "2.0.2" s.summary = "MMKV is a cross-platform key-value storage framework developed by WeChat." s.module_name = "MMKVAppExtension" @@ -31,7 +31,7 @@ Pod::Spec.new do |s| "GCC_PREPROCESSOR_DEFINITIONS" => "MMKV_IOS_EXTENSION", } - s.dependency 'MMKVCore', '~> 2.0.0' + s.dependency 'MMKVCore', '~> 2.0.2' end diff --git a/iOS/MMKVCore.podspec b/iOS/MMKVCore.podspec index ac778004..4b7910c0 100644 --- a/iOS/MMKVCore.podspec +++ b/iOS/MMKVCore.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKVCore" - s.version = "2.0.0" + s.version = "2.0.2" s.summary = "MMKVCore for MMKV. MMKV is a cross-platform key-value storage framework developed by WeChat." s.description = <<-DESC diff --git a/iOS/MMKVWatchExtension.podspec b/iOS/MMKVWatchExtension.podspec index e8b02c2a..b2e177e1 100644 --- a/iOS/MMKVWatchExtension.podspec +++ b/iOS/MMKVWatchExtension.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MMKVWatchExtension" - s.version = "2.0.0" + s.version = "2.0.2" s.summary = "MMKV is a cross-platform key-value storage framework developed by WeChat." s.module_name = "MMKVWatchExtension" @@ -31,7 +31,7 @@ Pod::Spec.new do |s| "GCC_PREPROCESSOR_DEFINITIONS" => "MMKV_IOS_EXTENSION", } - s.dependency 'MMKVCore', '~> 2.0.0' + s.dependency 'MMKVCore', '~> 2.0.2' end