Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/213.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在JNI/OpenGL ES加载代码期间,非常规且狡猾的Android崩溃 赏金_Android_Opengl Es_Crash_Java Native Interface_Android Ndk - Fatal编程技术网

在JNI/OpenGL ES加载代码期间,非常规且狡猾的Android崩溃 赏金

在JNI/OpenGL ES加载代码期间,非常规且狡猾的Android崩溃 赏金,android,opengl-es,crash,java-native-interface,android-ndk,Android,Opengl Es,Crash,Java Native Interface,Android Ndk,因为这对我来说是个重要的问题,所以我一直在悬赏。我并不是在寻找确切的答案——不管是什么答案让我解决这个问题,都会得到赏金。请确保您已经看到下面的编辑 编辑:我在Gdb死机的时候(通过“adb shell setprop debug.db.uid 32767”)成功捕捉到了它的崩溃,并注意到这与谷歌群组中提到的问题完全相同。显示的回溯与崩溃线程相同(除了精确地址)。我承认,我不是调试工具向导,所以如果你对我应该寻找什么有任何想法,请告诉我 又快又脏的破烂 我已经把大部分合理的大型应用程序代码剔除了

因为这对我来说是个重要的问题,所以我一直在悬赏。我并不是在寻找确切的答案——不管是什么答案让我解决这个问题,都会得到赏金。请确保您已经看到下面的编辑

编辑:我在Gdb死机的时候(通过“adb shell setprop debug.db.uid 32767”)成功捕捉到了它的崩溃,并注意到这与谷歌群组中提到的问题完全相同。显示的回溯与崩溃线程相同(除了精确地址)。我承认,我不是调试工具向导,所以如果你对我应该寻找什么有任何想法,请告诉我

又快又脏的破烂 <>我已经把大部分合理的大型应用程序代码剔除了,这样应用程序就可以做到:通过JNI包装器(从C++到java)加载一堆纹理,这样java库就可以处理我的解码,使OpenGL纹理脱离它们,并把屏幕清除成一个相当漂亮但却嘲弄的深蓝色。在libc它正在死亡,但每十次只有一次

更糟糕的是,它甚至看起来与我编写的任何代码都没有关系——它似乎是以延迟的方式发生的,但它似乎与垃圾收集器这样容易受到指责的东西没有关系。在我自己的代码中没有崩溃发生的特定点——它似乎在每次运行的基础上改变

长话短说 我最终得到了一个标准的崩溃转储,它有一个堆栈,它什么也不告诉我,因为它有两个条目,一个是libc,一个是看起来无效或空的堆栈帧。libc中解析的符号是pthread_mutex_unlock。我自己甚至不再使用这个函数,因为我已经不再需要多线程。(本机代码在曲面视图中调用,仅渲染。)

pthread_mutex_unlock导致分段错误,通常在地址0处,但有时是一个小值(小于0x200)而不是0。Bionic中的默认(也是最常见的)互斥体只有一个指针,它可以启动,那就是指向pthread_mutex_t结构本身的指针。但是,更复杂的互斥体(有几个选项)可能会使用额外的指针。所以,很可能libc是好的,libdvm也有问题(假设我可以信任我的堆栈跟踪,即使到目前为止)

请允许我注意,如果我做了以下两件事中的一件,这个问题似乎是可以重现的:禁用图像数据部分的加载(但仍在读取格式/尺寸信息),并保留用于将纹理加载到OpenGL中的缓冲区未初始化,或者通过仅禁用最终的glTexImage2D调用来禁用OpenGL纹理的创建

请注意,前面提到的用于将纹理加载到OpenGL的缓冲区只创建一次并销毁一次。我试着放大它,并确定我没有被特定于该缓冲区的缓冲区溢出问题所困扰

我能想到的罪魁祸首是:

  • 我没有正确使用JNI,它对堆栈做了一些不好的事情
  • 我在某个地方发生了一个一个接一个的错误,它破坏了堆栈帧
  • 我正在传递OpenGL ES一些不好的东西,它也在做同样不好的事情(tm)
  • 我的自定义滚动内存分配器无法正常工作
