Android系统的启动流程分析及如何看源码
来源:互联网 发布:淘宝高仿包包 编辑:程序博客网 时间:2024/05/23 02:15
Android系统的启动流程分析
最近在听到很多面试官问Android工程师的关于启动的问题,我最近研究了一番,大概理了一理,过程如下,文章末尾有看源码攻略。
##当用户按下物理按键对Android系统进行开机的时候,系统首先会加载的是Boot Loader,会进行一些手机各大厂商自定制的初始化操作,同时启动Android系统中第一个用户进程init(),部分关键性源码如下:
int main(int argc, char **argv){ ... log_init(); INFO("reading config file\n"); init_parse_config_file("/init.rc"); ...}
上述init方法主要是初始化一些log以及初始化一些配置文件,接下来我们找到init.rc这个方法,源码如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on ...
在init.rc中我们可以看到启动了一个关键的服务—zygote服务,zygote翻译过来是孵化器/受精卵的意思,这个zygote服务主要是守护别的服务不被杀死以及孵化出多个服务,或许到这里大家还不是很明白,接下来我们进入到zygote类中去看,源码如下:
int main(int argc, const char* const argv[]) { //设置zygote的参数 setArgv0(argv0, "zygote"); //设置zygote进程的名字 set_process_name("zygote") //调用Android运行时开启ZygoteInit runtime.start("com.android.internal.os.ZygoteInit", startSystemServer); }
在zygote中,进行了一些基本的设置,关键性的代码就是zygoteinit方法的调用,我们跟踪这个方法,源码如下:
public static void main(String argv[]) { ... //预加载开启过程中依赖的类 preloadClasses(); //预加载开启过程中依赖的文件 preloadResources(); ... if (argv[1].equals("true")) { //开启服务 startSystemServer(); } else if (!argv[1].equals("false")) { throw new RuntimeException(argv[0] + USAGE_STRING); } }
在zygoteinit方法中,执行了一些预加载操作,然后又开启了这个startSystemServer()服务,源码如下:
private static boolean startSystemServer()throws MethodAndArgsCaller , RuntimeException { String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003", "--capabilities=130104352,130104352", "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ... if ("1".equals(SystemProperties.get("ro.debuggable"))) debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; /* Request to fork the system server process */ //开启SystemServer.java类 pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); return true;}
上面这个方法是如何开启系统服务的呢?我们通过源码知道首先定义了一个数组,里面保存的是一个系统开启需要的一些基本参数,比如uid、gid等信息,在面向对象的程序设计中,这样的数组显然是不符合要求的,所以将该数组封装到一个叫做parseArgs的对象中,开启服务的时候,调用zygote.forkSystemServer(XXX)进行开启,这里的参数就是上述对象中的各个属性,以便传入相关的参数开启服务,接下来追踪到SystemServer类中,源码如下:
public static void main(String[] args) { ... //加载动态链接库, System.loadLibrary("android_servers"); init1(args); }
看到上面代码对于有过JNI了解的人应该很熟悉了吧,没错,上面的代码就是要去调用c语言了,首先加载了动态链接库,然后调用本地方法init1方法,,为什么要调c语言呢?因为这里的目的就是开启服务,一般服务都是和硬件挂钩的,所以用java是没办法调用到硬件的,既然上面代码动态加载了一个动态链接库,那我们就需要找到init的c代码,源码如下:
//init1方法即是android_server_SystemServer_init1方法static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },};static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) { system_init(); }
从上面的代码调用大家应该很清楚,最后是调用到了System_init()函数,注意:这里一直在调用c代码,也就是jni调用还没有结束,源码如下:
xtern "C" status_t system_init() { ... //开启相应服务 // Start the camera service CameraService::instantiate(); // Start the audio policy service AudioPolicyService::instantiate(); } ... //获取android 运行环境,并且调用SystemServer下的init2方法 runtime->callStatic("com/android/server/SystemServer", "init2"); ... return NO_ERROR;}
在system_init函数中开启相应的服务,然后通过Android运行时调用init2方法,这时又调用了java代码,也就是从java代码调到c代码开启服务,开启之后又调回到java代码,准备开机,源码如下:
public static final void init2() { Thread thr = new ServerThread(); thr.setName("android.server.ServerThread"); thr.start(); }//开启系统服务后的一个准备操作@Overridepublic void run() { ((ActivityManagerService)ActivityManagerNative.getDefault()) .systemReady(new Runnable() { public void run() { Slog.i(TAG, "Making services ready"); if (statusBarF != null) statusBarF.systemReady2(); if (batteryF != null) batteryF.systemReady(); if (connectivityF != null) connectivityF.systemReady(); if (dockF != null) dockF.systemReady(); if (usbF != null) usbF.systemReady(); if (uiModeF != null) uiModeF.systemReady(); if (recognitionF != null) recognitionF.systemReady(); Watchdog.getInstance().start(); ... });}
在上述init方法中开启了一个子线程,ServerThread其实是继承自Thread,所以上面我贴出了run方法,在run方法中进行了一些准备操作。准备操作调用了大量的systemReady()方法,源码如下:
public void systemReady(final Runnable goingCallback) { ... mMainStack.resumeTopActivityLocked(null); }final boolean resumeTopActivityLocked(ActivityRecord prev) { ActivityRecord next = topRunningActivityLocked(null); ... if (next == null) { // There are no more activities! Let's just start up the // Launcher... if (mMainStack) { //HomeActivity return mService.startHomeActivityLocked(); } } ... return true;}
在这里面就是开启Launcher。
至此,Android系统的整个启动过程介绍完毕,在整个启动过程中,我只是贴出了一部分源码,大量的不是很关键的没有贴出来,当然,对于技术大牛来说,弄清楚每一行才是他们的目标,但是对于一般的Android开发者而言,我们怎么才能快速的弄懂源码呢?该如何看源码呢?我的建议就是把各种判断去掉,把重复多次的去掉,这两部分其实占据了很大的篇幅,如果你 能把这些分离出来,剩下的干货其实是很好理清楚的。。
- Android系统的启动流程分析及如何看源码
- Android系统的启动流程简要分析
- Android系统的启动流程简要分析
- Android 5.0 Camera系统源码分析(1):CameraService启动流程
- Android 5.0 Camera系统源码分析(1):CameraService启动流程
- Android 5.0 Camera系统源码分析(1):CameraService启动流程
- 安卓系统的启动流程(源码分析)
- SpringMVC 启动流程及相关源码分析
- Android进阶系列之源码分析Activity的启动流程
- Android Activty的加载过程 启动流程 源码分析
- Android Service的启动流程源码分析(8.0)
- 结合源码探讨Android系统的启动流程
- 结合源码探讨Android系统的启动流程
- 源码角度分析Android启动流程
- Android源码(3) --- 系统Launcher 启动流程
- Android的开机流程及对应源码位置分析
- Android的开机流程及对应源码位置分析
- android系统的启动流程
- SQL right()函数
- 压缩算法——谷歌Webp
- springSecurity+cas 单点登录
- Bootstrap面板(Panels)
- [码]国外大牛整理的Java资源 !
- Android系统的启动流程分析及如何看源码
- mongoDB——副本集
- Spring MVC+Mybatis+Maven+Velocity+Mysql整合实例
- Exam_Codeforces
- 推荐WebRTC
- Armadillo_OpenBLAS_IntelMKL安装
- OpenCV下載與設定
- 网络连接正常但无法上网(能ping通外网DNS)解决方法
- php 实现不用递归的树形数组构造函数 无限级分类