Cenário 2: Chamadas sincronizadas sequenciais a partir de uma única thread do cliente
Quando uma única thread de um processo cliente invoca a mesma interface sincronizada do servidor múltiplas vezes em sequência, o resultado é uma serialização natural das requisições no servidor. A thread do cliente é bloqueada até que cada chamada anterior seja concluída, garantindo a ordem de execução.
using aidl::android::hardware::meuhal::IMeuHal;
int main() { const std::string servico = std::string() + IMeuHal::descriptor + "/padrao"; LOG(INFO) << "Obtendo proxy para: " << servico;
ndk::SpAIBinder vinculo(AServiceManager_getService(servico.c_str()));
if (vinculo.get() == nullptr) {
LOG(ERROR) << "Serviço indisponível.";
return 1;
}
auto halProxy = IMeuHal::fromBinder(vinculo);
if (!halProxy) {
LOG(ERROR) << "Falha ao obter interface.";
return 1;
}
// Chamadas sequenciais do mesmo ponto da execução
ndk::ScopedAStatus resultado;
for (int i = 0; i < 5; ++i) {
resultado = halProxy->executarAcao();
if (!resultado.isOk()) {
LOG(ERROR) << "Chamada " << i << " falhou.";
break;
}
}
LOG(INFO) << "Operações concluídas.";
return 0;
}
</div>### Cenário 1: Chamadas sincronizadas concorrentes a partir de múltiplas threads do cliente
Quando múltiplas threads dentro do mesmo processo cliente chamam a interface sincronizada simultaneamente, o comportamento no servidor depende de sua implementação de pool de threads. Se o servidor possuir múltiplas threads de despacho, as chamadas podem ser executadas de forma concorrente, não serial.
<div class="code-example">```
#include <aidl/android/hardware/meuhal/IMeuHal.h>
#include <android/binder_manager.h>
#include <android-base/logging.h>
#include <thread>
#include <vector>
using aidl::android::hardware::meuhal::IMeuHal;
void invocarServico(std::shared_ptr<IMeuHal> servico, int idThread) {
LOG(ERROR) << "Thread " << idThread << " iniciando.";
auto status = servico->executarAcao();
LOG(ERROR) << "Thread " << idThread << " finalizou. Status: "
<< (status.isOk() ? "OK" : "FALHA");
}
int main() {
const std::string nomeInstancia = std::string() + IMeuHal::descriptor + "/padrao";
ndk::SpAIBinder binder(AServiceManager_getService(nomeInstancia.c_str()));
auto halInterface = IMeuHal::fromBinder(binder);
const int NUM_THREADS = 4;
std::vector<std::thread> poolDeThreads;
for (int i = 0; i < NUM_THREADS; ++i) {
poolDeThreads.emplace_back(invocarServico, halInterface, i + 1);
}
for (auto& t : poolDeThreads) {
t.join();
}
return 0;
}
O método no servidor HAL pode conter operações de longa duração. Sua execução pode ocorrer em threads diferentes do pool do Binder, indicando potencial concorrência.
namespace aidl::android::hardware::meuhal {
::ndk::ScopedAStatus MeuHal::executarAcao() { LOG(ERROR) << "Método 'executarAcao' iniciado. ThreadID: " << std::this_thread::get_id(); // Simula trabalho std::this_thread::sleep_for(std::chrono::seconds(1)); LOG(ERROR) << "Método finalizado. ThreadID: " << std::this_thread::get_id(); return ndk::ScopedAStatus::ok(); }
} // namespace aidl::android::hardware::meuhal
</div>### Observações sobre Serialização
A serialização automática no servider não é garantida pelo AIDL em si. Para forçar a execução serial de todos os métodos, uma implementação de mutex ou fila de comandos é necessária dentro do código do servidor. A arquitetura do Binder e a configuração do pool de threads determinam o comportamento de concorrência.
</div>