Zygote冷启动流程

http://liuwangshu.cn/framework/applicationprocess/1.html

SystemServer(SystemServer组件是由Zygote进程负责启动的,启动的时候就会调用它的main函数,这个函数主要调用了JNI方法init1来做一些系统初始化的工作。init1这个函数是一个JNI方法,实现在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中:

通过startBootstrapServices,启动一堆服务,例如ActivityManagerService

ActivityManagerService会通过调用startProcessLocked函数来向Zygote进程发送请求,如下所示。

sdk版本28 代码4379行

//这里是关键,ActivityThread是后续整个启动的入口
// Start the process.  It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
final String entryPoint = "android.app.ActivityThread";
return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                    runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                    startTime);
调用到
 final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                            app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                            requiredAbi, instructionSet, invokeWith, app.startTime);
再调用到
 Process.ProcessStartResult startResult = Process.start(entryPoint,
                  app.processName, uid, uid, gids, debugFlags, mountExternal,
                  app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                  app.info.dataDir, entryPointArgs);
Process
public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

Process.start调用startViaZygote

//创建了字符串列表argsForZygote ,并将启动应用进程的启动参数保存在argsForZygote中
ArrayList<String> argsForZygote = new ArrayList<>();

代码437行
 synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
 }

zygoteSendArgsAndGetResult
zygoteSendArgsAndGetResult函数主要做的就是将传入的应用进程的启动参数argsForZygote,写入到ZygoteState中

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
primaryZygoteState =
        ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
public ZygoteProcess() {
    mZygoteSocketAddress =
            new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME,
                                   LocalSocketAddress.Namespace.RESERVED);
}
省略很多代码
}
com.android.internal.os.Zygote

Zygote.PRIMARY_SOCKET_NAME 
public static final String PRIMARY_SOCKET_NAME = "zygote";
Zygote.usapMain
ZygoteInit.zygoteInit
ZygoteInit.main
start-system-server 启动SystemServer--forkSystemServer
--enable-lazy-preload
caller = zygoteServer.runSelectLoop(abiList);//等待客户端请求
if (pollIndex == 0) {
    // Zygote server socket

    ZygoteConnection newPeer = acceptCommandPeer(abiList);
    peers.add(newPeer);
    socketFDs.add(newPeer.getFileDescriptor());

} else if (pollIndex < usapPoolEventFDIndex) {
    // Session socket accepted from the Zygote server socket

    try {
        ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);

}
ZygoteConnection.processOneCommand
//获取应用程序进程的启动参数
args = Zygote.readArgumentList(mSocketReader);
//创建应用程序进程
Zygote.forkAndSpecialize

forkAndSpecialize函数主要是通过fork当前进程来创建一个子进程的,如果pid等于0,则说明是在新创建的子进程中执行的,就会调用handleChildProc函数来启动这个子进程也就是应用程序进程
handleChildProc

if (!isZygote) {
    return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
            parsedArgs.mDisabledCompatChanges,
            parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
    return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
            parsedArgs.mRemainingArgs, null /* classLoader */);
}

ZygoteInit.zygoteInit—>RuntimeInit.applicationInit—>findStaticMain->invoke<android.app.ActivityThread>—>main函数

Method m;
try {
    m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
    throw new RuntimeException(
            "Missing static main on " + className, ex);
} catch (SecurityException ex) {
    throw new RuntimeException(
            "Problem getting static main on " + className, ex);
}

链接:https://www.jianshu.com/p/f7a30554fe55
六,App启动、Application生命周期
app的两种启动方式

1,冷启动
系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上

2,热启动
进程在后台运行,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application,因为一个应用从新进程的创建到进程的销毁,Application只会初始化一次。

App启动流程
用户点击app后会通知 ActivityManagerService 启动应用的入口 Activity, ActivityManagerService 发现这个应用还未启动,则会通知 Zygote 进程孵化出应用进程,然后在这个应用进程里执行 ActivityThread 的 main 方法。应用进程接下来通知 ActivityManagerService 应用进程已启动,ActivityManagerService 保存应用进程的一个代理对象,这样 ActivityManagerService 可以通过这个代理对象控制应用进程,然后 ActivityManagerService 通知应用进程创建入口 Activity 的实例,并执行它的生命周期函数。

上面的启动流程是 Android 提供的机制,我们只能在创建入口 Activity 的实例这里做文章,正常Main Activity 的启动流程:

-> Application 构造函数
-> Application.attachBaseContext()
-> Application.onCreate()
-> Activity 构造函数
-> Activity.setTheme()
-> Activity.onCreate()
-> Activity.onStart
-> Activity.onResume
-> Activity.onAttachedToWindow
-> Activity.onWindowFocusChanged
统计app启动时长的两种方式

1,本地通过adb命令行
adb shell am start -w packagename/activity 输入adb shell am start -W

com.qcl/com.qcl.MainActivity得到下面结果
Activity: com.qcl/.MainActivity
ThisTime: 83
TotalTime: 83
WaitTime: 94
TotalTime是我们真正的启动时间
2,通过收集log(可以用来获取线上启动时间)
开始时间:
冷启动在Application的attachBaseContext
热启动在入口activity的onRestart中
结束时间:在入口activity的onWindowFocusChanged

app的启动优化:
基于上面的启动流程我们尽量做到如下几点

1.Application的创建过程中尽量少的进行耗时操作
2.如果用到SharePreference,尽量在异步线程中操作
3.减少布局的层次,并且生命周期回调的方法中尽量减少耗时的操作
app启动遇见黑屏或者白屏问题
1,产生原因
其实显示黑屏或者白屏实属正常,这是因为还没加载到布局文件,就已经显示了window窗口背景,黑屏白屏就是window窗口背景
2,解决办法
通过设置设置Style
(1)设置背景图Theme
通过设置一张背景图。 当程序启动时,首先显示这张背景图,避免出现黑屏
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:screenOrientation">portrait</item>
<item name="android:windowBackground">>@mipmap/splash</item>

<item name="android:windowIsTranslucent">true</item> 
<item name="android:windowNoTitle">true</item> 

</style>
设置透明Theme
通过把样式设置为透明,程序启动后不会黑屏而是整个透明了,等到界面初始化完才一次性显示出来

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:screenOrientation">portrait</item>
</style>
两者对比:
Theme1 程序启动快,界面先显示背景图,然后再刷新其他界面控件。给人刷新不同步感觉。
Theme2 给人程序启动慢感觉,界面一次性刷出来,刷新同步
Zygote参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容