Ilova Android 9'da ishlagan va Android 10 yangilanishidan keyin o'sha telefonda o'ladi. Profilingiz tegilmagan, sertifikatlar bir xil, va halokat har qanday autentifikatsiya trafigidan oldin keladi. logcat avval null ko'rsatkichni ko'rsatadi, undan bir necha satr yuqorida esa Cannot run program ...: error=13, Permission denied. Bu xabar faylni ishga tushirish haqida, konfiguratsiyangizni o'qish haqida emas.

13-xato aslida nimani rad etadi

Android 10, API darajasi 29, ilovalarning o'z ma'lumotlar katalogiga yozgan fayllarini ishga tushirishini to'xtatdi. Qoida avval yoziladigan, keyin ishga tushiriladigan xotirani nishonga oladi, va assetsdan nusxa ko'chiruvchi ishga tushirgich aynan shuni yaratadi. ics-openvpn yadrosining eski yig'ishlari birinchi ishga tushishda APKdan ishga tushiriladigan openvpn faylini chiqaradi va uni ProcessBuilder orqali boshlaydi. Chiqarish hali ham muvaffaqiyatli; rad etiladigan narsa — ishga tushirish. API 29 ga mo'ljallangan ilova eskiroq versiya bilan chiqqan qurilmada ishlaganda ham bu qoidani meros oladi, shuning uchun yangilanish hech kim tegmasan yig'ishni buzishi mumkin.

Rad etishda bitta papka nomiga xos hech narsa yo'q. Ilova o'z ma'lumotlar katalogi ostida yaratgan fayl yo'ldan qat'i nazar bajarilmaydigan deb hisoblanadi, shuning uchun getFilesDir(), getCacheDir() va moslashtirilgan quyi katalog hammasi bir xil tarzda muvaffaqiyatsiz bo'ladi.

Yordamchi halokatini profil muammosidan ajrating

Yuqoridan aylantirish o'rniga jarayon boshlanishi atrofidagi jurnalni o'qing. Izlanadigan imzo — error=13 satri, va uning ustidagi stek izi odatda ProcessBuilder ni chaqirgan ishga tushirgich usulini nomlaydi:

adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"

Agar yordamchi hech qachon boshlanmagan bo'lsa, siz OpenVPN jurnal chiqishini umuman ko'rmaysiz: na shifr muzokarasi, na surilgan marshrutlar, na DNS sozlamasi. Agar o'sha satrlar paydo bo'lib, xatolik keyinroq kelsa, binar ishlagan va muammo profilda, serverda yoki marshrutlash qatlamida. Shu bitta farq .ovpn fayllarini tahrirlashga ketadigan ko'p vaqtni tejaydi, ular hech qachon aybdor bo'lmagan. Shuningdek, quyidagi ikki tuzatishdan qaysi biri sizga haqiqatan kerakligini aytadi.

Sinab ko'rayotgan qurilmangizdagi API darajasini ham tekshiring, yig'ish konfiguratsiyangizdagini emas. API 28 dagi emulyator tasviri hech narsani qayta hosil qilmaydi, chunki cheklov faqat 29 dan yuqoriga ta'sir qiladi. Shu bilan birga yig'ish faylingizdagi maqsadli SDK ni tekshiring: aynan uni ko'tarish bu qoidani ichkariga tortadi.

adb shell getprop ro.build.version.sdk

Nega binarni boshqa joyga nusxalash yordam bermaydi

Ko'rinib turgan yechim, yordamchini boshqa yoziladigan katalogga yozish, asl nusxa muvaffaqiyatsiz bo'lgan sabab bilan muvaffaqiyatsiz bo'ladi. Android hali ham ilovaning mahalliy kutubxonalar katalogiga o'rnatilgan umumiy kutubxonalarni ishga tushirishga ruxsat beradi, chunki ularni o'rnatuvchi paketlaydi, ishlash vaqtida yozilmaydi. Aynan shu katalog ishga tushirgich ko'rsatishi kerak bo'lgan yagona joy. Ishlash vaqtida o'zingiz chiqaradigan har qanday narsa, qanday nom bermang, rad etilgan toifada qoladi.

Tashqi xotira undan yomonroq: u noexec bilan ulangan, va u yerda qo'yilgan yordamchini hech bir ilova ishga tushira olmaydi. Ilova ma'lumotlarini tozalash ham eski xatti-harakatni qaytarmaydi, chunki keyingi ishga tushirish shunchaki o'sha bajarilmaydigan nusxani qayta yaratadi.

Ishga tushirgichni paketlangan kutubxonaga yo'naltiring

Yordamchi nomini umumiy kutubxona nomiga o'zgartiring va uni qo'llab-quvvatlaydigan har bir ABI uchun jniLibs ostida taqdim eting, so'ng ishga tushirgich API 28 dan boshlab o'rnatilgan kutubxona yo'lini qaytarsin:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    return new File(context.getApplicationInfo().nativeLibraryDir,
                    "libovpnexec.so").getPath();
}

Ushbu yo'lda haqiqiy fayl bo'lishi uchun kutubxona o'rnatish paytida chiqarilishi kerak, shuning uchun android:extractNativeLibs="true" ni <application> elementiga o'rnating. Agar manifest birlashtiruvchisi boshqa qiymat keltirsa, uning yoniga tools:replace="android:extractNativeLibs" qo'shing. application elementi ma'lumotnomasi bu atribut nimani boshqarishini hujjatlashtiradi.

Ishga tushirgichni qo'lda yamoqlaganda takrorlangan mahalliy o'zgaruvchidan ehtiyot bo'ling. Eski manbalar o'sha usulda keyinroq nativeAPI deb e'lon qiladi, va ikkinchi e'lon ishlash vaqti emas, kompilyatsiya xatosi, shuning uchun yig'ish tez muvaffaqiyatsiz bo'ladi va xatoni payqash oson. Gradle blokidagi ABI ro'yxatini qo'shgan papkalaringiz bilan uyg'un saqlang.

Chiqarish artefaktini sinov yig'ishi bilan moslashtiring

Debug APK tunnelni ko'tarishi mumkin, chiqarish bundle esa hali ham halokatga uchraydi, chunki bundle mahalliy kutubxonalarni boshqa shaklda paketlaydi va ularni arxivdan siqilgan holda taqdim etishi mumkin. Agar faqat bundle dan olingan yig'ishlar muvaffaqiyatsiz bo'lsa, buni gradle.properties ga qo'shing va qayta yig'ing:

android.bundle.enableUncompressedNativeLibs=false

So'ng o'rnatilgan paket kutilgan ABI ni xabar qilishiga ishonch hosil qiling, va ikkalasini ham taqdim etsangiz, tekshiruvni 32 bitli va 64 bitli qurilmada takrorlang. Paket menejeri tanlagan ABI ni nomlaydi, shuning uchun 32 bitga qaytgan qurilma halokat hisobotida emas, shu yerda ko'rinadi:

adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbi

Bitta ABI uchun yetishmayotgan kutubxona asl ruxsat xatosini faqat o'sha qurilmada qayta hosil qiladi, shuning uchun bitta muvaffaqiyatli sinov telefoni dalil emas. Manifest bayrog'ini, kutubxona nomini va bundle sozlamasini birga taqdim eting; birini o'zgartirib qolganini unutish sizni o'sha halokatga qaytaradi. Barqaror yechim — yamoqni abadiy ko'tarish emas, qo'llab-quvvatlanadigan yadro chiqarishiga o'tish.

O'xshash maqolalar