android-linux系统调用原理之整体系统框架实现原理之OPEN实现.docx
【
相关源码版本:
LINUX内核源码版本:linux-3.0.86
UBOOT版本:uboot-2010.12.
Android系统源码版本:Android-5.0.2】
对于安桌系统来说系统调用就是指:Andriod层调用Linux函数。由于安桌层在文件系统层,而LINUX层在内核层,两者是在不同的地址空间的。内核空间是高地址1G空间,余下的就是应用空间。对于32ARM则最大能寻址空间是4G。则高1G共内核调用低3G供应用层调用。应用层通过系统调用可以陷入内核空间(SWI指令),因此间接的可以认为应用程序可以访问全部4G地址空间。如下图所示:
从上面分析可知系统调用在安桌层和内核层必须是一一对应的。下面列出在不同层原函数文件位置
安桌层:
系统调用序号文件列表:diordnr5.0.2\bionic\libc\kernel\uapi\asm-arm\asm\Unistd.h(内核根据应用传过来的这个索引号来调用对应于应用层调用的系统调用函数)
函数申明路径:diordnr5.0.2\bionic\libc\bionic\*(不同系统调用对应不同的函数文件 eg:open.cpp 等)
内核层:
系统调用序号文件列表:include\asm-generic\Unistd.h
系统调用函数列表:arch\arm\kernel\calls.S
函数申明路径:include\linux\ syscalls.h
下面以open系统调用为例,描述OPEN函数的实现流程(我们只分析主线 结节不是本文目的):
安桌层:
bionic\libc\bionic\open.cpp: Open()--->__openat()--->
bionic\libc\arch-arm\syscalls\__openat.S: ENTRY(__openat)--->SWI陷入内核
内核层:由应用层发起的中断进入内核中断向量的软件中断地址入口处
arch\arm\kernel\entry-armv.S : __vectors_start:W(ldr) pc, .LCvswi + stubs_offset--->
arch\arm\kerne\entry-common.S: ENTRY(vector_swi)--->adr tbl, sys_call_table @ load syscall table pointer--->#include "calls.S"--->ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine(根据应用层传入的索引号去调用calls.s中的不同函数)--->calls.S: CALL(sys_open==SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
int, mode))--->
\fs\open.c:SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
int, mode)//经过内核系统中的宏定义经过转换之后上面宏等于
asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
int mode);这个原型。这儿就与应用层调用的参数对应上了。
经过上面流程就进入了内核的open(应用层是OPEN原函数,实际经过转换之后进入内核的函数是__openat,内核层函数原型名字始终是应用层函数的前面加上sys_)真正处理的地方子。下面就来专分析
asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
int mode);的实现原理。
\fs\open.c:SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
int, mode)--->do_sys_open():fd(需返回给应用层的文件描述符)--->struct file *f = do_filp_open(dfd, tmp, &op, lookup);打开从应层传进来的文件路径的文件,并且得到一个f文件指针,根据UDEV设备模型,F文件的f->const struct file_operations *f_op;原素(如果是驱动文件)就是指向我们注册驱动注册的驱动函数。这个是fd返回给应用层最后通过能调用驱动操作函数的根本原理。--->fd_install(fd, f);让打开的文件得到的文件指针与要返回的文件描述符fd关键起来。只有这儿关键来了当在应用层通过f操作时才能进入内核调用对应的注册函数。--->return fd;--->返回安桌swi陷入下一个地址处继续执行。(从应用层进入内核层:SWI陷入后应用层就停止等到内核返回。这儿可以看成进程的上下文件,上文是应用层,下文是内核层。上文会得到下文返回才会继续执行。并且可中断可抢占。这样就才可以实现多程)。应用层得到fd,再来操作这个fd时通过陷入进入内核,内核会去查找这个fd对应用的f文件并且得到f_ops元素,当然对应的系统调用还会有他自己的一些执行流程。
asmlinkage是gcc标签,代表函数读取的参数来自于栈中,而非寄存器。
安卓系统中进程与线程异同:
进程:每个App在启动前必须先创建一个进程,该进程是由Zygote fork出来的,进程具有独立的资源空间,用于承载App上运行的各种Activity/Service等组件。进程对于上层应用来说是完全透明的,这也是google有意为之,让App程序都是运行在Android Runtime。大多数情况一个App就运行在一个进程中,除非在AndroidManifest.xml中配置Android:process属性,或通过native代码fork进程。
线程:线程对应用开发者来说非常熟悉,比如每次new Thread().start()都会创建一个新的线程,该线程并没有自己独立的地址空间,而是与其所在进程之间资源共享。从Linux角度来说进程与线程都是一个task_struct结构体,除了是否共享资源外,并没有其他本质的区别。
【
system_server进程:是用于管理整个Java framework层,包含ActivityManager,PowerManager等各种系统服务;
Zygote进程:是Android系统的首个Java进程,Zygote是所有Java进程的父进程,包括system_server进程以及所有的App进程都是Zygote的子进程,注意这里说的是子进程,而非子线程。
】
Fork创建是创建进程,pthread创建是线程。