我们还是一cameraserver进程为例,看它是如何被系统加载运行起来的。
frameworks/av/camera/cameraserver/cameraserver.rc
1 service cameraserver /system/bin/cameraserver
2 class main
3 user cameraserver
4 group audio camera input drmrpc
5 ioprio rt 4
6 writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
从cameraserver.rc我们可以知道cameraserver 这个service对应的程序文件为/system/bin/cameraserver,在init进程解析完对应的rc文件后,会把这个进程运行起来,解析过程就不详述。
system/core/init/builtins.cpp
261 static int do_exec(const std::vector<std::string>& args) {
262 Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args);
263 if (!svc) {
264 return -1;
265 }
266 if (!svc->Start()) {
267 return -1;
268 }
269 waiting_for_exec = true;
270 return 0;
271 }
init进程会调用do_exec()函数就是把service对应的进程运行起来,这个函数在不同版本的android源码中,里面的代码有些不一样。
system/core/init/service.cpp
318 bool Service::Start() {
...
388 NOTICE("Starting service '%s'...\n", name_.c_str());
389
390 pid_t pid = fork(); //创建出一个新进程
391 if (pid == 0) { //如果是子进程,会走进这个条件
392 umask(077);
...
476 if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { //加载进程
477 ERROR("cannot execve('%s'): %s\n", strs[0], strerror(errno));
478 }
479
480 _exit(127);
481 }
482
483 if (pid < 0) { //如果fork 进程失败
484 ERROR("failed to start '%s'\n", name_.c_str());
485 pid_ = 0;
486 return false;
487 }
488 //父进程,也就是init进程会跑下面的代码
489 time_started_ = gettime();
490 pid_ = pid;
...
499 NotifyStateChange("running");
500 return true;
501 }
到这里基本上就很清晰了,init启动service进程主要是通过fork()和execve()实现的,所以下面我们重点跟踪和了解这两个函数的实现。
1、fork创建子进程
fork()函数声明在 bionic/libc/include/unistd.h…
81 extern pid_t fork(void);
82 extern pid_t vfork(void);
…
fork()实现在 bionic/libc/bionic/fork.cpp
34 #define FORK_FLAGS (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD)
36 int fork() {
37 __bionic_atfork_run_prepare();
38
39 pthread_internal_t* self = __get_thread();
40
41 // Remember the parent pid and invalidate the cached value while we fork.
42 pid_t parent_pid = self->invalidate_cached_pid();
43
44 #if defined(__x86_64__) // sys_clone's last two arguments are flipped on x86-64.
45 int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, &(self->tid), NULL);
46 #else
47 int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));
48 #endif
49 if (result == 0) {
50 self->set_cached_pid(gettid());
51 __bionic_atfork_run_child();
52 } else {
53 self->set_cached_pid(parent_pid);
54 __bionic_atfork_run_parent();
55 }
56 return result;
57 }
里面又通过syscall()系统调用函数来创建进程,注意传入的参数是__NR_clone和FORK_FLAGS。
syscall在 arm64的实现 bionic/libc/arch-arm64/bionic/syscall.S
29 #include <private/bionic_asm.h>
30
31 ENTRY(syscall)
32 /* Move syscall No. from x0 to x8 */
33 mov x8, x0
34 /* Move syscall parameters from x1 thru x6 to x0 thru x5 */
35 mov x0, x1
36 mov x1, x2
37 mov x2, x3
38 mov x3, x4
39 mov x4, x5
40 mov x5, x6
41 svc #0 //可以认为执行了svc指令后,会到kernel中断相应函数
42
43 /* check if syscall returned successfully */
44 cmn x0, #(MAX_ERRNO + 1) //x0 - MAX_ERRNO -1
45 cneg x0, x0, hi //
46 b.hi __set_errno_internal
47
48 ret //调用返回
49 END(syscall)
kernel对应的处理流程
linux-4.10/arch/arm64/kernel/entry.S
…
328 ventry el0_sync // Synchronous 64-bit EL0
329 ventry el0_irq // IRQ 64-bit EL0
330 ventry el0_fiq_invalid // FIQ 64-bit EL0
331 ventry el0_error_invalid // Error 64-bit EL0
…
我们继续看el0_sync:的实现
511 /*
512 * EL0 mode handlers.
513 */
514 .align 6
515 el0_sync:
516 kernel_entry 0 //kernel_entry 很重要,后面会讲
517 mrs x25, esr_el1 // read the syndrome register
518 lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class
519 cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state //比较两个值是否相等
520 b.eq el0_svc //如果上面比较的结果相等,就跳转到el0_svc
...
接着看el0_sev里面的处理
/*
795 * SVC handler.
796 */
797 .align 6
798 el0_svc:
799 adrp stbl, sys_call_table // load syscall table pointer //处理函数表格地址
//在syscall.S中通过指令 mov x8, x0 将__NR_clone 参数保存到x8,下面的w8 也就是x8
800 uxtw scno, w8 // syscall number in w8
801 mov sc_nr, #__NR_syscalls //系统调用number的最大值
802 el0_svc_naked: // compat entry point
803 stp x0, scno, [sp, #S_ORIG_X0] // save the original x0 and syscall number
804 enable_dbg_and_irq
805 ct_user_exit 1
806
807 ldr x16, [tsk, #TSK_TI_FLAGS] // check for syscall hooks
808 tst x16, #_TIF_SYSCALL_WORK
809 b.ne __sys_trace
810 cmp scno, sc_nr // check upper syscall limit
811 b.hs ni_sys
812 ldr x16, [stbl, scno, lsl #3] // address in the syscall table
813 blr x16 // call sys_* routine
814 b ret_fast_syscall
815 ni_sys:
816 mov x0, sp
817 bl do_ni_syscall
818 b ret_fast_syscall
819 ENDPROC(el0_svc)
我们重点关注下面这两条指令
812 ldr x16,[stbl, scno, lsl #3] // address in thesyscall table
813 blr x16 // call sys_*routine
LDR R0,[R1,R2,LSL #