Quando comecei a aprender sobre a Hardware Abstration Layer (HAL), notei que da forma como eu esteva fazendo, era preciso que o código da aplicação que fazia o uso do serviço da HAL tinha que estar junto com o código do meu produto. Essa abordagem não fazia o menor sentido, uma vez que para fazer as aplicações, é bem mais prático utilizar o Android Studio e embarcar a aplicação por meio dele. Isso me incomodou durante um tempo, mas agora vou compartilhar uma possível solução para esse problema 🫠 .
Atualmente estou fazendo um device driver do Display OLED 128x64 0.96" I2C e junto com ele uma HAL para escrever mensagens no display e limpar a tela. Por fim, queria fazer uma aplicação que consumisse o serviço dessa HAL. Com essa necessidade, aproveitei para fazer o uso da HAL Manager e gerar minha aplicação direto do Android Studio.
HAL Manager
Criei os seguintes arquivos no caminho device/casa/jaodroid/interfaces/interfaces/oled/aidl/oled_manager, a partir da raiz do AOSP:
packagecasa.hal.oledmanager;importandroid.util.Log;importandroid.os.ServiceManager;importandroid.os.IBinder;importandroid.os.RemoteException;importcasa.hal.oled.IOled;publicclassOledManager{privateIBinderservice;privateIOledoledInterface;privatestaticfinalStringINTERFACE="casa.hal.oled.IOled/default";privatestaticOledManagerinstance;privateOledManager(){service=ServiceManager.getService(INTERFACE);if(service==null)Log.e("OledManager","Service not available");oledInterface=IOled.Stub.asInterface(service);if(oledInterface==null)Log.e("OledManager","Oled Interface not available");}publicstaticOledManagergetInstance(){if(instance==null)instance=newOledManager();returninstance;}publicbooleanclearDisplay()throwsRemoteException{returnoledInterface.clearDisplay();}publicbooleanwriteString(Stringtext)throwsRemoteException{returnoledInterface.writeString(text);}}
Por fim, precisamos adicionar o OledManger no produto:
O HAL Manager fica situado dentro da partição system_ext (linha 6 do Android.bp). Geralmente precisamos fazer o uso dessa partição quando algo em partições distintas. Nesse caso, a HAL está na partição vendor, mas para utilizar o HAL Manager precisamos de coisas que estão na partição system. Como é o caso do android.os.ServiceManager (linha 4 do OledManager.java). O código fonte do ServiceManger está em:
.../** * Manage binder services as registered with the binder context manager. These services must be * declared statically on an Android device (SELinux access_vector service_manager, w/ service * names in service_contexts files), and they do not follow the activity lifecycle. When * building applications, android.app.Service should be preferred. * * @hide **/@SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)publicfinalclassServiceManager{...
Observe que a linha 8 possui o comentário @hide. Em resumo, aplicações que estão nas partições vendor, product ou data não podem acessar as hidden APIs (para mais informações acesse o link). Dessa forma, para fazermos a comunicação entre essas essas partições devemos utilizar a partição system_ext (mais informações)
No arquivo MainActivity.java precisamos importar a nossa biblioteca (linha 4) e então instanciar o manager (linha 16). Até o momento, a HAL só possui os métodos writeString e clearDisplay e esses métodos são utilizados nas linhas 31 e 41, respectivamente.
Aplicação sendo executada.
Conclusão
Sem dúvidas criar aplicações direto pelo Android Studio facilita muito a vida do desenvolvedor. O Hal Manager torna possível fazer esse link entre código nativo do AOSP e a aplicação no Android Studio. Existem outras formas de adicionar uma aplicação ao produto, mas não sei se seriam mais eficientes do que a forma que foi aprensentada nesse post. A HAL que eu criei segue a mesma estrutura da apresentada no post sobre AIDL, por isso não achei interessante compartilhar o fonte. Sobre o Device Driver pretendo fazer um post no futuro.