Sem o código-fonte, como os desenvolvedores conseguem componentes de hardware, como câmeras, funcionando em ROMs personalizadas? A resposta é um BLOB, correção e muita depuração.
Com o lançamento do Android Oreo e de muitos dispositivos, como o Xiaomi Redmi Nota 3, Google Nexus 5 e outros recebendo-o não oficialmente, provavelmente é justo perguntar por que os mesmos recursos (principalmente a câmera) tendem a ser quebrados quando os desenvolvedores portam uma ROM baseada no Android Open Source Project (AOSP). Você provavelmente já viu tópicos de ROMs no fórum XDA com uma longa lista de recursos quebrados no topo. “O que funciona” seguido por uma lista de recursos funcionais e, abaixo, o icônico “O que não funciona? Você me diz!" são dois refrões populares em nossos fóruns que praticamente se tornaram meme em lugares como Reddit e Twitter.
Por que tantas funcionalidades são interrompidas sempre que um desenvolvedor tenta portar uma ROM AOSP para seu dispositivo? A resposta básica é que, como as funções mudam nas diferentes versões do Android, os drivers de dispositivos antigos empacotados como BLOBs não funcionarão 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 “shim”, mas o processo envolvido é complicado, demorado e, às vezes, muito difícil de depurar.
Neste artigo, descreveremos como funcionam os calços, 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 OxygenOS. Embora os telefones OnePlus sejam conhecidos por sua facilidade de desenvolvimento personalizado, há muito trabalho que os desenvolvedores fazem nos bastidores para tornar as portas AOSP estáveis.
O que é um calço ou um BLOB?
Para começar a entender parte do que os desenvolvedores estão fazendo, primeiro precisamos explicar algumas coisas. Embora o sistema operacional Android seja de código aberto (é chamado de Android Open Source Project por um motivo), o software (sem o kernel) fornecido em milhares de dispositivos Android não é. Os desenvolvedores não têm acesso ao código-fonte do Experiência Samsung, EMUI, Oxygen OSou qualquer outra versão de terceiros 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 skins do Android, pois elas não serão modificar e construir essas ROMs. Isso seria verdade, se não fosse por um grande motivo: as peças necessárias para fazer a câmera funcionar corretamente, principalmente o câmera HAL (Camada de Abstração de Hardware), são também fonte fechada.
O problema de ter não apenas o HAL da câmera, mas também o código fechado da ROM é que os desenvolvedores que trabalham na portabilidade do AOSP para seus dispositivos ficarão trabalhando cego. A ROM OEM de código fechado é capaz de interagir perfeitamente com o HAL da câmera porque o OEM tem acesso à fonte HAL da câmera. O HAL da câmera é o que permite que a ROM “converse” com o hardware da câmera – sem ele, 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.
À medida que o hardware da câmera se torna cada vez mais complexo (o advento de câmeras duplas, por exemplo), ter acesso à fonte HAL da câmera tornaria a portabilidade de uma ROM AOSP com uma câmera funcional uma tarefa muito mais fácil.
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), então não poderão distribuir a fonte. Em segundo lugar, 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 este código-fonte (ao contrário do código-fonte do kernel que elas são obrigado a liberar sob a GPL), portanto, eles 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 em ROMs AOSP? A resposta é um BLOB, shim e muita depuração.
Um dispositivo BLOBO (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 eles são capazes de extrair. Agora, o tópico “BLOBs de câmera” foi OnePlus há muito atormentado por muitos meses, mas a verdade é que os desenvolvedores sempre tiveram acesso aos BLOBs da câmera. O o código-fonte HAL da câmera é o bilhete dourado para desenvolvedores aqui, mas isso nunca, jamais será liberado devido ao risco legal que colocaria empresas como a OnePlus.
Assim, os desenvolvedores que desejam trazer o AOSP para um dispositivo ficam apenas com BLOBs do HAL da câmera para os quais não têm acesso ao código-fonte. Raramente, ou nunca, um desenvolvedor pode emparelhar seu código ROM AOSP com a câmera HAL BLOB e esperar que funcione, então, para preencher a lacuna entre os dois, os desenvolvedores criam o que é chamado de “calço.”
"Calçar" é "cunhar (algo) ou preencher um espaço". Isso é efetivamente o que um desenvolvedor faz quando escrevendo um calço – eles adicionam código para permitir que o BLOB interaja com o código-fonte AOSP em que estão trabalhando com. Calços são usados para fazer BLOBs de todos os tipos diferentes funcionarem com AOSP, mas geralmente é o BLOB da câmera que requer mais calços. Como mencionamos antes, o shimming é necessário não apenas para portar versões mais recentes do Android para um dispositivo (como todos aqueles ROMs não oficiais do Android Oreo), mas também necessários ao portar o AOSP da mesma versão do Android para esse dispositivo.
Leitura recomendada: Da loja à prateleira: uma capitulação detalhada de por que os dispositivos MSM8974 são excluídos do Nougat
O OnePlus 2, por exemplo, recebeu seu última grande atualização oficial do sistema operacional na forma de Android 6.0 Marshmallow. O dispositivo, no entanto, na verdade tem ROMs personalizadas baseadas em AOSP totalmente funcionais baseado no Android Nougat, e isso graças ao trabalho árduo dos desenvolvedores e seus esforços. Estaremos detalhando alguns exemplos de calços, mas primeiro precisamos falar sobre como exatamente funcionam os calços.
Como funciona o calço?
Como os desenvolvedores não têm acesso ao HAL da câmera ou à fonte ROM OEM (e apenas aos binários pré-compilados), eles não podem saber quais funções o HAL da câmera espera. Por causa disso, muitas vezes há uma incompatibilidade entre o nome da função que a câmera HAL 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 do função que a câmera HAL BLOB espera, mas esta nova função apenas executa o que o desenvolvedor deseja isso para. Essa nova função que atua como intermediária entre o BLOB e o AOSP é o shim. Este cenário específico em que o BLOB não consegue encontrar a função que procura é um dos mais comuns 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 OxygenOS e a câmera OnePlus. Se usarmos BLOBs de câmera retirados do OxygenOS Nougat para o OnePlus 3T para construir uma ROM Nougat baseada em AOSP, podemos ter problemas. Isso ocorre porque os BLOBs da câmera (que foram originalmente compilados pelo OEM) serão capazes de fazer referência a todas as funções necessárias no OxygenOS, mas como o A ROM AOSP compilada pode não ter essas funções ou pode tê-las compilado com um nome diferente (levando assim a uma incompatibilidade entre os símbolos de função), haverá um erro. Isso pode ser corrigido criando uma nova função na ROM AOSP com o nome que o BLOB espera – nosso shim.
Os 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, portanto, para evitar codificação referências a funções, o compilador cria uma tabela de símbolos que outras funções podem usar para sempre se referir à direita função. Quando você altera o nome de uma função antes de compilar, seu símbolo também muda, então basicamente qualquer alteração que o OEM faz para a fonte HAL da câmera antes da compilação exigirá que os desenvolvedores criem um novo calço.
A explicação que oferecemos até agora faz parecer que criar calços é fácil. 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 renomeações de funções. Conversamos com Sultanxda, desenvolvedor reconhecido pelo XDA, que nos deu um exemplo de um dos calços mais difíceis em que trabalhou.
Shimming - não é tão fácil quanto parece
Para quem não está familiarizado com o OnePlus 3T, a câmera frontal estava bastante quebrada inicialmente ROMs personalizadas baseadas em AOSP. Para começar, tentar tirar qualquer foto com mais de 8 MP resultaria em batendo. Na sua tentativa de resolver esta questão, Sultanxda fez várias calços para permitir que a câmera frontal do OnePlus 3T funcione corretamente.
Shim #1 – Alterando o nome do pacote da câmera
Para evitar que a câmera frontal travasse sempre que o usuário tirasse uma foto com mais de 8 MP, Sultanxda forçou a câmera HAL a identificar todas as câmeras como sendo a câmera OnePlus. Isso é feito porque o OnePlus decidiu dedicar uma função auxiliar a determinados aplicativos (isOnePlusCamera
, isFacebookCamera
, etc.) por algum motivo. Sultanxda corrigiu isso ajustando o HAL da câmera para apontar para uma nova função que sempre retorna “verdadeiro” como se o usuário estivesse usando a câmera OnePlus – mesmo quando não está.
Calço #2 - Desativar QuadraCfa
Para sua próxima correção, ele teve que desativar o QuadraCfa, que é presumivelmente uma tecnologia proprietária da Qualcomm relacionada à câmera. Dizemos presumivelmente porque nem eu nem Sultanxda sabemos exatamente o que é QuadraCfa, mas Sultanxda sabe que quebrou a câmera frontal sempre que foi ativada.
Ele observou que o QuadraCfa se habilitaria de alguma forma, mas não tinha certeza de por que ou como isso acontecia. Resolver isso exigiu uma modificação pouco convencional de sua parte. Em um shim convencional, a função shim, quando compilada, fornece o símbolo ausente que o BLOB está procurando. Nesse caso, o BLOB já tinha os símbolos de que precisava – aqueles que presumivelmente representavam as funções que iniciavam o QuadraCfa.
Assim, ele precisava substituir os símbolos usados pela câmera HAL e, em essência, torná-los “ausentes” para que dele calços forneceriam esses símbolos “ausentes”. A única maneira de fazer isso é através edição hexadecimal da própria câmera HAL. A edição hexadecimal consiste basicamente em examinar um monte de jargões desorganizados na forma de dados binários para encontrar uma agulha no palheiro - seja 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, Sultanxda conseguiu evitar a edição hexadecimal das funções por trás do QuadraCfa, em vez disso edição hexadecimal dos nomes dos símbolos para anulá-los.
Calço #3 – Correção de falha de luz brilhante
Em seguida, Sultanxda identificou que tirar uma foto da câmera frontal sob condições de muita iluminação faria com que a câmera travasse. Para reproduzir esse bug em seu próprio dispositivo, Sultanxda na verdade ligou a função de lanterna de seu OnePlus One e direcionou a luz para a câmera frontal do OnePlus 3T para fazê-lo travar e produzir logs utilizáveis! Depois de descobrir qual função estava causando o travamento, 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 nº 4 - Imagens da câmera frontal de baixa resolução
Depois de corrigir a falha de luz brilhante com o calço anterior, Sultanxda descobriu outro bug que na verdade surgiu como resultado direto desse calço: fotos de câmera frontal de baixa resolução. Em vez de tirar fotos com a resolução solicitada pelo usuário (por exemplo, 16MP), a imagem resultante seria tirada com 4MP.
Resolver isso exigiu que ele corrigisse as funções handleSuperResolution
e isSuperResolution
para sempre retornar verdadeiro, mas SOMENTE quando a câmera frontal estiver ativa (caso contrário, a câmera travaria ao tirar fotos do sensor traseiro).
Lição aprendida – Calçar pode ser difícil
Sultanxda admite que os calços que ele teve que criar para fazer a câmera frontal do OnePlus 3T funcionar não representam o exemplo típico de calço. Ele está bastante orgulhoso de seu calço, dada sua complexidade e a rara necessidade de editar hexadecimalmente o próprio BLOB. Mas este exemplo apenas mostra como pode ser difícil fazer o hardware da câmera funcionar em determinados dispositivos.
Que suas aventuras com a câmera sejam menos dolorosas do que as minhas. -Sultanxda
Registros, registros e mais registros. Sem uma maneira consistente de reproduzir uma falha e sem registros, os desenvolvedores têm pouca esperança de encontrar a origem do problema. Mesmo que descubram a causa do problema, nem sempre é uma solução simples. Todo o processo de localização e eliminação desses bugs pode levar dias ou semanas e é a razão pela qual consertar a câmera em ROMs AOSP é uma das tarefas mais difíceis.
Se o seu dispositivo tiver uma ROM AOSP portada para ele com hardware totalmente funcional, esperamos que você possa começar a aprecio a luta que esses desenvolvedores podem ter enfrentado para trazer a você aqueles características. Aprecie-os pelo seu trabalho, porque não é fácil. É muito trabalho que a grande maioria dos usuários nem notará, já que desenvolvedores talentosos em nossos fóruns estão cuidando de muitas partes invisíveis do Android.
Gostaríamos de agradecer especialmente a Sultanxda pelas diversas contribuições que ele sugeriu na elaboração deste artigo.