Arquitetura do sistema iOS
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 UNIX
muitas melhorias e inovações com base no XNU.
Arquitetura do kernel XNU
- XNU consiste em
Mach
,BSD
eIOKit(驱动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
POSIX
O IEEE desenvolveu padrões para garantir que o software seja executado em vários sistemas UNIX , e o iOS BSD
tornou-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 Task
que é 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
-
fork novo processo;
-
Alocar memória para Mach-O;
-
Analisar Mach-O;
-
Leia as informações do cabeçalho Mach-O;
-
Atravesse as informações do comando de carga e mapeie Mach-O para a memória;
-
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 .