mirror of
https://github.com/android/ndk-samples
synced 2025-11-04 06:15:39 +08:00
Compare commits
2 Commits
b21d220f67
...
9e8268863e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e8268863e | ||
|
|
edd51066ac |
@@ -1,9 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
project(HelloJniCallback LANGUAGES C)
|
||||
project(HelloJniCallback LANGUAGES CXX)
|
||||
|
||||
add_library(hello-jnicallback SHARED hello-jnicallback.c)
|
||||
include(AppLibrary)
|
||||
|
||||
add_app_library(hello-jnicallback SHARED hello-jnicallback.cpp)
|
||||
|
||||
# Include libraries needed for hello-jnicallback lib
|
||||
target_link_libraries(hello-jnicallback
|
||||
android
|
||||
log
|
||||
|
||||
@@ -48,9 +48,9 @@ TickContext g_ctx;
|
||||
*
|
||||
* hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
Java_com_example_hellojnicallback_MainActivity_stringFromJNI(JNIEnv* env,
|
||||
jobject thiz) {
|
||||
jobject) {
|
||||
#if defined(__arm__)
|
||||
#if defined(__ARM_ARCH_7A__)
|
||||
#if defined(__ARM_NEON__)
|
||||
@@ -82,8 +82,7 @@ Java_com_example_hellojnicallback_MainActivity_stringFromJNI(JNIEnv* env,
|
||||
#else
|
||||
#define ABI "unknown"
|
||||
#endif
|
||||
return (*env)->NewStringUTF(env,
|
||||
"Hello from JNI ! Compiled with ABI " ABI ".");
|
||||
return env->NewStringUTF("Hello from JNI ! Compiled with ABI " ABI ".");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -100,35 +99,35 @@ void queryRuntimeInfo(JNIEnv* env, jobject instance) {
|
||||
// shared lib got loaded, we just directly use them
|
||||
// static function does not need instance, so we just need to feed
|
||||
// class and method id to JNI
|
||||
jmethodID versionFunc = (*env)->GetStaticMethodID(
|
||||
env, g_ctx.jniHandlerClz, "getBuildVersion", "()Ljava/lang/String;");
|
||||
jmethodID versionFunc = env->GetStaticMethodID(
|
||||
g_ctx.jniHandlerClz, "getBuildVersion", "()Ljava/lang/String;");
|
||||
if (!versionFunc) {
|
||||
LOGE("Failed to retrieve getBuildVersion() methodID @ line %d", __LINE__);
|
||||
return;
|
||||
}
|
||||
jstring buildVersion =
|
||||
(*env)->CallStaticObjectMethod(env, g_ctx.jniHandlerClz, versionFunc);
|
||||
const char* version = (*env)->GetStringUTFChars(env, buildVersion, NULL);
|
||||
jstring buildVersion = static_cast<jstring>(
|
||||
env->CallStaticObjectMethod(g_ctx.jniHandlerClz, versionFunc));
|
||||
const char* version = env->GetStringUTFChars(buildVersion, NULL);
|
||||
if (!version) {
|
||||
LOGE("Unable to get version string @ line %d", __LINE__);
|
||||
return;
|
||||
}
|
||||
LOGI("Android Version - %s", version);
|
||||
(*env)->ReleaseStringUTFChars(env, buildVersion, version);
|
||||
env->ReleaseStringUTFChars(buildVersion, version);
|
||||
|
||||
// we are called from JNI_OnLoad, so got to release LocalRef to avoid leaking
|
||||
(*env)->DeleteLocalRef(env, buildVersion);
|
||||
env->DeleteLocalRef(buildVersion);
|
||||
|
||||
// Query available memory size from a non-static public function
|
||||
// we need use an instance of JniHandler class to call JNI
|
||||
jmethodID memFunc = (*env)->GetMethodID(env, g_ctx.jniHandlerClz,
|
||||
"getRuntimeMemorySize", "()J");
|
||||
jmethodID memFunc =
|
||||
env->GetMethodID(g_ctx.jniHandlerClz, "getRuntimeMemorySize", "()J");
|
||||
if (!memFunc) {
|
||||
LOGE("Failed to retrieve getRuntimeMemorySize() methodID @ line %d",
|
||||
__LINE__);
|
||||
return;
|
||||
}
|
||||
jlong result = (*env)->CallLongMethod(env, instance, memFunc);
|
||||
jlong result = env->CallLongMethod(instance, memFunc);
|
||||
LOGI("Runtime free memory size: %" PRId64, result);
|
||||
(void)result; // silence the compiler warning
|
||||
}
|
||||
@@ -144,23 +143,22 @@ void queryRuntimeInfo(JNIEnv* env, jobject instance) {
|
||||
* we rely on system to free all global refs when it goes away;
|
||||
* the pairing function JNI_OnUnload() never gets called at all.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
|
||||
JNIEnv* env;
|
||||
memset(&g_ctx, 0, sizeof(g_ctx));
|
||||
|
||||
g_ctx.javaVM = vm;
|
||||
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR; // JNI version not supported.
|
||||
}
|
||||
|
||||
jclass clz =
|
||||
(*env)->FindClass(env, "com/example/hellojnicallback/JniHandler");
|
||||
g_ctx.jniHandlerClz = (*env)->NewGlobalRef(env, clz);
|
||||
jclass clz = env->FindClass("com/example/hellojnicallback/JniHandler");
|
||||
g_ctx.jniHandlerClz = static_cast<jclass>(env->NewGlobalRef(clz));
|
||||
|
||||
jmethodID jniHandlerCtor =
|
||||
(*env)->GetMethodID(env, g_ctx.jniHandlerClz, "<init>", "()V");
|
||||
jobject handler = (*env)->NewObject(env, g_ctx.jniHandlerClz, jniHandlerCtor);
|
||||
g_ctx.jniHandlerObj = (*env)->NewGlobalRef(env, handler);
|
||||
env->GetMethodID(g_ctx.jniHandlerClz, "<init>", "()V");
|
||||
jobject handler = env->NewObject(g_ctx.jniHandlerClz, jniHandlerCtor);
|
||||
g_ctx.jniHandlerObj = env->NewGlobalRef(handler);
|
||||
queryRuntimeInfo(env, g_ctx.jniHandlerObj);
|
||||
|
||||
g_ctx.done = 0;
|
||||
@@ -175,9 +173,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
*/
|
||||
void sendJavaMsg(JNIEnv* env, jobject instance, jmethodID func,
|
||||
const char* msg) {
|
||||
jstring javaMsg = (*env)->NewStringUTF(env, msg);
|
||||
(*env)->CallVoidMethod(env, instance, func, javaMsg);
|
||||
(*env)->DeleteLocalRef(env, javaMsg);
|
||||
jstring javaMsg = env->NewStringUTF(msg);
|
||||
env->CallVoidMethod(instance, func, javaMsg);
|
||||
env->DeleteLocalRef(javaMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -189,23 +187,23 @@ void* UpdateTicks(void* context) {
|
||||
TickContext* pctx = (TickContext*)context;
|
||||
JavaVM* javaVM = pctx->javaVM;
|
||||
JNIEnv* env;
|
||||
jint res = (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_6);
|
||||
jint res = javaVM->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||
if (res != JNI_OK) {
|
||||
res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
|
||||
res = javaVM->AttachCurrentThread(&env, NULL);
|
||||
if (JNI_OK != res) {
|
||||
LOGE("Failed to AttachCurrentThread, ErrorCode = %d", res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
jmethodID statusId = (*env)->GetMethodID(
|
||||
env, pctx->jniHandlerClz, "updateStatus", "(Ljava/lang/String;)V");
|
||||
jmethodID statusId = env->GetMethodID(pctx->jniHandlerClz, "updateStatus",
|
||||
"(Ljava/lang/String;)V");
|
||||
sendJavaMsg(env, pctx->jniHandlerObj, statusId,
|
||||
"TickerThread status: initializing...");
|
||||
|
||||
// get mainActivity updateTimer function
|
||||
jmethodID timerId =
|
||||
(*env)->GetMethodID(env, pctx->mainActivityClz, "updateTimer", "()V");
|
||||
env->GetMethodID(pctx->mainActivityClz, "updateTimer", "()V");
|
||||
|
||||
struct timeval beginTime, curTime, usedTime, leftTime;
|
||||
const struct timeval kOneSecond = {(__kernel_time_t)1,
|
||||
@@ -224,7 +222,7 @@ void* UpdateTicks(void* context) {
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
(*env)->CallVoidMethod(env, pctx->mainActivityObj, timerId);
|
||||
env->CallVoidMethod(pctx->mainActivityObj, timerId);
|
||||
|
||||
gettimeofday(&curTime, NULL);
|
||||
timersub(&curTime, &beginTime, &usedTime);
|
||||
@@ -243,14 +241,14 @@ void* UpdateTicks(void* context) {
|
||||
|
||||
sendJavaMsg(env, pctx->jniHandlerObj, statusId,
|
||||
"TickerThread status: ticking stopped");
|
||||
(*javaVM)->DetachCurrentThread(javaVM);
|
||||
javaVM->DetachCurrentThread();
|
||||
return context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to Java side to start ticks, caller is from onResume()
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv* env,
|
||||
jobject instance) {
|
||||
pthread_t threadInfo_;
|
||||
@@ -261,9 +259,9 @@ Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv* env,
|
||||
|
||||
pthread_mutex_init(&g_ctx.lock, NULL);
|
||||
|
||||
jclass clz = (*env)->GetObjectClass(env, instance);
|
||||
g_ctx.mainActivityClz = (*env)->NewGlobalRef(env, clz);
|
||||
g_ctx.mainActivityObj = (*env)->NewGlobalRef(env, instance);
|
||||
jclass clz = env->GetObjectClass(instance);
|
||||
g_ctx.mainActivityClz = static_cast<jclass>(env->NewGlobalRef(clz));
|
||||
g_ctx.mainActivityObj = env->NewGlobalRef(instance);
|
||||
|
||||
int result = pthread_create(&threadInfo_, &threadAttr_, UpdateTicks, &g_ctx);
|
||||
assert(result == 0);
|
||||
@@ -278,8 +276,8 @@ Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv* env,
|
||||
* we need to hold and make sure our native thread has finished before return
|
||||
* for a clean shutdown. The caller is from onPause
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_example_hellojnicallback_MainActivity_StopTicks(
|
||||
JNIEnv* env, jobject instance) {
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_example_hellojnicallback_MainActivity_StopTicks(JNIEnv* env, jobject) {
|
||||
pthread_mutex_lock(&g_ctx.lock);
|
||||
g_ctx.done = 1;
|
||||
pthread_mutex_unlock(&g_ctx.lock);
|
||||
@@ -293,8 +291,8 @@ JNIEXPORT void JNICALL Java_com_example_hellojnicallback_MainActivity_StopTicks(
|
||||
}
|
||||
|
||||
// release object we allocated from StartTicks() function
|
||||
(*env)->DeleteGlobalRef(env, g_ctx.mainActivityClz);
|
||||
(*env)->DeleteGlobalRef(env, g_ctx.mainActivityObj);
|
||||
env->DeleteGlobalRef(g_ctx.mainActivityClz);
|
||||
env->DeleteGlobalRef(g_ctx.mainActivityObj);
|
||||
g_ctx.mainActivityObj = NULL;
|
||||
g_ctx.mainActivityClz = NULL;
|
||||
|
||||
Reference in New Issue
Block a user