千里之行,始于足下。
一、Android
Activity启动流程 (API 28)
Step1. 从点击应用图标到AMS的调用
1 | 1. Launcher调用startActivity |
Step2. AMS调用Zygote创建app进程
在ActivitySupervisor#startSpecificActivityLocked方法中,会判断app进程是否已经被创建,r如果已经创建,则直接从Step5开始继续。则如果还没有被创建,则开始进行app进程初始化工作:
1 | void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { |
创建app进程的方法调用流程为:
1 | 1. ActivitySupervisor#startProcessLocked |
Step3. Zygote处理Socket请求,创建子进程并反射调用ActivityThread的main函数
在Android系统启动进行初始化时,首先会初始化Zygote进程的相关内容。在ZygoteInit的main函数中,会初始化ZygoteServer,并调用ZygoteServer#runSelectLoop来死循环监听Socket的Client(AMS)发来的消息。方法调用流程为:
1 | 1. ZygoteServer#runSelectLoop |
processOneCommand方法代码如下
1 | Runnable processOneCommand(ZygoteServer zygoteServer) { |
接着执行子进程,这里即app进程流程
1 | 1. ZygoteConnection#handleChildProc |
Step4. ActivityThread的main方法
1 | 1. ActivityThread的mian方法中,启动了主线程looper,并创建了ActivityThread实例,然后调用ActivityThread#attach |
Step5. Activity的启动
在Step4的第四步中,AMS#attachApplicationLocked方法首先会通过AIDL调用ApplicationThread#bindApplication,然后调用了ActivityStackSupervisor#attachApplicationLocked。前者会完成Application的创建和启动,由于AIDL方法会阻塞调用方的继续执行,在Application完成创建和启动后,AMS会继续执行到ActivityStackSupervisor#attachApplicationLocked,该方法内部会尝试从ActivityList缓存中寻找app进程是否有待启动的activity(这里是有缓存的activity的,在Step1的第10步中,在启动activity之前会先判断app进行有没有启动,没有的话先启动app进程,待启动的activity已经被缓存起来了)。如果有的话会调用realStartActivityLocked:
1 | final boolean realStartActivityLocked(...) throws RemoteException { |
在注释1和注释2处,向ClientTransaction中添加了LaunchActivityItem和ResumeActivityItem,记住这两个item,后面会有用。然后执行了mService.getLifecycleManager().scheduleTransaction(clientTransaction);
1 | ClientLifecycleManager#scheduleTransaction方法: |
mClient就是在客户端的实现是ApplicationThread,所以最终执行到了ApplicationThread#scheduleTransaction方法:
1 | 1. ApplicationThread#scheduleTransaction |
TrasactionExecutor#execute方法如下
1 | public void execute(ClientTransaction transaction) { |
其实就是顺序执行了LaunchActivityItem和ResumeActivityItem(还记得这两个item吗)的execute方法:
1 | @Override |
handleLaunchActivity和handleResumeActivity中完成了Activity的创建和展示,具体的代码细节就不贴了。到这里整个app就启动起来了。
View绘制流程 (API 28)
在上面Activity的启动流程中,最后会调用handleResumeActivity,绘制流程就从这里开始分析。
handleResumeActivity方法中会调用performResultActivity,该方法中会调用Activity#performResume,从而完成对onStart和onResume方法的回调。
再回到handleResumeActivity方法中,该方法中有一段关键代码:
1 | if (r.window == null && !a.mFinished && willBeVisible) { |
WindowManagerImpl是典型的桥接模式实现,内部将所有方法都委托给了WindowManagerGlobal来实现,所以直接看WindowManagerGlobal#addView:
1 | public void addView(View view, ViewGroup.LayoutParams params, |
ViewRootImpl#setView中调用了requestLayout:
1 | @Override |
在performTraversals方法中依次调用了performMeasure、performLayout、performDraw方法来完成View绘制的三大流程:测量、布局和绘制。另外ViewRootImpl中还涉及到了Choreographer屏幕刷新机制、invalidate和requestLayout的区别等内容,这里就不再多介绍了,我也懒得写了吼吼吼😎
Android消息机制
Android消息机制中主要有Handler、Looper、MessageQueue、ThreadLocal、ThreadLocalMap等几个重点类。但是实在不知道该写点啥,感觉没什么难点(菜鸡的迷之自信)。随便写点个人理解吧。(可能有误
- Android是以消息机制为驱动的系统,事件在底层产生,传到系统层,再由系统层用AIDL的方式分发给各应用进程,应用受到事件后进行相应的处理。如果没有事件产生,应用进程需要等待消息的产生再做相应的处理。所以必然有某种等待消息时的阻塞机制。
- ApplicationThread作为Binder机制在client中的实现类,在接收到消息之后使用mH将消息直接传递给ActivityThread,具体的行为都是在ActivityThread中进行的。mH是ActivityThread中的Handler类型的成员变量,在ActivityThread#main中会初始化Looper,Looper的初始化线程为主线程,所以消息都是在主线程中处理的。
- 在ActivityThread#main中,最后两行代码:
1 | Looper.loop(); |
也就是如果执行到了Looper.loop()的下一行,程序就会抛出异常然后退出,所以Looper.loop()必然需要是死循环。
- Looper#loop为死循环,其实并不是因为loop中的死循环阻塞了,而是因为方法中的queue.next()阻塞了,一旦queue.next()返回空的msg,方法就会return从而退出,所以正常情况下queue.next()要么返回正常的msg,要么阻塞。如果返回了空msg,则代表程序要退出了(针对main looper而言)。
1 | public static void loop() { |
MessageQueue#next方法中有对同步屏障进行处理的代码,可以看出单纯设置msg.setAsynchronous(true)并不能生成同步屏障,生成同步屏障需要msg.target == null
1
2
3
4
5
6
7
8
9Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}MessageQueue中有postSyncBarrier方法,该方法是唯一可以产生msg.target == null的方法,在Handler中所有sendMessage、postDelay等方法最终都会走到enqueueMessage方法中,该方法会给message.target赋值:
1
2
3
4
5
6
7private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}MessageQueue#next方法中的nextPollTimeoutMillis变量,-1代表一直阻塞,直到调用nativeWake来唤醒;0代表不会阻塞,立即返回;>0代表最长阻塞nextPollTimeoutMillis毫秒,期间如果调用nativeWake则立即返回。
IdleHandler只会在MessageQueue#next第一次循环时被调用。(?
ThreadLocal并不是线程本地变量,ThreadLocalMap才是,只不过通过ThreadLocal可以取出Thread中的ThreadLocalMap。ThreadLocalMap是ThreadLocal中的静态内部类。
ThreadLocalMap中的数据结构是数组+Map。Map的key为软引用,意味着如果key的实例没有强引用存在时,不会因为ThreadLocalMap中的引用导致内存泄漏。同时在ThreadLocalMap的set/get/remove等方法中,会检查key为空的内容,将value也置为空,防止value的内存泄漏。