几天来,我一直在梳理我的代码,寻找这样的罪犯(甚至更多!)。我很犹豫是否使用调试器,因为此崩溃似乎对时间敏感。但是,我仍然可以在启用调试选项的情况下,完全未优化自己的本机代码,从而导致崩溃。(gdb本身以爬网方式运行,连接时应用程序也是如此)

我做过的事
  • 使用CheckJNI
  • 尽可能地精简代码,直到它停止崩溃
  • 编写了一个信号处理程序,并对一个小型日志系统进行了编码,以转储在抛出信号之前所做的最后一件事情
  • 试图(但失败)加剧问题
  • 两端都有加粗的本机堆数组。他们从未改变
  • 已审核代码路径中100%的代码。(我只是没有看到问题。)
  • 当我修复一个小错误时,问题神奇地消失了,运行代码50次以确保这是真的,然后在第二天第一次运行时崩溃了。(哦,我从来没有对虫子这么生气过!)
以下是LogCat中常见的本机崩溃信息片段:

I/DEBUG   ( 5818): signal 11 (SIGSEGV), fault addr 00000000
I/DEBUG   ( 5818):  r0 0000006e  r1 00000080  r2 fffffc5e  r3 100ffe58
I/DEBUG   ( 5818):  r4 00000000  r5 00000000  r6 00000000  r7 00000000
I/DEBUG   ( 5818):  r8 00000000  r9 8054f999  10 10000000  fp 0013e768
I/DEBUG   ( 5818):  ip 3b9aca00  sp 100ffe58  lr afd10640  pc 00000000  cpsr 60000010
I/DEBUG   ( 5818):  d0  643a64696f72646e  d1  6472656767756265
I/DEBUG   ( 5818):  d2  8083297880832965  d3  8083298880832973
I/DEBUG   ( 5818):  d4  8083291080832908  d5  8083292080832918
I/DEBUG   ( 5818):  d6  8083293080832928  d7  8083294880832938
I/DEBUG   ( 5818):  d8  0000000000000000  d9  0000000000000000
I/DEBUG   ( 5818):  d10 0000000000000000  d11 0000000000000000
I/DEBUG   ( 5818):  d12 0000000000000000  d13 0000000000000000
I/DEBUG   ( 5818):  d14 0000000000000000  d15 0000000000000000
I/DEBUG   ( 5818):  d16 0000000000000000  d17 3fe999999999999a
I/DEBUG   ( 5818):  d18 42eccefa43de3400  d19 3fe00000000000b4
I/DEBUG   ( 5818):  d20 4008000000000000  d21 3fd99a27ad32ddf5
I/DEBUG   ( 5818):  d22 3fd24998d6307188  d23 3fcc7288e957b53b
I/DEBUG   ( 5818):  d24 3fc74721cad6b0ed  d25 3fc39a09d078c69f
I/DEBUG   ( 5818):  d26 0000000000000000  d27 0000000000000000
I/DEBUG   ( 5818):  d28 0000000000000000  d29 0000000000000000
I/DEBUG   ( 5818):  d30 0000000000000000  d31 0000000000000000
I/DEBUG   ( 5818):  scr 80000012
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818):          #00  pc 00000000  
I/DEBUG   ( 5818):          #01  pc 0001063c  /system/lib/libc.so
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818): code around pc:
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818): code around lr:
I/DEBUG   ( 5818): afd10620 e1a01008 e1a02007 e1a03006 e1a00005 
I/DEBUG   ( 5818): afd10630 ebfff95d e1a05000 e1a00004 ebffff46 
I/DEBUG   ( 5818): afd10640 e375006e 03a0006e 13a00000 e8bd81f0 
I/DEBUG   ( 5818): afd10650 e304cdd3 e3043240 e92d4010 e341c062 
I/DEBUG   ( 5818): afd10660 e1a0e002 e24dd008 e340300f e1a0200d 
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818): stack:
I/DEBUG   ( 5818):     100ffe18  00000000  
I/DEBUG   ( 5818):     100ffe1c  00000000  
I/DEBUG   ( 5818):     100ffe20  00000000  
I/DEBUG   ( 5818):     100ffe24  ffffff92  
I/DEBUG   ( 5818):     100ffe28  100ffe58  
I/DEBUG   ( 5818):     100ffe2c  00000000  
I/DEBUG   ( 5818):     100ffe30  00000080  
I/DEBUG   ( 5818):     100ffe34  8054f999  /system/lib/libdvm.so
I/DEBUG   ( 5818):     100ffe38  10000000  
I/DEBUG   ( 5818):     100ffe3c  afd10640  /system/lib/libc.so
I/DEBUG   ( 5818):     100ffe40  00000000  
I/DEBUG   ( 5818):     100ffe44  00000000  
I/DEBUG   ( 5818):     100ffe48  00000000  
I/DEBUG   ( 5818):     100ffe4c  00000000  
I/DEBUG   ( 5818):     100ffe50  e3a07077  
I/DEBUG   ( 5818):     100ffe54  ef900077  
I/DEBUG   ( 5818): #01 100ffe58  00000000  
I/DEBUG   ( 5818):     100ffe5c  00000000  
I/DEBUG   ( 5818):     100ffe60  00000000  
I/DEBUG   ( 5818):     100ffe64  00000000  
I/DEBUG   ( 5818):     100ffe68  00000000  
I/DEBUG   ( 5818):     100ffe6c  00000000  
I/DEBUG   ( 5818):     100ffe70  00000000  
I/DEBUG   ( 5818):     100ffe74  00000000  
I/DEBUG   ( 5818):     100ffe78  00000000  
I/DEBUG   ( 5818):     100ffe7c  00000000  
I/DEBUG   ( 5818):     100ffe80  00000000  
I/DEBUG   ( 5818):     100ffe84  00000000  
I/DEBUG   ( 5818):     100ffe88  00000000  
I/DEBUG   ( 5818):     100ffe8c  00000000  
I/DEBUG   ( 5818):     100ffe90  00000000  
I/DEBUG   ( 5818):     100ffe94  00000000  
I/DEBUG   ( 5818):     100ffe98  00000000  
I/DEBUG   ( 5818):     100ffe9c  00000000  
使用NDKR6,Android平台2.2(API级别8),仅使用-Wall-Werror编译,ARM模式

