[英]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.