You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AAssetManager打开文件时崩溃问题求助

AAssetManager调用AAssetManager_open时崩溃的问题排查与解决

崩溃堆栈

#00 pc 00000000000cdd91  /apex/com.android.runtime/lib64/bionic/libc.so (pthread_mutex_lock+1) (BuildId: fa337969c798946280caa45e2d71a2e7)
#01 pc 0000000000050115  /system/lib64/libc++.so (std::__1::mutex::lock()+5) (BuildId: 3324cfa90a3aa967ca9e5c4269b1b7f2)
#02 pc 0000000000018875  /system/lib64/libandroid.so (AAssetManager_open+53) (BuildId: 094d5e744838e61070f3b00f0a8d3c31)

该崩溃由无效Java对象引用导致,现有实现代码如下:

Java层代码

public class MainActivity extends SDLActivity
{

    private AssetManager mgr;

    native void initAManager(AssetManager mgr);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mgr = this.getAssets();
        super.onCreate(savedInstanceState);
        initAManager(mgr);
    }

    /* ... */
}

Native层代码

static jobject omgr = NULL;
static AAssetManager* gmgr = NULL;

JNIEXPORT void JNICALL Java_com_example_MainActivity_initAManager(JNIEnv* env, jobject thiz, jobject mgr) {
    omgr = (*env)->NewGlobalRef(env, mgr);
    gmgr = AAssetManager_fromJava(env, omgr);
}

/* ... */

int open_file(struct ctx mctx, char* name) {
    if((*mctx->env)->IsSameObject(mctx->env, omgr, NULL)) {
        log_print("Asset manager object is invalid"); // 日志中从未出现该行!
    }
    
    AAsset* asset = AAssetManager_open(gmgr, name, AASSET_MODE_RANDOM); // 该行崩溃
    /* ... */
}

已尝试的方案:

  • 应用后期通过JNI动态获取AssetManager,但对象会被垃圾回收变为NULL
  • 更新工具链后问题依旧

解决思路与代码优化

1. 修正对象有效性检查逻辑

IsSameObject无法准确判断已被GC回收的Java对象,改用IsValidObject做有效性校验:

int open_file(struct ctx mctx, char* name) {
    JNIEnv* env = mctx->env;
    if (omgr == NULL || !(*env)->IsValidObject(env, omgr)) {
        log_print("Asset manager object is invalid");
        return -1;
    }
    // ...
}

2. 避免存储全局AAssetManager指针

AAssetManager_fromJava返回的指针依赖于Java层AssetManager对象的生命周期,一旦Java对象被回收,该指针会变成野指针。建议每次使用时通过全局引用的Java对象重新获取:

static jobject omgr = NULL;

JNIEXPORT void JNICALL Java_com_example_MainActivity_initAManager(JNIEnv* env, jobject thiz, jobject mgr) {
    // 先释放旧引用,避免内存泄漏
    if (omgr != NULL) {
        (*env)->DeleteGlobalRef(env, omgr);
    }
    omgr = (*env)->NewGlobalRef(env, mgr);
}

int open_file(struct ctx mctx, char* name) {
    JNIEnv* env = mctx->env;
    if (omgr == NULL || !(*env)->IsValidObject(env, omgr)) {
        log_print("Asset manager object is invalid");
        return -1;
    }
    
    AAssetManager* gmgr = AAssetManager_fromJava(env, omgr);
    if (gmgr == NULL) {
        log_print("Failed to retrieve AAssetManager");
        return -1;
    }
    
    AAsset* asset = AAssetManager_open(gmgr, name, AASSET_MODE_RANDOM);
    // ...
}

3. 维护Java层与Native层引用的生命周期同步

在Activity销毁时主动释放Native层的全局引用,避免内存泄漏和无效引用:
Java层补充代码:

@Override
protected void onDestroy() {
    destroyAManager();
    super.onDestroy();
}

native void destroyAManager();

Native层补充代码:

JNIEXPORT void JNICALL Java_com_example_MainActivity_destroyAManager(JNIEnv* env, jobject thiz) {
    if (omgr != NULL) {
        (*env)->DeleteGlobalRef(env, omgr);
        omgr = NULL;
    }
}

4. 确保线程安全

如果open_file在非JNI调用线程执行,需要先将线程Attach到VM并获取当前线程的JNIEnv:

int open_file(struct ctx mctx, char* name) {
    JNIEnv* env = NULL;
    // 假设mctx中保存了JavaVM指针
    if ((*mctx->vm)->AttachCurrentThread(mctx->vm, &env, NULL) != JNI_OK) {
        log_print("Failed to attach thread");
        return -1;
    }
    
    // 执行AssetManager操作...
    
    (*mctx->vm)->DetachCurrentThread(mctx->vm);
    return 0;
}

内容的提问来源于stack exchange,提问作者scored

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:34:53