我正在研究任何想法,特别是那些可以确定的方式验证的想法。如果更多信息有帮助,请留下评论(如果你不能,请留下答案),我会尽快更新我的问题。谢谢你读到这里

JNI接口 有j2n和n2j调用。目前唯一的j2n调用如下:

private static class Renderer implements GLSurfaceView.Renderer {
    public void onDrawFrame(GL10 gl) {
        GraphicsLib.graphicsStep();
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GraphicsLib.graphicsInit(width, height);
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Do nothing.
    }
}
此代码通过此接口:

public class GraphicsLib {

     static {
         System.loadLibrary("graphicslib");
     }

     public static native void graphicsInit(int width, int height);
     public static native void graphicsStep();
}
在本机端看起来像:

extern "C" {
    JNIEXPORT void JNICALL FN(graphicsInit)(JNIEnv* env, jobject obj,  jint width, jint height);
    JNIEXPORT void JNICALL FN(graphicsStep)(JNIEnv* env, jobject obj);
};
函数定义本身以原型的副本开始

graphicsInit只存储传递的尺寸,并稍微设置OpenGL,而没有任何特别有趣的内容。graphicsStep将屏幕清除为漂亮的颜色,并调用
LoadSprites(env)

更复杂的一面由LoadSprites()中使用的n2j调用组成,该调用每帧加载一个sprite。这不是一个优雅的解决方案,但它一直在工作,这次崩溃除外

LoadSprites的工作原理如下:

