OpenVPN pomoćni binarni program ne radi na Androidu 10: dozvola odbijena
Android 10 odbija da izvrši pomoćni fajl koji je aplikacija upisala u vlastito skladište. Pročitajte logcat, isporučite pomoćni program kao izvornu biblioteku i popravite bundle buildove.
Aplikacija je radila na Androidu 9 i umire na istom telefonu nakon nadogradnje na Android 10. Vaš profil je netaknut, certifikati su isti, a pad dolazi prije ikakvog saobraćaja autentifikacije. Logcat prvo pokazuje null pokazivač, a nekoliko redova iznad stoji Cannot run program ...: error=13, Permission denied. Ta poruka govori o izvršavanju fajla, ne o čitanju vaše konfiguracije.
Šta greška 13 zapravo odbija
Android 10, nivo API-ja 29, zaustavio je aplikacije u izvršavanju fajlova koje su upisale u vlastiti direktorij podataka. Pravilo cilja na skladište koje je prvo upisivo pa izvršivo, što je upravo ono što stvara pokretač koji kopira iz assets. Starije verzije jezgre ics-openvpn raspakiraju izvršni fajl openvpn iz APK-a pri prvom pokretanju i startaju ga pomoću ProcessBuilder. Raspakivanje i dalje uspijeva; odbija se izvršavanje. Aplikacija koja cilja API 29 nasljeđuje pravilo čak i kada radi na uređaju koji je stigao sa starijim izdanjem, zato nadogradnja može pokvariti build koji niko nije dirao.
Ništa u vezi s odbijanjem nije specifično za jedno ime mape. Fajl koji je aplikacija napravila unutar svog direktorija podataka tretira se kao neizvršiv bez obzira na putanju, pa getFilesDir(), getCacheDir() i prilagođeni poddirektorij svi padaju na isti način.
Odvojite pad pomoćnog programa od problema s profilom
Čitajte log oko pokretanja procesa umjesto da skrolate od vrha. Potpis koji tražite je red error=13, a stack trace iznad njega obično navodi metodu pokretača koja je pozvala ProcessBuilder:
adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"Ako se pomoćni program nikad nije pokrenuo, nećete vidjeti nikakav OpenVPN izlaz u logu: ni pregovaranje šifri, ni progurane rute, ni DNS konfiguraciju. Ako se ti redovi ipak pojave i pad dođe kasnije, binarni program je radio, a problem je u profilu, serveru ili sloju usmjeravanja. Ta jedna razlika štedi mnogo vremena utrošenog na uređivanje fajlova .ovpn koji nikad nisu bili krivi. Također vam kaže koja od dvije ispravke ispod vam je zaista potrebna.
Provjerite i nivo API-ja na uređaju koji testirate, ne onaj u vašoj konfiguraciji builda. Slika emulatora na API-ju 28 ne reprodukuje ništa, jer ograničenje djeluje tek od 29 naviše. Istovremeno provjerite ciljni SDK u svojoj build datoteci: upravo ga podizanje uvlači to pravilo.
adb shell getprop ro.build.version.sdkZašto kopiranje binarnog programa drugdje ne pomaže
Očigledno zaobilazno rješenje, upisivanje pomoćnog programa u drugi upisivi direktorij, pada iz istog razloga kao i original. Android još uvijek dozvoljava izvršavanje dijeljenih biblioteka instaliranih u direktorij izvornih biblioteka aplikacije, jer ih pakira instalater, a ne upisuje se u vrijeme izvršavanja. Taj direktorij je jedino mjesto na koje pokretač treba da pokazuje. Sve što sami raspakirate u vrijeme izvršavanja, kako god da ga nazovete, ostaje u odbijenoj kategoriji.
Eksterno skladište je gore: montirano je s noexec, a pomoćni program tamo ne može pokrenuti nijedna aplikacija. Brisanje podataka aplikacije također ne vraća staro ponašanje, jer sljedeće pokretanje jednostavno ponovo stvara istu neizvršivu kopiju.
Usmjerite pokretač na pakiranu biblioteku
Preimenujte pomoćni program u ime dijeljene biblioteke i isporučite ga pod jniLibs za svaki ABI koji podržavate, a zatim neka pokretač vraća putanju instalirane biblioteke od API-ja 28 nadalje:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new File(context.getApplicationInfo().nativeLibraryDir,
"libovpnexec.so").getPath();
}Biblioteka mora biti raspakirana pri instalaciji da bi ta putanja sadržavala stvarni fajl, pa postavite android:extractNativeLibs="true" na element <application>. Ako merger manifesta unese drugu vrijednost, dodajte tools:replace="android:extractNativeLibs" pored toga. referenca elementa application dokumentuje šta ta atribut kontroliše.
Pazite na dupliranu lokalnu varijablu kada pokretač krpate ručno. Stariji izvori deklarišu nativeAPI kasnije u istoj metodi, a druga deklaracija je greška pri kompajliranju, a ne u vrijeme izvršavanja, pa build brzo pada i grešku je lako uočiti. Držite listu ABI-ja u Gradle bloku usklađenom s mapama koje dodajete.
Uskladite release artefakt s testnim buildom
Debug APK može podići tunel dok release bundle još pada, jer bundle pakira izvorne biblioteke u drugom obliku i može ih posluživati komprimovane iz arhive. Ako padaju samo buildovi iz bundlea, dodajte ovo u gradle.properties i ponovo izgradite:
android.bundle.enableUncompressedNativeLibs=falseZatim potvrdite da instalirani paket prijavljuje ABI koji očekujete, i ponovite provjeru na 32-bitnom i 64-bitnom uređaju ako isporučujete oba. Upravitelj paketa navodi ABI koji je odabrao, pa se uređaj koji je pao na 32 bita pojavljuje ovdje, a ne u izvještaju o padu:
adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbiNedostajuća biblioteka za jedan ABI reprodukuje izvornu grešku dozvole samo na tom uređaju, zato jedan uspješan testni telefon nije dokaz. Isporučite manifest zastavicu, ime biblioteke i postavku bundlea zajedno; promjena jednog i zaboravljanje ostalih vraća vas na isti pad. Trajno rješenje je preći na održavano izdanje jezgre umjesto vječnog nošenja zakrpe.