Kako zaobiti skriti črni seznam API-jev v sistemu Android 9+

Google je v sistemu Android 9 uvedel omejitve, do katerih API-jev lahko dostopajo razvijalci. Tukaj je opisano, kako zaobiti te skrite omejitve API-ja.

Davnega leta 2018 je Google izdal Android Pie. Med spremembami uporabniškega vmesnika in novimi funkcijami je bilo tudi nekaj sprememb na strani razvijalca. Te spremembe so vključevale nove API-je, popravke napak za obstoječe API-je in tudi omejitve dostopa do skritih API-jev.

Na srečo pa obstajajo načini, kako se tem omejitvam izogniti. Preden se lotim tega, kako zaobiti omejitve, bi moral pojasniti, kaj so skriti API-ji, zakaj so bili sploh omejeni in zakaj bi morda želeli dostopati do njih.

Skriti API-ji so API-ji v sistemu Android, ki jih razvijalci aplikacij običajno ne vidijo. Če pogledate kodo AOSP, boste videli cel kup razredov, spremenljivk in metod, ki imajo @hide pripis v bloku komentarja nad njimi.

Ta opomba daje navodila kateremu koli orodju, ki ga Google uporabi pri prevajanju SDK-ja, da izključi element pod njim. Ta SDK se nato razdeli razvijalcem znotraj SDK-jev, prenesenih prek Android Studia. Razen če uporabljate spremenjen SDK, bo Android Studio mislil, da kateri koli od teh skritih elementov preprosto ne obstaja. Če ga poskusite uporabiti neposredno, ga bo prikazal rdeče in zavrnil prevajanje.

Obstaja veliko razlogov, zakaj je lahko API skrit. Nekatere stvari so namenjene samo uporabi notranjih ali sistemskih aplikacij in ne bodo delovale, če jih uporablja aplikacija tretje osebe. Druge so poskusne ali nestabilne in bodo morda v prihodnosti odstranjene ali spremenjene. Nekateri so celo samo API-ji, ki jih Google ne želi vključiti v običajni cikel zastaranja, če bodo kdaj odstranjeni.

Medtem ko ima standardni Android SDK a veliko v njem, včasih ni dovolj. Včasih želite narediti nekaj, kar že obstaja v sistemu Android, vendar preprosto ni javno izpostavljeno.

Na primer, veliko aplikacij, ki jih izdelujem, vključno z SystemUI Tuner in Pripomočki za zaklenjeni zaslon, uporabite kup različnih skritih API-jev. SystemUI Tuner potrebuje dostop do nekaterih za pravilno sledenje, spreminjanje in ponastavitev možnosti. Lockscreen Widgets med drugim uporablja nekatere za prikaz ozadja pod njim.

Večini razvijalcev ni treba dostopati do skritih API-jev, včasih pa so lahko zelo uporabni.

Z izdajo Androida 9 (Pie) je Google predstavil skriti črni seznam API-jev. Niso bili vključeni vsi skriti API-ji in obstajale so različne ravni seznamov. Do skritih API-jev na seznamu dovoljenih lahko dostopa kdorkoli. Do skritih API-jev na svetlo sivem seznamu lahko dostopa katera koli aplikacija, vendar bodo v prihodnjih različicah Androida morda nedostopni. Do vsega na temno sivem seznamu so lahko dostopale samo aplikacije, ki ciljajo na ravni API-ja pred Pie (tj. pred nivojem API-ja 28). Aplikacijam, ki ciljajo na Pie in novejše, bi bil zavrnjen dostop. Nazadnje, do skritih API-jev na črnem seznamu ni mogla dostopati nobena nesistemska aplikacija (ali aplikacija, ki ni na belem seznamu), ne glede na ciljni API.

Android 10 je spremenil organizacijo seznamov in jih nekoliko poenostavil, vendar je ideja ostala enaka. Aplikacije so lahko dostopale do nekaterih skritih API-jev, medtem ko so bili drugi blokirani. Android 11 okrepljeno zaznavanje dostopa do blokirati obvoznico uporabljeno za pito in 10.

V vseh različicah Androida vsakič, ko aplikacija tretje osebe poskuša dostopati do skritega API-ja na črnem seznamu, Android vrže ustrezno napako »not found«.

Pravzaprav obstaja kar nekaj načinov, kako priti mimo skrite črne liste API-jev. Glede na vaše potrebe lahko izberete tiste, ki delujejo za vse različice Androida, tiste, ki delujejo samo za Android 9 in 10, tiste, ki uporabljajo izvorno kodo C++, in tiste, ki v celoti temeljijo na Javi. Obstaja celo razvojna rešitev z uporabo ADB.

ADB rešitev

Če vaša naprava uporablja Android Pie, zaženite naslednja dva ukaza ADB, da omogočite skriti dostop do API-ja.

adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1

Če vaša naprava uporablja Android 10 ali novejši, zaženite naslednji ukaz ADB, da omogočite skriti dostop do API-ja.

adb shell settings put global hidden_api_policy 1

Za vrnitev na privzeto vedenje preprosto zamenjajte put z delete in odstranite 1.

