簡體   English   中英

System.load 加載兩次本機庫時崩潰

[英]Crash in native libraries loaded twice by System.load

這里我有兩個活動: HomeActivity (啟動器活動)和MainActivity (加載本機庫和調用本機方法):

public class HomeActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(HomeActivity.this, MainActivity.class);
                startActivity(intent);
            }
        });
    }
}

public class MainActivity extends AppCompatActivity {

    // Used to load the 'reproducecrash' library on application startup.

    private ActivityMainBinding binding;

    @SuppressLint("UnsafeDynamicallyLoadedCode")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        //copy .so to app file directory
        File libSavePath = new File(getFilesDir().getAbsolutePath() + "/libreproducecrash.so");
        try {
            InputStream is = getAssets().open("libreproducecrash.so");
            FileOutputStream fos = new FileOutputStream(libSavePath);
            byte[] buffer=new byte[1024];
            int byteCount=0;
            while((byteCount=is.read(buffer))!=-1) {
                fos.write(buffer,0,byteCount);
            }
            fos.flush();
            fos.close();
            is.close();
        }catch (Exception e){
            e.printStackTrace();
        }

        System.load(libSavePath.getPath());
        Log.i("MyLogger", libSavePath.getPath() + " loaded");

        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'reproducecrash' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

我將庫編譯輸出路徑重定向到app/src/main/assets 並在運行時將其復制到應用程序文件目錄(模擬從遠程服務器下載庫)。 通過調用System.load將本機庫加載到 VM 並進行任何 jni 調用。 一切正常,而當我退出MainActivity然后再次進入時應用程序崩潰,即使是本機方法中的第一條日志消息也不會發出

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_reproducecrash_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {

    __android_log_print(ANDROID_LOG_INFO, "MyLogger", "Logging in JNI");
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

我已經將最小可復現代碼上傳到github,請查看這里,謝謝!

更新logcat 報告:

2022-12-12 20:10:32.446 21013-21013/com.example.reproducecrash I/MyLogger: /data/user/0/com.example.reproducecrash/files/libreproducecrash.so loaded
2022-12-12 20:10:32.446 21013-21013/com.example.reproducecrash I/MyLogger: Logging in JNI
2022-12-12 20:10:32.496 21013-21013/com.example.reproducecrash I/Quality: Skipped: false 1 cost 25.242748
2022-12-12 20:10:32.919 21013-21035/com.example.reproducecrash E/BLASTBufferQueue: BLASTBufferItemConsumer::onDisconnect()
2022-12-12 20:10:36.294 21013-21035/com.example.reproducecrash E/BLASTBufferQueue: BLASTBufferItemConsumer::onDisconnect()
2022-12-12 20:10:43.026 21013-21013/com.example.reproducecrash I/oplus.android.OplusFrameworkFactoryImpl: get feature:IOplusDynamicVsyncFeature
2022-12-12 20:10:43.026 21013-21013/com.example.reproducecrash I/oplus.android.OplusFrameworkFactoryImpl: get feature:IOplusDynamicVsyncFeature
2022-12-12 20:10:43.026 21013-21013/com.example.reproducecrash I/oplus.android.OplusFrameworkFactoryImpl: get feature:IOplusDynamicVsyncFeature
2022-12-12 20:10:43.047 21013-21013/com.example.reproducecrash I/MyLogger: /data/user/0/com.example.reproducecrash/files/libreproducecrash.so loaded
2022-12-12 20:10:43.047 21013-21013/com.example.reproducecrash A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xe010 in tid 21013 (.reproducecrash), pid 21013 (.reproducecrash)

更新
添加了一個靜態布爾值以避免兩次加載庫但仍然崩潰:

private static boolean sLibLoaded = false;

if(!sLibLoaded) {
    System.load(libSavePath.getPath());
    Log.i("MyLogger", libSavePath.getPath() + " loaded"); 
    sLibLoaded = true;
}

正如@Michael 所說,確保庫復制加載一次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM