Câmeras em ROMs personalizadas: como os desenvolvedores fazem o hardware funcionar sem o código-fonte

Com o lançamento do Android Oreo e muitos dispositivos, como o Xiaomi Redmi Note 3, o Google Nexus 5 e outros que o recebem oficialmente, provavelmente é justo imaginar por que os mesmos recursos (principalmente a câmera) tendem a ser quebrados quando os desenvolvedores portam um Android Open ROM baseada em projeto de origem (AOSP). Você provavelmente já viu tópicos de ROMs no fórum com uma longa lista de recursos desfeitos no topo. “O que funciona”, seguido de uma lista de recursos em funcionamento, e abaixo o icônico “O que não funciona? Diga-me! ”São dois refrões populares em nossos fóruns que praticamente se tornaram um meme em lugares como Reddit e Twitter.

Por que tanta funcionalidade é interrompida sempre que um desenvolvedor tenta portar uma ROM AOSP no dispositivo? A resposta básica é que, como as funções mudam nas diferentes versões do Android, os drivers de dispositivo antigos empacotados como BLOBs não funcionam com versões mais recentes do Android, ou mesmo apenas com o AOSP padrão. Para superar isso, os desenvolvedores usam o que é chamado de "calço", mas o processo envolvido é complicado, demorado e às vezes muito difícil de depurar.

Neste artigo, descreveremos como os calços funcionam, especialmente no que diz respeito ao funcionamento adequado da câmera em ROMs baseadas em AOSP. Usaremos o OnePlus 3T como exemplo. Observe que a dificuldade envolvida em fazer com que esses recursos funcionem é altamente específica do dispositivo.

OnePlus 3T executando o OxygenOS. Embora os telefones OnePlus sejam conhecidos por sua facilidade de desenvolvimento personalizado, há muito trabalho que os desenvolvedores fazem nos bastidores para criar portas estáveis ​​do AOSP.


O que é um calço ou um BLOB?

Para começar a entender parte do que os desenvolvedores estão fazendo, precisamos primeiro explicar algumas coisas. Embora o sistema operacional Android seja de código aberto (é chamado de Projeto de código aberto do Android por um motivo), o software (sem o kernel) enviado em milhares de dispositivos Android não é. Os desenvolvedores não têm acesso ao código fonte do Samsung Experience, EMUI, OxygenOS ou qualquer outro tipo de Android do Android.

Agora, os desenvolvedores que portam o AOSP padrão para um dispositivo que não seja do Google provavelmente não se importam com o código-fonte dessas capas do Android, pois não vão modificar e criar essas ROMs. Isso seria verdade, se não por um grande motivo: as peças necessárias para que a câmera funcione corretamente, principalmente a câmera HAL (Hardware Abstraction Layer), também são de código fechado .

O problema de ter não apenas a câmera HAL, mas também a fonte fechada da ROM é que os desenvolvedores que trabalham na portabilidade do AOSP em seus dispositivos estarão trabalhando às cegas . A ROM do OEM de código fechado é capaz de interagir com a câmera HAL muito bem, porque o OEM tem acesso à fonte HAL da câmera. A HAL da câmera é o que permite à ROM "conversar" com o hardware da câmera - sem ela, a câmera não funcionaria. Pense na câmera HAL como o volante e os pedais do carro. O volante / pedais permitem o controle dos componentes internos do veículo, fornecendo uma interface externa para o motorista (a ROM) fazer uso dos componentes internos.

Gráfico mostrando a arquitetura da câmera. Fonte: Google

À medida que o hardware da câmera se torna cada vez mais complexo (o advento das câmeras duplas, por exemplo), o acesso à fonte HAL da câmera tornaria mais fácil a portabilidade de uma ROM AOSP com uma câmera funcional.

No entanto, os OEMs não fornecem acesso à fonte HAL da câmera por vários motivos. Primeiro, se eles não tiverem todos os direitos de propriedade da câmera HAL (como quando incorporam propriedade intelectual de outras empresas), eles não poderão distribuir a fonte. Segundo, liberar a fonte HAL da câmera pode comprometer sua própria propriedade intelectual. Finalmente, as empresas não têm obrigação legal de fornecer esse código-fonte (diferentemente do código-fonte do kernel que são obrigadas a liberar sob a GPL), portanto, elas não têm incentivo para liberá-lo. Portanto, sem acesso à fonte HAL da câmera, como exatamente os desenvolvedores fazem a câmera funcionar nas ROMs AOSP? A resposta é um BLOB, shim e muita e muita depuração.

Um dispositivo BLOB (Binary Large OBject) contém binários pré-empacotados, que são a forma compilada de software. Nesse caso, a fonte HAL da câmera é compilada pelo OEM e enviada nos dispositivos como binários. Quando os desenvolvedores falam sobre BLOBs, eles se referem aos binários fornecidos em dispositivos ativos que podem extrair. Agora, o tópico "BLOBs de câmeras" atormenta o OnePlus há muitos meses, mas a verdade é que os desenvolvedores sempre tiveram acesso aos BLOBs de câmeras. O código-fonte HAL da câmera é o bilhete de ouro para os desenvolvedores aqui, no entanto, mas isso nunca será lançado devido ao risco legal em que colocaria empresas como a OnePlus.

Assim, os desenvolvedores que desejam trazer o AOSP para um dispositivo ficam apenas com os BLOBs da câmera HAL para os quais eles não têm acesso ao código-fonte. Raramente, se é que um desenvolvedor pode emparelhar seu código AOSP ROM com a câmera HAL BLOB e esperar que funcione, então, a fim de preencher a lacuna entre os dois, os desenvolvedores criam o que é chamado de " calço ".

"Calçar" é "calçar (algo) ou preencher um espaço". Isso é efetivamente o que um desenvolvedor faz ao escrever um calço - eles adicionam código para permitir que o BLOB faça interface com o código-fonte AOSP com o qual está trabalhando . Os calços são usados ​​para fazer com que os BLOBs de todos os tipos diferentes funcionem com o AOSP, mas geralmente é o BLOB da câmera que requer mais shimming. Como mencionamos anteriormente, o shimming é necessário não apenas para portar versões mais recentes do Android em um dispositivo (como todas as ROMs não oficiais do Android Oreo), mas também é necessário ao portar o AOSP da mesma versão do Android para esse dispositivo.

Leitura recomendada: da loja à prateleira: uma análise aprofundada do motivo pelo qual os dispositivos MSM8974 são excluídos do Nougat

O OnePlus 2, por exemplo, recebeu sua última atualização oficial do sistema operacional na forma do Android 6.0 Marshmallow. O dispositivo, no entanto, realmente possui ROMs personalizadas baseadas em AOSP, totalmente funcionais, baseadas no Android Nougat, e isso é graças ao trabalho árduo dos desenvolvedores e seus shims. Iremos detalhar alguns exemplos de calços, mas primeiro precisamos falar sobre como exatamente os calços funcionam.


Como funciona o shimming?

Como os desenvolvedores não têm acesso à fonte HAL da câmera ou à ROM OEM (e apenas aos binários pré-compilados), eles não podem saber quais funções a HAL da câmera espera. Por esse motivo, geralmente há uma incompatibilidade entre o nome da função que o HAL da câmera está procurando e o nome real da função no código AOSP com o qual o desenvolvedor está trabalhando.

Para resolver esse problema, o desenvolvedor simplesmente cria uma nova função que usa o mesmo nome da função que a câmera HAL BLOB espera, mas essa nova função apenas executa o que o desenvolvedor deseja. Essa nova função que atua como intermediária entre o BLOB e o AOSP é o calço. Esse cenário específico em que o BLOB falha ao encontrar a função que ele procura é um dos mais comuns em que é necessário um calço.

Diagrama de pintura MS muito simples, mostrando onde é necessário um calço.

Talvez as coisas façam um pouco mais de sentido com um exemplo hipotético envolvendo o OnePlus 3T. Criaremos um exemplo usando o OxygenOS e a câmera OnePlus. Se usarmos BLOBs de câmera retirados do OxygenOS Nougat para o OnePlus 3T para criar uma ROM Nougat baseada em AOSP, podemos ter problemas. Isso ocorre porque os BLOBs da câmera (que foram originalmente compilados pelo OEM) poderão fazer referência a todas as funções necessárias no OxygenOS, mas como a ROM AOSP compilada pode não ter essas funções ou pode ter sido compilada com um nome diferente ( levando a uma incompatibilidade entre os símbolos de função), haverá um erro. Isso pode ser corrigido através da criação de uma nova função na ROM do AOSP com o nome que o BLOB espera - nosso calço.

Símbolos em um contexto de programação são usados ​​para se referir a funções específicas no código. Os símbolos são necessários porque a posição de uma função pode mudar quando o código é editado e, para evitar referências codificadas às funções, o compilador cria uma tabela de símbolos que outras funções podem usar para sempre se referir à função correta. Quando você altera o nome de uma função antes da compilação, seu símbolo também muda; portanto, basicamente qualquer alteração que o OEM faça na fonte HAL da câmera antes da compilação exigirá que os desenvolvedores criem um novo calço.

Visualizando uma tabela de símbolos com o funil. Fonte: Apriorit

A explicação que oferecemos até agora parece fácil criar calços. Alterar alguns nomes de funções aqui e ali não parece muito difícil, certo? Se fosse assim tão fácil. A realidade dos calços envolve mais do que apenas renomear funções. Conversamos com o desenvolvedor reconhecido Sultanxda, que foi capaz de nos fornecer um exemplo de um dos calços mais difíceis em que ele trabalhou.


Shimming - Não é tão fácil quanto parece

Para aqueles que não estão familiarizados com o OnePlus 3T, a câmera frontal foi quebrada inicialmente em ROMs personalizadas baseadas em AOSP. Para começar, tentar tirar qualquer foto acima de 8MP resultaria em falha. Na tentativa de resolver esse problema, Sultanxda fez vários calços para permitir que a câmera frontal OnePlus 3T funcionasse corretamente.

Calço # 1 - Alterando o nome do pacote da câmera

Para impedir que a câmera frontal falhe sempre que o usuário tirar uma foto acima de 8MP, Sultanxda forçou a câmera HAL a identificar todas as câmeras como a câmera OnePlus. Isso é feito porque o OnePlus decidiu dedicar uma função auxiliar a determinadas aplicações ( isOnePlusCamera, isFacebookCamera, etc.) por algum motivo. A Sultanxda corrigiu isso ajustando o HAL da câmera, apontando para uma nova função que sempre retorna "true" como se o usuário estivesse usando a câmera OnePlus - mesmo quando não estiver.

Calço # 2 - Desativar QuadraCfa

Para seu próximo calço, ele teve que desativar o QuadraCfa, que é presumivelmente uma tecnologia proprietária da Qualcomm relacionada à câmera. Dizemos que é provável que nem eu nem a Sultanxda tenham certeza do que QuadraCfa é, mas a Sultanxda sabe que ela quebrou a câmera frontal sempre que foi ativada.

Ele observou que o QuadraCfa se habilitaria de alguma forma, mas não sabia ao certo por que ou como estava fazendo isso. Para resolver isso, foi necessária uma modificação pouco convencional da parte dele. Em um calço convencional, a função de calço, quando compilada, fornece o símbolo ausente que o BLOB está procurando. Nesse caso, o BLOB já possuía os símbolos de que precisava - os que presumivelmente representavam as funções que estavam iniciando o QuadraCfa.

Bless Hex Editor. O programa Sultanxda usado.

Portanto, ele precisava substituir os símbolos usados ​​pela câmera HAL e, em essência, torná-los "ausentes" para que seus calços fossem fornecer esses símbolos "ausentes". A única maneira de fazer isso é através da edição hexadecimal da própria câmera HAL . A edição hexadecimal é basicamente examinar um monte de bobagens desorganizadas na forma de dados binários, a fim de encontrar uma agulha no palheiro - uma função ou uma string que você deseja editar.

A edição hexadecimal de uma função é substancialmente mais difícil do que a edição hexadecimal de uma string, mas, felizmente, o Sultanxda conseguiu evitar a edição hexadecimal das funções por trás do QuadraCfa, editando hexadecimalmente os nomes dos símbolos para anular esses símbolos.

Calço # 3 - Bright Light Crash Fix

Em seguida, Sultanxda identificou que tirar uma foto da câmera frontal quando sob condições de luz intensa causaria o travamento da câmera. Para reproduzir esse bug em seu próprio dispositivo, Sultanxda ativou a função de lanterna do seu OnePlus One e acendeu a luz na frente da câmera frontal do OnePlus 3T, a fim de travá- lo e produzir logs utilizáveis! Depois de descobrir que função estava causando o acidente, ele criou um calço para forçar o dispositivo a usar o modo de pouca luz o tempo todo para a câmera frontal.

Calço # 4 - Fotos da câmera frontal de baixa resolução

Depois de corrigir a falha da luz brilhante com o calço anterior, Sultanxda descobriu outro bug que surgiu como resultado direto desse calço: fotos de câmera frontal de baixa resolução. Em vez de tirar fotos na resolução solicitada pelo usuário (por exemplo, 16MP), a foto resultante seria tirada em 4MP.

Para resolver isso, é necessário que ele handleSuperResolution as funções handleSuperResolution e isSuperResolution para sempre retornar true, mas SOMENTE quando a câmera frontal estiver ativa (caso contrário, a câmera trava ao tirar fotos do sensor traseiro).


Lição aprendida - O calço pode ser difícil

Sultanxda admite que os calços que ele teve que criar para fazer funcionar a câmera frontal OnePlus 3T não representam seu exemplo típico de calço. Ele se orgulha de seu calço, dada a sua complexidade e a rara necessidade de editar o próprio BLOB. Mas este exemplo mostra apenas o quão difícil pode ser fazer o hardware da câmera funcionar em determinados dispositivos.

Que suas aventuras com calços de câmera sejam menos dolorosas do que as minhas. -Sultanxda

Logs, logs e mais logs. Sem uma maneira consistente de reproduzir uma falha e sem registros, os desenvolvedores têm poucas esperanças de encontrar a fonte do problema. Mesmo que eles encontrem o que causa o problema, nem sempre é uma solução direta. Todo o processo de encontrar e esmagar esses bugs pode levar dias ou semanas e é a razão pela qual fixar a câmera nas ROMs AOSP é uma das tarefas mais difíceis.

Se o seu dispositivo possui uma ROM AOSP portada com hardware totalmente funcional, esperamos que você possa começar a apreciar a luta pela qual esses desenvolvedores podem ter passado para oferecer esses recursos. Aprecie-os pelo seu trabalho, porque não é fácil. É um monte de trabalho que a grande maioria dos usuários nem notará, pois desenvolvedores talentosos em nossos fóruns cuidam de muitas partes invisíveis do Android.

Gostaríamos de agradecer especialmente a Sultanxda pelas muitas contribuições que ele sugeriu na elaboração deste artigo.