Table of Contents

Android

Android este o stivă software pentru dispozitive mobile, ce constă în: sistem de operare, middleware și aplicații. Popularitatea Android este în continuă creștere, fiind disponibil pe telefoane, tablete și o varietate largă de alte sisteme incorporate (e.g. Android TV Box). O varietate largă de companii producătoare de telefoane mobile și tablete au adoptat Android pentru produsele lor (Samsung, HTC, Motorola, LG, Sony, Asus, Acer, Huawei etc.).

Arhitectura unui sistem Android

Deși Android este un sistem bazat pe kernelul Linux, modul în care sistemul este alcătuit diferă de sistemele embedded obișnuite bazate pe Linux. Acest lucru este vizibil la toate nivelele sistemului, inclusiv la nivelul dezvoltatorului de aplicații.

Arhitectura unui sistem Android

Android vine cu o serie de particularități specifice, cum ar fi:

Aplicațiile Android sunt compuse componente (components) slab cuplate. Componentele unei aplicații pot invoca și folosi serviciile oferite de componentele altor aplicații. Modul de apelare a acestor componente nu se face prin apelarea unei funcții speciale main, ci prin legarea componentei de anumite evenimente predefinite numite intents. Astfel, la producerea unui eveniment componentele pot fi activate si raspunde la acel eveniment. Componentele trebuie de asemenea să implementeze un lifecycle management (o serie de callback-uri), doarece ele pot fi oricând oprite de către sistem.

Când o componentă este activată, fie de sistem, fie de o altă aplicație, acea componentă va porni în cadrul unui nou proces. Mai departe, în mod implicit, toate compomentele aplicaței vor rula în cadrul aceluiași proces. Acestu lucru are implicații asupra modului în care operațiile de durată sau blocante trebuie tratate în cadrul unei aplicații Android. Deoarece utilizatorul poate porni oricâte componente, Android folosește mecanismul de OOM (Out-of-Memory) killer al kernel-ului pentru a opri procese în momentul în care sistemul rămâne fără resurse. Dacă mecanismul de lifecycle management este implementat corect acest lucru nu va fi observat de către utilizator.

Android folosește propriul mecanism de RPC/IPC (remote procedure call/inter-process communication), numit Binder. Acest mecanism folosește este implementat la nivelul kernel-ului și expus în user-space prin /dev/binder.

Securitatea este impusă prin mecanismele existente în kernel de izolare a proceselor. Astfel, pe lângă izolarea memoriei proceselor, fiecare aplicație primește și un UID (user identifier) și GID (group identifier) propriu pentru a izola accesul la fișiere. Fiecare aplicație Android este, în esență, un “utilizator” separat în sistem.

Kernel

Kernelul Linux utilizat de Android folosește o serie de patch-uri aplicate versiunii oficiale (“vanilla”) disponibilă pe www.kernel.org. Orice distribuție de Linux vine cu o versiune personalizată a kernel-ului, fiecare aplicându-i o serie de patch-uri pentru a repara unele bug-uri și a îmbunătății performanța. În acest sens Android nu diferă de orice altă distribuție care folosește kernelul Linux. Pentru a putea rula user-space-ul Android, kernel-ul folosit conține o serie de patch-uri care adaugă unele funcționalități specifice Android:

Wakelocks reprezintă o soluție la problema power management-ului folosită în Android. Pentru a reduce consumul, modelul folosit de Android este de a ține sistemul în starea de sleep în orice moment când el nu este folosit. Pentru a permite totuși aplicațiilor să facă procesări importante sau pentru a primi input de la utilizator un wakelock poate fi folosit pentru a ține sistemul pornit. Acestea folosesc funcționalitate deja existentă în kernel, însă introduc un nou model scriere a driverelor și a aplicațiilor low-level, care le fac incompatibile cu kernel-ele “vanilla”.

