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开发者而言,我们怎么才能快速的弄懂源码呢?该如何看源码呢?我的建议就是把各种判断去掉,把重复多次的去掉,这两部分其实占据了很大的篇幅,如果你 能把这些分离出来,剩下的干货其实是很好理清楚的。。

1 0
原创粉丝点击