GameAssetsInfo gai;
void LoadSprites(JNIEnv* env)
{
    InitGameAssets(gai, env);
    CatchJNIException(env, "j0");
    ...
    static int z = 0;
    if (z < numSprites)
    {
        CatchJNIException(env, "j1");
        OpenGameImage(gai, SpriteIDFromNumber(z));
        CatchJNIException(env, "j2");
        unsigned int actualWidth = GetGameImageWidth(gai);
        CatchJNIException(env, "j3");
        unsigned int actualHeight = GetGameImageHeight(gai);
        CatchJNIException(env, "j4");
        ...
        jint i;
        int r = 0;
        CatchJNIException(env, "j5");
        do {
            CatchJNIException(env, "j6");
            i = ReadGameImage(gai);
            CatchJNIException(env, "j7");
            if (i > 0)
            {
                // Deal with the pure data chunk -- One line at a time.
                CatchJNIException(env, "j8");
                StoreGameImageChunk(gai, (int*)sprites[z].data + r, 0, i);
                ...
                r += sprites[z].width;
                CatchJNIException(env, "j9");
                UnreadGameImage(gai);
                CatchJNIException(env, "j10");
            } else {
                break;
            }
        } while (true);

        CatchJNIException(env, "j11");
        CloseGameImage(gai);
        CatchJNIException(env, "j12");

        ... OpenGL ES calls ...

        glTexImage2D( ... );

        z++;
    }

    CatchJNIException(env, "j13");
}
void InitGameAssets(GameAssetsInfo& gameasset, JNIEnv* env)
{
    CatchJNIException(env, "jS0");
    FST;
    char str[64];
    sprintf(str, "%s/GameAssets", ROOTSTR);

    gameasset.env = env;
    CatchJNIException(gameasset.env, "jS1");
    gameasset.cls = gameasset.env->FindClass(str);
    CatchJNIException(gameasset.env, "jS2");
    gameasset.openAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenAsset", "(I)V");
    CatchJNIException(gameasset.env, "jS3");
    gameasset.readAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadAsset", "()I");
    CatchJNIException(gameasset.env, "jS4");
    gameasset.closeAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseAsset", "()V");
    CatchJNIException(gameasset.env, "jS5");
    gameasset.buffID = gameasset.env->GetStaticFieldID(gameasset.cls, "buff", "[B");

    CatchJNIException(gameasset.env, "jS6");
    gameasset.openImage = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenImage", "(I)V");
    CatchJNIException(gameasset.env, "jS7");
    gameasset.readImage = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadImage", "()I");
    CatchJNIException(gameasset.env, "jS8");
    gameasset.closeImage = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseImage", "()V");
    CatchJNIException(gameasset.env, "jS9");
    gameasset.buffIntID = gameasset.env->GetStaticFieldID(gameasset.cls, "buffInt", "[I");
    CatchJNIException(gameasset.env, "jS10");
    gameasset.imageWidth = gameasset.env->GetStaticFieldID(gameasset.cls, "imageWidth", "I");
    CatchJNIException(gameasset.env, "jS11");
    gameasset.imageHeight = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHeight", "I");
    CatchJNIException(gameasset.env, "jS12");
    gameasset.imageHasAlpha = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHasAlpha", "I");
    CatchJNIException(gameasset.env, "jS13");
}

void OpenGameAsset(GameAssetsInfo& gameasset, int rsc)
{
    FST;
    CatchJNIException(gameasset.env, "jS14");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openAsset, rsc);
    CatchJNIException(gameasset.env, "jS15");
}

void CloseGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS16");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeAsset);
    CatchJNIException(gameasset.env, "jS17");
}

int ReadGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS18");
    int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readAsset);
    CatchJNIException(gameasset.env, "jS19");
    if (ret > 0)
    {
    CatchJNIException(gameasset.env, "jS20");
        gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffID);
    CatchJNIException(gameasset.env, "jS21");
        gameasset.arr = reinterpret_cast<jbyteArray*>(&gameasset.obj);
    }
    return ret;
}

void UnreadGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS22");
    gameasset.env->DeleteLocalRef(gameasset.obj);
    CatchJNIException(gameasset.env, "jS23");
}

void StoreGameAssetChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
    FST;
    CatchJNIException(gameasset.env, "jS24");
    gameasset.env->GetByteArrayRegion(*gameasset.arr, offset, length, (jbyte*)store);
    CatchJNIException(gameasset.env, "jS25");
}

