La helpa duumaĵo de OpenVPN fiaskas en Android 10: permeso rifuzita
Android 10 rifuzas plenumi helpilon, kiun la apo skribis en sian propran konservejon. Legu logcat, liveru la helpilon kiel denaska biblioteko kaj ripari bundle-konstruojn.
La apo funkciis en Android 9 kaj mortas en la sama telefono post la ĝisdatigo al Android 10. Via profilo estas netuŝita, la atestiloj estas la samaj, kaj la paneo venas antaŭ ajna aŭtentiga trafiko. Logcat unue montras nulan montrilon, kaj kelkajn liniojn super ĝi staras Cannot run program ...: error=13, Permission denied. Tiu mesaĝo temas pri plenumo de dosiero, ne pri legado de via agordo.
Kion fakte rifuzas eraro 13
Android 10, API-nivelo 29, haltigis apojn plenumi dosierojn, kiujn ili skribis en sian propran datuman dosierujon. La regulo celas konservejon skribeblan kaj poste plenumeblan, kio estas ĝuste tio, kion kreas lanĉilo, kiu kopias el assets. Pli malnovaj konstruoj de la kerno ics-openvpn malpakis plenumeblan dosieron openvpn el la APK ĉe la unua rulo kaj lanĉas ĝin per ProcessBuilder. La malpakado ankoraŭ sukcesas; rifuzata estas la plenumo. Apo celanta API 29 heredas la regulon eĉ kiam ĝi ruliĝas sur aparato liverita kun pli malnova eldono, kaj tial ĝisdatigo povas rompi konstruon, kiun neniu tuŝis.
Nenio en la rifuzo estas specifa por unu dosieruja nomo. Dosiero, kiun la apo kreis sub sia datuma dosierujo, estas traktata kiel neplenumebla sendepende de la vojo, do getFilesDir(), getCacheDir() kaj propra subdosierujo ĉiuj fiaskas same.
Apartigu la paneon de la helpilo disde profila problemo
Legu la protokolon ĉirkaŭ la proceza starto anstataŭ rulumi de la supro. La serĉenda sigelo estas la linio error=13, kaj la stokspuro super ĝi kutime nomas la lanĉilan metodon, kiu vokis ProcessBuilder:
adb logcat -d | grep -n -i -E "cannot run program|permission denied|startOpenVPN"Se la helpilo neniam startis, vi tute ne vidos eliron de la OpenVPN-protokolo: nek ĉifra intertraktado, nek puŝitaj vojoj, nek DNS-agordo. Se tiuj linioj tamen aperas kaj la fiasko venas poste, la duumaĵo ruliĝis kaj la problemo estas en la profilo, la servilo aŭ la enkursiga tavolo. Tiu sola distingo ŝparas multan tempon, kiun oni alie pasigus redaktante dosierojn .ovpn, kiuj neniam kulpiĝis. Ĝi ankaŭ diras al vi, kiun el la du riparioj sube vi vere bezonas.
Kontrolu ankaŭ la API-nivelon sur la aparato, kiun vi testas, ne tiun en via konstrua agordo. Emulatora bildo sur API 28 reproduktas nenion, ĉar la limigo mordas nur de 29 supren. Samtempe kontrolu la celan SDK en via konstrua dosiero: ĝia plialtigo estas tio, kio altiras la regulon.
adb shell getprop ro.build.version.sdkKial kopii la duumaĵon aliloke ne helpas
La evidenta ĉirkaŭvojo, skribi la helpilon en alian skribeblan dosierujon, fiaskas pro la sama kialo kiel la originalo. Android ankoraŭ permesas plenumi komunaĵajn bibliotekojn instalitajn en la denaskan bibliotekan dosierujon de la apo, ĉar la instalilo pakaĵas ilin anstataŭ skribi ilin dum rulado. Tiu dosierujo estas la sola loko, al kiu la lanĉilo devus montri. Ĉio, kion vi mem malpakas dum rulado, kiel ajn vi nomas ĝin, restas en la rifuzita kategorio.
Ekstera konservejo estas pli malbona: ĝi estas muntita kun noexec, kaj helpilon metitan tie neniu apo povas starti. Viŝi la datumojn de la apo ankaŭ ne restarigas la malnovan konduton, ĉar la sekva lanĉo simple rekreas la saman neplenumeblan kopion.
Direktu la lanĉilon al pakaĵita biblioteko
Renomu la helpilon al komunaĵa biblioteka nomo kaj liveru ĝin sub jniLibs por ĉiu ABI, kiun vi subtenas, poste lasu la lanĉilon redoni la vojon de la instalita biblioteko ekde API 28:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
return new File(context.getApplicationInfo().nativeLibraryDir,
"libovpnexec.so").getPath();
}La biblioteko devas esti malpakita ĉe instalado, por ke tiu vojo enhavu realan dosieron, do agordu android:extractNativeLibs="true" sur la elemento <application>. Se manifesta kunfandilo enportas alian valoron, aldonu tools:replace="android:extractNativeLibs" apud ĝi. La referenco pri la elemento application dokumentas, kion la atributo regas.
Atentu duoblan lokan variablon, kiam vi flikŝtopas la lanĉilon permane. Pli malnovaj fontoj deklaras nativeAPI poste en la sama metodo, kaj dua deklaro estas kompila eraro anstataŭ rultempa eraro, do la konstruo fiaskas rapide kaj la eraro facile videblas. Tenu la ABI-liston en la Gradle-bloko kongrua kun la dosierujoj, kiujn vi aldonas.
Agordu la eldonan artefakton al la testa konstruo
Debug-APK povas levi la tunelon dum eldona bundle ankoraŭ paneas, ĉar bundle pakaĵas denaskajn bibliotekojn en alia formo kaj povas liveri ilin kunpremitaj el la arkivo. Se nur bundle-derivitaj konstruoj fiaskas, aldonu ĉi tion al gradle.properties kaj rekontruu:
android.bundle.enableUncompressedNativeLibs=falsePoste konfirmu, ke la instalita pakaĵo raportas la ABI, kiun vi atendas, kaj ripetu la kontrolon sur 32-bita kaj 64-bita aparatoj, se vi liveras ambaŭ. La pakaĵmastrumilo nomas la ABI, kiun ĝi elektis, do aparato, kiu refalis al 32 bitoj, aperas ĉi tie anstataŭ en panea raporto:
adb shell dumpsys package com.example.openvpn | grep -i primaryCpuAbiMankanta biblioteko por unu ABI reproduktas la originan permeseraron nur sur tiu aparato, kaj tial unu sukcesa testa telefono ne estas pruvo. Liveru la manifestan flagon, la bibliotekan nomon kaj la bundle-agordon kune; ŝanĝi unu kaj forgesi la aliajn resendos vin al la sama paneo. La daŭra solvo estas transiri al prizorgata kerna eldono anstataŭ porti la flikaĵon eterne.