被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。并在运行时将其复制到app文件目录(模拟从远程服务器下载库)。通过调用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所说,确保库复制负载和一次。

最新更新