Mellékleteink: HUP | Gamekapocs
Keres

Így kerülte meg a Facebook az Android korlátait

Gálffy Csaba, 2013. március 06. 11:26
Ez a cikk több évvel ezelőtt születetett, ezért előfordulhat, hogy a tartalma már elavult.
Frissebb anyagokat találhatsz a keresőnk segítségével:

Az androidos Facebook-alkalmazásokat tavaly írta át az alapoktól újra a cég fejlesztői csapata. Az új, appok azonban két helyen is a régi Android korlátaiba ütköztek, ezért a mérnökök leültek és alaposan átolvasták a forráskódot. Az eredmény két látványos hack lett - annak jobb értelmében.

A HTML5-JavaScript kombinációt használó, rendkívül lassú androidos alkalmazásokat tavaly dobta ki a Facebook, helyükre valódi, natív alkalmazások kerültek. Az újraíráskor a fejlesztők számos optimalizációs lépést vettek végig, a kód nagy részét JavaScript helyett Javában írták, ennek keretében rengeteg metódust atomizáltak. Ennek folyományaként a metódusok száma drasztikusan megnőtt, cserébe az alkalmazás futásának hatékonysága is emelkedett. A fejlesztés során azonban nem várt problémába ütközött a csapat - a Dalvik VM két különböző korlátja miatt az alkalmazások  már nem futottak 4.0-s verziónál régebbi Androidon, pontosan a nagy metódusszám miatt.

A LinearAlloc 5 megabájtja

A kihívástól a fejlesztők nem riadtak vissza, a rendszer mélyében matatva kiiktatták a megfelelő korlátozásokat - a történetet pedig blogbejegyzésben foglalták össze. Az első limitáció a telepítési fázisra vonatkozik. A normális installálási folyamat során lefut a dexopt nevű program, amely az alkalmazás bájtkódját módosítja a céltelefon függvényében. A dexopt azonban egy fix méretű, LinearAlloc nevezetű metóduspuffert használ, ennek 5 megabájtos mérete pedig kicsinek bizonyult a Facebook alkalmazásainak esetében. Az Android 4.0-tól felfelé a puffer mérete 8-16 megabájt, a korábbi kiadások azonban egységesen 5 megabájtban korlátozták ezt.

Az ilyenkor szokásos megoldás az alkalmazás feldarabolása úgy, hogy egyenként egyik elem se lépje át a korlátot - ez azonban a Facebook fejlesztői szerint nem volt járható út. A megoldás a másodlagos dex-fájlok injektálása közvetlenül a Java class loaderbe. Ez normálisan nem lehetséges, de az Android forráskódjának megvizsgálása után a fejlesztők arra jutottak, hogy a Java Reflection API segítségével módosítható a loader belső szerkezete, és ez az akadály elhárítható.

A sikeres telepítést követően fedezték fel a fejlesztők, hogy a LinearAlloc limitációja futás közben is éles, így további ötletelésre van szükség. A fejlesztők mindent megpróbáltak a kódbázis méretének csökkentésére, a ProGuard agresszív használatától a metódusok számának csökkentéséig és a forráskód alapos átalakításáig. A csapat még saját profilozó eszközt is készített, amellyel a LinearAlloc legnagyobb felhasználóit azonosították - a próbálkozások azonban nem vezettek érdemi sikerre és a fejlesztés ezen pontján még nem is implementálták az alkalmazás teljes tervezett funkcionalitását. Az állás szerint a Facebook 2.0-s mobilalkalmazásai Android 4.0-ra korlátozódtak volna - ezzel pedig a piac több, mint kétharmadáról mondtak volna le.

A megoldás az Android forráskódjának alapos átfésülésében rejlett. A LinearAlloc puffer mérete alapértelmezésben 5 megabájt, a Facebook alkalmazásának ezzel szemben 8 megabájtra van szüksége a megfelelő futáshoz. A pufferméret növelésére van is lehetőség, a JNI kiterjesztés használatával a létező puffer nagyobbra cserélhető. A lépés rendkívül drasztikus: az alkalmazás ezzel már nem csak a Java oszályok betöltését, hanem a Dalvik VM egyik fix belső paraméterét írja át. A kód újabb alapos átnézése, a LinearAlloc összes létező felhasználásának áttekintését követően a Facebook megállapította, hogy a puffer méretének növelése mindaddig veszélytelen, míg az a program futásának elején történik.

Tesztelni, tesztelni

A nagy kérdés már csak az volt, hogy hogyan lehet futás közben lecserélni a LinearAlloc puffert. A forráskód újabb átnézésével sikerült megtalálni a választ a DvmGlobals objektum mélyén, mintegy 700 bájtra annak kezdetétől. Ennél pontosabb definíció, hogy a vmList objektum után néhány bájttal - ebben pedig van egy ismert érték, így pontosan betájolható a megcélzott, átírandó részlet. Az elképzelés szerint tehát a vmList megfelelő értékét kell kiolvasni a rendszer más részéből, majd ezt az értéket megkeresni a DvmGlobals objektumban, lépni néhány (meghatározott számú) bájtot a LinearAlloc fejlécéhez és kicserélni a puffert.

A megoldás kiválóan működött a referenciatelefonokon, néhány gyártó Android-implementációján azonban elhasalt, az amúgy tökéletesen kompatibilis rendszerek néhány bájttal odébb tették a fejléc kezdetét, így az egyszerű algoritmus nem talált rá. Az egyik modell a Samsung Galaxy S II volt, a legnépszerűbb Gingerbreaddel szerelt telefon - az újabb problémára tehát megoldást kellett találni. A második, finomított algoritus már érzékenyebben keresi a fejlécet, a beépített heurisztikával pedig kiváló találati arányt ért el.

Nagy kérdés maradt persze, hogy mennyire jó ez a találati arány. Ezért a Facebook az egyszerű hacket elkezdte manuálisan tesztelni minden elérhető okostelefonon, ehhez igénybe vették a DeviceAnywhere szolgáltatását is, amellyel valódi fizikai telefonokon tesztelhető a mobilalkalmazás, mindez távolról. A Facebook még a Google-től is kölcsönzött egy 70 modellt tartalmazó tesztlabort, a jó lefedettséget biztosító tesztelésen pedig minden egyes modell átment. Az alkalmazások végül decemberben kerültek ki a Play Store-ba, a telemetriai adatok szerint pedig a hack hibátlanul működik az összes telepítés esetében.

Facebook

Mit gondolsz? Mondd el!

Adatvédelmi okokból az adott hír megosztása előtt mindig aktiválnod kell a gombot! Ezzel a megoldással harmadik fél nem tudja nyomon követni a tevékenységedet a HWSW-n, ez pedig közös érdekünk.
A legnagyobb hazai termékfejlesztési konferencia november 21-22-én visszatér: 90 előadó, 1000 látogató, dedikált workshop nap, 6 szekció a UX-től az IoT-n át, egészen az AI-ig.