美文网首页
按下应用图标,追寻开启应用源码之旅

按下应用图标,追寻开启应用源码之旅

作者: 眼睛红红红 | 来源:发表于2019-11-12 18:30 被阅读0次

    今天跟同事讨论应用启动的问题,关于应用如何启动的 ,我想追踪下源码,但是却不知道从什么地方开始,于是我想就从按下应用图标开始到界面启动吧,于是坐下打开source insight,其实,最近总结了一点看源码的诀窍,就是你想要知道什么,你就从哪个地方开始看源码,直到源码实现了你所要知道的东西,其实源码为什么看起来这么费劲,实际上运用了大量的设计模式导致容易走入死胡同。那么怎么绕开这个呢?多看,多想。好了不废话,下面走入源码世界。

    在解析源码前,我们需要知道几个东西,1、init进程 2、zygote进程,3、systemserve。为什么会跟这几个相关联呢?别慌,下面就一一来作答,首先我们需要知道的是init进程,init进程是系统的第一个进程,我们要知道,系统启动的顺序,1、首先会加载引导程序,2然后启动Linux内核,3、最后启动init进程,那么init进程到底做了什么呢?其实init进程 主要创建和挂载启动所需的文件目录,其次初始化和启动服务(上述的systemserve)3、解析init.rc文件并启动zygote进程。通俗来讲init进程就是系统启动的入口。那么zygote进程是干嘛的呢?我们来看看源码。

    首先获取到一个zygoteserver对象,那么这个对象有什么用呢?继续看下面

    可以看到通过一个socket注册了一个与服务端连接的socket,那么为什么需要这个socket呢?我们要知道,在上面说了,init进程和zygote进程是在系统内部的,如果我们应用要启动需要zygote进程来加载资源和启动相关服务,这个时候就需要与服务端建立连接,所以需要注册一个serversocket.

    回到zygoteinit中去,除了注册serversocket,还做了什么呢?

    预加载资源,

    然后启动systemserver和等待activitymanagerservice的请求,好了这个时候前期工作已经完毕,记住一点这个时候的工作室在jni层完成的,

    接下来看看launcher的启动,launcher的启动是由activitymanagerservice来完成,刚刚上面说了,在runselectloop这个方法中实际上就是systemservice等待ams的请求,那么请求什么呢?实际上请求启动创建应用进程的,如果当前进程存在则启动,不存在则创建,怎么创建呢,其实是通过zygote的fork复制的,那为什么要复制呢?因为复制可以直接将需要的资源和虚拟机一起clone一份,减少资源加载和虚拟机的创建,接下来看ams的源码是怎么启动launcher的,

    首先,我们启动launcher之前肯定需要做几件事情,1,创建一个任务栈,为什么要这个,因为我们的activty需要放入栈中,因为栈中的数据我们可以通过压栈和弹栈操作,可以设置activty在栈中的位置,这个可以控制activty的启动模式,而且系统界面的调用也需要这个,比如我们当前应用需要调用系统的相册,电话,拍照等界面,这个时候将系统界面压栈,处于用户可视范围,调用完弹栈即可。回归上述,如何创建一个任务栈呢?接下来看源码

    创建完之后,我们需要让启动的home栈处于resume状态,因为启动的时候,需要将将要启动的activty置于这个栈的顶端。接下就是通过ams来启动launcher,那么启动之前我们需要做什么呢?可以对比下activty,我们需要知道当前launcher的intent的信息,

    是不是感觉跟mainfest.xml文件中mainactivity的设置很像呢?没错,这个就是设置launcher作为入口的。以上的启动条件全部准备好了,现在只需把launcher放入homestack中就可以了,后续就会通过startActivityLocked方法启动launcher了。

    综上,我们来总结下流程:

    1、首先会开启一个init进程,因为这个进程是系统的第一个进程,所以这个进程需要创建和挂载启动所需的文件资源,然后启动必要的服务,例如BootLoader引导服务。启动zygote进程。

    2、zygote进程会创建一个server端的socket,然后预加载资源,启动systemserver,等待AMS发送的请求,

    3、AMS会请求启动一个应用进程,同时AMS会创建一个任务栈,

    4、确保任务栈处于resume状态

    5、然后设置启动launcher需要的intent的信息作为启动的信息携带者

    6、将launcher放入创建的任务栈中,调用startActivityLocked启动。

    此时从系统到launcher启动已经完成了,但是此时页面并没有启动,activity这个时候还没有启动,接下来我们看看activity怎么启动的。

    首先我们启动activty是通过startactivty来启动activty的,我们直接进入startactivty源码内部去看看。

    startactivty直接调用了startActivityForResult方法,我们继续探寻startActivityForResult的源码,看看这个方法内部做了什么

    mInstrumentation是用来监控应用程序和系统的交互

    在这里,创建了一个AMS的代理类来执行Ams的一些操作,这里使用了代理模式,使得服务端和应用端能够执行相应的方法。此时执行程序的操作就交给AMS来完成了,这段代码重要的功能便是将调用者转给AMS,接下来我们区看AMS的startactivty方法。

    这段代码直接返回AMS的startActivityAsUser方法,那么这个方法是干什么的呢/我们去内部看看,

    这个方法最重要的一点就是根据userID来确定启动的权限。

    检查权限后创建intent,并根据intent的相关信息找到指定的需要启动的activty,此时找到对应的activty需要将activity放入栈中,而根据上述来说,activityStack是管理栈的,

    ,栈创建完毕,直接调用栈的resumeTopActivityUncheckedLocked方法,那么这个方法是干嘛的呢?

    确保栈顶的activty是处于resume状态,这样能够即将能够展示在界面。这个时候我们进入方法resumeTopActivityinnerLocked内部可以看到调用ActivtyThread的scheduleLaunchActivity方法,那么此时,启动来到ActivtyThread中,ActivtyThread的实现类是applicationThread,这个类是AMS所在进程与应用进程的通信桥梁,这个ActivtyThread是管理activity的线程管理类。在ActivtyThread中会调用scheduleLanucgActivty方法,这个就是发送启动消息的。那么我们来看看发送消息。

    发送消息后肯定要处理消息,接下来看看怎么去处理这个消息的。

    终于看到了执行启动activty的方法了,就是它,这个performLaunchActivity,到这里activty就启动了,那么在启动之前还会初始化一些信息,看看初始化哪些必要信息呢?

    看上述红箭头指示,

    1,获取一个activityInfo,内部包含了启动的activty的所有信息,

    2、创建context上下文对象

    3、创建activty的对象,

    4、创建一个application

    5、初始化一个activty,将上述获取的参数传入activty中

    调用了activty的oncreate的生命周期方法,到此时,整个activity才真正的启动了。

    相关文章

      网友评论

          本文标题:按下应用图标,追寻开启应用源码之旅

          本文链接:https://www.haomeiwen.com/subject/ofltictx.html