ॲप 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 सेटिंग एकत्र द्या; एक बदलून बाकी विसरल्यास तुम्ही त्याच क्रॅशवर परत येता। टिकाऊ उपाय म्हणजे पॅच कायम ढोण्याऐवजी देखभाल केलेल्या कोअर रिलीझकडे जाणे।

संबंधित लेख