void OpenGameImage(GameAssetsInfo& gameasset, int rsc)
{
    FST;
    CatchJNIException(gameasset.env, "jS26");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openImage, rsc);
    CatchJNIException(gameasset.env, "jS27");
    gameasset.l_imageWidth = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageWidth);
    CatchJNIException(gameasset.env, "jS28");
    gameasset.l_imageHeight = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHeight);
    CatchJNIException(gameasset.env, "jS29");
    gameasset.l_imageHasAlpha = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHasAlpha);
    CatchJNIException(gameasset.env, "jS30");
}

void CloseGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS31");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeImage);
    CatchJNIException(gameasset.env, "jS32");
}

int ReadGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS33");
    int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readImage);
    CatchJNIException(gameasset.env, "jS34");
    if ( ret > 0 )
    {
        CatchJNIException(gameasset.env, "jS35");
        gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffIntID);
        CatchJNIException(gameasset.env, "jS36");
        gameasset.arrInt = reinterpret_cast<jintArray*>(&gameasset.obj);
    }
    return ret;
}

void UnreadGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS37");
    gameasset.env->DeleteLocalRef(gameasset.obj);
    CatchJNIException(gameasset.env, "jS38");
}

void StoreGameImageChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
    FST;
    CatchJNIException(gameasset.env, "jS39");
    gameasset.env->GetIntArrayRegion(*gameasset.arrInt, offset, length, (jint*)store);
    CatchJNIException(gameasset.env, "jS40");
}

int GetGameImageWidth(GameAssetsInfo& gameasset) { return gameasset.l_imageWidth; }
int GetGameImageHeight(GameAssetsInfo& gameasset) { return gameasset.l_imageHeight; }
int GetGameImageHasAlpha(GameAssetsInfo& gameasset) { return gameasset.l_imageHasAlpha; }
GameAssetInfo和相关代码的相关部分仅从本机代码调用,其工作原理如下:

GameAssetsInfo gai;
void LoadSprites(JNIEnv* env)
{
    InitGameAssets(gai, env);
    CatchJNIException(env, "j0");
    ...
    static int z = 0;
    if (z < numSprites)
    {
        CatchJNIException(env, "j1");
        OpenGameImage(gai, SpriteIDFromNumber(z));
        CatchJNIException(env, "j2");
        unsigned int actualWidth = GetGameImageWidth(gai);
        CatchJNIException(env, "j3");
        unsigned int actualHeight = GetGameImageHeight(gai);
        CatchJNIException(env, "j4");
        ...
        jint i;
        int r = 0;
        CatchJNIException(env, "j5");
        do {
            CatchJNIException(env, "j6");
            i = ReadGameImage(gai);
            CatchJNIException(env, "j7");
            if (i > 0)
            {
                // Deal with the pure data chunk -- One line at a time.
                CatchJNIException(env, "j8");
                StoreGameImageChunk(gai, (int*)sprites[z].data + r, 0, i);
                ...
                r += sprites[z].width;
                CatchJNIException(env, "j9");
                UnreadGameImage(gai);
                CatchJNIException(env, "j10");
            } else {
                break;
            }
        } while (true);

        CatchJNIException(env, "j11");
        CloseGameImage(gai);
        CatchJNIException(env, "j12");

        ... OpenGL ES calls ...

        glTexImage2D( ... );

        z++;
    }

    CatchJNIException(env, "j13");
}
void InitGameAssets(GameAssetsInfo& gameasset, JNIEnv* env)
{
    CatchJNIException(env, "jS0");
    FST;
    char str[64];
    sprintf(str, "%s/GameAssets", ROOTSTR);

    gameasset.env = env;
    CatchJNIException(gameasset.env, "jS1");
    gameasset.cls = gameasset.env->FindClass(str);
    CatchJNIException(gameasset.env, "jS2");
    gameasset.openAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenAsset", "(I)V");
    CatchJNIException(gameasset.env, "jS3");
    gameasset.readAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadAsset", "()I");
    CatchJNIException(gameasset.env, "jS4");
    gameasset.closeAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseAsset", "()V");
    CatchJNIException(gameasset.env, "jS5");
    gameasset.buffID = gameasset.env->GetStaticFieldID(gameasset.cls, "buff", "[B");

    CatchJNIException(gameasset.env, "jS6");
    gameasset.openImage = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenImage", "(I)V");
    CatchJNIException(gameasset.env, "jS7");
    gameasset.readImage = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadImage", "()I");
    CatchJNIException(gameasset.env, "jS8");
    gameasset.closeImage = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseImage", "()V");
    CatchJNIException(gameasset.env, "jS9");
    gameasset.buffIntID = gameasset.env->GetStaticFieldID(gameasset.cls, "buffInt", "[I");
    CatchJNIException(gameasset.env, "jS10");
    gameasset.imageWidth = gameasset.env->GetStaticFieldID(gameasset.cls, "imageWidth", "I");
    CatchJNIException(gameasset.env, "jS11");
    gameasset.imageHeight = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHeight", "I");
    CatchJNIException(gameasset.env, "jS12");
    gameasset.imageHasAlpha = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHasAlpha", "I");
    CatchJNIException(gameasset.env, "jS13");
}

