Il servizievole Android


Sono un grafomane, un po’ logorroico.

android_logoLa povera Redazione (grazie, Gilberto) deve combattere ogni volta con un tizio che tenta di sforare in tutti i modi lo spazio graziosamente concessogli in una rivista che (purtroppo) non ha uscite frequentissime (al momento). Di conseguenza qualche volta riscrivo dei pezzi per rientrare nelle sei o otto pagine permesse, o mi è capitato un paio di volte di mollare un riquadro. Quindi, dopo questo corsivo, ve ne consegno uno visto che oramai l’avevo scritto. Si riferisce all’articolo sul numero 68 di L&C. attualmente in edicola e parla del modo in cui Android gestisce i suoi servizi.

Inoltre, visto che ho rotto il ghiaccio con il post precedente contenente un video, l’anno scorso avevo fatto un seminario su Android al Java Users Group di Padova quando ancora era un droide poco conosciuto; diciamo che buona parte di quanto detto è ancora attuale, se a qualcuno può interessare. Le slide proiettate nel video le trovate invece qui.

I servizi sono ospitati in thread con periodo di esecuzione indefinito chiamati empty nel gergo di Android, in quanto non associati a componenti grafici: come tali possono essere terminati immediatamente qualora non siano utilizzati e le risorse di sistema scarseggino. Ma in presenza di Activity utilizzanti il servizio, essi hanno una probabilità minore di essere terminati rispetto alle Activity non in primo piano. Sono realizzati mediante classi che ereditano da android.app.Service (gli IntentReceiver sono simili, ma per questi l’interfaccia grafica è opzionale); sono schedulati dall’ambiente in modo da essere eseguiti a priorità inferiore rispetto a quella dell’Activity in foreground. Un esempio di utilizzo potrebbe essere per lo scaricamento di un file in background mentre si compone un messaggio di posta elettronica.

Una Activity è in grado di richiedere un servizio preesistente o di definirne uno per i fatti suoi, che è creato se non era già attivo: i metodi utilizzabili sono bindService() e startService(). La differenza tra i due è che mentre il servizio con il primo metodo può terminare qualora non ci siano Activity che lo referenzino, nel secondo caso deve essere terminato tramite stopService(). Un servizio può esso stesso richiedere di terminare mediante il metodo stopSelf().

bindService() provoca l’invocazione del metodo onBind() sul servizio referenziato: questo deve ritornare un oggetto che rappresenti la connessione e implementi l’interfaccia IBinder. Il “contratto” al quale risponde un servizio è specificato mediante l’Android Interface Definition Language (AIDL). Praticamente corrisponde a una definizione di interfaccia Java, con in più la specifica degli identificatori in, out o inout (qualora un oggetto sia in input al metodo, in output o input/output) che precedano i parametri dei metodi di tipo classe, ma non i tipi semplici (int, float, …).

Qual è il meccanismo di Inter-Process Communication (IPC) che consente al processo dell’Activity di comunicare in modo efficiente con il processo del servizio? E’ un componente di Android chiamato OpenBinder, che discende nientemeno che dal mitico BeOS. Dopo il fallimento di Be, PalmSource ne acquistò le spoglie ereditando anche la tecnologia del Binder, che era il modo preferito per IPC fra le applicazioni di BeOS. Si può pensare che questa tecnologia sia più sofisticata del COM per Microsoft Windows, in quanto non solo consente di contattare un altro processo, ma consente anche di ricevere le risposte da parte di quest’ultimo e di gestire eventuali casi di ricorsione fra le invocazioni. PalmSource fu in seguito fagocitata da Access, la quale non sapendo che farsene delle varie tecnologie BeOS fu convinta da alcuni dei dipendenti ex-Be a rilasciarle in open source; una di costoro era Dianne Hackborn, che ora lavora in Google. OpenBinder in Android è un po’ meno sofisticato di quello per BeOS; è implementato tramite un driver Linux che rende disponibile un device file /dev/binder, sul quale i processi possono agire mediante ioctl().