Android 系统性能优化(21)---App启动原理分析及启动时间优化
一、启动原理解析
Android是基于Linux内核的,当手机启动,加载完Linux内核后,会由Linux系统的init祖先进程fork出Zygote进程,所有的Android应用程序进程以及系统服务进程都是这个Zygote的子进程(由它fork出来的)。其中最重要的一个就是SystemServer,在ZygoteInit类的main方法中,会调用startSystemServer方法开启系统里面重要的服务,包括ActivityManagerService(Activity管理器,简称AMS,可以理解为一个服务进程,负责Activity的生命周期管理)、PackageManagerService(包管理器)、WindowManagerService(窗口管理器)、PowerManagerService(电量管理器)等等,这个过程中还会创建系统上下文。
- public final class SystemServer {
- //zygote的主入口
- public static void main(String[] args) {
- new SystemServer().run();
- }
- public SystemServer() {
- // Check for factory test mode.
- mFactoryTestMode = FactoryTest.getMode();
- }
- private void run() {
- ...ignore some code...
- //加载本地系统服务库,并进行初始化
- System.loadLibrary("android_servers");
- nativeInit();
- // 创建系统上下文
- createSystemContext();
- //初始化SystemServiceManager对象,下面的系统服务开启都需要调用SystemServiceManager.startService(Class<T>),这个方法通过反射来启动对应的服务
- mSystemServiceManager = new SystemServiceManager(mSystemContext);
- //开启服务
- try {
- startBootstrapServices();
- startCoreServices();
- startOtherServices();
- } catch (Throwable ex) {
- Slog.e("System", "******************************************");
- Slog.e("System", "************ Failure starting system services", ex);
- throw ex;
- }
- ...ignore some code...
- }
- //初始化系统上下文对象mSystemContext,并设置默认的主题,mSystemContext实际上是一个ContextImpl对象。调用ActivityThread.systemMain()的时候,会调用ActivityThread.attach(true),而在attach()里面,则创建了Application对象,并调用了Application.onCreate()。
- private void createSystemContext() {
- ActivityThread activityThread = ActivityThread.systemMain();
- mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
- }
- //在这里开启了几个核心的服务,因为这些服务之间相互依赖,所以都放在了这个方法里面。
- private void startBootstrapServices() {
- ...ignore some code...
- //初始化ActivityManagerService
- mActivityManagerService = mSystemServiceManager.startService(
- ActivityManagerService.Lifecycle.class).getService();
- mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
- //初始化PowerManagerService,因为其他服务需要依赖这个Service,因此需要尽快的初始化
- mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
- // 现在电源管理已经开启,ActivityManagerService负责电源管理功能
- mActivityManagerService.initPowerManagement();
- // 初始化DisplayManagerService
- mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
- //初始化PackageManagerService
- mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
- ...ignore some code...
- }
- }
注意一个很重要的地方
- private void createSystemContext() {
- ActivityThread activityThread = ActivityThread.systemMain();
- mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
- }
二、当我们点击了一个APP图标时发生了什么
系统第一个启动的APP是Lancher,也就是我们手机的主界面,继承自Activity,实现了点击事件、触摸、长按等接口,在android源码Lancher.java中,我们可以看到onclick方法
- public void onClick(View v) {
- ...ignore some code...
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- // Open shortcut
- final Intent intent = ((ShortcutInfo) tag).intent;
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
- //开始开启Activity
- boolean success = startActivitySafely(v, intent, tag);
- if (success && v instanceof BubbleTextView) {
- mWaitingForResume = (BubbleTextView) v;
- mWaitingForResume.setStayPressed(true);
- }
- } else if (tag instanceof FolderInfo) {
- //如果点击的是图标文件夹,就打开文件夹
- if (v instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) v;
- handleFolderClick(fi);
- }
- } else if (v == mAllAppsButton) {
- ...ignore some code...
- }
- }
可以看出我们点击了主界面上的应用图标后调用的就是startActivitySafely这个方法,继续深入进去,然后再往下走,我们发现调用的是startActivity方法,最后会调用Instrumentation.execStartActivity(),Instrumentation这个类就是完成对Application和Activity初始化和生命周期的工具类,然后Instrumentation会通过ActivityManagerService的远程接口向AMS发消息,让他启动一个Activity。 也就是说调用startActivity(Intent)以后, 会通过Binder IPC机制, 最终调用到ActivityManagerService。AMS会通过socket通道传递参数给Zygote进程。Zygote孵化自身, 并调用ZygoteInit.main()方法来实例化ActivityThread对象并最终返回新进程的pid。ActivityThread随后依次调用Looper.prepareLoop()和Looper.loop()来开启消息循环。在ActivityThread会创建并绑定Application,这个时候才会realStartActivity(),并且AMS会将生成的Activity加到ActivityTask的栈顶,并通知ActivityThread暂停当前Activity(暂停Lancher,进入我们自己的APP)。
三、Application在何处初始化
- mgr.attachApplication(mAppThread)
在makeApplication方法中,最后调用的是instrumentation.callApplicationOnCreate(app);
这个方法里面的onCreate就是调用了我们Application的OnCreate方法。
- public Application makeApplication(boolean forceDefaultAppClass,
- Instrumentation instrumentation) {
- if (mApplication != null) {
- return mApplication;
- }
- Application app = null;
- String appClass = mApplicationInfo.className;
- if (forceDefaultAppClass || (appClass == null)) {
- appClass = "android.app.Application";
- }
- try {
- java.lang.ClassLoader cl = getClassLoader();
- if (!mPackageName.equals("android")) {
- initializeJavaContextClassLoader();
- }
- ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
- app = mActivityThread.mInstrumentation.newApplication(
- cl, appClass, appContext);
- appContext.setOuterContext(app);
- } catch (Exception e) { }
- mActivityThread.mAllApplications.add(app);
- mApplication = app;
- //传进来的是null,所以这里不会执行,onCreate在上一层执行
- if (instrumentation != null) {
- try {
- instrumentation.callApplicationOnCreate(app);
- } catch (Exception e) {
- }
- }
- ...ignore some code...
- }
- return app;
- }
四、什么地方我们可以进行优化
五、冷启动与热启动的区别
2 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。热启动因为会从已有的进程中来启动,所以热启动就不会走 Application 这步了,而是直接走 MainActivity,所以热启动的过程不必创建和初始化 Application,因为一个应用从新进程的创建到进程的销毁,Application 只会初始化一次。
六、时间定义
- ThisTime: 最后一个启动的Activity的启动耗时
- 自己的所有Activity的启动耗时
- WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)
1.上一个Activity的onPause()——2.系统调用AMS耗时——3.第一个Activity(也许是闪屏页)启动耗时——4.第一个Activity的onPause()耗时——5.第二个Activity启动耗时
那么,ThisTime表示5(最后一个Activity的启动耗时)。TotalTime表示3.4.5总共的耗时(如果启动时只有一个Activity,那么ThisTime与TotalTime就是一样的)。WaitTime则表示所有的操作耗时,即1.2.3.4.5所有的耗时。
- public void reportFullyDrawnLocked() {
- final long curTime = SystemClock.uptimeMillis();
- if (displayStartTime != 0) {
- reportLaunchTimeLocked(curTime);
- }
- final ActivityStack stack = task.stack;
- if (fullyDrawnStartTime != 0 && stack != null) {
- final long thisTime = curTime - fullyDrawnStartTime;
- final long totalTime = stack.mFullyDrawnStartTime != 0
- ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
- }
七、为什么启动时会出现短暂黑屏或白屏的现象
八、冷启动优化
- <style name="AppTheme.Launcher">
- <item name="android:windowBackground">@drawable/bg</item>
- </style>
- <activity
- android:name=".activity.SplashActivity"
- android:screenOrientation="portrait"
- android:theme="@style/AppTheme.Launcher"
- >
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- //替换为原来的主题,在onCreate之前调用
- setTheme(R.style.AppTheme);
- super.onCreate(savedInstanceState);
- }
- <style name="AppTheme.Launcher">
- <item name="android:windowBackground">@null</item>
- </style>
- 延迟初始化
- 后台任务
- 界面预加载
- new Thread(){
- @Override
- public void run() {
- initNim();
- initImagePicker();
- initOkHttp();
- }
- }.start();
九、优化启动时间的一个很好用的工具 TraceView
- File file = new File(Environment.getExternalStorageDirectory(), "app7");
- Log.i(TAG, "onCreate: " + file.getAbsolutePath());
- Debug.startMethodTracing(file.getAbsolutePath());
- //对全局属性赋值
- mContext = getApplicationContext();
- mMainThread = Thread.currentThread();
- mMainThreadId = android.os.Process.myTid();
- mMainLooper = getMainLooper();
- mHandler = new Handler();
- initNim();
- initImagePicker();
- initOkHttp();
- Debug.stopMethodTracing();
- cd Desktop
- adb pull /storage/sdcard/app7.trace
一、启动原理解析
Android是基于Linux内核的,当手机启动,加载完Linux内核后,会由Linux系统的init祖先进程fork出Zygote进程,所有的Android应用程序进程以及系统服务进程都是这个Zygote的子进程(由它fork出来的)。其中最重要的一个就是SystemServer,在ZygoteInit类的main方法中,会调用startSystemServer方法开启系统里面重要的服务,包括ActivityManagerService(Activity管理器,简称AMS,可以理解为一个服务进程,负责Activity的生命周期管理)、PackageManagerService(包管理器)、WindowManagerService(窗口管理器)、PowerManagerService(电量管理器)等等,这个过程中还会创建系统上下文。
- public final class SystemServer {
- //zygote的主入口
- public static void main(String[] args) {
- new SystemServer().run();
- }
- public SystemServer() {
- // Check for factory test mode.
- mFactoryTestMode = FactoryTest.getMode();
- }
- private void run() {
- ...ignore some code...
- //加载本地系统服务库,并进行初始化
- System.loadLibrary("android_servers");
- nativeInit();
- // 创建系统上下文
- createSystemContext();
- //初始化SystemServiceManager对象,下面的系统服务开启都需要调用SystemServiceManager.startService(Class<T>),这个方法通过反射来启动对应的服务
- mSystemServiceManager = new SystemServiceManager(mSystemContext);
- //开启服务
- try {
- startBootstrapServices();
- startCoreServices();
- startOtherServices();
- } catch (Throwable ex) {
- Slog.e("System", "******************************************");
- Slog.e("System", "************ Failure starting system services", ex);
- throw ex;
- }
- ...ignore some code...
- }
- //初始化系统上下文对象mSystemContext,并设置默认的主题,mSystemContext实际上是一个ContextImpl对象。调用ActivityThread.systemMain()的时候,会调用ActivityThread.attach(true),而在attach()里面,则创建了Application对象,并调用了Application.onCreate()。
- private void createSystemContext() {
- ActivityThread activityThread = ActivityThread.systemMain();
- mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
- }
- //在这里开启了几个核心的服务,因为这些服务之间相互依赖,所以都放在了这个方法里面。
- private void startBootstrapServices() {
- ...ignore some code...
- //初始化ActivityManagerService
- mActivityManagerService = mSystemServiceManager.startService(
- ActivityManagerService.Lifecycle.class).getService();
- mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
- //初始化PowerManagerService,因为其他服务需要依赖这个Service,因此需要尽快的初始化
- mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
- // 现在电源管理已经开启,ActivityManagerService负责电源管理功能
- mActivityManagerService.initPowerManagement();
- // 初始化DisplayManagerService
- mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
- //初始化PackageManagerService
- mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
- ...ignore some code...
- }
- }
注意一个很重要的地方
- private void createSystemContext() {
- ActivityThread activityThread = ActivityThread.systemMain();
- mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
- }
二、当我们点击了一个APP图标时发生了什么
系统第一个启动的APP是Lancher,也就是我们手机的主界面,继承自Activity,实现了点击事件、触摸、长按等接口,在android源码Lancher.java中,我们可以看到onclick方法
- public void onClick(View v) {
- ...ignore some code...
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- // Open shortcut
- final Intent intent = ((ShortcutInfo) tag).intent;
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
- //开始开启Activity
- boolean success = startActivitySafely(v, intent, tag);
- if (success && v instanceof BubbleTextView) {
- mWaitingForResume = (BubbleTextView) v;
- mWaitingForResume.setStayPressed(true);
- }
- } else if (tag instanceof FolderInfo) {
- //如果点击的是图标文件夹,就打开文件夹
- if (v instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) v;
- handleFolderClick(fi);
- }
- } else if (v == mAllAppsButton) {
- ...ignore some code...
- }
- }
可以看出我们点击了主界面上的应用图标后调用的就是startActivitySafely这个方法,继续深入进去,然后再往下走,我们发现调用的是startActivity方法,最后会调用Instrumentation.execStartActivity(),Instrumentation这个类就是完成对Application和Activity初始化和生命周期的工具类,然后Instrumentation会通过ActivityManagerService的远程接口向AMS发消息,让他启动一个Activity。 也就是说调用startActivity(Intent)以后, 会通过Binder IPC机制, 最终调用到ActivityManagerService。AMS会通过socket通道传递参数给Zygote进程。Zygote孵化自身, 并调用ZygoteInit.main()方法来实例化ActivityThread对象并最终返回新进程的pid。ActivityThread随后依次调用Looper.prepareLoop()和Looper.loop()来开启消息循环。在ActivityThread会创建并绑定Application,这个时候才会realStartActivity(),并且AMS会将生成的Activity加到ActivityTask的栈顶,并通知ActivityThread暂停当前Activity(暂停Lancher,进入我们自己的APP)。
三、Application在何处初始化
- mgr.attachApplication(mAppThread)
在makeApplication方法中,最后调用的是instrumentation.callApplicationOnCreate(app);
这个方法里面的onCreate就是调用了我们Application的OnCreate方法。
- public Application makeApplication(boolean forceDefaultAppClass,
- Instrumentation instrumentation) {
- if (mApplication != null) {
- return mApplication;
- }
- Application app = null;
- String appClass = mApplicationInfo.className;
- if (forceDefaultAppClass || (appClass == null)) {
- appClass = "android.app.Application";
- }
- try {
- java.lang.ClassLoader cl = getClassLoader();
- if (!mPackageName.equals("android")) {
- initializeJavaContextClassLoader();
- }
- ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
- app = mActivityThread.mInstrumentation.newApplication(
- cl, appClass, appContext);
- appContext.setOuterContext(app);
- } catch (Exception e) { }
- mActivityThread.mAllApplications.add(app);
- mApplication = app;
- //传进来的是null,所以这里不会执行,onCreate在上一层执行
- if (instrumentation != null) {
- try {
- instrumentation.callApplicationOnCreate(app);
- } catch (Exception e) {
- }
- }
- ...ignore some code...
- }
- return app;
- }
四、什么地方我们可以进行优化
五、冷启动与热启动的区别
2 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。热启动因为会从已有的进程中来启动,所以热启动就不会走 Application 这步了,而是直接走 MainActivity,所以热启动的过程不必创建和初始化 Application,因为一个应用从新进程的创建到进程的销毁,Application 只会初始化一次。
六、时间定义
- ThisTime: 最后一个启动的Activity的启动耗时
- 自己的所有Activity的启动耗时
- WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)
1.上一个Activity的onPause()——2.系统调用AMS耗时——3.第一个Activity(也许是闪屏页)启动耗时——4.第一个Activity的onPause()耗时——5.第二个Activity启动耗时
那么,ThisTime表示5(最后一个Activity的启动耗时)。TotalTime表示3.4.5总共的耗时(如果启动时只有一个Activity,那么ThisTime与TotalTime就是一样的)。WaitTime则表示所有的操作耗时,即1.2.3.4.5所有的耗时。
- public void reportFullyDrawnLocked() {
- final long curTime = SystemClock.uptimeMillis();
- if (displayStartTime != 0) {
- reportLaunchTimeLocked(curTime);
- }
- final ActivityStack stack = task.stack;
- if (fullyDrawnStartTime != 0 && stack != null) {
- final long thisTime = curTime - fullyDrawnStartTime;
- final long totalTime = stack.mFullyDrawnStartTime != 0
- ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
- }
七、为什么启动时会出现短暂黑屏或白屏的现象
八、冷启动优化
- <style name="AppTheme.Launcher">
- <item name="android:windowBackground">@drawable/bg</item>
- </style>
- <activity
- android:name=".activity.SplashActivity"
- android:screenOrientation="portrait"
- android:theme="@style/AppTheme.Launcher"
- >
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- //替换为原来的主题,在onCreate之前调用
- setTheme(R.style.AppTheme);
- super.onCreate(savedInstanceState);
- }
- <style name="AppTheme.Launcher">
- <item name="android:windowBackground">@null</item>
- </style>
- 延迟初始化
- 后台任务
- 界面预加载
- new Thread(){
- @Override
- public void run() {
- initNim();
- initImagePicker();
- initOkHttp();
- }
- }.start();
九、优化启动时间的一个很好用的工具 TraceView
- File file = new File(Environment.getExternalStorageDirectory(), "app7");
- Log.i(TAG, "onCreate: " + file.getAbsolutePath());
- Debug.startMethodTracing(file.getAbsolutePath());
- //对全局属性赋值
- mContext = getApplicationContext();
- mMainThread = Thread.currentThread();
- mMainThreadId = android.os.Process.myTid();
- mMainLooper = getMainLooper();
- mHandler = new Handler();
- initNim();
- initImagePicker();
- initOkHttp();
- Debug.stopMethodTracing();
- cd Desktop
- adb pull /storage/sdcard/app7.trace