void OpenGameAsset(GameAssetsInfo& gameasset, int rsc)
{
    FST;
    CatchJNIException(gameasset.env, "jS14");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openAsset, rsc);
    CatchJNIException(gameasset.env, "jS15");
}

void CloseGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS16");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeAsset);
    CatchJNIException(gameasset.env, "jS17");
}

int ReadGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS18");
    int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readAsset);
    CatchJNIException(gameasset.env, "jS19");
    if (ret > 0)
    {
    CatchJNIException(gameasset.env, "jS20");
        gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffID);
    CatchJNIException(gameasset.env, "jS21");
        gameasset.arr = reinterpret_cast<jbyteArray*>(&gameasset.obj);
    }
    return ret;
}

void UnreadGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS22");
    gameasset.env->DeleteLocalRef(gameasset.obj);
    CatchJNIException(gameasset.env, "jS23");
}

void StoreGameAssetChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
    FST;
    CatchJNIException(gameasset.env, "jS24");
    gameasset.env->GetByteArrayRegion(*gameasset.arr, offset, length, (jbyte*)store);
    CatchJNIException(gameasset.env, "jS25");
}

void OpenGameImage(GameAssetsInfo& gameasset, int rsc)
{
    FST;
    CatchJNIException(gameasset.env, "jS26");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openImage, rsc);
    CatchJNIException(gameasset.env, "jS27");
    gameasset.l_imageWidth = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageWidth);
    CatchJNIException(gameasset.env, "jS28");
    gameasset.l_imageHeight = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHeight);
    CatchJNIException(gameasset.env, "jS29");
    gameasset.l_imageHasAlpha = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHasAlpha);
    CatchJNIException(gameasset.env, "jS30");
}

void CloseGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS31");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeImage);
    CatchJNIException(gameasset.env, "jS32");
}

int ReadGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS33");
    int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readImage);
    CatchJNIException(gameasset.env, "jS34");
    if ( ret > 0 )
    {
        CatchJNIException(gameasset.env, "jS35");
        gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffIntID);
        CatchJNIException(gameasset.env, "jS36");
        gameasset.arrInt = reinterpret_cast<jintArray*>(&gameasset.obj);
    }
    return ret;
}

void UnreadGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS37");
    gameasset.env->DeleteLocalRef(gameasset.obj);
    CatchJNIException(gameasset.env, "jS38");
}

void StoreGameImageChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
    FST;
    CatchJNIException(gameasset.env, "jS39");
    gameasset.env->GetIntArrayRegion(*gameasset.arrInt, offset, length, (jint*)store);
    CatchJNIException(gameasset.env, "jS40");
}

int GetGameImageWidth(GameAssetsInfo& gameasset) { return gameasset.l_imageWidth; }
int GetGameImageHeight(GameAssetsInfo& gameasset) { return gameasset.l_imageHeight; }
int GetGameImageHasAlpha(GameAssetsInfo& gameasset) { return gameasset.l_imageHasAlpha; }
请注意游戏资产代码中明显缺乏线程安全性

让我知道更多信息是否有用。

我无法回答:(,我刚刚遇到了一个类似的问题,注意到java文档某处说什么时候有线程(如果你在做OpenGL,那么就有线程)。你需要
char str[64];
sprintf(str, "%s/GameAssets", ROOTSTR);