ആപ്പ് 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 ക്രമീകരണം എന്നിവ ഒരുമിച്ച് നൽകുക; ഒന്ന് മാറ്റി മറ്റുള്ളവ മറന്നാൽ അതേ ക്രാഷിലേക്ക് തിരികെ വരും. ശാശ്വത പരിഹാരം പാച്ച് എന്നേക്കും ചുമക്കുന്നതിന് പകരം പരിപാലിക്കപ്പെടുന്ന കോർ റിലീസിലേക്ക് മാറുന്നതാണ്.

അനുബന്ധ ലേഖനങ്ങൾ