Skip to content

Commit

Permalink
Merge pull request Tencent#244 from Tencent/dev
Browse files Browse the repository at this point in the history
v1.0.19
  • Loading branch information
lingol authored Apr 22, 2019
2 parents 87eaabe + 0a58f89 commit 834da9e
Show file tree
Hide file tree
Showing 39 changed files with 357 additions and 192 deletions.
2 changes: 1 addition & 1 deletion Android/MMKV/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ 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=1.0.18
VERSION_NAME_PREFIX=1.0.19
#VERSION_NAME_SUFFIX=-SNAPSHOT
VERSION_NAME_SUFFIX=
2 changes: 2 additions & 0 deletions Android/MMKV/mmkv/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ android {
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
// ndk doesn't have targetSDK support
//minSdkVersion = 26
}
buildTypes {
release {
Expand Down
9 changes: 5 additions & 4 deletions Android/MMKV/mmkv/src/main/cpp/MMKV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ bool MMKV::ensureMemorySize(size_t newSize) {
m_size *= 2;
} while (lenNeeded + futureUsage >= m_size);
MMKVInfo(
"extending [%s] file size from %zu to %zu, incoming size:%zu, futrue usage:%zu",
"extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu",
m_mmapID.c_str(), oldSize, m_size, newSize, futureUsage);

// if we can't extend size, rollback to old state
Expand Down Expand Up @@ -1316,14 +1316,15 @@ void MMKV::removeValuesForKeys(const std::vector<std::string> &arrKeys) {

#pragma mark - file

void MMKV::sync() {
void MMKV::sync(bool sync) {
SCOPEDLOCK(m_lock);
if (m_needLoadFromFile || !isFileValid()) {
return;
}
SCOPEDLOCK(m_exclusiveProcessLock);
if (msync(m_ptr, m_size, MS_SYNC) != 0) {
MMKVError("fail to msync [%s]:%s", m_mmapID.c_str(), strerror(errno));
auto flag = sync ? MS_SYNC : MS_ASYNC;
if (msync(m_ptr, m_size, flag) != 0) {
MMKVError("fail to msync[%d] [%s]:%s", flag, m_mmapID.c_str(), strerror(errno));
}
}

Expand Down
2 changes: 1 addition & 1 deletion Android/MMKV/mmkv/src/main/cpp/MMKV.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class MMKV {

// you don't need to call this, really, I mean it
// unless you care about out of battery
void sync();
void sync(bool sync = true);

static bool isFileValid(const std::string &mmapID);

Expand Down
7 changes: 4 additions & 3 deletions Android/MMKV/mmkv/src/main/cpp/MMKVLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ void _MMKVLogWithLevel(
if (length < 0) { // something wrong
message = {};
} else if (length < sizeof(buffer)) {
message = string(buffer, length);
message = string(buffer, static_cast<unsigned long>(length));
} else {
message.resize(length, '\0');
message.resize(static_cast<unsigned long>(length), '\0');
va_start(args, format);
std::vsnprintf(message.data(), length + 1, format, args);
std::vsnprintf(const_cast<char *>(message.data()), static_cast<size_t>(length) + 1,
format, args);
va_end(args);
}

Expand Down
156 changes: 117 additions & 39 deletions Android/MMKV/mmkv/src/main/cpp/MmapedFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,15 @@ MmapedFile::MmapedFile(const std::string &path, size_t size, bool fileType)
}
}
} else {
m_fd = open(ASHMEM_NAME_DEF, O_RDWR);
if (m_fd < 0) {
MMKVError("fail to open ashmem:%s, %s", m_name.c_str(), strerror(errno));
} else {
if (ioctl(m_fd, ASHMEM_SET_NAME, m_name.c_str()) != 0) {
MMKVError("fail to set ashmem name:%s, %s", m_name.c_str(), strerror(errno));
} else if (ioctl(m_fd, ASHMEM_SET_SIZE, size) != 0) {
MMKVError("fail to set ashmem:%s, size %zu, %s", m_name.c_str(), size,
strerror(errno));
} else {
m_segmentSize = static_cast<size_t>(size);
m_segmentPtr = (char *) mmap(nullptr, m_segmentSize, PROT_READ | PROT_WRITE,
MAP_SHARED, m_fd, 0);
if (m_segmentPtr == MAP_FAILED) {
MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));
m_segmentPtr = nullptr;
} else {
return;
}
m_fd = ASharedMemory_create(m_name.c_str(), size);
if (m_fd >= 0) {
m_segmentSize = static_cast<size_t>(size);
m_segmentPtr =
(char *) mmap(nullptr, m_segmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);
if (m_segmentPtr == MAP_FAILED) {
MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));
m_segmentPtr = nullptr;
}
close(m_fd);
m_fd = -1;
}
}
}
Expand All @@ -102,24 +89,14 @@ MmapedFile::MmapedFile(int ashmemFD)
if (m_fd < 0) {
MMKVError("fd %d invalid", m_fd);
} else {
char name[ASHMEM_NAME_LEN] = {0};
if (ioctl(m_fd, ASHMEM_GET_NAME, name) != 0) {
MMKVError("fail to get ashmem name:%d, %s", m_fd, strerror(errno));
} else {
m_name = string(name);
int size = ioctl(m_fd, ASHMEM_GET_SIZE, nullptr);
if (size < 0) {
MMKVError("fail to get ashmem size:%s, %s", m_name.c_str(), strerror(errno));
} else {
m_segmentSize = static_cast<size_t>(size);
MMKVInfo("ashmem verified, name:%s, size:%zu", m_name.c_str(), m_segmentSize);
m_segmentPtr = (char *) mmap(nullptr, m_segmentSize, PROT_READ | PROT_WRITE,
MAP_SHARED, m_fd, 0);
if (m_segmentPtr == MAP_FAILED) {
MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));
m_segmentPtr = nullptr;
}
}
m_name = ASharedMemory_getName(m_fd);
m_segmentSize = ASharedMemory_getSize(m_fd);
MMKVInfo("ashmem name:%s, size:%zu", m_name.c_str(), m_segmentSize);
m_segmentPtr =
(char *) mmap(nullptr, m_segmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);
if (m_segmentPtr == MAP_FAILED) {
MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));
m_segmentPtr = nullptr;
}
}
}
Expand Down Expand Up @@ -267,3 +244,104 @@ bool zeroFillFile(int fd, size_t startPos, size_t size) {
}
return true;
}