Očitno ti ukazi niso ravno uporabni za produkcijsko aplikacijo. Iz prve roke vam lahko povem, da je pravilno poučevanje uporabnikov o uporabi ADB neverjetno težko. Lahko pa so koristni, če morate posodobiti staro aplikacijo, da bo skladna z novimi omejitvami.

Nadomestna/JNI rešitev

Skriti črni seznam API-jev lahko zaobidete na dva načina z uporabo JNI v aplikaciji za Android. Ena deluje za Android 9 in 10, druga pa za Android 9 in novejše.

Android 9 in 10

Če že imate izvorni del svoje aplikacije, bo to enostavno implementirati. Samo uporabite JNI_OnLoad() funkcijo.

static art:: Runtime* runtime = nullptr;

extern "C"jint JNI_OnLoad(JavaVM *vm, void *reserved){
...
runtime = reinterpret_cast<: javavmext>(vm)->GetRuntime();
runtime->SetHiddenApiEnforcementPolicy(art:: hiddenapi:: EnforcementPolicy:: kNoChecks);
...
}

Upoštevajte, da ta metoda deluje samo v sistemih Android 9 in 10.

Android 9 in novejši

Za katero koli različico Androida imate na izbiro dve knjižnici za obhod skrite omejitve API-ja: FreeReflection in RestrictionBypass.

Oba sta enostavna za izvedbo in uporabo.

Za implementacijo FreeReflection, dodajte odvisnost svojemu build.gradle na ravni modula.

implementation 'me.weishu: free_reflection: 3.0.1'

Nato preglasi attachBaseContext() v vašem razredu aplikacije.

@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);
Reflection.unseal(base);
}

Če nimate razreda aplikacije, ga lahko preprosto dodate. Ustvarite nov razred, ki se razširi Application in nato pokažite nanj v svojem AndroidManifest.xml.

primer:

publicclassAppextendsApplication{
...
@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);

Reflection.unseal(base);
}
}

<manifest>
...
...
name=".App">
...
application>
manifest>

Za implementacijo RestrictionBypass, dodajte repozitorij JitPack v build.gradle na ravni projekta.

allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}

Nato dodajte odvisnost v build.gradle na ravni modula.

implementation 'com.github.ChickenHook: RestrictionBypass: 2.2'

In to je to. Ta knjižnica samodejno odstrani omejitve črnega seznama.

Java rešitev

Čeprav so rešitve JNI učinkovite, včasih morda ne želite uporabljati izvorne kode. Če še ne delate stvari v C++, lahko vaši aplikaciji doda nepotrebno velikost, skupaj z omejitvami platforme. Na srečo obstajajo načini, kako zaobiti skriti črni seznam API-jev samo z uporabo Jave.

Android 9 in 10

V Androidih 9 in 10 lahko uporabite tako imenovani dvojni odsev ali meta-odsev, da obidete skriti črni seznam API-jev. Ker sistem samo preverja, kaj kličejo aplikacije tretjih oseb, ga dvojni odsev zavede, da misli, da sistem izvaja skrite klice API-ja.

Ta trik je mogoče uporabiti za klic metode, ki vaši aplikaciji omogoči skrite izjeme API-ja, primerno poimenovane setHiddenApiExemptions(). Preprosto dodajte naslednjo kodo nekje na začetku življenjskega cikla vaše aplikacije (na primer kode aplikacije onCreate() način) in bo obšel črni seznam.

Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

Class vmRuntimeClass = (Class) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", newClass[] { String[].class} );

Object vmRuntime = getRuntime.invoke(null);
setHiddenApiExemptions.invoke(vmRuntime, newString[][] { newString[] { "L" } });

Če je vaša aplikacija združljiva z različicami Androida, starejšimi od 9, ne pozabite zaviti tega v preverjanje različice.

Android 9 in novejši

Če želite zaobiti skriti črni seznam API-jev v sistemu Android 9 in kateri koli novejši različici, lahko uporabite knjižnico LSPosed. Ta knjižnica uporablja Javin Unsafe API, zato je malo verjetno, da se bo kdaj zlomila.

Če ga želite implementirati, samo dodajte odvisnost v build.gradle na ravni modula.

implementation 'org.lsposed.hiddenapibypass: hiddenapibypass: 2.0'

Nato ga uporabite, da obidete črni seznam.

HiddenApiBypass.addHiddenApiExemptions("L");

Če je vaša aplikacija združljiva z različicami Androida, starejšimi od 9, ne pozabite zaviti tega v preverjanje različice.

Zaključek in več informacij

V sistemu Android je na voljo veliko možnosti za obhod skritega črnega seznama API-jev, ne glede na to, katero različico platforme ciljate ali uporabljate. Če vas zanima več o delovanju teh metod in knjižnic, si oglejte naslednje povezave.

  • Moja vprašanja in odgovori Stack Overflow.
  • LSposed's Hidden API Bypass knjižnica na GitHubu.
  • Knjižnica RestrictionBypass podjetja ChickenHook na GitHubu.
  • tiannova knjižnica FreeReflection na GitHubu.
  • Googlova dokumentacija o skritem črnem seznamu API-jev.