Deoarece modelul folosit de aplicațiile Android (bazat pe components și intents) diferă de aplicațiile obișnuite, a fost nevoie și de modificarea comportamentului kernelului în condiții de epuizare a resurselor. Pe lânga OOM killer, Andoid conține si un low-memory killer a cărui rol este de a opri componentele care nu au mai fost folosite de mult timp înainte de a se ajunge într-o situație de OOM.

Binder este mecanismul de RPC/IPC folosit de Android pentru comunicarea între componente. În esență Binder oferă capabilități de invocare remote a obiectelor, asemănătoare cu obiectele COM din Windows.

O altă modalitate de IPC este memoria partajată (shared memory). Android folosește ashmem pentu a evita unele dezavantaje ale Posix SHM, care poate permite unor aplicații malicioase să compromită sistemul.

Logger este un înlocuitor pentru sistemul classic de logging al kernelului (syslog) menit să reducă numărul task switch-uri și scrieri în fișier prin menținerea unui buffere circulare în RAM unde stochează fiecare eveniment primit.

User-Space

După cum se poate vedea în figura de mai jos root filesystemul unui sistem Android este împărțit în mai multe imagini.  Rootfs-ul unui sistem Android

Imaginea RAM disk este gândită să fie cât mai mică și să ofere scheletul inițial al sistemului pentru a încărca și celelalte imagini. Ea este de obicei stocată ca o arhivă pentru a-i reduce dimensiunea și este decompresată în RAM la pornirea sistemului. Este montată în mod normal read-only în /. /cache, /data și /system sunt de obicei încărcate direct ca partiții prezente în memoria non-volatilă. /system conține restul sistemului și este de asemenea montată read-only, față de /cache și /data care sunt montate read-write. Folosirea unui sistem de fișiere unificat este descurajată, în general, deoarece îngreunează actualizarea sistemului și crearea unei proceduri de recuperare fail-safe.

Figura de mai jos prezintă structura de fișiere a unui sistem Android tipic.

 Ierarhia de fișiere

Boot sequence

Bootarea unui sistem Android urmează aceeași pași ca orice sistem embedded bazat pe Linux. La pornirea sistemului procesorul începe să execute instrucțiuni de la o adresă predefinită. La acea adresă se află mapat codul bootloader-ului, a cărui responsabilitate este de a initializa memoria RAM și controler-ul acesteia și de a încarca kernelul și imaginea RAM disk-ului în memorie. Execuția apoi este pasată kernelului care initializează restul perifericelor și subsistemelor, montează partițiia de root și pornește procesul init. init setează apoi variabilele de mediu, montează partițiile sistemului și pornește procesele daemon. După pornirea daemonilor, procesul de bootare continuă cu pornirea componentelor specifice Android (ex. mașina virtuală Dalvik, Zygote, …). Zygote este un daemon special, folosit pentru a porni toate celelalte aplicații Android. La pornire el încarcă toate clasele Java și resursele de care o aplicație ar putea avea nevoie, iar apoi asteaptă cereri de pornire a altor aplicații. O nouă aplicație este pornită de Zygote printr-un apel fork, obținând astfel o copie a mașinii virtuale Dalvik cu toate clasele deja preîncărcate. Deoarece Linux folosește politica de COW (copy-on-write) pentru fork, acest apel nu va duce și la copierea claselor preîncărcate.

 Secvența de boot a unui sistem Android

adb

adb (Android Debug Bridge) este un utilitar folosit pe un sistem Android atât pentru debuggarea și dezvoltarea sistemului, cât și a aplicațiilor. Pentru a vedea o lista cu toate dispozitivele atasate se poate rula: adb devices. Pentru a obține acces pe device se rulează: adb shell. O altă comandă utilă, cu care putem vedea mesajele de logging este: adb logcat. Transferul de fișiere între device și host se face cu: adb push <fisier> pentru a copia un fisier pe device și adb pull <fisier> pentru a copiat un fișier de pe device. Pentru transferul mai multor fișiere exista comanda: adb [<optiuni>] sync [<director>]

Referințe