Binari pembantu OpenVPN gagal pada Android 10: kebenaran ditolak
Android 10 enggan melaksanakan pembantu yang ditulis aplikasi ke storannya sendiri. Baca logcat, hantar pembantu sebagai pustaka asli dan baiki binaan bundle.
Aplikasi berfungsi pada Android 9 dan mati pada telefon yang sama selepas kemas kini ke Android 10. Profil anda tidak disentuh, sijil sama, dan ranap berlaku sebelum sebarang trafik pengesahan. Logcat memaparkan penuding nol dahulu, dan beberapa baris di atasnya terdapat Cannot run program ...: error=13, Permission denied. Mesej itu tentang melaksanakan fail, bukan tentang membaca konfigurasi anda.
Apa yang sebenarnya ditolak oleh ralat 13
Android 10, tahap API 29, menghentikan aplikasi daripada melaksanakan fail yang ditulis ke direktori datanya sendiri. Peraturan ini menyasarkan storan yang boleh ditulis dahulu kemudian dilaksanakan, dan itulah yang dicipta oleh pelancar yang menyalin daripada assets. Binaan lama teras ics-openvpn menyahpek fail boleh laksana openvpn daripada APK pada jalan pertama dan memulakannya dengan ProcessBuilder. Penyahlakan masih berjaya; pelaksanaan yang ditolak. Aplikasi yang menyasarkan API 29 mewarisi peraturan itu walaupun berjalan pada peranti yang dikeluarkan dengan versi lebih lama, sebab itu kemas kini boleh merosakkan binaan yang tidak disentuh sesiapa.
Tiada apa dalam penolakan itu khusus untuk satu nama folder. Fail yang dicipta aplikasi di bawah direktori datanya dianggap tidak boleh laksana tanpa mengira laluan, jadi getFilesDir(), getCacheDir() dan subdirektori tersuai semuanya gagal dengan cara yang sama.
Asingkan ranap pembantu daripada masalah profil
Baca log di sekitar permulaan proses dan bukan menatal dari atas. Tandatangan yang dicari ialah baris error=13, dan surih tindanan di atasnya biasanya menamakan kaedah pelancar yang memanggil ProcessBuilder:
adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"Jika pembantu tidak pernah bermula, anda tidak akan melihat sebarang keluaran log OpenVPN: tiada rundingan sifer, tiada laluan ditolak, tiada konfigurasi DNS. Jika baris itu muncul dan kegagalan datang kemudian, binari itu berjalan dan masalahnya ada pada profil, pelayan atau lapisan penghalaan. Satu perbezaan itu menjimatkan banyak masa yang sebaliknya habis untuk menyunting fail .ovpn yang tidak pernah bersalah. Ia juga memberitahu anda yang mana antara dua pembaikan di bawah yang benar-benar anda perlukan.
Semak juga tahap API pada peranti yang anda uji, bukan yang ada dalam konfigurasi binaan anda. Imej emulator pada API 28 tidak menghasilkan apa-apa, kerana sekatan itu hanya menggigit dari 29 ke atas. Semak SDK sasaran dalam fail binaan anda pada masa yang sama: menaikkannya itulah yang menarik peraturan ini masuk.
adb shell getprop ro.build.version.sdkMengapa menyalin binari ke tempat lain tidak membantu
Jalan pintas yang jelas, menulis pembantu ke direktori lain yang boleh ditulis, gagal atas sebab yang sama dengan yang asal. Android masih membenarkan pelaksanaan pustaka kongsi yang dipasang ke direktori pustaka asli aplikasi, kerana pemasang yang membungkusnya dan bukan ditulis semasa jalan. Direktori itulah satu-satunya tempat pelancar patut tuju. Apa sahaja yang anda nyahpek sendiri semasa jalan, apa pun namanya, kekal dalam kategori ditolak.
Storan luaran lebih teruk: ia dipasang dengan noexec, dan pembantu yang diletakkan di situ tidak boleh dimulakan oleh mana-mana aplikasi. Memadam data aplikasi juga tidak memulihkan tingkah laku lama, kerana jalan seterusnya hanya mencipta semula salinan tidak boleh laksana yang sama.
Halakan pelancar ke pustaka yang dibungkus
Namakan semula pembantu kepada nama pustaka kongsi dan hantarkannya di bawah jniLibs untuk setiap ABI yang anda sokong, kemudian biar pelancar memulangkan laluan pustaka yang dipasang dari API 28 dan seterusnya:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new File(context.getApplicationInfo().nativeLibraryDir,
"libovpnexec.so").getPath();
}Pustaka itu mesti dinyahpek semasa pemasangan supaya laluan itu mengandungi fail sebenar, jadi tetapkan android:extractNativeLibs="true" pada elemen <application>. Jika penggabung manifes membawa nilai lain, tambah tools:replace="android:extractNativeLibs" di sebelahnya. rujukan elemen application mendokumenkan apa yang dikawal oleh atribut itu.
Awas pemboleh ubah tempatan berganda apabila anda menampal pelancar dengan tangan. Sumber lama mengisytiharkan nativeAPI lebih kemudian dalam kaedah yang sama, dan pengisytiharan kedua ialah ralat kompilasi bukan ralat masa jalan, jadi binaan gagal cepat dan kesilapan mudah dilihat. Kekalkan senarai ABI dalam blok Gradle selari dengan folder yang anda tambah.
Padankan artifak keluaran dengan binaan ujian
APK debug boleh menaikkan terowong sementara bundle keluaran masih ranap, kerana bundle membungkus pustaka asli dalam bentuk berbeza dan boleh menyajikannya termampat dari arkib. Jika hanya binaan terbitan bundle gagal, tambahkan ini ke gradle.properties dan bina semula:
android.bundle.enableUncompressedNativeLibs=falseKemudian pastikan pakej yang dipasang melaporkan ABI yang anda jangkakan, dan ulangi pemeriksaan pada peranti 32-bit dan 64-bit jika anda menghantar kedua-duanya. Pengurus pakej menamakan ABI yang dipilihnya, jadi peranti yang jatuh ke 32 bit muncul di sini dan bukan dalam laporan ranap:
adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbiPustaka yang hilang untuk satu ABI menghasilkan semula ralat kebenaran asal hanya pada peranti itu, sebab itu satu telefon ujian yang berjaya bukan bukti. Hantar bendera manifes, nama pustaka dan tetapan bundle bersama-sama; menukar satu dan melupakan yang lain membawa anda kembali ke ranap yang sama. Pembaikan berkekalan ialah beralih ke keluaran teras yang diselenggara dan bukan membawa tampalan itu selamanya.