OpenVPN palīgbinārais fails neizdodas operētājsistēmā Android 10: piekļuve liegta
Android 10 atsakās izpildīt palīgu, ko lietotne ierakstījusi savā krātuvē. Lasiet logcat, piegādājiet palīgu kā vietējo bibliotēku un izlabojiet bundle būvējumus.
Lietotne darbojās operētājsistēmā Android 9 un mirst tajā pašā telefonā pēc atjauninājuma uz Android 10. Jūsu profils ir neskarts, sertifikāti ir tie paši, un avārija iestājas pirms jebkādas autentifikācijas plūsmas. Logcat vispirms rāda nulles rādītāju, un dažas rindas virs tā atrodas Cannot run program ...: error=13, Permission denied. Šis ziņojums ir par faila izpildi, nevis par jūsu konfigurācijas lasīšanu.
Ko kļūda 13 patiesībā atsaka
Android 10, API līmenis 29, apturēja lietotņu spēju izpildīt failus, ko tās ierakstījušas savā datu direktorijā. Noteikums vēršas pret krātuvi, kas vispirms ir rakstāma un pēc tam izpildāma, un tieši to rada palaidējs, kas kopē no assets. Vecāki ics-openvpn kodola būvējumi pirmajā palaišanā izpako no APK izpildāmo failu openvpn un palaiž to ar ProcessBuilder. Izpakošana joprojām izdodas; atteikta tiek tieši izpilde. Lietotne, kas mērķē uz API 29, manto noteikumu arī tad, kad darbojas ierīcē, kas nākusi ar vecāku versiju, tāpēc atjauninājums var salauzt būvējumu, kam neviens nav pieskāries.
Atteikumā nav nekā raksturīga vienam mapes nosaukumam. Fails, ko lietotne izveidojusi savā datu direktorijā, tiek uzskatīts par neizpildāmu neatkarīgi no ceļa, tāpēc getFilesDir(), getCacheDir() un pielāgota apakšdirektorija visas neizdodas vienādi.
Atdaliet palīga avāriju no profila problēmas
Lasiet žurnālu ap procesa palaišanu, nevis ritiniet no augšas. Paraksts, ko meklēt, ir rinda error=13, un steka izsekojums virs tās parasti nosauc palaidēja metodi, kas izsauca ProcessBuilder:
adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"Ja palīgs nekad nav startējis, jūs vispār neredzēsiet OpenVPN žurnāla izvadi: ne šifru sarunas, ne aizstumtus maršrutus, ne DNS konfigurāciju. Ja šīs rindas tomēr parādās un kļūme nāk vēlāk, binārais fails darbojās un problēma ir profilā, serverī vai maršrutēšanas slānī. Šī vienīgā atšķirība ietaupa daudz laika, kas citādi aizietu, labojot failus .ovpn, kuri nekad nav bijuši vainīgi. Tā arī pasaka, kura no divām zemāk esošajām labojumiem jums patiešām vajadzīga.
Pārbaudiet arī API līmeni ierīcē, kuru testējat, nevis to, kas ir jūsu būvējuma konfigurācijā. Emulatora attēls ar API 28 neko neatveido, jo ierobežojums kodas tikai no 29 uz augšu. Tajā pašā laikā pārbaudiet mērķa SDK savā būvējuma failā: tieši tā pacelšana ievelk šo noteikumu.
adb shell getprop ro.build.version.sdkKāpēc binārā faila kopēšana citur nepalīdz
Acīmredzamā apiešana, palīga ierakstīšana citā rakstāmā direktorijā, neizdodas tā paša iemesla dēļ kā oriģināls. Android joprojām atļauj izpildīt koplietotās bibliotēkas, kas instalētas lietotnes vietējo bibliotēku direktorijā, jo tās iepako instalētājs, nevis tās tiek rakstītas izpildes laikā. Tieši šī direktorija ir vienīgā vieta, uz kuru palaidējam jānorāda. Viss, ko jūs pats izpakojat izpildes laikā, lai kā to sauktu, paliek atteiktajā kategorijā.
Ārējā krātuve ir sliktāka: tā ir montēta ar noexec, un tur ievietotu palīgu nevar palaist neviena lietotne. Arī lietotnes datu notīrīšana neatjauno veco uzvedību, jo nākamā palaišana vienkārši atkal izveido to pašu neizpildāmo kopiju.
Novirziet palaidēju uz iepakotu bibliotēku
Pārdēvējiet palīgu par koplietotās bibliotēkas nosaukumu un piegādājiet to zem jniLibs katrai atbalstītajai ABI, pēc tam ļaujiet palaidējam no API 28 atgriezt instalētās bibliotēkas ceļu:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new File(context.getApplicationInfo().nativeLibraryDir,
"libovpnexec.so").getPath();
}Bibliotēka ir jāizpako instalēšanas laikā, lai šajā ceļā būtu īsts fails, tāpēc iestatiet android:extractNativeLibs="true" elementam <application>. Ja manifestu savienotājs ienes citu vērtību, pievienojiet tools:replace="android:extractNativeLibs" tam blakus. application elementa atsauce dokumentē, ko šis atribūts kontrolē.
Uzmanieties no dublēta vietējā mainīgā, kad palaidēju labojat ar roku. Vecāki avoti tajā pašā metodē vēlāk deklarē nativeAPI, un otrā deklarācija ir kompilēšanas, nevis izpildes kļūda, tāpēc būvējums ātri neizdodas un kļūdu ir viegli pamanīt. Turiet Gradle bloka ABI sarakstu saskaņotu ar mapēm, ko pievienojat.
Saskaņojiet izlaiduma artefaktu ar testa būvējumu
Atkļūdošanas APK var pacelt tuneli, kamēr izlaiduma bundle joprojām avarē, jo bundle iepako vietējās bibliotēkas citā formā un var tās pasniegt saspiestas no arhīva. Ja neizdodas tikai no bundle iegūti būvējumi, pievienojiet šo gradle.properties failam un pārbūvējiet:
android.bundle.enableUncompressedNativeLibs=falsePēc tam apstipriniet, ka instalētā pakotne ziņo gaidīto ABI, un atkārtojiet pārbaudi 32 bitu un 64 bitu ierīcē, ja piegādājat abas. Pakotņu pārvaldnieks nosauc izvēlēto ABI, tāpēc ierīce, kas atkritusi uz 32 bitiem, parādās šeit, nevis avārijas ziņojumā:
adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbiTrūkstoša bibliotēka vienai ABI atkārto sākotnējo piekļuves kļūdu tikai tajā ierīcē, tāpēc viens veiksmīgs testa tālrunis nav pierādījums. Piegādājiet manifesta karodziņu, bibliotēkas nosaukumu un bundle iestatījumu kopā; mainot vienu un aizmirstot pārējos, jūs atgriezīsities pie tās pašas avārijas. Ilgtspējīgais risinājums ir pāriet uz uzturētu kodola laidienu, nevis mūžīgi nēsāt lāpu.