Sistema iOS e arquitetura do kernel (XNU)

Arquitetura do sistema iOS

imagem.png

Dividido em quatro camadas de cima para baixo:

  • Camada de experiência do usuário
  • A camada de estrutura do aplicativo será App开发usada
  • Camada de estrutura principal.
  • A camada Darwin pertence ao sistema iOS 核心e pertence ao estado do kernel.

O kernel de Darwin é o XNU, que fez UNIXmuitas melhorias e inovações com base no XNU.

Arquitetura do kernel XNU

imagem.png

  • XNU consiste em Mach, BSDe IOKit(驱动API).
  • Mach e BSD são responsáveis ​​por diferentes tarefas do sistema mostrado na figura

Mach

Mach é o grau em que 微内核os microkernels podem melhorar um sistema 模块化, fornecendo 内存保护um mecanismo de passagem de mensagens.

BSD

BSD é uma adaptação do Mach novamente 封装, 宏内核fornecendo uma interface de kernel mais moderna e fácil de usar

宏内核Também chamado de single core, tem maior desempenho e ainda continua rodando em condições de alta carga 高效.

BSD é compatível com POSIX

POSIXO IEEE desenvolveu padrões para garantir que o software seja executado em vários sistemas UNIX , e o iOS BSDtornou-se compatível com POSIX 类 UNIX 系统.

Por exemplo, o BSD construirá um modelo de processo UNIX e criará um modelo de encadeamento compatível com POSIX pthread.

processo

Mach

Um processo é representado como uma Tarefa em Mach, Mach Taskque é o ambiente e o contêiner para a execução da thread.

O estado do usuário aciona uma armadilha por meio da função mach_msg_trap() e muda para o estado do kernel Mach, que é completado pela função mach_msg() em Mach 进程间通信.

Mach usa a função mach_msg_trap() para acionar uma armadilha para processamento 异常消息,

BSD

进程在BSD中表示为Process,BSD Process扩展了 Mach Task增加进程 ID信号信息等,。

BSD 在Mach异常消息机制的基础上建立了信号处理机制,用户态产生的信号会先被 Mach 转换成异常,BSD 将异常再转换成信号

线程

Mach Thread 表示一个线程,是 Mach 里的最小执行单位。Mach Thread 有自己的状态,包括机器状态、线程栈、调度优先级、调度策略、内核 Port、异常 Port。

Mach Thread 也可以扩展为 Uthread,通过 `BSD Process`` 处理。

IOKit

IOKit 是硬件驱动程序的运行环境,包含电源、内存、CPU 等信息。

IOKit 底层 libkern 使用 C++ 子集 Embedded C++ 编写了驱动程序基类,比如 OSObject、OSArray、OSString 等,新驱动可以继承这些基类来写。

XNU 加载 App

iOS 的可执行文件和动态库都是 Mach-O 格式,所以加载 APP 实际上就是加载 Mach-O 文件。

苹果公司已经将 darwin_xnu 开源,放到Github了, 地址是 darwin-xnu

整个 fork 进程,加载解析 Mach-O 文件的过程可以在 XNU 的源代码中查看,代码路径是 darwin-xnu/bsd/kern/kern_exec.c,代码如下:

int __mac_execve(proc_t p, struct __mac_execve_args *uap, int32_t *retval)
{
    // 字段设置
    int is_64 = IS_64BIT_PROCESS(p);
    struct vfs_context context;
    struct uthread  *uthread; // 线程
    task_t new_task = NULL;   // Mach Task(进程)
    
    context.vc_thread = current_thread();
    context.vc_ucred = kauth_cred_proc_ref(p);
    
    // 分配大块内存,不用堆栈是因为 Mach-O 结构很大。
    char *bufp = kheap_alloc(KHEAP_TEMP,
	    sizeof(*imgp) + sizeof(*vap) + sizeof(*origvap), Z_WAITOK | Z_ZERO);
    image_params *imgp = (struct image_params *) bufp; // Mach-O参数
    
    // 初始化 imgp 结构里的公共数据
    imgp->ip_user_fname = uap->fname; // 可执行程序的文件名
	imgp->ip_user_argv = uap->argp; // 参数列表
	imgp->ip_user_envv = uap->envp; // 环境列表
    
    uthread = get_bsdthread_info(current_thread()); // 初始化线程
    if (uthread->uu_flag & UT_VFORK) {
        imgp->ip_flags |= IMGPF_VFORK_EXEC;
        in_vfexec = TRUE;
    } else {
        // 程序如果是启动态,就需要 fork 新进程
        imgp->ip_flags |= IMGPF_EXEC;
        // fork 新进程和线程
        imgp->ip_new_thread = fork_create_child(current_task(),
                    NULL, p, FALSE, p->p_flag & P_LP64, TRUE);
 
        new_task = get_threadtask(imgp->ip_new_thread);
        context.vc_thread = imgp->ip_new_thread;
    }
    
    // 加载解析 Mach-O
    error = exec_activate_image(imgp);

    if (!error && !in_vfexec) {
        p = proc_exec_switch_task(p, current_task(), new_task, imgp->ip_new_thread);
    
        should_release_proc_ref = TRUE;
    }
 
    kauth_cred_unref(&context.vc_ucred);
    
    if (!error) {
        task_bank_init(get_threadtask(imgp->ip_new_thread));
        proc_transend(p, 0);
 
        thread_affinity_exec(current_thread());
 
        // 继承进程处理
        if (!in_vfexec) {
            proc_inherit_task_role(get_threadtask(imgp->ip_new_thread), current_task());
        }
 
        // 设置进程的主线程
        thread_t main_thread = imgp->ip_new_thread;
        task_set_main_thread_qos(new_task, main_thread);
    }
    ...
}

Como o arquivo Mach-O é muito grande, a função __mac_execve primeiro alocará um grande 堆内存imgp para Mach-O e, em seguida, inicializará os dados públicos no imgp. Depois que a memória é processada, um novo processo e thread são bifurcados por meio da função fork_create_child(). Após a bifurcação do novo processo, ele analisará e carregará o arquivo Mach-O na memória imgp por meio da função exec_activate_image(). Por fim, use a função task_set_main_thread_qos() para definir a qos do processo recém-bifurcado 主线程.

exec_mach_imgact()Carregue o arquivo Mach-O por meio da função load_machfile() e carregue-o na memória por meio do mapeamento de acordo com as informações do comando load obtidas após a análise do Mach-O. Use também a função activate_exec_state() para processar e analisar as informações e configurações estruturais após o carregamento do Mach-O 执行 App 的入口点.

Depois de definir o ponto de entrada, a função load_dylinker() será usada para analisar e carregar dyld e, em seguida, alterar o endereço do ponto de entrada para o endereço de entrada de dyld. Após esta etapa, 内核o carregamento do arquivo Mach-O está parcialmente concluído. Tudo o que resta é carregar a 用户态camada App dyld.

O processo completo de carregamento do aplicativo XNU

  1. fork novo processo;

  2. Alocar memória para Mach-O;

  3. Analisar Mach-O;

  4. Leia as informações do cabeçalho Mach-O;

  5. Atravesse as informações do comando de carga e mapeie Mach-O para a memória;

  6. Inicie o modo de usuário dyld, o processo de acompanhamento não tem nada a ver com o modo kernel darwin_xnu, o processo dyld pode se referir à otimização de inicialização do iOS - introdução do processo dyld4 .

Acho que você gosta

Origin juejin.im/post/7255902957035438138
Recomendado
Clasificación