OpenVPN-hjelpebinæra feilar på Android 10: tilgang nekta
Android 10 nektar å køyre ein hjelpar appen har skrive til sitt eige lager. Les logcat, lever hjelparen som eit innebygd bibliotek, og reparer bundle-bygg.
Appen verka på Android 9 og døyr på same telefon etter oppdateringa til Android 10. Profilen din er urørt, sertifikata er dei same, og krasjet kjem før nokon autentiseringstrafikk. Logcat viser først ein null-peikar, og nokre linjer over han står Cannot run program ...: error=13, Permission denied. Den meldinga handlar om å køyre ei fil, ikkje om å lese konfigurasjonen din.
Kva feil 13 eigentleg avviser
Android 10, API-nivå 29, stoppa apper frå å køyre filer dei hadde skrive i si eiga datamappe. Regelen rammar lager som først er skrivbart og deretter køyrbart, og det er nøyaktig det ein oppstartar som kopierer ut av assets lagar. Eldre bygg av ics-openvpn-kjerna pakkar ut ei køyrbar fil openvpn frå APK-en ved første køyring og startar ho med ProcessBuilder. Uttpakkinga lukkast framleis; det er køyringa som blir avvist. Ein app som rettar seg mot API 29 arvar regelen sjølv når han køyrer på eining som kom med eldre versjon, og difor kan ei oppdatering øydeleggje eit bygg som ingen har rørt.
Ingenting ved avvisinga er spesifikt for eitt mappenamn. Ei fil appen har laga under datamappa si blir handsama som ikkje køyrbar uansett sti, så getFilesDir(), getCacheDir() og ei eiga undermappe feilar alle på same måte.
Skil krasjet til hjelparen frå eit profilproblem
Les loggen rundt prosessstarten i staden for å rulle frå toppen. Signaturen du leitar etter er linja error=13, og stakksporet over ho nemner vanlegvis oppstartarmetoden som kalla på ProcessBuilder:
adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"Om hjelparen aldri starta, ser du inga OpenVPN-logutskrift i det heile: inga chiffer-forhandling, ingen dytta ruter, ingen DNS-konfigurasjon. Om dei linjene likevel dukkar opp og feilen kjem seinare, køyrde binæra, og problemet ligg i profilen, tenaren eller rutingslaget. Den eine skilnaden sparer mykje tid som elles ville gått med til å redigere filer .ovpn som aldri var skuldige. Han fortel deg òg kva av dei to rettingane nedanfor du faktisk treng.
Sjekk òg API-nivået på eininga du testar, ikkje det i byggjekonfigurasjonen din. Eit emulatorbilete på API 28 attskapar ingenting, fordi avgrensinga først bit frå 29 og oppover. Sjekk samstundes mål-SDK-en i byggjefila di: det er hevinga av han som dreg regelen inn.
adb shell getprop ro.build.version.sdkKvifor det ikkje hjelper å kopiere binæra ein annan stad
Den openberre omvegen, å skrive hjelparen til ei anna skrivbar mappe, feilar av same grunn som originalen. Android tillèt framleis å køyre delte bibliotek som er installerte i den innebygde bibliotekmappa til appen, fordi installasjonsprogrammet pakkar dei i staden for at dei blir skrivne ved køyring. Den mappa er den einaste staden oppstartaren bør peike på. Alt du sjølv pakkar ut ved køyring, kva du enn kallar det, blir i den avviste kategorien.
Eksternt lager er verre: det er montert med noexec, og ein hjelpar som ligg der kan ikkje startast av nokon app. Å tømme appdata gjenopprettar heller ikkje den gamle åtferda, fordi neste køyring berre lagar den same ikkje-køyrbare kopien på nytt.
Rett oppstartaren mot eit pakka bibliotek
Gi hjelparen nytt namn til eit delt-biblioteknamn og lever han under jniLibs for kvar ABI du støttar, og la deretter oppstartaren returnere stien til det installerte biblioteket frå API 28 og oppover:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new File(context.getApplicationInfo().nativeLibraryDir,
"libovpnexec.so").getPath();
}Biblioteket må pakkast ut ved installasjon for at den stien skal innehalde ei ekte fil, så set android:extractNativeLibs="true" på elementet <application>. Om ein manifest-samanslåing dreg inn ein annan verdi, legg til tools:replace="android:extractNativeLibs" ved sida av. referansen for application-elementet dokumenterer kva attributtet styrer.
Pass på ein duplisert lokal variabel når du patchar oppstartaren for hand. Eldre kjelder deklarerer nativeAPI seinare i same metode, og ein andre deklarasjon er ein kompileringsfeil og ikkje ein køyrefeil, så bygget feilar raskt og feilen er lett å sjå. Hald ABI-lista i Gradle-blokka i takt med mappene du legg til.
Få utgivingsartefakten til å passe med testbygget
Ein debug-APK kan reise tunnelen medan ein utgivings-bundle framleis krasjar, fordi ein bundle pakkar innebygde bibliotek i ei anna form og kan levere dei komprimerte frå arkivet. Om berre bundle-avleidde bygg feilar, legg til dette i gradle.properties og bygg på nytt:
android.bundle.enableUncompressedNativeLibs=falseStadfest deretter at den installerte pakken rapporterer ABI-en du forventar, og gjenta kontrollen på ei 32-bit og ei 64-bit eining om du leverer begge. Pakkehandsamaren nemner ABI-en han valde, så ei eining som fall tilbake til 32 bit dukkar opp her i staden for i ein krasjrapport:
adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbiEit manglande bibliotek for éin ABI attskapar den opphavlege tilgangsfeilen berre på den eininga, og difor er éin vellukka testtelefon ikkje prov. Lever manifestflagget, biblioteknamnet og bundle-innstillinga saman; endrar du éin og gløymer dei andre, er du tilbake ved same krasj. Den varige løysinga er å gå over til ei vedlikehalden kjerneutgåve i staden for å bere patchen for alltid.