Android Embarcado: Compilando e Executando o Android Automotive OS para Raspberry Pi

O Android Automotive é uma modificação do AOSP (Android Open Source Project) feita oficialmente pelo Google e anunciada no Google I/O de 2017[1]. Este sistema de código aberto, livre para qualquer pessoa baixar e modificar da forma que preferir, possui interface amigável e implementação de uma HAL (Hardware Abstraction Layer) específica para a comunicação com veículos: VHAL (Vehicle Hardware Abstraction Layer).

Os grandes fabricantes de carros têm demonstrado interesse em desenvolver produtos a partir dessa modificação. Pode-se citar como exemplos a Volvo, que foi a primeira fabricante a anunciar um carro com Android Automotive em 2019, o Volvo XC40 [2], e a Honda, que anunciou em setembro desse ano que lançará modelos com o Sistema Operacional da Google em 2022. [3]

Este artigo tem como objetivo ensinar o passo a passo de como utilizar o Android Automotive em uma plataforma popular como um Raspberry Pi.

Android Automotive
Figura 1: Imagem interna de um Volvo XC40 com tela de multimídia e computador de bordo controlados a partir do Android Automotive.

Android Automotive x Android Auto

Já é comum encontrar carros que são anunciados com o Android Auto, mas cuidado: Android Auto e Android Automotive não são a mesma coisa. 

O Android Auto é uma aplicação do Android disponível para celular e que necessita do suporte da central multimídia do carro. Dessa forma o seu celular terá uma segunda tela, a do carro, em modo Android Auto, que lhe permitirá usar aplicativos que estão instalados em seu celular, como Google Maps, Spotify, Waze etc. [4]

O Android Automotive, diferente do Android Auto, não é apenas uma aplicação e sim um sistema Android por completo, feito para ser tanto computador de bordo quanto central multimídia. Além de executar as aplicações como o Android Auto, o Android Automotive realiza a coleta de diversas informações do carro como velocidade, temperatura de motor e rodas, RPM, controlar vidros e ar-condicionado. [5]

O objeto deste artigo é Android Automotive, um sistema Android completo que será instalado em uma Raspberry Pi.

Raspberry Pi 4 Modelo B

Popular no mundo dos makers, a Raspberry Pi é uma placa de desenvolvimento modelada pela Raspberry Foundation, feita com SoC’s da Broadcom que possuem o núcleo ARM.

Se tratando de Android puro, nesta versão de Android Automotive para Raspberry é utilizado o Android 11, na qual o Google recomenda uma quantidade acima de 2GB de memória RAM. Logo, as duas únicas opções disponíveis para esse projeto são a Raspberry Pi 4 Modelo B de 4GB e a de 8GB de RAM.

Para mais informações sobre a Raspberry 4, recomendo o artigo do Fábio Souza [9].

Android Automotive
Figura 2: Raspberry Pi 4 Modelo B

Pré-requisitos

Para colocar em prática o passo a passo contido neste artigo, será necessário:

  • Um computador de 64-bits com pelo menos 150GB de espaço em disco e no mínimo 16GB de memória RAM.
  • Ubuntu 18.04 (Bionic Beaver) é o SO recomendado e testado pelo Google. Nada impede de você usar outra distribuição, mas talvez seja necessária alguma adaptação.
  • Raspberry Pi 4 Modelo B de 4GB ou 8GB de RAM
  • Um pendrive ou cartão SD de pelo menos 16GB para armazenar as imagens geradas
  • Um display de pelo menos 1024×600 de densidade de pixels ou um monitor HD
  • Conhecimento intermediário em uso de terminal no Linux
  • Conhecimento intermediário com uso de Git

Esta versão de Android Automotive para Raspberry foi desenvolvida pela empresa Snapp Automotive[6] com código-fonte disponível no GitHub [7], e este, por si, foi baseado no projeto Android on Raspberry que  também está disponível no GitHub [8].

Configuração inicial

Bibliotecas e Toolchain

Antes de baixar e compilar o Android, é necessária a instalação de algumas bibliotecas e da toolchain para compilação do kernel. Você pode utilizar os comandos abaixo para instalá-las.

$ sudo apt install git-core gnupg flex bison build-essential zip curl zlib1g-dev x11proto-core-dev libx11-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig libncurses5 procps libssl-dev bc fdisk eject 
$ sudo apt install gcc-aarch64-linux-gnu

Repo

Instale a ferramenta repo que baixa e agrupa todos os repositórios git do Android.

$ sudo curl https://storage.googleapis.com/git-repo-downloads/repo > /bin/repo
$ sudo chmod a+x ~/bin/repo

Verifique se foi instalado corretamente usando o seguinte comando:

$ repo version

Baixando o código-fonte

Para baixar o código-fonte do Android Automotive, primeiramente crie uma pasta para o seu projeto: 

$ mkdir android-automotive
$ cd android-automotive

Agora é preciso baixar a versão oficial Android 11 diretamente dos repositórios do Google. A label utilizada será a android11-qpr2-release executada no comando a seguir:

$ repo init -u https://android.googlesource.com/platform/manifest -b android11-qpr2-release

Após concluir o init, os arquivos de manifest dos projetos Android on Raspberry e Snapp Automotive devem ser clonados para dentro da pasta android-automotive/.repo/local_manifests, seguindo o comando:

$ git clone https://github.com/snappautomotive/firmware_rpi-local_manifests.git .repo/local_manifests -b sa-main

Então é o momento de sincronizar o código. Esta é a etapa mais demorada, pois o seu computador estará baixando em torno de 100GB de arquivos. Então, pode deixar durante a noite e ir dormir. O comando para sincronizar é o seguinte:

$ repo sync

Ajustes de código

Após sincronizar o código, alguns ajustes serão necessários

 Pendrive ou Cartão SD

No projeto da Snapp Automotive, por padrão está configurado para iniciar o sistema utilizando um pendrive. Já no projeto Android on Raspberry o padrão é o cartão SD. Caso deseje, essa configuração pode ser alterada no arquivo fstab.rpi4 localizada na pasta device/snappautomotive/rpi/.  Basta copiar o arquivo fstab do projeto arpi e sobreescrever no projeto snappautomotive para trocar as opções de pendrive para cartão SD, a partir do comando abaixo:

$ cp device/arpi/rpi4/fstab.rpi4 device/snappautomotive/rpi/

Caso prefira iniciar o sistema pelo pendrive não é preciso realizar nenhuma alteração.

 Ajustes de Framework

Para conseguir compilar o Android, o projeto Android on Raspberry necessita de alguns ajustes relacionados ao Framework, mais especificamente nos códigos de Bluetooth, Audio e Camera [11]. Seguem os caminhos dos arquivos e os patches que devem ser aplicados:

Remover resolv_gold_test de platform_testing

Aplique o patch abaixo na pasta platform_testing/

diff --git a/build/tasks/tests/native_test_list.mk b/build/tasks/tests/native_test_list.mk
index b1565ecf..b73ab0ac 100644
--- a/build/tasks/tests/native_test_list.mk
+++ b/build/tasks/tests/native_test_list.mk
@@ -110,7 +110,6 @@ native_tests := \
     prioritydumper_test \
     puffin_unittest \
     recovery_unit_test \
-    resolv_gold_test \
     resolv_integration_test \
     resolv_unit_test \
     scrape_mmap_addr \

Adicionar Hardware Reset ao Bluetooth HCI

Aplique o patch abaixo na pasta system/bt/

diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index 976d91d56..5bed58b4c 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -375,6 +375,18 @@ static void event_finish_startup(UNUSED_ATTR void* context) {
   startup_future = NULL;
 }
 
+#include <fcntl.h>
+#include <sys/ioctl.h>
+static void hw_reset(bool reset) {
+  unsigned buf[8] = { 8 * 4, 0, 0x38041, 8, 8, 128, 0, 0};
+  buf[6] = reset ? 0 : 1;
+  int fd = open("/dev/vcio", 0);
+  if (fd >= 0) {
+    ioctl(fd, _IOWR(100, 0, char *), buf);
+    close(fd);
+  }
+}
+
 static void startup_timer_expired(UNUSED_ATTR void* context) {
   LOG_ERROR(LOG_TAG, "%s", __func__);
 
@@ -385,7 +397,9 @@ static void startup_timer_expired(UNUSED_ATTR void* context) {
     LOG_ERROR(LOG_TAG, "%s: waiting for abort_timer", __func__);
     return;
   }
-
+  hw_reset(true);
+  sleep(2);
+  hw_reset(false);
   abort();
 }

Desabilitar o Low Power mode do Bluetooth e habilitar compilação para HAL de Camera e Audio

Aplique o patch abaixo na pasta hardware/interfaces/

diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 3e8b71570..6c934e355 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -8,7 +8,6 @@ cc_binary {
     // location for init to start it and the build system does not support
     // having two binaries installable to the same location even if they are
     // not installed in the same build.
-    compile_multilib: "32",
     srcs: ["service.cpp"],
 
     cflags: [
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index d809313db..d63c51856 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -343,7 +343,7 @@ void VendorInterface::OnFirmwareConfigured(uint8_t result) {
   lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
   ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
 
-  bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
+  bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
   lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
 
   ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index 9ddf65144..27bf32b43 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -154,7 +154,6 @@ cc_binary {
     proprietary: true,
     relative_install_path: "hw",
     srcs: ["external-service.cpp"],
-    compile_multilib: "32",
     init_rc: ["android.hardware.camera.provider@2.5-external-service.rc"],
     shared_libs: [
         "android.hardware.camera.common@1.0",

Compilando o Código-fonte

Após todos os ajustes de código necessários chegou o momento de compilar tudo e gerar as imagens necessárias para executar o Android [12].

 Compilando o Linux

O Android é um sistema operacional que usa o núcleo Linux para o controle de hardware, logo, é necessário gerar as imagens do Linux para que o Raspberry consiga executar o Android. Para compilar o Linux kernel use os comandos a seguir:

$ cd kernel/arpi
$ ARCH=arm64 scripts/kconfig/merge_config.sh arch/arm64/configs/bcm2711_defconfig kernel/configs/android-base.config kernel/configs/android-recommended.config
$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make Image.gz
$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- DTC_FLAGS="-@" make broadcom/bcm2711-rpi-4-b.dtb
$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- DTC_FLAGS="-@" make overlays/vc4-kms-v3d-pi4.dtbo

Você pode usar o comando –j[n] junto ao comando make para indicar a quantidade de threads do processador que você quer usar e assim deixar a compilação mais rápida.

Com isso, são geradas três imagens:

  • Image.gz: Imagem principal do Linux
  • bcm2711-rpi-4-b.dtb: Imagem de Device Tree para o Raspberry
  • vc4-kms-v3d-pi4.dtbo: Imagem de Device Tree Overlays para o Raspberry

Agora volte para a raiz do projeto:

$ cd ../..

Compilando o Android Automotive

E agora continue a compilação do Android com os comandos a seguir:

$ source build/envsetup.sh
$ lunch snapp_car_rpi4-userdebug
$ make ramdisk systemimage vendorimage

O comando make de compilação do Android também permite usar o –j[n].

Com isso, são geradas mais três imagens:

  • ramdisk.img: Possui aplicações básicas e arquivos de inicialização do sistema
  • system.img: Contém binários, bibliotecas nativas, bibliotecas Java, arquivos de configuração e de aplicações padrão
  • vendor.img: Assim como a system.img, contém binários e bibliotecas, porém essas fornecidas pelos desenvolvedores de softwares proprietários.

Preparando o Dispositivo de Memória

Tendo todas as imagens geradas, agora podemos organizar o nosso dispositivo de memória.

A partir deste momento será mencionado somente cartão SD, mas se você estiver utilizando pendrive a configuração é a mesma.

O cartão deve ser formatado em 4 partições, configurado conforme indicado abaixo:

  • Partição 1: FAT32 – 128MB – Partição Primária – Flags de BOOT e LBA 
  • Partição 2: EXT4 – 2048MB – Partição Primária
  • Partição 3: EXT4 – 128MB – Partição Primária
  • Partição 4: EXT4 – Restante da memória – Partição primária

Você pode usar o software GParted para formatar o cartão. Para verificar as partições em seu terminal use o comando lsblk, o seu cartão estará mais ou menos como a figura 3 a seguir:

Figura 3: Partições do cartão SD formatadas de acordo com as especificações anteriores

Tendo o cartão devidamente formatado, neste caso sendo sdb, agora transfira os arquivos e imagens necessários para ligar o Android na Raspberry. A partição 1 é responsável pela inicialização do sistema, onde estará o bootloader, o kernel, a ramdisk etc.

Primeiramente monte a partição no sistema com o comando mount:

$ sudo mount /dev/sdb1 /mnt

Agora comece a copiar todos os arquivos necessários para a partição, seguindo a ordem abaixo:

$ sudo cp device/snappautomotive/rpi/boot/* /mnt
$ sudo cp kernel/arpi/arch/arm64/boot/Image.gz /mnt
$ sudo cp kernel/arpi/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dtb /mnt
$ sudo cp out/target/product/rpi/ramdisk.img /mnt
$ sudo mkdir /mnt/overlays
$ sudo cp kernel/arpi/arch/arm64/boot/dts/overlays/vc4-kms-v3d-pi4.dtbo /mnt/overlays

Após copiar todos os arquivos, a partição 1 está devidamente configurada, agora desmonte-a.

$ sudo umount /mnt

As partições 2 e 3, recebem os arquivos que estão nas imagens system.img e vendor.img respectivamente. Para transferir os arquivos, use o comando dd, conforme abaxo:

$ sudo dd if=out/target/product/rpi/system.img of=/dev/sdb2 bs=1M 
$ sudo dd if=out/target/product/rpi/vendor.img of=/dev/sdb3 bs=1M

A partição 4 será responsável pelos dados de usuário, então, não é necessário copiar arquivos para ela e pode ser deixada em branco.

Ligando e Depurando o Android Automotive

Neste momento tudo está configurado corretamente e pronto pra iniciar, agora conecte o Raspberry ao seu display e ligue em uma fonte de 5V e 3A. Se tudo ocorrer como o esperado serão mostradas as seguintes telas iniciais do Android Automotive nas figuras 4, 5 e 6:

Android Automotive
Figura 4: Tela Inicial do Android Automotive com Mapa, Previsão do Tempo e Dispositivos Bluetooth

Android Automotive
Figura 5: Tela para controle de funções do carro

Android Automotive
Figura 6: Tela de aplicativos

Para facilitar o uso e desenvolvimento de aplicações, duas formas de depuração são úteis: 

  • Comunicação serial via UART 
  • Comunicação com o Android via adb.

 Comunicação via UART

A comunicação serial via UART, disponível na Raspberry, necessita de um conversor TTL para que as informações enviadas ou recebidas sejam capturadas pelo computador. Este conversor deve ser conectado à Raspberry conforme a figura 7 a seguir:

Figura 7: Conexão UART para USB

Conecte o USB ao seu computador e abra uma aplicação de comunicação serial de sua preferência, a que mostrarei a seguir é a aplicação minicom. As informações que aparecerão são relacionadas ao kernel e ainda é possível acessar o sistema de arquivos, como mostram as figuras 8 e 9 a seguir:

Figura 8: Informações recebidas via UART usando o minicom

Figura 9 : Acessando o sistema de arquivos do Android Automotive via UART

 Comunicação via adb

A comunicação via adb (Android Debug Bridge) é uma funcionalidade oficial, desenvolvida para o usuário se comunicar diretamente, via comandos, com o Android, podendo assim acessar o sistema de arquivos, instalar e desinstalar aplicativos, verificar informações de bateria  e etc. Como o Raspberry não tem um conector USB device, o adb é acessado via wifi, então, na interface do Android Automotive conecte a uma rede wifi e verifique qual endereço IP ficou configurado, de acordo com as figuras 10 e 11 a seguir:

Figura 10: Ligando o wifi no Android Automotive

Android Automotive
Figura 11: Após conectar a uma rede wifi verifique qual o endereço IP do dispositivo, neste caso é 192.168.xx.xx

Com um computador conectado à mesma rede wifi do Android Automotive, utilize o comando ‘adb connect <Endereço IP>’ e o computador estará apto a usar os comandos adb. A figura 12 ilustra um terminal conectado ao dispositivo via wifi, e utilizando alguns comandos.

Figura 12: Após conectar a uma rede wifi verifique qual o endereço IP do dispositivo, neste caso é 192.168.xx.xx

 Considerações Finais

O Android já é o sistema operacional mais usado no mundo [13] em dispositivos como smartphones, tablets, smartwatches e televisões, um novo caminho agora são carros inteligentes. Então por que não aproveitar o assunto do momento da tecnologia e testar em uma placa acessível.

Este artigo abordou a instalação do Android Automotive, versão do Android para carros, em uma Raspberry Pi, e mostrou como baixar o código fonte, fazer ajustes de código necessários, configurar o dispositivo de memória e ligar e depurar o Android Automotive pela UART e por adb.

Referências

Comentários:
Notificações
Notificar
7 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Hudson Costa
Hudson Costa
31/08/2023 16:39

sabe se é possível rodar esse sistema em um telefone android?
Minha visão é tipo o android auto quando rodava no telefone, aí para quem não tem multimídia em um veículo como moto fica mais fácil rodar no telefone

Pedro de Sousa Alves
Pedro de Sousa Alves
Reply to  Hudson Costa
14/09/2023 01:03

Android Automotive é diferente de android auto

Gabriel Montenegro Villacrez
Gabriel Montenegro Villacrez
26/11/2021 10:12

Muito Bom !!!
Parabéns pelo artigo!
Satisfação de ter te conhecido na faculdade, grande abraço!

luiz
luiz
22/11/2021 09:52

Excelente artigo, muito interessante. Não entendi se o carro já deve ter o Android Automotive, ou em quais carros posso conectar a Raspberry com a instalação mostrada no texto?

luiz
luiz
Reply to  Álison Venâncio
20/12/2021 16:23

E quais seriam essas alterações necessárias no AAOS? Eu percebi que só ajustando o kernel não habilitei a minha rede can

Abraço!

Home » Software » Android Embarcado: Compilando e Executando o Android Automotive OS para Raspberry Pi

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: