main.cpp: Entrada do Processo Init
int principal(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_callback_relatorio(AsanCallbackRelatorio);
#endif
definir_prioridade(PRIO_PROCESS, 0, -20);
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_principal(argc, argv);
}
if (argc > 1) {
const char* parametro = argv[1];
if (!strcmp(parametro, "subcontexto")) {
return SubcontextoPrincipal(argc, argv);
}
if (!strcmp(parametro, "config_selinux")) {
return ConfigurarSelinux(argv);
}
if (!strcmp(parametro, "segunda_etapa")) {
return SegundaEtapaPrincipal(argc, argv);
}
}
return PrimeiraEtapaPrincipal(argc, argv);
}
O ponto de entrada principal analisa argumentos para determinar a fase de inicialização:
- Sem argumentos: Executa PrimeiraEtapaPrincipal()
- config_selinux: Chama ConfigurarSelinux()
- segunda_etapa: Executa SegundaEtapaPrincipal()
- Casos especiais (ueventd/subcontxeto) não abordados
first_stage_init.cpp: Primeira Fase
int PrimeiraEtapaPrincipal(int argc, char** argv) {
std::vector<std::pair<std::string, int>> erros;
tempo_inicio = boot_clock::now();
// Configuração básica do sistema
umask(0);
clearenv();
setenv("PATH", _PATH_PADRAO, 1);
// Montagem de sistemas de arquivos essenciais
montar("tmpfs", "/dev", "tmpfs", MS_NOSUID, "modo=0755");
montar("proc", "/proc", "proc", 0, "hidepid=2");
montar("sysfs", "/sys", "sysfs", 0, NULL);
// Criação de dispositivos críticos
criar_dispositivo("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
criar_dispositivo("/dev/random", S_IFCHR | 0666, makedev(1, 8));
// Preparação para segunda etapa
montar("tmpfs", kRecursosSegundaEtapa, "tmpfs", MS_NOEXEC, "modo=0755");
// Carregamento de módulos do kernel
if (!CarregarModulosKernel()) {
LOG(ERRO) << "Falha ao carregar módulos";
}
// Transição para configuração SELinux
const char* argumentos[] = {"/sistema/bin/init", "config_selinux", nullptr};
execv(argumentos[0], const_cast<char**>(argumentos));
return 1;
}
Principais operações:
- Montagem de sistemas de arquivos temporários (/dev, /proc, /sys)
- Criação de dispositivos essenciais (/dev/kmsg, /dev/random)
- Configuração de permissões e ambiente básico
- Carregamento de módulos do kernel
- Preparação para transição de fase
selinux.cpp: Configuração do SELinux
int ConfigurarSelinux(char** argv) {
IniciarRegistroKernel();
std::string politica;
// Carregar política de segurança
LerPolitica(&politica);
auto auxiliar = SnapuserdSelinuxHelper::CriarSeNecessario();
if (auxiliar) {
auxiliar->IniciarTransicao();
}
CarregarPoliticaSelinux(politica);
if (auxiliar) {
auxiliar->FinalizarTransicao();
}
// Aplicar contextos SELinux
selinux_android_restorecon("/dev/selinux/", SELINUX_ANDROID_RESTORECON_RECURSE);
SelinuxAtivarCumprimento();
// Transição para segunda etapa
const char* argumentos[] = {"/sistema/bin/init", "segunda_etapa", nullptr};
execv(argumentos[0], const_cast<char**>(argumentos));
return 1;
}
Fluxo principal:
- Carregamento da política de segurança
- Coordenação com snapuserd para partições dinâmicas
- Aplicação de contextos SELinux
- Ativação do modo de cumprimento
second_stage_main: Segunda Fase
int SegundaEtapaPrincipal(int argc, char** argv) {
IniciarRegistroKernel();
LOG(INFO) << "Segunda etapa iniciada";
// Inicialização de subsistemas
InicializarPropriedades();
MontarSistemasArquivosExtras();
// Configuração SELinux final
InicializarRotulosSelinux();
RestaurarContextoSelinux();
// Configuração de eventos
Epoll epoll;
epoll.AdicionarCallback(ReapProcessos);
InstalarManipuladorSinais(&epoll);
// Serviços essenciais
IniciarServicoPropriedades();
ManipuladorMontagem manipulador(&epoll);
// Carregamento de scripts de inicialização
Analisador analisador = CriarAnalisador();
analisador.AnalisarConfig("/sistema/etc/init/hw/init.rc");
analisador.AnalisarConfig("/vendor/etc/init");
// Loop principal de eventos
while (true) {
auto tempo_acao = CalcularProximaAcao();
auto resultado = epoll.Esperar(tempo_acao);
ManipularMensagensControle();
}
return 0;
}
Componentes críticos:
- Inicialização do sistema de propriedades
- Carregamento de scripts init.rc
- Configuração do epoll para gerenciamento de eventos
- Loop principal para processamento de ações
- Inicialização de serviços essenciais
Inicialização do Zygote
O script init.rc dispara o início do Zygote:
start zygote
O comando start é processado pelo gerenciador de ações, executando o binário definido para o serviço zygote.