#pragma mark - ashmem
#include "native-bridge.h"
#include <dlfcn.h>

#define ASHMEM_NAME_LEN 256
#define __ASHMEMIOC 0x77
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)

void *loadLibrary() {
auto name = "libandroid.so";
static auto handle = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
if (handle == RTLD_DEFAULT) {
MMKVError("unable to load library %s", name);
}
return handle;
}

typedef int (*AShmem_create_t)(const char *name, size_t size);

int ASharedMemory_create(const char *name, size_t size) {
int fd = -1;
if (g_android_api >= __ANDROID_API_O__) {
static auto handle = loadLibrary();
static AShmem_create_t funcPtr =
(handle != nullptr)
? reinterpret_cast<AShmem_create_t>(dlsym(handle, "ASharedMemory_create"))
: nullptr;
if (funcPtr) {
fd = funcPtr(name, size);
if (fd < 0) {
MMKVError("fail to ASharedMemory_create %s with size %z, errno:%s", name, size,
strerror(errno));
}
} else {
MMKVWarning("fail to locate ASharedMemory_create() from loading libandroid.so");
}
}
if (fd < 0) {
fd = open(ASHMEM_NAME_DEF, O_RDWR);
if (fd < 0) {
MMKVError("fail to open ashmem:%s, %s", name, strerror(errno));
} else {
if (ioctl(fd, ASHMEM_SET_NAME, name) != 0) {
MMKVError("fail to set ashmem name:%s, %s", name, strerror(errno));
} else if (ioctl(fd, ASHMEM_SET_SIZE, size) != 0) {
MMKVError("fail to set ashmem:%s, size %zu, %s", name, size, strerror(errno));
}
}
}
return fd;
}

typedef size_t (*AShmem_getSize_t)(int fd);

size_t ASharedMemory_getSize(int fd) {
size_t size = 0;
if (g_android_api >= __ANDROID_API_O__) {
static auto handle = loadLibrary();
static AShmem_getSize_t funcPtr =
(handle != nullptr)
? reinterpret_cast<AShmem_getSize_t>(dlsym(handle, "ASharedMemory_getSize"))
: nullptr;
if (funcPtr) {
size = funcPtr(fd);
if (size == 0) {
MMKVError("fail to ASharedMemory_getSize:%d, %s", fd, strerror(errno));
}
} else {
MMKVWarning("fail to locate ASharedMemory_create() from loading libandroid.so");
}
}
if (size == 0) {
int tmp = ioctl(fd, ASHMEM_GET_SIZE, nullptr);
if (tmp < 0) {
MMKVError("fail to get ashmem size:%d, %s", fd, strerror(errno));
} else {
size = static_cast<size_t>(tmp);
}
}
return size;
}

std::string ASharedMemory_getName(int fd) {
// Android Q doesn't have ASharedMemory_getName()
// I've make a request to Google, https://issuetracker.google.com/issues/130741665
// There's nothing we can do before it's supported officially by Google
if (g_android_api >= 29) {
return "";
}

char name[ASHMEM_NAME_LEN] = {0};
if (ioctl(fd, ASHMEM_GET_NAME, name) != 0) {
MMKVError("fail to get ashmem name:%d, %s", fd, strerror(errno));
return "";
}
return string(name);
}
12 changes: 5 additions & 7 deletions Android/MMKV/mmkv/src/main/cpp/MmapedFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,8 @@
#include <sys/ioctl.h>
#include <sys/mman.h>

#define ASHMEM_NAME_LEN 256
#define ASHMEM_NAME_DEF "/dev/ashmem"

#define __ASHMEMIOC 0x77
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)

