O Android está na moda. E não estamos falando de nenhum novo robozinho da Sony ou da Honda. Estamos falando do sistema operacional do Google (ou da Google, como preferirem), desenvolvido especialmente para dispositivos móveis.
Como é um sistema aberto (apesar de não ter necessariamente todo código-fonte disponível), todos querem embarcar o Android em seus dispositivos e se aproveitar de toda a infraestrutura de aplicações e serviços disponíveis no mercado.
Uma característica que ajuda na escolha deste sistema operacional é que ele usa o kernel do Linux. Mas o que isso significa? O Android é uma distribuição Linux? Como ele funciona internamente? É isso que veremos nesta série de artigos sobre a arquitetura interna do Android.
HISTÓRICO
Em 2005, uma empresa chamada Android Inc., que desenvolvia um sistema operacional móvel de mesmo nome, foi comprada pelo Google. Com a popularização do uso de smartphones trazida pelo iPhone da Apple, o Google sentiu que poderia expandir seu negócio de venda de anúncios também em dispositivos móveis.
Em 2007, para cuidar do projeto Android, o Google criou a Open Handset Alliance, um consórcio de empresas de tecnologia envolvidas no mercado de dispositivos móveis (HTC, Sony, Intel, Motorola, Sansumg, etc). No fim deste mesmo ano, é liberada a primeira versão do Android, juntamente com o SDK para o desenvolvimento de aplicações.
ARQUITETURA BÁSICA
O Android é um sistema operacional baseado no kernel do Linux. Apesar de ter sido desenvolvido inicialmente para smartphones, hoje é usado em diversas outras aplicações como tablets e até relógios.
Apesar de ser baseado no kernel do Linux, existe pouca coisa em comum com distribuições Linux convencionais (embarcadas ou não). À grosso modo, o Android é uma máquina virtual Java rodando sobre o kernel do Linux, dando suporte para o desenvolvimento de aplicações Java através de um conjunto de bibliotecas e serviços. Sua arquitetura tem basicamente 4 camadas:
Linux kernel: o Android usa o kernel do Linux com alguns patchs, que adicionam algumas funcionalidades através de módulos do kernel. Veremos mais adiante quais são estas funcionalidades.
Bibliotecas e serviços: aqui estão as bibliotecas básicas do sistema como a Bionic, aOpenGL/ES para trabalhar com gráficos, e a SQLite para trabalhar com banco de dados. Aqui também estão os serviços providos para as camadas superiores, incluindo a máquina virtual Java (Dalvik). A maior parte destas bibliotecas e serviços estão desenvolvidos em C e C++.
Framework: esta camada é desenvolvida quase toda em Java, e faz a interface com as aplicações Android. Ela provê um conjunto de bibliotecas para acessar os diversos recursos do dispositivo como interface gráfica, telefonia, localizador (GPS), banco de dados persistente, armazenamento no cartão SD, etc.
Aplicações: é aqui que ficam as aplicações (desenvolvidas em Java) para o Android. E é um dos grandes segredos do sucesso da plataforma, já que possui mais de 250.000 aplicações no Android Market, e continua crescendo cada dia que passa.
Parece simples, não? Nem tanto assim. Se olharmos para a arquitetura interna do Android, veremos o nível de complexidade deste sistema operacional:
Realmente muita coisa acontece quando rodamos uma simples aplicação. Vamos então tentar entender melhor tudo isso?
O KERNEL
Vimos que o Android usa uma versão modificada do kernel do Linux. Dentre as principais modificações, temos:
binder: sabemos que em todo sistema operacional com suporte à memória virtual, os processos rodam em diferentes regiões de memória. Isso significa que nenhum processo tem acesso à região de memória de outro processo. E por isso precisamos de um mecanismo de comunicação entre processos. Mas quem esta acostumado com o padrão System V IPCusado em sistemas Linux tradicionais para comunicação entre processos (message queues, semáforos e shared memory) vai precisar “voltar à escola”. O Android usa o Binder para a comunicação entre processos. Ele implementa um modulo no kernel em “drivers/misc/binder.c” para esta tarefa. Toda comunicação entre processos no Android passa pelo binder. Para o desenvolvedor de aplicações Android, o processo é transparente, já que é abstraído pelas bibliotecas do sistema.
ashmem: um novo mecanismo de compartilhamento de memória, onde dois processos podem se comunicar através desta região compartilhada de memória. É mais leve e simples de usar, e tem melhor suporte a dispositivos com pouca memória, já que tem a capacidade de descartar regiões de memória compartilhada de maneira segura em caso de pouca memória disponível. Sua implementação encontra-se em “mm/ashmem.c”.
logger: o Android possui um sistema global de logs, implementado através de um módulo do kernel. Ele cria 4 arquivos de dispositivo em “/dev/log”, cada um representando um buffer diferente:
# ls -l /dev/log
crw-rw--w- root log 10, 54 1970-01-01 00:00 system
crw-rw--w- root log 10, 55 1970-01-01 00:00 radio
crw-rw--w- root log 10, 56 1970-01-01 00:00 events
crw-rw--w- root log 10, 57 1970-01-01 00:00 main
|
Para as aplicações acessarem o sistema de log, basta abrir e ler ou escrever num destes arquivos de dispositivo. A implementação deste módulo no kernel encontra-se em “drivers/misc/logger.c”.
wakelocks: se um dispositivo Android ficar um tempo sem ser usado, entrará em modo de baixo consumo para garantir economia de bateria. O módulo de wakelock permite que as aplicações desabilitem o mecanismo de baixo consumo. Por exemplo, se você precisar executar um processo em background que não pode ser interrompido para entrar em modo de baixo consumo, este módulo possibilita a desativação temporária deste recurso até que seu processo finalize a execução. Sua implementação encontra-se em “kernel/power/wakelock.c”.
oom handling: implementado em “drivers/misc/lowmemorykiller.c”, controla o uso de memória do sistema e mata processos se verificar que a memória disponível esta abaixo de um valor mínimo aceitável.
timed GPIO: possibilita acionar saídas de I/O de forma temporizada. Está implementado em “drives/misc/timed_gpio.c”.
O SISTEMA DE ARQUIVOS
Esta é a árvore de diretórios de um sistema de arquivos para o Android:
$ sudo tree -d -L 2 .
.
|-- acct
| `-- uid
|-- cache
| `-- lost+found
|-- config
|-- d -> /sys/kernel/debug
|-- data
| |-- anr
| |-- app
| |-- app-private
| |-- backup
| |-- bootchart
| |-- dalvik-cache
| |-- data
| |-- dontpanic
| |-- local
| |-- lost+found
| |-- misc
| |-- property
| |-- secure
| |-- system
| `-- tombstones
|-- dev
|-- mnt
| |-- asec
| |-- sdcard
| `-- secure
|-- part-3
|-- proc
|-- sbin
|-- sys
`-- system
|-- app
|-- bin
|-- etc
|-- fonts
|-- framework
|-- lib
|-- media
|-- ti-dsp
|-- usr
`-- xbin
|
Bem diferente de um sistema Linux convencional, não é verdade? Os dois principais diretórios são o “data”, que armazena os dados das aplicações, e o “system”, com as bibliotecas (system/lib), serviços (system/bin e system/xbin) e aplicações Java (system/app).
E por falar em bibliotecas do sistema, nada de glibc ou uClibc. O Android implementou uma biblioteca chamada Bionic para usar como biblioteca do sistema. Porque? Me parece que o Google tem algum problema com licenças GPL, e eles tiraram do user space todo e qualquer software com licença GPL. A Bionic usa a licensa BSD, e suporta as arquiteturas x86 e ARM.
Agora, se alguém do Google esta lendo este artigo, por favor me respondam, porque vocês não usaram o Busybox??? Bom, tenho quase certeza de que também tem a ver com a licensaGPL do Busybox. De qualquer forma, o Android usa o Toolbox, uma implementação no mesmo esquema do Busybox, que também traz um conjunto (mais limitado) de comandos e ferramentas úteis para gerenciar um sistema Android. Repare nos executáveis que fazem um link para o toolbox na listagem abaixo:
$ ls -l /system/bin
lrwxrwxrwx system system 2011-08-13 04:24 reboot -> toolbox
-rwxr-xr-x system system 9648 2011-08-13 04:24 audioloop
-rwxr-xr-x system system 100916 2011-08-13 04:24 iptables
-rwxr-xr-x system system 9748 2011-08-13 04:24 sdcard
lrwxrwxrwx system system 2011-08-13 04:24 ps -> toolbox
lrwxrwxrwx system system 2011-08-13 04:24 top -> toolbox
-rw-r--r-- system system 5372 2011-08-13 04:24 testwrap
lrwxrwxrwx system system 2011-08-13 04:24 mount -> toolbox
-rwxr-xr-x system system 5548 2011-08-13 04:24 dvz
-rwxr-xr-x system system 18112 2011-08-13 04:24 debuggerd
lrwxrwxrwx system system 2011-08-13 04:24 ln -> toolbox
lrwxrwxrwx system system 2011-08-13 04:24 ifconfig -> toolbox
lrwxrwxrwx system system 2011-08-13 04:24 renice -> toolbox
-rwxr-xr-x system system 10792 2011-08-13 04:24 showlease
drwxr-xr-x system system 2011-08-13 04:24 sgx
lrwxrwxrwx system system 2011-08-13 04:24 start -> toolbox
...
|
O Android ainda usa por padrão o SQLite como gerenciador de banco de dados para as aplicações e o OpenGl/ES como biblioteca gráfica, dentre outras bibliotecas disponíveis.
OS SERVIÇOS BÁSICOS
Se listarmos os processos rodando em um dispositivo com Android, a saída será mais ou menos essa:
# ps
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 504 416 c00c1b9c 0000877c S /init
root 2 0 0 0 c0072c34 00000000 S kthreadd
root 3 2 0 0 c00656f0 00000000 S ksoftirqd/0
root 4 2 0 0 c008a23c 00000000 S watchdog/0
root 5 2 0 0 c006fc14 00000000 S events/0
root 6 2 0 0 c006fc14 00000000 S khelper
root 10 2 0 0 c0078bc8 00000000 S async/mgr
root 13 2 0 0 c006fc14 00000000 S suspend
root 229 2 0 0 c009ef8c 00000000 S sync_supers
root 231 2 0 0 c009f7bc 00000000 S bdi-default
root 233 2 0 0 c006fc14 00000000 S kblockd/0
root 246 2 0 0 c006fc14 00000000 S ksuspend_usbd
root 250 2 0 0 c0240bc4 00000000 S khubd
root 253 2 0 0 c0269074 00000000 S kseriod
root 261 2 0 0 c006fc14 00000000 S twl4030-irqchip
root 262 2 0 0 c0207a40 00000000 S twl4030-irq
root 292 2 0 0 c006fc14 00000000 S kmmcd
root 308 2 0 0 c006fc14 00000000 S musb_hdrc
root 310 2 0 0 c006fc14 00000000 S rpciod/0
root 319 2 0 0 c008a434 00000000 S khungtaskd
root 320 2 0 0 c009a628 00000000 S kswapd0
root 322 2 0 0 c006fc14 00000000 S aio/0
root 323 2 0 0 c006fc14 00000000 S nfsiod
root 324 2 0 0 c006fc14 00000000 S crypto/0
root 474 2 0 0 c021a7f0 00000000 S mtdblockd
root 546 2 0 0 c006fc14 00000000 S kondemand/0
root 547 2 0 0 c006fc14 00000000 S kconservative/0
root 553 2 0 0 c006fc14 00000000 S usbhid_resumer
root 557 2 0 0 c02e760c 00000000 S binder_deferred
root 589 2 0 0 c02d7f9c 00000000 S mmcqd
root 609 1 488 172 c00c1b9c 0000877c S /sbin/ueventd
root 887 1 736 332 c00633f0 afd0c63c S /system/bin/sh
system 889 1 808 248 c02e69e8 afd0b81c S /system/bin/servicemanager
root 890 1 3864 584 ffffffff afd0becc S /system/bin/vold
root 891 1 3836 556 ffffffff afd0becc S /system/bin/netd
root 892 1 668 256 c031bfb8 afd0c1ec S /system/bin/debuggerd
root 893 1 1272 540 c0076e64 afd0becc S /system/bin/rild
root 894 1 61364 26520 c00c1b9c afd0b964 S zygote
media 895 1 26872 5132 ffffffff afd0b81c S /system/bin/mediaserver
bluetooth 896 1 1256 564 c00c1b9c afd0c82c S /system/bin/dbus-daemon
root 897 1 816 308 c0373d78 afd0b57c S /system/bin/installd
keystore 898 1 1744 424 c031bfb8 afd0c1ec S /system/bin/keystore
system 899 1 736 328 c00633f0 afd0c63c S /system/bin/sh
root 901 1 3352 156 ffffffff 00008294 S /sbin/adbd
root 948 2 0 0 c006fc14 00000000 S pvr_timer/0
root 962 2 0 0 c006fc14 00000000 S pvr_workqueue
system 978 894 166280 70284 ffffffff afd0b81c S system_server
root 988 2 0 0 c006fc14 00000000 S omaplfb
app_21 1057 894 78324 23540 ffffffff afd0c7ac S com.android.inputmethod.latin
radio 1066 894 85216 23928 ffffffff afd0c7ac S com.android.phone
system 1067 894 76424 27816 ffffffff afd0c7ac S com.android.systemuiueventd
app_14 1068 894 83528 33064 ffffffff afd0c7ac S com.android.launcher
app_3 1120 894 76456 23620 ffffffff afd0c7ac S android.process.acore
app_1 1180 894 73848 22596 ffffffff afd0c7ac S com.android.email
app_4 1192 894 73320 22316 ffffffff afd0c7ac S android.process.media
app_2 1215 894 71424 21416 ffffffff afd0c7ac S com.android.bluetooth
app_10 1243 894 72164 21456 ffffffff afd0c7ac S com.android.deskclock
app_25 1263 894 81444 21620 ffffffff afd0c7ac S com.android.mms
app_26 1290 894 72016 21800 ffffffff afd0c7ac S com.android.providers.calendar
app_16 1309 894 71832 21144 ffffffff afd0c7ac S com.android.quicksearchbox
app_17 1323 894 71388 20588 ffffffff afd0c7ac S com.android.music
app_27 1336 894 70796 20068 ffffffff afd0c7ac S com.android.protips
app_13 1352 894 72452 21376 ffffffff afd0c7ac S com.cooliris.media
root 5267 2 0 0 c00ced38 00000000 S flush-0:12
system 5336 899 884 272 c0076e64 afd0becc S sleep
root 5348 887 896 312 00000000 afd0b57c R ps
root 5349 1 740 332 c00633f0 afd0c63c S /system/bin/sh
|
Três pontos interessantes aqui:
1. O processo “init” é o pai de todos os processos que rodam em user space, como o “/sbin/ueventd” e o “/system/bin/mediaserver”.
2. O processo “kthreadd” é o pai de todas as threads do kernel como o “ksoftirqd” e o “khelper”.
3. O processo “zygote” é o pai de todas as aplicações rodando no Android, como o “android.process.media” e o “com.android.email”. Tudo que roda em cima de uma máquina virtual, tem como antecessor comum o processo “zygote”.
A MÁQUINA VIRTUAL DALVIK
E por falar em máquina virtual, o Android usa uma implementação da JVM chamada Dalvik. A Dalvik não consome bytecode Java, mas sim dexcode. Para isso, o Google desenvolveu uma ferramenta, chamada “dx”, que converte Java bytecodes (*.class) em dexcodes (*.dex).
Além disso, desde a versão 2.2 (Froyo), o Android possui uma implementação de JIT (Just-in-time), que compila dexcodes para a arquitetura-alvo em tempo de execução, tornando a execução dos processos consideravelmente mais rápidas, já que não precisa ficar interpretando dexcodes.
Junto com a máquina virtual Dalvik, o Android usa o framework Apache Harmony, desenvolvido pela Apache Software Fundation como biblioteca padrão de classes Java.
AS APLICAÇÕES
As aplicações são escritas em Java. Existem bibliotecas Java disponíveis para acessar todos os recursos do dispositivo.
Ao executar uma aplicação, o processo “zygote” cria uma instância da máquina virtual Dalvik para executá-la. E cada aplicação roda com um UID (user ID) diferente. Dê uma olhada na coluna “USER” da listagem de processos acima. Isso protege as aplicações umas das outras, e do sistema como um todo, limitando acesso aos arquivos do sistema e aos recursos do dispositivo através de permissões de usuário.
Fonte: Sergio Prado
Postagens Relacionadas