In my Google Play developer console, I see a lot of crashes in NewStringUTF() like so:
  #00  pc 00000000001b9f22  /system/lib/libart.so (art::IndirectReferenceTable::Add(art::IRTSegmentState, art::ObjPtr<art::mirror::Object>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+630)
  #01  pc 00000000002ad461  /system/lib/libart.so (_jthrowable* art::JNIEnvExt::AddLocalReference<_jthrowable*>(art::ObjPtr<art::mirror::Object>)+32)
  #02  pc 0000000000298e49  /system/lib/libart.so (art::JNI::NewStringUTF(_JNIEnv*, char const*)+416)
  #03  pc 000000000024baf0  /data/app/com.steenriver.littlecrane-1vpoZWmGtL5mN2uxtEBltA==/lib/arm/liblittlecrane.so (androidsupport_reportFailedLaunch(char const*)+64)
  ...
So the actually crash is in IndirectReferenceTable::Add() call.
Why would the NewStringUTF() call fail? I pass it a normal ASCII string, and my 'env' pointer is not null.
My code:
bool androidsupport_reportFailedLaunch( const char* msg )
{
        if ( !androidsupport_engine.app ) return false;
        JNIEnv* env = androidsupport_engine.app->appThreadEnv;
        if ( !env ) return false;
        jstring jniText = env->NewStringUTF( msg );
        EXCEPTION_RETURN( env );
        ...
The msg parameter is not nil, and points to a const char* that is in static memory, as the function is called like so:
androidsupport_reportFailedLaunch( "Incompatible device." );
The JNIEnv* is cached, but it was attached to the native thread like so:
    int error = (*android_app->activity->vm)->AttachCurrentThread(android_app->activity->vm, &android_app->appThreadEnv, NULL);
    if (error) android_app->appThreadEnv = NULL;
according to an Android example by nvidia.