OpenVPN көмекші бинарі Android 10-да істемейді: рұқсат берілмеді
Android 10 қолданба өз қоймасына жазған көмекші файлды орындаудан бас тартады. logcat оқыңыз, көмекшіні жергілікті кітапхана ретінде жеткізіңіз және bundle құрастыруларын түзетіңіз.
Қолданба Android 9-да жұмыс істеді және Android 10-ға жаңартқаннан кейін сол телефонда өледі. Профиліңізге тиілмеген, сертификаттар бірдей, ал құлау кез келген аутентификация трафигінен бұрын келеді. logcat алдымен нөлдік көрсеткішті көрсетеді, ал одан бірнеше жол жоғары тұр Cannot run program ...: error=13, Permission denied. Бұл хабарлама файлды орындау туралы, конфигурацияңызды оқу туралы емес.
13-қате шын мәнінде нені қабылдамайды
Android 10, API деңгейі 29, қолданбалардың өз деректер каталогына жазған файлдарын орындауын тоқтатты. Ереже алдымен жазылатын, сосын орындалатын қойманы көздейді, және дәл осыны assets ішінен көшіретін іске қосқыш жасайды. ics-openvpn ядросының ескі құрастырулары бірінші іске қосқанда APK-дан орындалатын openvpn файлын шығарып, оны ProcessBuilder арқылы іске қосады. Шығару әлі де сәтті; қабылданбайтыны — орындау. API 29-ға бағытталған қолданба бұл ережені ескірек шығарылыммен келген құрылғыда жұмыс істегенде де мұраланады, сондықтан жаңарту ешкім тимеген құрастыруды бұзуы мүмкін.
Бас тартуда бір қалта атауына тән ештеңе жоқ. Қолданба өз деректер каталогының астында жасаған файл жолға қарамастан орындалмайтын деп саналады, сондықтан getFilesDir(), getCacheDir() және теңшелген қосалқы каталог бәрі бірдей сәтсіз болады.
Көмекші құлауын профиль мәселесінен ажыратыңыз
Процестің басталуы айналасындағы логты оқыңыз, жоғарыдан айналдырмаңыз. Іздейтін қолтаңба — error=13 жолы, ал оның үстіндегі стек ізі әдетте ProcessBuilder-ін шақырған іске қосқыш әдісін атайды:
adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"Егер көмекші ешқашан іске қосылмаса, OpenVPN лог шығысын мүлде көрмейсіз: шифр келіссөзі де, жіберілген маршруттар да, DNS конфигурациясы да жоқ. Егер сол жолдар пайда болып, сәтсіздік кейінірек келсе, бинар жұмыс істеген және мәселе профильде, серверде немесе маршруттау қабатында. Осы бір айырмашылық .ovpn файлдарын өңдеуге кетердей көп уақытты үнемдейді, олар ешқашан кінәлі болмаған. Ол сондай-ақ төмендегі екі түзетудің қайсысы шынымен керек екенін айтады.
Сынап жатқан құрылғыдағы API деңгейін де тексеріңіз, құрастыру конфигурацияңыздағыны емес. API 28-дегі эмулятор бейнесі ештеңені қайта шығармайды, өйткені шектеу тек 29-дан жоғары әсер етеді. Сонымен бірге құрастыру файлыңыздағы мақсатты SDK-ны тексеріңіз: дәл оны көтеру осы ережені ішке тартады.
adb shell getprop ro.build.version.sdkНеге бинарды басқа жерге көшіру көмектеспейді
Айқын айналма жол, көмекшіні басқа жазылатын каталогқа жазу, түпнұсқа сәтсіз болған себеппен сәтсіз болады. Android әлі де қолданбаның жергілікті кітапханалар каталогына орнатылған ортақ кітапханаларды орындауға рұқсат береді, өйткені оларды орнатушы жинақтайды, орындалу кезінде жазылмайды. Дәл сол каталог — іске қосқыш сілтеуі тиіс жалғыз орын. Орындалу кезінде өзіңіз шығаратынның бәрі, қалай атасаңыз да, қабылданбаған санатта қалады.
Сыртқы қойма одан да нашар: ол noexec-пен тіркелген, ал сонда қойылған көмекшіні ешбір қолданба іске қоса алмайды. Қолданба деректерін тазалау да ескі мінез-құлықты қайтармайды, өйткені келесі іске қосу сол орындалмайтын көшірмені қайта жасайды.
Іске қосқышты жинақталған кітапханаға бағыттаңыз
Көмекшіні ортақ кітапхана атауына өзгертіп, оны қолдайтын әрбір ABI үшін jniLibs астында жеткізіңіз, сосын іске қосқыш API 28-ден бастап орнатылған кітапхана жолын қайтарсын:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new File(context.getApplicationInfo().nativeLibraryDir,
"libovpnexec.so").getPath();
}Бұл жолда нақты файл болуы үшін кітапхана орнату кезінде шығарылуы керек, сондықтан android:extractNativeLibs="true" мәнін <application> элементіне орнатыңыз. Егер manifest біріктіргіші басқа мән әкелсе, оның қасына tools:replace="android:extractNativeLibs" қосыңыз. application элементінің анықтамасы бұл атрибут нені басқаратынын сипаттайды.
Іске қосқышты қолмен патчтағанда қайталанған жергілікті айнымалыдан сақ болыңыз. Ескі дереккөздер сол әдісте кейінірек nativeAPI деп жариялайды, ал екінші жариялау орындалу емес, компиляция қатесі, сондықтан құрастыру тез сәтсіз болады және қатені байқау оңай. Gradle блогындағы ABI тізімін қосқан қалталарыңызбен үйлестіріп ұстаңыз.
Шығарылым артефактісін сынақ құрастыруымен сәйкестендіріңіз
Жөндеу APK туннельді көтере алады, ал шығарылым bundle әлі құлайды, өйткені bundle жергілікті кітапханаларды басқа пішінде жинақтап, оларды мұрағаттан сығылған күйде ұсына алады. Тек bundle-дан шыққан құрастырулар сәтсіз болса, мынаны gradle.properties-не қосып, қайта құрастырыңыз:
android.bundle.enableUncompressedNativeLibs=falseСосын орнатылған пакет күткен ABI-ді хабарлайтынын растаңыз, екеуін де жеткізсеңіз, тексеруді 32 биттік және 64 биттік құрылғыда қайталаңыз. Пакет менеджері таңдаған ABI-ін атайды, сондықтан 32 битке қайтқан құрылғы құлау есебінде емес, осында көрінеді:
adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbiБір ABI үшін жоқ кітапхана бастапқы рұқсат қатесін тек сол құрылғыда қайта шығарады, сондықтан бір сәтті сынақ телефоны дәлел емес. Manifest жалаушасын, кітапхана атауын және bundle параметрін бірге жеткізіңіз; біреуін өзгертіп, қалғанын ұмытсаңыз, сол құлауға қайта ораласыз. Тұрақты шешім — патчты мәңгі алып жүру емес, қолдау көрсетілетін ядро шығарылымына көшу.