为什么Android每当启动一个新的应用程序时会通过“throw new ZygoteInit.MethodAndArgsCaller(m, argv)”进入ActivityThread的main函数

关于与这个问题,其实在两年前研究Android启动过程的时候就发现,这是一个很有意思的地方,奈何工作繁忙的原因,一直没有时间去深究,最近终于有了闲暇的时间,就仔细的想了一下,总结出了一个原因,更准确的说是一种猜想,接下来就让咱们一起了分析一下:

通过Android源码我们可以发现:
1、启动一个Android应用程序在ZygoteInit.java的顺序如图:
Zygote会fork出一个新的进程

2、当fork返回0时就表示进入了子进程的执行如图:
在新的进程中会调用handleChildProc函数

3、在handleChildProc函数处理的最后会调用 ZygoteInit.invokeStaticMain函数,在 ZygoteInit.invokeStaticMain函数中会抛出MethodAndArgsCaller异常,如图:
抛出MethodAndArgsCaller异常

4、最终这个这个MethodAndArgsCaller异常会被ZygoteInit的main函数捕获,如图:
捕获MethodAndArgsCaller

5、调用MethodAndArgsCaller的run方法,启动ActivityThread的main方法,开启Android的应用程序,如图:
这里写图片描述

以上就是Android每启动一个应用程序的主要过程,那我们来分析一下原因:

首先、我们要先清楚,抛异常这一操作会引发什么?
我们知道,当一个函数抛出异常后,这个异常会依次传递给调用它的函数,知道这个异常被捕获,如果这个异常一直没有被处理,最终就会引起程序的崩溃。

其次、在传递异常的时候,应用程序的栈发生了什么变化?
这就要牵涉到函数的执行模型了,我们知道,程序都是有一个个函数组成的(除了汇编程序),c/c++/java/..等高级语言编写的应用程序,在执行的时候,他们都拥有自己的栈空间(是一种先进后出的内存区域),用于存放函数的返回地址和函数的临时数据,每调用一个函数时,就会把函数的返回地址和相关数据压入栈中,当一个函数执行完后,就会从栈中弹出,cpu会根据函数的返回地址,执行上一个调用函数的下一条指令。
所以,在抛出异常后,如果异常没有在当前的函数中捕获,那么当前的函数执行就会异常的退出,从应用程序的栈弹出,并将这个异常传递给上一个函数,直到异常被捕获处理,否则,就会引起程序的崩溃。
那我们来看一下fork出新的子进程后,函数的执行流程:
handleChildProc——>ZygoteInit.invokeStaticMain(抛异常)——>ZygoteInit.main——>MethodAndArgsCaller.run——>ActivityThread.main

最后、为什么要用抛异常的方式去启动ActivityThread的main函数呢?而不直接在在ZygoteInit.invokeStaticMain中通过反射调用ActivityThread.main?
我们可以回想一下,无论我们写c程序还是java程序,他们都只有一个入口就是main函数,当main函数返回退出后就代表整个程序退出了,根据上面分析的函数的执行模型,程序的main函数应该是每一个应用程序最后退出的函数,应该位于栈的底部。同理,Android应用程序的入口是ActivityThread.main函数,所以它也应该位于新的进程的栈的ZygoteInit.main函数的上面,这样才能实现直接退出应用程序,但是Android每fork一个新进程的时候,它都会先调用handleChildProc函数做一些,子进程的处理,此时应用程序栈的最低部函数是handleChildProc,接着还会压入ZygoteInit.invokeStaticMain函数。

**所以这里通过抛异常的方式启动ActivityThread.main函数主要是清理应用程序栈中ZygoteInit.main以上的函数栈帧,以实现当ActivityThread.main函数退出时,能直接退出整个应用程序。
当ActivityThread的main退出后,就会退回到MethodAndArgsCaller.run而这个函数直接就退回到ZygoteInit.main函数,而ZygoteInit.main也无其他的操作,直接退出了函数,这样整个应用程序将会完全退出**。

好了,整个分析过程就完了,欢迎大家吐槽

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
try { Class<?> cls = null; cls = context.getClassLoader().loadClass(clsName); mFactory = (SystemUIFactory) cls.newInstance(); mFactory.init(context, fromTest); } catch (Throwable t) { Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t); throw new RuntimeException(t); }中如何防止出现以下错误:java.lang.RuntimeException: Unable to create application com.android.systemui.SystemUIApplication: java.lang.RuntimeException: java.lang.IllegalStateException: Replacing existing organizer currently unsupported at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6882) at android.app.ActivityThread.access$1500(ActivityThread.java:265) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2122) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:334) at android.app.ActivityThread.main(ActivityThread.java:7985) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013) Caused by: java.lang.RuntimeException: java.lang.IllegalStateException: Replacing existing organizer currently unsupported at com.android.systemui.SystemUIFactory.createFromConfig(SystemUIFactory.java:77) at com.android.systemui.SystemUIFactory.createFromConfig(SystemUIFactory.java:56) at com.android.systemui.SystemUIAppComponentFactory.lambda$instantiateApplicationCompat$0(SystemUIAppComponentFactory.java:68) at com.android.systemui.SystemUIAppComponentFactory.$r8$lambda$zKKm1nezMgurYfpE42JHdUJUlZ0(Unknown Source:0) at com.android.systemui.SystemUIAppComponentFactory$$ExternalSyntheticLambda1.onContextAvailable(Unknown Source:2) at com.android.systemui.SystemUIApplication.onCreate(SystemUIApplication.java:83) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1223) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6877)
最新发布
06-06

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值