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参考