Analisi dei meccanismi di basso livello per l`IPC su piattaforma

Transcript

Analisi dei meccanismi di basso livello per l`IPC su piattaforma
Facoltà di Ingegneria
Corso di Studi in Ingegneria Informatica
Elaborato finale in Sistemi Operativi
Analisi dei meccanismi di basso livello per
l’IPC su piattaforma Android
Anno Accademico 2011/2012
Candidato:
Alessandro Terracciano
matr. N46000716
Indice
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Introduzione
4
Capitolo 1. Android Architecture
5
1.1
1.2
1.3
1.4
1.5
Linux Kernel
Libraries
Android Runtime
Application Framework
Applications
6
6
7
8
8
Capitolo 2. Application Fundamentals
9
2.1
2.1.1
2.1.2
2.1.3
2.1.4
2.2
2.3
2.4
2.4.1
2.4.2
2.4.3
Application Component
Activities
Services
Content Provider
Broadcast Receives
Intents
Manifest File
Processes and Threads
Processes
Process Lifecycle
Threads
10
10
11
13
13
14
16
16
17
17
19
Capitolo 3. Interprocess Comunication
20
3.1
3.1.2
3.1.3
3.2
3.3
Binder
Communication Model
IPC Mechanims
Application Launch
Considerations
21
21
22
28
30
Conclusioni e Sviluppi Futuri
Bibliografia
32
33
III
Introduzione
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Negli ultimi anni si sta assistendo ad una progressiva diffusione dei dispositivi mobili. Tale
progresso è dovuto sicuramente ad una significativa evoluzione di tipo hardware, ma
soprattutto a un sistema software in grado di adattarsi alle esigenze dell'utente. Parliamo
quindi di Android. La piattaforma include un sistema operativo basato su Linux, un insieme
di supporti multimediali e offre un ambiente di sviluppo per le applicazioni. Ha come
principale scopo quello di fornire tutto ciò che un utente ha bisogno per raggiungere i propri
obiettivi. Android è una piattaforma completamente open-source, e la sua altissima
diffusione è dovuta al fatto che abbia costi ridotti di accesso e di sviluppo. Inoltre consente
una gestione automatica delle applicazioni e la sua estrema portabilità ne garantisce
l'implementazione di un gran numero di dispositivi mobili (smartphone, tablet, netbook,
ebook reader, ecc.).
Fu sviluppato nel 2003 da una startup californiana di nome Android Inc., acquistato poi nel
2005 da Google. Nello stesso anno poi fu fondata l'Open Handset Alliance, un team formato
da: operatori telefonici (Vodafone, T-Mobile, Telecom Italia, ecc), produttori di dispositivi
mobili (HTC, Motorola, Samsung, ecc.), altri tipi di produttori (Intel, Nvidia, Texas
Instruments) e compagnie di sviluppo software e di commercializzazione. Tutto finalizzato a
creare standard aperti per dispositivi mobili.
4
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Capitolo 1
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Android Architecture
Android è una collezione di software ben gestito ed organizzato, con la particolarità di potersi
adattare a qualsiasi dispositivo mobile. Per tale motivo questa piattaforma riesce a coprire la
compatibilità con numerosi apparecchi, garantendone anche l'integrità. Possiede un'architettura
abbastanza complessa, ed è costituita da un insieme di moduli, organizzata a livelli, che a loro volta
sono formati da un insieme di componenti.
Figura 1.1 – Layered Architecture
L’intera struttura comprende il sistema operativo, middleware e altre applicazioni importanti.
5
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
L’architettura[1] è ben rappresentata nella Figura 1.1. Il sistema è composto da cinque sezioni in
quattro livelli principali, dove ogni livello fornisce servizi a quello superiore. L'architettura a livelli,
infatti, è spesso utilizzata per la sua versatilità e robustezza. Grazie a ciò, si è ridotto il numero di
interconnessioni tra i moduli, proprio perchè ogni strato comunica soltanto con quello adiacente.
Analizziamo nel dettaglio ogni singolo livello.
1.1 Linux Kernel
Il cuore del sistema è basato sul kernel Linux, versione 2.6. In questo livello sono
implementati direttamente tutti i driver di controllo hardware del dispositivo, quindi
fornisce un'ottima astrazione tra le applicazioni dei livelli superiori con lo strato inferiore al
kernel stesso: l'hardware. Inoltre possiede una serie di meccanismi e strategie per la
gestione dei processi che saranno chiarite nel capitolo 3.
1.2 Libraries
Il livello successivo è costituito dalle librerie native. Si tratta di un insieme di file utilizzati
dal dispositivo per poter gestire dati di diversa tipologia. Sono scritte nel linguaggio C o
C++, specifiche ad un particolare hardware, e sono accessibili da parte dello sviluppatore
attraverso il livello superiore Framework Application.
In Figura 1.1 sono presenti alcune librerie di notevole importanza:
-
Surface Manager: gestisce l'accesso al sottosistema di visualizzazione e
compone i livelli grafici 2D e 3D. Si basa sull'off-screen buffering, cioè tutte le
operazioni grafiche dei processi vengono prima elaborate su un buffer, e poi
vengono composte da un insieme di applicazioni per rappresentarle sul display.
-
OpenGL: consiste in un supporto per la grafica ad alte prestazioni 2D e 3D. Ha
avuto varie versioni, infatti le OpenGL|ES 1.0 e 1.1 sono stati supportati da
Android 1.0 e a partire da Android 2.2, è arrivata alla versione 2.2.
-
SGL: è il motore grafico 2D sottostante, a cui si appoggiano OpenGL e Surface
Manager.
-
Media Framework: fornisce diversi codec multimediali che consentono la
6
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
registrazione e la riproduzione di diversi formati multimediali. Basato su
OpenCORE PacketVideo e supporta diversi formati quali: MPEG4, H.264,
MP3, AAC, AMR, JPG e PNG.
-
FreeType: libreria che si occupa di altri tipi di formati multimediali.
-
SSL: garantisce la sicurezza delle applicazioni, oramai sostituito da TLS.
-
SQLite: si tratta di un database engine transazionale molto potente e leggero. A
differenza dei comuni database SQL, SQLite effettua operazioni transazionali
direttamente su file e non ha un processo server separato. Infatti è possibile
modificarne la posizione in memoria senza comprometterne il funzionamento.
-
WebKit: un moderno motore del browser web che migliora l'utilizzo delle risorse
remote.
-
System C Library: implementazione BSD-derived della libreria standard C
System(libc), pensata per dispositivi basati su Linux.
1.3 Android Runtime
Da come si intuisce dal diagramma in Figura 1.1, questa parte dell'architettura in realtà non
è un vero e proprio livello, perchè fa ancora parte della categoria Libraries. Il fatto che sia
definita come sezione a parte, implica che queste librerie siano di notevole importanza ai
fini delle elaborazioni dei processi. Parliamo della macchina virtuale che ha il compito di
fornire un'ulteriore astrazione alle applicazioni di alto livello.
Complessivamente è composto da due componenti:
-
Core Libraries: comprende un set di librerie di base che fornisce la maggior
parte delle funzionalità offerte dal linguaggio di programmazione Java.
-
Dalvik VM: è una macchina virtuale ottimizzata per l'occupazione di memoria
minima. Ogni applicazione Android gira in un proprio processo, con la propria
istanza nella macchina virtuale. Dalvik è stato ideato con lo scopo di far girare
diverse istanze della macchina virtuale contemporaneamente in modo efficiente.
Si basa sul kernel Linux e nasconde al sistema operativo sottostante la gestione
della memoria e quella dei thread.
7
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
1.4
Application Framework
In questo livello Android mette a disposizione un ambiente di sviluppo, offrendo quindi la
possibilità agli sviluppatori di poter creare applicazioni nel modo più ricco e innovativo
possibile. Questo è possibile perchè essi hanno pieno accesso alle stesse API utilizzate dalle
applicazioni di base. L'architettura è stata progettata con lo scopo di poter sfruttare il
concetto del riuso delle componenti; chiunque può creare e pubblicare le proprie
applicazioni, dando la possibilità ad alti utenti di utilizzarle. Questo stesso meccanismo
consente all'utente di sostituire i componenti standard con versioni personalizzate.
Alcuni componenti che questo livello comprende sono:
-
View System: un insieme di risorse estendibile di “Viste” che consentono la
creazione di applicazioni offrendo una vasta gamma di strumenti utili.
-
Content Provider: consente la condivisione di dati o l’accesso di dati condivisi
da altre applicazioni.
-
Activity Manager: gestisce il ciclo di vita delle applicazioni del livello
successivo.
-
Resource Manager: gestisce tutte le risorse usate dalle applicazioni del livello
successivo.
1.5
Applications
L’ultimo livello dell’architettura consiste in una serie di applicazioni utilizzati dall’utente.
Quest’ultime sono scritte in linguaggio Java e apre infinite opportunità per lo sviluppatore.
Ci sono diverse applicazioni standard, pre-installate sul dispositivo mobile, per esempio:
SMS Client app, Dialer, Web Browser, Contact Manager, e altre applicazioni preferite
dall’utente.
8
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Capitolo 2
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Application Fundamentals
Si vuole adesso cercare di capire la logica usata dal sistema per far sì che le applicazioni possano
coesistere in modo efficiente. Android, è un sistema operativo multi-utente Linux, dove ogni
applicazione è un User diverso. Per impostazione predefinita, questo User viene associato ad un
User ID, usato solo dal sistema, e quest’ultimo imposta le autorizzazioni per tutti i file di una
applicazione in modo tale che solo l'User ID assegnato a tale applicazione può accedervi. Ogni
processo ha una propria macchina virtuale (attraverso la Dalvik VM), quindi il codice
dell’applicazione è eseguito in modo isolato. Per default, ogni applicazione gira su un processo
Linux, e tale processo può essere avviato, nel caso uno dei componenti dell’applicazione deve
essere necessariamente eseguito; fermato, nel caso in cui nessun componente viene eseguito
(operazione effettuata per guadagnare spazio in memoria per l’elaborazione di altri processi). In
questo modo, Android implementa il principio di privilegio minimo, cioè che ogni applicazione ha
accesso solo alle componenti che deve utilizzare. Si crea quindi un ambiente sicuro che evita
accessi a parti del sistema non consentite, per esempio ad una applicazione non è consentita
l’accesso ai dati di un’altra. Tuttavia, ci sono diversi modi che consentono la condivisione dei dati.
E 'possibile, per esempio, che due applicazioni possano condividere lo stesso User ID, in questo
caso essi sono in grado di accedere ad altri file. Per risparmiare risorse del sistema, le applicazioni
con lo stesso User ID possono anche organizzare l'esecuzione nello stesso processo e condividere
la stessa VM.
9
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
2.1
Application Component
Le applicazioni Android sono formate da un insieme di componenti[2]. La maggior parte di
questi, vengono utilizzati dal sistema per accedere all’applicazione stessa. Alcuni
dipendono l’una dall’altra, e ognuno svolge un ruolo specifico che aiuta a definire il
comportamento generale dell’applicazione. Ci sono quattro diversi tipi di componenti. Ogni
tipologia ha uno scopo distinto e specifico, con un ciclo di vita diverso che caratterizza come
il componente viene creato e distrutto.
2.1.1 Activities
Un’attività[3] è un tipo di componente che fornisce una schermata agli utenti con cui
possono interagire al fine di fare operazioni; per esempio comporre il telefono cellulare,
scattare una foto, invia una e-mail o visualizzare una mappa. Quando viene eseguita
l’applicazione per la prima volta, viene presentata all’utente un’attività “principale”, e può
iniziarne altre, al fine di eseguire diverse azioni. Ogni volta che inizia una nuova attività,
quella precedente viene arrestata, restando conservata dal sistema in una pila chiamata
"Stack Back". E’ uno stack del tipo “last in – first out”, cioè quando l’utente ha terminato
l’attività corrente, viene effettuata un’operazione di “pop” sullo stack, dando quindi la
possibilità di eseguire attività sospese in precedenza. Nella Figura 2.1 viene illustrato questo
meccanismo.
Figura 2.1 – Activity con Stack Back
10
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Quando un'attività viene fermata da una nuova, viene informata di questo cambiamento di
stato attraverso i metodi di callback del ciclo di vita dell'attività. Ci sono metodi di callback
diversi che un'attività possa ricevere, e ciascuno offre l'opportunità di svolgere un lavoro
specifico. Per esempio, all’atto di un blocco, l’attività dovrebbe rilasciare tutti gli oggetti di
grandi dimensioni, come ad esempio le connessioni di rete o un database. Quando invece
viene sbloccata, ha la possibilità di riacquistare le risorse possedute in precedenza.
Un'attività può avere tre stati essenzialmente:
-
Resumed: indicato anche come running, è l’attività in primo piano, ovvero quella
usata dall’utente al momento.
-
Paused: attività in primo piano che non è immediatamente utilizzata. Questo
capita spesso quando si ha l’esecuzione di più applicazioni contemporaneamente
da parte dell’utente. All’alternare dell’utilizzo di ogni applicazione, quest’ultima
effettua transizioni dallo stato Resumed a Paused.
-
Stopped: non è più visibile da parte dell’utente, e si tratta di applicazioni bloccate
o sospese. I dati associati vengono conservati in memoria, fino a quando
l’applicazione cambia stato o viene rimosso. La rimozione avviene dal sistema se
c’è la necessità di ulteriore spazio in memoria da parte di altre applicazioni
attive, o dall’utente qualora decide di non utilizzarla più.
2.1.2 Services
Un servizio[4] è un componente di un'applicazione in grado di eseguire operazioni di lunga
durata in background, e non fornisce un'interfaccia utente. Un componente di una
applicazione può avviare un servizio e continuerà a funzionare in background anche se
l'utente passa ad un'altra applicazione. Questo può relazionarsi ad un altro servizio, può
interagire con esso e può anche eseguire la comunicazione interprocesso (IPC). Ad esempio,
un servizio potrebbe gestire le transazioni in rete, ascoltare musica, eseguire file I/O, ecc.
Può essere di due tipi:
-
Started: quando una attività invoca la funzione StartService(), avvia un servizio
che viene eseguito in background indefinitamente, anche se l’attività che l’ha
11
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
creato viene distrutta. In genere esegue un singolo compito, tutto nascosto agli
occhi dell’utente.
-
Bound: un servizio è bound quando è definito da un componente che invoca la
chiamata bindService(). Offre una interfaccia client-server che consente ai
componenti di interagire con il servizio, inviare richieste, ottenere risultati, e
anche farlo attraverso i processi con la comunicazione interprocesso (IPC).
Spesso i servizi bound impongono dei vincoli sul suo utilizzo, questo perché solo alcune
applicazioni hanno il permesso di utilizzarli. Quando si crea un servizio del genere, ogni
applicazione che deve usarla, deve fornire un IBinder, elemento utile per l’interazione con il
servizio.
Ci sono tre modi per definire l’interfaccia:
-
Estensione della classe Binder: questa tecnica è preferita quando il servizio è
semplicemente un lavoro di background. Se è privato per la propria applicazione
e viene eseguito nello stesso processo client, allora è necessario creare
l'interfaccia estendendo la classe Binder e restituendo un'istanza (usando la
funzione onBind() ). Dopo di che, una applicazione riceve l’oggetto e, tramite i
metodi pubblici della classe, riesce ad utilizzare il servizio.
-
Utilizzo di un Messenger: in questo caso l’interfaccia è munita di un Messaggero,
un particolare gestore in grado di rispondere a diversi tipi di oggetti Message.
Quindi la condivisione dell’IBinder avviene attraverso uno scambio messaggi
con il processo client. Questo è il modo più semplice per eseguire la
comunicazione interprocesso (IPC), in quanto le code Messenger possono essere
gestite da un singolo thread.
-
Utilizzo AIDL: in realtà la tecnica precedente si basa su questa, la differenza
sostanziale è che mentre il Messaggero gestisce tutti i messaggi con un solo
thread (e ciò implica che un solo messaggio alla volta può essere gestito), AIDL
effettua l’operazione contemporaneamente, definendo una struttura basata sulla
programmazione multi-threading.
12
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
2.1.3 Content Provider
I Content Provider gestiscono l’accesso ad un insieme strutturato di dati, garantendone la
sicurezza e l’integrità. Sono l’interfaccia standard che collega i dati di un processo con
l’esecuzione di uno o più processi. Infatti se uno di questi vuole accedere ai dati del Content
Provider, deve utilizzare un oggetto ContentResolver per comunicare con il provider.
Quest’ultimo riceverà le richieste, eseguirà le rispettive operazioni e restituirà i risultati. Un
Content Provider è implementato come una sottoclasse di ContentProvider e deve definire
un insieme standard di API che consente ad altre applicazioni per eseguire le transazioni sui
dati o file.
2.1.4 Broadcast Receives
I Broadcast Receives sono dei componenti utili alle applicazioni per ricevere e rispondere ad
annunci broadcast provenienti dal sistema. Per esempio, potrebbero esserci annunci riguardo
lo stato dello schermo, della batteria, e altri tipi di stati di altri elementi del dispositivo. Sono
privi di interfaccia, nel senso che non sono visibili all’utente, ma utilizzano una barra di
stato per le notifiche, che consentono all’applicazione di ricevere gli eventi broadcast dal
sistema. Quindi funge da "gateway" per altri componenti, inoltre i compiti che può
effettuare sono ridotti, ad esempio, potrebbe avviare un servizio per l’esecuzione di
operazioni in base ad un evento.
Un aspetto unico di Android è che qualsiasi applicazione può aprire il componente di un'altra
applicazione. Ad esempio, se l’utente desidera catturare una foto con la fotocamera del dispositivo,
non c’è bisogno di integrare o collegare il codice della applicazione della fotocamera, ma si avvia
semplicemente l'attività nella applicazione che cattura una foto. Quando si avvia un componente,
inizia il processo per l'applicazione (se non è già in esecuzione) e istanzia le classi necessarie per il
componente. A differenza della maggior parte delle applicazioni su altri sistemi, le applicazioni
Android non hanno un unico punto di ingresso (non c'è una funzione main(), per esempio). Poiché il
sistema esegue ogni applicazione in un processo separato, questa non può direttamente attivare un
componente da un'altra applicazione, dato che i permessi dei file limitano l'accesso.
13
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Il sistema Android, tuttavia, può. Quindi, per avviare un componente in un'altra applicazione, è
necessario inviare un messaggio al sistema per indicarne l'intenzione di attivazione.
2.2
Intents
Quando il sistema desidera attivare un componente di una applicazione, lo può fare
attraverso un messaggio asincrono: l’intento[5]. Si tratta di un oggetto Intent, una struttura
dati che, nel caso di attività e servizi, fornisce una descrizione astratta di una operazione da
effettuare; mentre per le notifiche broadcast, definisce una descrizione di qualcosa che è
accaduto e che deve essere annunciato.
Figura 2.2 – Intent graph
Esistono meccanismi separati per fornire intenti ad ogni tipo di componente:
-
startActivity() per avviare una attività.
-
startService() per avviare un servizio.
-
bindService() per stabilire una connessione tra il componente chiamante e un
servizio destinazione (se non è già in esecuzione, può avviarlo).
-
sendBroadcast() per effettuare annunci dal sistema.
Un oggetto Intent è un insieme di informazioni, utili sia al componente che riceve l'intento
(come l'azione da intraprendere, o i dati da elaborare), sia per il sistema Android (come la
categoria del componente che deve gestire l'intento e le istruzioni su come avviare un'attività
di destinazione). Principalmente, esso può contenere diversi elementi:
-
Component Name : Il nome del componente che deve gestire l'intento. Questo
campo è un oggetto ComponentName, e viene impostato attraverso le funzioni
setComponent(), setClass(), o setClassName().
14
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
-
Action : una stringa che definisce l'azione da compiere, o, nel caso di intenti
broadcast, l'azione che ha avuto luogo e che deve essere segnalata. La classe
Intent definisce un certo numero di costanti azioni ( per esempio:
ACTION_CALL per avviare una telefonata, ACTION_EDIT per i dati
dell’attività di visualizzazione che l’utente può modificare, ACTION_SYNC per
sincronizzare i dati su un server con i dati del dispositivo mobile, ecc).
-
Data : indica l’URI dei dati che devono essere attuati, e il tipo MIME di tali dati.
Per esempio se l’azione è ACTION_EDIT, il campo dati conterrà l'URI del
documento da visualizzare per l'editing; se l'azione è ACTION_CALL, il campo
di dati sarebbe un URI con il numero da chiamare.
-
Category : è una stringa contenente informazioni aggiuntive sul tipo di
componente che dovrebbe gestire l'intento. Come si fa per le azioni, la classe
Intent definisce le costanti di categoria (CATEGORY_BROWSABLE per
invocare il browser per visualizzare i dati, CATEGORY_HOME per la
visualizzazione sulla schermata principale, ecc).
-
Extra : sono essenzialmente coppie chiave-valore per le informazioni aggiuntive
che devono essere consegnate al componente per gestire l’intento.
-
Flags : possono essere di vario tipo: alcune indicano al sistema Android il modo
di avvio di una attività, e come trattarla dopo che è stata lanciata.
Gli intenti possono essere suddivisi in due gruppi:
Intenti espliciti: si considera il componente di destinazione attraverso il suo nome (il campo
nome, citato in precedenza, ha un valore impostato). Poiché i nomi dei componenti
generalmente non sono noti agli sviluppatori, gli intenti espliciti sono tipicamente utilizzati
per applicazioni interne. Per esempio per avviare una attività subordinata o parallela.
Intenti impliciti: sono spesso utilizzati per attivare componenti in altre applicazioni.
In questo caso si definisce l’azione da seguire anziché il nome del destinatario. Il problema
però, è che in assenza di destinazione, il sistema Android deve trovare il migliore
componente che gestisca l'intento. Lo fa confrontando il contenuto dell'oggetto Intent con i
filtri intenti associati ai componenti. Ogni filtro descrive una funzionalità del componente,
15
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
cioè un insieme di intenti che è disposto a ricevere. In questo modo se l’intento è uno
esplicito, è sempre consegnato al suo obiettivo (per via del nome), e quindi non importa ciò
che contiene, il filtro non viene consultato; se invece è un intento implicito, quest’ultimo
può passare solo attraverso i filtri intenti forniti dal componente.
2.3
Manifest File
Prima di avviare un componente dell'applicazione, il sistema deve sapere se esiste, e lo fa
leggendo il file AndroidManifest.xml dell'applicazione, cioè il file manifesto[6].
L'applicazione deve dichiarare tutti i suoi componenti in questo file, che deve essere alla
base della directory di una applicazione.
Il manifesto oltre a specificare i componenti dell'applicazione, ha altri compiti quali:
-
Identificare tutte le autorizzazioni richieste dalle applicazioni (per esempio
l'accesso a Internet).
-
Dichiarare il livello minimo di API richiesto dall'applicazione, per consentire a
quest’ultima di utilizzarle.
-
Definire le caratteristiche hardware e software utilizzate o richieste
dall'applicazione, ad esempio una fotocamera, servizi bluetooth, ecc.
Come visto nel precedente paragrafo, è possibile avviare e gestire attività, servizi e notifiche
broadcast attraverso gli intenti. Quando si dichiara un componente nel manifesto
dell'applicazione, è possibile includere i filtri intenti, in modo che possa rispondere ad
intenti provenienti da altre applicazioni.
2.4
Processes and Threads
Quando un componente di una applicazione viene avviata e l'applicazione non dispone di
altri componenti in esecuzione, il sistema Android avvia un nuovo processo Linux, con un
singolo thread di esecuzione[7]. Per impostazione predefinita, tutti i componenti della stessa
applicazione sono eseguiti nello stesso processo e anche nello stesso thread (definito come
thread "main"). Se un componente di una applicazione inizia, ed esiste già un processo per
la stessa l'applicazione (perché un altro componente della medesima è già presente), allora
16
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
viene avviato in quel processo e utilizza lo stesso thread. Tuttavia, è possibile organizzare i
componenti della stessa applicazione in processi separati, o creare thread aggiuntivi per
qualsiasi processo.
2.4.1 Processes
Tutti i componenti della stessa applicazione sono eseguiti nello stesso processo, e la maggior
parte delle applicazioni non dovrebbero cambiare questo tipo di gestione. Tuttavia, alcune
non rispettano questa condizione, ed è necessario scoprire a quale processo un certo
componente appartiene. Questo è possibile farlo considerando il file manifesto, dove ogni
tipo di componente supporta un particolare attributo, che specifica il processo in cui tale
elemento deve essere eseguito. È possibile impostare questo attributo in modo che ogni
componente viene eseguito in un proprio processo, o che alcuni lo condividano, mentre altri
non lo fanno, dando quindi la possibilità a più applicazioni di ottenere lo stesso User ID.
A volte capita che Android si trova nella condizione di decidere di arrestare un processo,
specialmente quando si riduce lo spazio in memoria, che è richiesta da altri processi, ovvero
quelli più immediatamente al servizio dell'utente. I componenti delle applicazioni in
esecuzione nel processo arrestato, sono di conseguenza distrutti. Al momento di decidere
quale deve essere arrestato, il sistema Android pesa la loro importanza in base all’utilizzo
dell’applicazione da parte dell'utente. Per esempio, è più probabile che il sistema arresti
delle attività non visibili anziché quelle visibili. La decisione di terminare un processo,
pertanto, dipende dallo stato dei sui componenti in esecuzione.
2.4.2 Process Lifecycle
Il sistema Android tenta di mantenere un processo di applicazione il più a lungo possibile,
ma deve prima rimuovere quelli vecchi per recuperare memoria per far spazio ad quelli
nuovi o più importanti. Per determinare quali devono essere mantenuti e quali rimossi, il
sistema li classifica in una "gerarchia di importanza" in base ai componenti in esecuzione
nel processo e allo stato di tali componenti. Quelli meno importanti verranno eliminati
17
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
prima, poi toccherà a quelli con l'importanza successiva più bassa, e così via, in modo tale
da recuperare le risorse del sistema.
Ci sono cinque livelli nella gerarchia (definiti in ordine di importanza):
1) Foreground Process: è il tipo di processo in primo piano, che è necessario per le
operazioni che l'utente sta facendo. In generale, sono pochi i processi di primo piano che
esistono in un dato momento. Essi vengono arrestati per ultimo, tipo se la memoria è
così bassa che impedisce al processo stesso di continuare la sua esecuzione. In genere
però è difficile arrivare a questo tipo di situazione.
2) Visible Process: non ha componenti in primo piano, ma ancora influenza quello che
l'utente vede sullo schermo. Un processo visibile è considerato estremamente importante
e non deve essere arrestato. L’arresto avviene solo se è necessario per mantenere tutti i
processi in primo piano in esecuzione.
3) Service Process: sono processi di servizio, che l'utente non vede, ma che utilizza
comunque (come ad esempio la riproduzione di musica in sottofondo o il download di
dati in rete). Il sistema cerca di tenerli sempre in esecuzione, a meno che non c'è
abbastanza memoria che consente la coesistenza insieme ai processi di primo piano e
visibili.
4) Background Process: anche questi processi non sono visibili dall’utente, ma a
differenza dei Service Process, questi non hanno alcuna relazione con le operazioni
dell’utente, e il sistema può ucciderli in qualsiasi momento per recuperare la memoria
per i processi sopra citati.
5) Empty Process: si tratta di un processo che non possiede componenti delle applicazioni
attive. L'unica ragione che giustifica questo tipo di processo in vita, è per scopi di
caching, ovvero per migliorare i tempi di avvio di un componente di una applicazione. Il
sistema uccide spesso questi processi, al fine di bilanciare le risorse di sistema
complessive tra le cache dei processo e le cache del kernel sottostante.
18
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
2.4.3 Threads
All’avvio di una applicazione, il sistema crea un thread di esecuzione, che prende il nome di
"main". Questo thread è molto importante perché ha il compito di fornire tutti gli elementi
necessari per definire un’intefaccia utente. All’atto della creazione di un componente, il
sistema non crea un thread separato per ogni istanza. Tutti i componenti vengono eseguiti
nello stesso processo, e sono istanziati nel thread main. Il modello a unico thread però,
appesantisce il carico di lavoro di quest’ultimo. Infatti se il thread esegue operazioni molto
lunghe, queste causerebbero il blocco dell’interfaccia utente. Quindi, per risolvere il
problema, si può adottare la soluzione di far compiere operazioni che richiedono un tempo
non trascurabile in thread separati. In questo caso si ottiene una implementazione dei threads
definita come Thread-safe. Tuttavia, poiché con questi meccanismi la complessità delle
operazioni crescono, questo tipo di codice può risultare complicato e difficile da mantenere.
Una soluzione, è quella di gestire le interazioni più complesse con un thread di lavoro,
considerando l'utilizzo di un gestore che elabora i messaggi consegnati dal thread main a
quelli separati.
19
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Capitolo 3
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Interprocess Comunication
Nei capitoli precedenti, è stata fatta una panoramica generale di come è strutturato Android,
privilegiando quelle che sono le relazioni tra i componenti di questo sistema operativo. In questo
capitolo si vuole affrontare il discorso dell’IPC di questa piattaforma. Prima di ciò, però, conviene
dare un’occhiata ancora una volta all’architettura di Android, entrando nel dettaglio.
Figura 3.1 – Overall Architecture
20
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Anche se non sembra, questa rappresenta la stessa architettura raffigurata nella Figura 1.1 del primo
capitolo, con la differenza che questa[8] è strutturata in base ai componenti. Infatti sono presenti
alcuni elementi che già sono stati accennati in precedenza. Oltre a questi ce ne sono altri in Figura
3.1. Per esempio nella sezione dedicata alle macchine virtuali è presente un elemento di nome
Zygote, che si occupa di clonare una Dalvik VM per ogni processo. I blocchetti in figura hanno
colori diversi (che li diversifica in base alla tipologia), e sono separati da particolari elementi che ne
consentono la relazione tra essi. In particolare tra le applicazioni utente e i componenti del sistema
ci sono le API, e tra il kernel Linux e le macchine virtuali c’è una particolare interfaccia definita
come JNI. Quest’ultima è di notevole importanza, perché, siccome il kernel è basato sul linguaggio
C/C++, e le macchine virtuali e le applicazioni lavorano in Java, la JNI ha il compito di “convetire”
il linguaggio da C/C++ in Java e viceversa. Un ultimo elemento non ancora visto nell’architettura è
un’elemento di nome Binder, tema principale della tesi, che si occupa della comunicazione
interprocesso.
3.1
Binder
Come definito nel paragrafo 1.1, il cuore di Android è basato sul kernel Linux 2.6. Pertanto
ci si aspetta che i meccanismi per la comunicazione interprocesso, siano quelli forniti da
Linux per questo tipo di kernel, come ad esempio elementi del tipo: Signals, Piper, Sockets,
Message Queues, Semaphores, Shared Memory, ecc. In realtà Android non fa uso di alcun
meccanismo citato, ma si basa su un particolare costrutto chiamato Binder.
3.1.1 Communication Model
Il modello[9] di comunicazione interprocesso di Binder è di tipo client-server. Da un lato,
quindi, c’è il client che effettua le richieste (munito di interfaccia, chiaramente), dall’altro,
invece, è presente il server, che risponde alle richieste del client. Siccome ci sono più client
di server, quest’ultimo utilizza un insieme di thread per gestire tutte le richieste concorrenti.
21
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Figura 3.2 – Binder Comunication
Considerata la Figura 3.2, si nota subito al centro il Binder Driver che funge da ottimo
gestore tra i due processi. Il processo A è il client e, tramite l'oggetto proxy, instaura una
comunicazione con il Binder. Il processo B, invece, è il processo server, munito di più
thread. Il Binder, quindi, verifica la disponibilità del processo B, controllando la possibilità
d’utilizzo di ogni thread in esecuzione nel processo stesso. Nel caso in cui ci sia la
disponibilità da parte di un thread ad elaborare le richieste, il Binder inoltra il messaggio dal
proxy al destinatario.
3.1.2 IPC Mechanism
Il Binder utilizza un piccolo modulo kernel personalizzato. Tale modulo, è definito in modo
tale da eseguire efficientemente le comunicazioni tra i processi come "migrazione dei
thread". Questo effetto, si presenta quando diversi processi utilizzano meccanismi IPC[10],
dando l’illusione di avere dei thread che saltano da un processo all’altro. In realtà questo
tipo di meccanismo non è implementato, ma è emulato dal kernel. Android utilizza un IPC
Binder che mette a disposizione un pool di thread ad ogni processo, usati per gestire gli
22
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
eventi locali (quindi le comunicazioni) del processo stesso. Oltre all’IPC, il Binder ha anche
il dovere di monitorare i riferimenti agli oggetti attraverso i processi. Ciò comporta la
mappatura dei riferimenti degli oggetti remoti in un unico processo, mentre l'oggetto reale è
presente in quello di accoglienza. In questo modo gli oggetti non vengono distrutti fino a
quando altri processi hanno riferimenti su di loro.
Quando un thread vuole partecipare ad un IPC (o cominciare un IPC con un altro processo,
o di ricevere una chiamata in entrata IPC), la prima cosa che deve fare è aprire il driver
fornito dal kernel Binder. Quest’ultimo associa un descrittore di file a quel thread, che il
modulo del kernel utilizza per identificare gli iniziatori e i beneficiari dell’IPC Binder. Con
questo descrittore di file, tutte le interazioni con il meccanismo IPC avverranno attraverso
un piccolo insieme comandi ioctl. I comandi sono:
-
BINDER_WRITE_READ : invia prima un parametro per definire una particolare
operazione (0 nel caso di nessuna operazione), poi attende a sua volta un
parametro e restituisce il risultato.
-
BINDER_SET_WAKEUP_TIME : imposta il tempo previsto dell’evento all’atto
di un processo chiamante.
-
BINDER_SET_IDLE_TIMEOUT : imposta il tempo di inattività del thread (in
attesa di una nuova transazione in entrata) prima del time out.
-
BINDER_SET_REPLY_TIMEOUT : definisce il tempo di attesa dei thread fino al
time out.
-
BINDER_SET_MAX_THREADS : imposta il numero massimo di thread che un
driver può creare, per definire il pool di thread di un processo.
Il comando più importante è BINDER_WRITE_READ, che è alla base di tutte le operazioni
IPC. È necessario garantire che ci sia sempre un thread a disposizione (fino al numero
massimo di thread consentito) in modo che l’IPC possa essere elaborato. Il driver si occupa
anche del risveglio dei thread nel pool, quando è il momento di elaborare gli eventi asincroni
nuovi nel processo locale.
23
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Come detto in precedenza, la funzionalità di base del driver, è incapsulato nel
funzionamento BINDER_WRITE_READ, ben definita dalla struttura in Figura 3.3:
Figura 3.3 – Binder_Write_Read
Al richiamo del driver, write_buffer contiene un insieme di comandi di esecuzione, e
read_buffer è riempito con una serie di risposte per il thread che deve essere eseguito. In
generale, il buffer di scrittura contiene zero o alcuni parametri che definiscono i comandi
(solitamente di incremento/decremento dei riferimenti agli oggetti) e termina con un
comando che richiede una risposta (come l'invio di una transazione o di un tentativo di
acquisire un riferimento di un oggetto). Il buffer di ricezione viene riempito in modo
analogo a quello di scrittura, e termina con il risultato dato dall'ultimo comando scritto o un
comando che consente l’esecuzione di una nuova operazione nidificata.
In Figura 3.4 è presente un elenco di comandi che possono essere inviati da un processo al
driver, opportunamente commentato.
24
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Figura 3.4 – Binder Driver Command
25
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Il comando più interessante è bcTRANSACTION, che avvia una transazione IPC, e
restituire una risposta, rispettivamente. La struttura dei dati di questo comando è definita in
Figura 3.5.
Figura 3.5 – Binder bcTRANSACTION
Così, per avviare una transazione IPC, viene eseguita una ioctl BINDER_READ_WRITE
con il buffer di scrittura bcTRANSACTION definita da un binder_transaction_data. La
struttura è l'handle dell'oggetto che deve ricevere la transazione, formato da codice che
indica all'oggetto che cosa fare quando riceve l'operazione, priorità del thread per eseguire
l'IPC e un buffer di dati contenente quelli di transazione (ci sarebbe anche un ulteriore
buffer (opzionale) per i meta-dati).
26
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Quindi, dato l’handle, il driver determina in quale processo questi oggetti vivono, e invia la
transazione a uno dei thread in attesa nel suo pool (se è necessario viene creato). Questo
thread rimarrà in attesa in una ioctl BINDER_WRITE_READ aspettando l’evento dal
driver, per ottenere i comandi necessari per l'esecuzione. Una volta eseguite tutte le
operazioni, il thread ritornerà con un comando brTRANSACTION, lo stesso usato per
inviare i dati, che si ritrovano disponibili nello spazio locale del processo. Il destinatario,
avrà quindi nel suo spazio utente la transazione verso l’oggetto, in modo da effettuare
elaborazioni, e restituire i risultati. A questo punto, si definisce un buffer di scrittura con il
comando bcREPLY, una struttura binder_transaction_data contenente i dati risultanti.
Questo buffer viene restituito con una ioctl BINDER_WRITE_READ sul driver, inviando la
risposta al processo originale, e lasciando il thread in attesa dell'operazione successiva da
eseguire. Il thread main torna finalmente dalla sua BINDER_WRITE_READ, proprio con il
comando brREPLY contenente i dati di risposta.
Inoltre il thread originale può anche ricevere comandi brTRANSACTION mentre è in attesa
di una risposta, attraverso il meccanismo basato sulla ricorsione. Comunque sarà
responsabilità del driver tenere traccia di tutte le transazioni attive, in modo che possa
inviarle al thread corretto quando si verifica una ricorsione.
Una delle più importanti responsabilità del driver, è quella di eseguire il mapping di oggetti
da un processo ad un altro. Ci sono due forme distinte di riferimento ad un oggetto:
-
come un indirizzo nello spazio di memoria di un processo.
-
come un handle di 32 bit.
Queste rappresentazioni sono mutuamente esclusive, infatti tutti i riferimenti in un processo
per oggetti locali sono sottoforma di indirizzo, mentre tutti quelli definiti in un altro
processo sono definiti tramite handle, per esempio il campo principale di
binder_transaction_data, quando si invia una transazione, contiene un handle per l'oggetto di
destinazione. Il destinatario, tuttavia, vede questo come un puntatore all'oggetto nel suo
spazio di indirizzi locale. Quindi il driver conserva le mappature di puntatori degli handle tra
i processi, in modo tale da effettuare sempre questa traduzione.
27
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Il driver consente anche l’invio dei riferimenti agli oggetti attraverso operazioni. Questo
viene fatto mettendo il riferimento all'oggetto per il buffer di transazione, lasciando al driver
il compito di tradurre questo riferimento a quello corrispondente nel processo ricevente. Per
fare la traduzione dei riferimenti, bisogna sapere dove sono situati nei dati di transazione. In
questo caso, si considera il buffer aggiuntivo definito come offset, che contiene una serie di
indici, che descrivono il luogo in cui sono presenti gli oggetti di transazione. Il driver può
quindi riscrivere i dati del buffer, traducendo ciascuno di questi oggetti dal riferimento del
processo inviante, al riferimento corretto del processo ricevente. Si noti che il driver non sa
nulla di un oggetto Binder particolare, fino a quando non lo invia ad un particolare processo.
A quel punto il driver aggiunge l'indirizzo dell'oggetto nella sua tabella di mappatura e
chiede al processo proprietario il permesso di mantenerne un riferimento. Quando nessun
processo possiede il riferimento dell'oggetto, quest’ultimo viene rimosso dalla tabella e il
suo processo proprietario viene avvisato dell’evento. Questo meccanismo evita il
mantenimento da parte del driver di un oggetto, finché è utilizzato solo dal suo processo
locale.
3.2
Application Launch
Dato le conoscenze acquisite finora, in questo paragrafo si cercherà di capire quali sono le
operazioni e le fasi dietro all’inizio di una applicazione Android[11]. Come tutti i sistemi
Linux, in fase di avvio, il bootloader carica il kernel ed avvia il processo init. Prima di tutto
l’init avvia i processi Linux di basso livello, per la gestione delle interfacce hardware. Dopo
di che, viene avviato Zygote, processo che inizializza l'istanza della prima macchina virtuale
Dalvik e pre-carica tutti i framework più comuni utilizzate dalle varie applicazioni. Zygote
si mette poi in ascolto su un’interfaccia, per le future richieste di creazione di macchine
virtuali per i processi di nuove applicazioni utili al sistema, infine avvia un processo ben
gestito chiamato server di sistema.
Tutto inizia da una piattaforma di base, e hanno la priorità d’avvio tutti i servizi manager e
hardware di questo contesto. A questo punto il sistema è pronto a lanciare tutte le
applicazioni home.
28
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
Figura 3.6 – Application Launch
Quando l’utente clicca su una applicazione, l’evento (in Figura 3.6) si traduce in una
chiamata all’intento startActivity() che, come descritto nel paragrafo 2.2 effettua una
richiesta per la creazione di una attività. Tale oggetto, attraverso il Binder IPC, viene
indirizzato all’Activity Manager Service.
Quest’ultimo, ha il compito di fare alcune azioni:
1) Il primo passo è quello di raccogliere informazioni sull'oggetto intento. Questo viene
fatto utilizzando il metodo resolveIntent(), e le informazioni di destinazione vengono
salvate nell’intento stesso (per evitare di rifare questo passo).
2) Il passo successivo è quello di verificare se l'utente dispone di privilegi sufficienti per
richiamare il componente di destinazione dell'intento. Questa operazione viene eseguita
chiamando il metodo grantUriPermissionLocked().
29
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
3) Superate le fasi precedenti, si passa a verificare l’esistenza del processo di quella
tipologia, controllando il ProcessRecord. Se questo è nullo allora l’Activity Manager
Service deve provvedere alla creazione di un nuovo processo.
Ci sono tre fasi distinte per il lancio del processo:
1) Process Creation: viene creato un nuovo processo richiamando il metodo
startProcessLocked(), che invia argomenti dal processo Zygote tramite la sua
interfaccia. Quest’ultimo crea un'istanza di un thread (ActivityThread) munito di
macchina virtuale, restituendo il pid del processo appena creato.
2) Application Binding: in questa fase si collega il processo alla specifica
applicazione, preparando gli strumenti necessari in memoria, utili per
l’elaborazione. L’Activity Manager chiama quindi bindApplication sull'oggetto
thread, che invia un messaggio BIND_APPLICATION alla coda di messaggi, e
viene recuperato dall'oggetto handler che, tramite la funzione handleMessage(),
attiva l'azione specifica dei messaggi con handleBindApplication(). L’Activity
Manager, a sua volta, richiama makeApplication(), che carica specifiche classi
per le applicazioni in memoria.
3) Activity Launch: dopo la fase precedente, il sistema contiene il processo
associato all'applicazione, con le classi private caricate in memoria. Ora avviene
l’effettiva creazione dell’attività con il metodo realStartActivity() che chiama
sheduleLaunchActivity() sull'oggetto thread dell'applicazione, inviando il
messaggio LAUNCH_ACTIVITY alla coda messaggi. L'attività inizia il suo
ciclo di vita gestito con onCreate(), viene in primo piano con onRestart() e inizia
a interagire con l'utente con il metodo onStart().
3.3
Considerations
Infine, si vuole spiegare il motivo per cui Android utilizza il tipo di meccanismi
precedentemente descritti, in alternativa a quelli offerti dal kernel Linux (Signals, Piper,
Sockets, Message Queues, Semaphores, Shared Memory). Il problema principale sta nel
codice. In genere, per consentire un’ottima comunicazione tra i processi, bisogna avere un
30
Analisi dei meccanismi di basso livello per l’IPC su piattaforma Android
insieme di implementazioni che garantiscano un IPC efficiente. Nel campo informatico,
l’efficienza di un codice si basa anche sulla complessità e considerando l’importanza di
questi elementi, si lavora quindi con un codice abbastanza corposo. Per Android è un
enorme problema, perchè questo sistema operativo ha il compito di privilegiare
l’interattività con l’utente. Infatti, con il modello di processo descritto precedentemente, gli
sviluppatori non hanno la necessità di conoscere di quale processo un oggetto Binder fa
parte, ma possono trattare semplicemente qualsiasi istanza come se fosse elemento
appartenente al processo locale. Si evidenzia subito uno dei vantaggi di questa flessibilità,
ovvero che il Binder è in grado di funzionare anche in situazioni estreme. Infatti se il driver
del kernel, che attua il meccanismo IPC Binder, non è disponibile, sarà possibile eseguire
tutti gli elementi in un unico processo. In questo modo se ne garantisce anche l’affidabilità
dell’intero sistema.
Insomma, la logica utilizzata che ha favorito la scelta di tali meccanismi, è finalizzata alla
definizione di un sistema operativo in grado di mantenere la dinamicità e l’efficienza allo
stesso tempo, infatti questo spiega anche il motivo per cui Android può essere installato su
diverse macchine, evitando particolari modifiche hardware, ma soprattutto consentendo la
personalizzazione dei tool, utili sia al sistema che all’utente.
31
Conclusioni e Sviluppi Futuri
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Android è destinato a diventare il sistema più diffuso e conosciuto rispetto ad altri, data la sua
crescita in questo ultimo periodo. Infatti Andy Rubin, capo di uno dei più importanti settori di
Google (cioè quello dedicato allo sviluppo di Android), afferma che "L'obiettivo del progetto Open
Source Android è quello di creare un vero e proprio
successo, che migliora l'esperienza mobile degli utenti".
E non solo. Questo sistema tende anche ad estendere i
propri domini in applicazioni quotidianamente usate (per
esempio avremo l’estensione delle funzionalità di
Google Chrome e di Abode). Il punto di forza deriva
sicuramente dal fatto che il sistema operativo è opensource, pertanto se si considera il numero di sviluppatori
che dedicano il loro lavoro ad applicazioni Android, si
intuisce subito che il suo progresso avviene in maniera
esponenziale. Nonostante sia una piattaforma giovane, Android è stato ideato con aspetti
estremamente potenti, avendo in futuro la possibilità di diventare una risorsa indispensabile ai fini
di soddisfare una utenza sempre più esigente.
32
Bibliografia
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
[1]
Google, Android Developers, August 2011
http://developer.android.com/about/versions/index.html
[2]
Google, Android Developers, Android API Guides, “Application Fundamentals”,
August 2011
http://developer.android.com/guide/components/fundamentals.html
[3]
Google, Android Developers, Android API Guides, “Activities”, August 2011
http://developer.android.com/guide/components/activities.html
[4]
Google, Android Developers, Android API Guides, “Services”, August 2011
http://developer.android.com/guide/components/services.html
[5]
Google, Android Developers, Android API Guides, “Intents and Intent Filter”,
August 2011
http://developer.android.com/guide/components/intents-filters.html
[6]
Google, Android Developers, Android API Guides, “Android Manifest”,
August 2011
http://developer.android.com/guide/topics/manifest/manifest-intro.html
33
[7]
Google, Android Developers, Android API Guides, “Processes and Threads”,
August 2011
http://developer.android.com/guide/components/processes-and-threads.html
[8]
“Android Internals – Android Builders Summit”, Karim Yaghmour, April 2011
http://events.linuxfoundation.org/slides/2011/abs/abs2011_yaghmour_internals.pdf
[9]
“Binder Android – Android Interprocess Comunication”, RUB University, Thorsten
Schreiber, October 2011
http://www.nds.rub.de/media/attachments/files/2012/03/binder.pdf
[10] “Binder IPC Mechanism”, PalmSource Unc., August 2005
http://www.angryredplanet.com/~hackbod/openbinder/docs/html/BinderIPCMechan
ism.html
[11] “Android Application Launch”, Radhika Karandikar, April 2010
http://multi-core-dump.blogspot.it/2010/04/android-application-launch.html
34