OpenVPN सहायक बाइनरी Android 10 मा असफल: अनुमति अस्वीकृत
Android 10 ले एपले आफ्नै भण्डारणमा लेखेको सहायक फाइल चलाउन अस्वीकार गर्छ। logcat पढ्नुहोस्, सहायकलाई नेटिभ लाइब्रेरीका रूपमा पठाउनुहोस् र bundle बिल्ड ठीक गर्नुहोस्।
एप 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 सेटिङ सँगै पठाउनुहोस्; एउटा बदलेर बाँकी बिर्सनुभयो भने तपाईं त्यही क्र्यासमा फर्किनुहुन्छ। दिगो समाधान भनेको प्याच सधैं बोक्नुको सट्टा मर्मत गरिने कोर रिलिजमा जानु हो।