Skip to content

Commit 76bc4e5

Browse files
committed
Jolt: add installAndroidTraceCallback()
1 parent 7d0e53c commit 76bc4e5

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

src/main/java/com/github/stephengold/joltjni/Jolt.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,16 @@ public static long hashCombine(long oldHash, Vec3Arg vector) {
430430
*/
431431
native public static boolean implementsDeterminismLog();
432432

433+
/**
434+
* Install an alternative trace callback that sends to the Android log with
435+
* the specified priority and tag.
436+
*
437+
* @param priority the desired priority of trace output in the log
438+
* @param tag the log tag to identify trace output (may be {@code null})
439+
*/
440+
native public static void installAndroidTraceCallback(
441+
int priority, String tag);
442+
433443
/**
434444
* Install the specified assert callback.
435445
*

src/main/native/glue/j/Jolt.cpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,74 @@ JNIEXPORT jboolean JNICALL Java_com_github_stephengold_joltjni_Jolt_implementsDe
326326
#endif
327327
}
328328

329+
JavaVM *gpVM; // the virtual machine used by both AndroidTrace() and JavaTrace()
330+
331+
#ifdef ANDROID
332+
jclass gLogClass;
333+
jint gPriority;
334+
jmethodID gPrintlnMethodId;
335+
jstring gTag;
336+
static void AndroidTrace(const char *inFormat, ...) {
337+
// Format the message:
338+
va_list list;
339+
va_start(list, inFormat);
340+
char buffer[1024];
341+
vsnprintf(buffer, sizeof(buffer), inFormat, list);
342+
va_end(list);
343+
//
344+
bool attachedHere = false;
345+
JNIEnv *pAttachEnv;
346+
jint retCode = gpVM->GetEnv((void**)&pAttachEnv, JNI_VERSION_1_6);
347+
if (JNI_EDETACHED == retCode) { // Attach env to the JVM:
348+
JavaVMAttachArgs jvmArgs;
349+
jvmArgs.version = JNI_VERSION_1_6;
350+
retCode = gpVM->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&pAttachEnv), &jvmArgs);
351+
}
352+
JPH_ASSERT(JNI_OK == retCode);
353+
// Create a Java string for the message:
354+
jstring javaString = pAttachEnv->NewStringUTF(buffer);
355+
JPH_ASSERT(NULL != javaString);
356+
EXCEPTION_CHECK(pAttachEnv)
357+
// Send the message to the log with the configured priority and tag:
358+
pAttachEnv->CallStaticIntMethod(
359+
gLogClass, gPrintlnMethodId, gPriority, gTag, javaString);
360+
// Ignore the return value; don't check for exceptions.
361+
//
362+
if (attachedHere) { // Detach env from the JVM:
363+
gpVM->DetachCurrentThread();
364+
}
365+
}
366+
#endif
367+
368+
/*
369+
* Class: com_github_stephengold_joltjni_Jolt
370+
* Method: installAndroidTraceCallback
371+
* Signature: (ILjava/lang/String;)V
372+
*/
373+
JNIEXPORT void JNICALL Java_com_github_stephengold_joltjni_Jolt_installAndroidTraceCallback
374+
(JNIEnv *pEnv, jclass, jint priority, jstring tag) {
375+
#ifdef ANDROID
376+
jint fail = pEnv->GetJavaVM(&gpVM);
377+
JPH_ASSERT(0 == fail);
378+
gLogClass = pEnv->FindClass("android/util/Log");
379+
JPH_ASSERT(NULL != gLogClass);
380+
EXCEPTION_CHECK(pEnv)
381+
gLogClass = (jclass) pEnv->NewGlobalRef(gLogClass);
382+
JPH_ASSERT(NULL != gLogClass);
383+
gPrintlnMethodId = pEnv->GetStaticMethodID(
384+
gLogClass, "println", "(ILjava/lang/String;Ljava/lang/String;)I");
385+
JPH_ASSERT(NULL != gPrintlnMethodId);
386+
EXCEPTION_CHECK(pEnv)
387+
//
388+
gPriority = priority;
389+
gTag = (NULL == tag) ? NULL : (jstring) pEnv->NewGlobalRef(tag);
390+
Trace = AndroidTrace;
391+
#elif defined(JPH_DEBUG)
392+
std::cout << "Jolt.installAndroidTraceCallback() has no effect on desktop platforms."
393+
<< std::endl;
394+
#endif
395+
}
396+
329397
/*
330398
* Class: com_github_stephengold_joltjni_Jolt
331399
* Method: installAssertCallback
@@ -469,7 +537,6 @@ JNIEXPORT void JNICALL Java_com_github_stephengold_joltjni_Jolt_installIgnoreAss
469537
#endif
470538
}
471539

472-
JavaVM *gpVM;
473540
jmethodID gFlushMethodId, gPrintMethodId;
474541
jobject gTraceStream;
475542
static void JavaTrace(const char *inFormat, ...) {

0 commit comments

Comments
 (0)