enum : bool { MMAP_FILE = false, MMAP_ASHMEM = true };

extern const int DEFAULT_MMAP_SIZE;
Expand Down Expand Up @@ -79,4 +72,9 @@ extern MMBuffer *readWholeFile(const char *path);
extern bool zeroFillFile(int fd, size_t startPos, size_t size);
extern bool createFile(const std::string &filePath);

// for Android Q limiting ashmem access
extern int ASharedMemory_create(const char *name, size_t size);
extern size_t ASharedMemory_getSize(int fd);
extern std::string ASharedMemory_getName(int fd);

#endif //MMKV_MMAPEDFILE_H
24 changes: 20 additions & 4 deletions Android/MMKV/mmkv/src/main/cpp/native-bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static jmethodID g_callbackOnCRCFailID = nullptr;
static jmethodID g_callbackOnFileLengthErrorID = nullptr;
static jmethodID g_mmkvLogID = nullptr;
static JavaVM *g_currentJVM = nullptr;
int g_android_api = __ANDROID_API_L__;

extern "C" JNIEXPORT JNICALL jint JNI_OnLoad(JavaVM *vm, void *reserved) {
g_currentJVM = vm;
Expand Down Expand Up @@ -73,6 +74,20 @@ extern "C" JNIEXPORT JNICALL jint JNI_OnLoad(JavaVM *vm, void *reserved) {
MMKVError("fail to get method id for mmkvLogImp");
}

// get current API level by accessing android.os.Build.VERSION.SDK_INT
jclass versionClass = env->FindClass("android/os/Build$VERSION");
if (versionClass) {
jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
if (sdkIntFieldID) {
g_android_api = env->GetStaticIntField(versionClass, sdkIntFieldID);
MMKVInfo("current API level = %d", g_android_api);
} else {
MMKVError("fail to get field id android.os.Build.VERSION.SDK_INT");
}
} else {
MMKVError("fail to get class android.os.Build.VERSION");
}

return JNI_VERSION_1_6;
}

Expand Down Expand Up @@ -477,8 +492,8 @@ extern "C" JNIEXPORT JNICALL jbyteArray Java_com_tencent_mmkv_MMKV_decodeBytes(J
if (kv && oKey) {
string key = jstring2string(env, oKey);
MMBuffer value = kv->getBytesForKey(key);
jbyteArray result = env->NewByteArray(value.length());
if (result) {
if (value.length() > 0) {
jbyteArray result = env->NewByteArray(value.length());
env->SetByteArrayRegion(result, 0, value.length(), (const jbyte *) value.getPtr());
return result;
}
Expand Down Expand Up @@ -560,10 +575,11 @@ extern "C" JNIEXPORT JNICALL void Java_com_tencent_mmkv_MMKV_clearAll(JNIEnv *en
}
}

extern "C" JNIEXPORT JNICALL void Java_com_tencent_mmkv_MMKV_sync(JNIEnv *env, jobject instance) {
extern "C" JNIEXPORT JNICALL void
Java_com_tencent_mmkv_MMKV_sync(JNIEnv *env, jobject instance, jboolean sync) {
MMKV *kv = getMMKV(env, instance);
if (kv) {
kv->sync();
kv->sync((bool) sync);
}
}

Expand Down
2 changes: 2 additions & 0 deletions Android/MMKV/mmkv/src/main/cpp/native-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ void mmkvLog(int level,
const std::string &function,
const std::string &message);

extern int g_android_api;

#endif //MMKV_NATIVE_BRIDGE_H
15 changes: 11 additions & 4 deletions Android/MMKV/mmkv/src/main/java/com/tencent/mmkv/MMKV.java
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,15 @@ public void removeValueForKey(String key) {

// you don't need to call this, really, I mean it
// unless you care about out of battery
public native void sync();
public void sync() {
sync(true);
}

public void async() {
sync(false);
}

private native void sync(boolean sync);

public static native boolean isFileValid(String mmapID);

Expand Down Expand Up @@ -614,14 +622,13 @@ public Editor clear() {

@Override
public boolean commit() {
sync();
sync(true);
return true;
}

@Override
public void apply() {
// TODO: create a thread?
//sync();
sync(false);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions Android/MMKV/mmkvdemo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ repositories {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
// implementation project(':mmkv')
implementation 'com.tencent:mmkv:1.0.18'
// implementation 'com.tencent:mmkv-static:1.0.18'
implementation 'com.tencent:mmkv:1.0.19'
// implementation 'com.tencent:mmkv-static:1.0.19'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ private MMKV testMMKV(String mmapID, String cryptKey, boolean decodeOnly, String
Log.i("MMKV", "string after set null: " + kv.decodeString("null string")
+ ", containsKey:" + kv.contains("null string"));

//kv.sync();
//kv.async();
//kv.clearAll();
kv.clearMemoryCache();
Log.i("MMKV", "allKeys: " + Arrays.toString(kv.allKeys()));
Expand Down
Loading

0 comments on commit 834da9e

Please sign in to comment.