A. Activity的启动流程
开发中我们会调用startActivity来启动一个Activity,最终会调到 startActivityForResult :
Instrumentation 是android系统里面的一套控制方法或者“钩子”。这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行。
Application和Activity的所有生命周期中,都会先调用Instrumentation提供的相应方法(如callActivityOnCreate,callApplicationOnCreate,newActivity,callActivityOnNewIntent)
Instrumentation.execStartActivity
ActivityTaskManager.getService()返回了一个IActivityTaskManager,拿到的是ATMS的代理对象,跨进程调用了ATMS的startActivity方法。
ActivityStarter.startActivityMayWait
ActivityStarter中做了一系列的调用(收集Intent信息,处理startActivityForResult,做一些校验判断等),最终进入startActivityUnchecked。
startActivityUnchecked
startActivityUnchecked中处理了关于Activity启动模式的处理,接着真正的resume我们的Activity
这里会先判断应用进程是否创建,创建了就进入 realStartActivityLocked ,没创建就会调用 ActivityManagerInternal.startProcess
①热启动realStartActivityLocked
接着看ActivityThread中接收并处理消息的handleMessage
前面realStartActivityLocked方法中通过addCallback,传入参数LaunchActivityItem。executeCallbacks方法中取出callbacks集合中的LaunchActivityItem,并调用其execute方法
handleLaunchActivity
②冷启动创建应用进程ActivityManagerInternal.startProcess
ActivityManagerInternal的实现类是AMS中的LocalService,AMS通过Socket与Zygote通信,fork出App进程,app进程创建后,会执行ActivityThread的main方法(Android进程入口方法)
调用ActivityThread的attach
[4]thread.bindApplication 这是一个binder通信的过程
ActivityThread内部的Handler接收到BIND_APPLICATION消息
回到上面attachApplicationLocked的mAtmInternal.attachApplication,调用ATMS的attachApplication
看到了似曾相识的realStartActivityLocked,后面流程和之前一样。Activity启动流程分析完毕。
总结
1)与Activity管理有关的类:
ActivityRecord :历史栈中的一个条目,代表一个Activity
TaskRecord :内部维护了一个ArrayList<ActivityRecord> ,来保存ActivityRecord
ActivityStack :内部维护了一个ArrayList<TaskRecord>,用来管理TaskRecord
ActivityStackSupervisor :用来管理ActivityStack的
2)Activity启动流程
B. Android应用程序启动流程总结
AMS主要功能:
AMS是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作。还负责启动或杀死应用程序的进程。
WMS主要功能:
为所有窗口分配Surface。
管理Surface的显示顺序、尺寸、位置。
管理窗口动画。
输入系统相关:WMS是派发系统按键和触摸消息的最佳人选,当接收到一个触摸事件,它需要寻找一个最合适的窗口来处理消息。
PWS主要功能:
PMS 用来管理跟踪所有应用APK,包括安装,卸载,解析,控制权限等。
SystemServer也是一个进程,包括AMS、PMS、WMS等等。
zygote意为“受精卵“。Android是基于Linux系统的,而在Linux中,所有的进程都是由init进程直接或者是间接fork出来的,zygote进程也不例外。
App进程是用户点击桌面icon时,通过Launcher进程请求SystemServer,再调用Zygote孵化的。
①点击启动一个App,Launcher进程采用Binder IPC向ActivityManagerService发起startActivity请求;
②ActivityManagerService接收到请求后,向zygote进程发送创建进程的请求;
③Zygote进程fork出新的子进程,即App进程;
④App进程通过Binder IPC向sytem_server进程发起绑定Application请求;
⑤system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheleLaunchActivity请求;
⑥App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
⑦主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。
⑧到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。
备注:
Launcher,PMS,Zygote,App进程是三个独立的进程,相互通信就需要使用进程间通信机制。与Zygote通信是使用的socket通信,Launcher,PMS,App进程间使用的是Binder机制。
C. Android的文件系统和分区表谁能给我详细地讲一讲
Android系统启动流程如下:
1、启动电源以及系统启动
当电源按下时引导芯片代码从预定义的地方(固化在ROM)开始执行。加载引导程序BootLoader到RAM,然后执行。
2、引导程序BootLoader
引导程序BootLoader是在Android操作系统开始运行前的一个小程序,它的主要作用使把系统OS拉起来并运行。
3、Linux内核启动
当内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。当内核完成系统设置时,它首先在系统文件中寻找init.rc文件,并启动init进程。
4、init进程启动
初始化和启动属性服务,并且启动Zygote进程。
5、Zygote进程启动
创建java虚拟机并为Java虚拟机注册JNI方法,创建服务器端Socket,启动SystemServer进程。
6、SystemServer进程启动
启动Binder线程池和SystemServiceManager,并且启动各种系统服务。
7、Launcher启动
被SystemServer进程启动的AMS会启动Launcher,Launcher启动会将已安装的快捷图标显示在界面上。
D. android activitythread 怎么启动
首先看一下Android系统的启动流程: bootloader 引导程序 kernel 内核 init init初始化(这个大家都比较熟悉了,不要多说) loads several daemons and services, including zygote see /init.rc and init..rc zygote 这个是占用时间最多的
E. android preload怎么用
首先看一下Android系统的启动流程:
bootloader
引导程序
kernel
内核
init
init初始化(这个大家都比较熟悉了,不要多说)
loads several daemons and services, including zygote
see /init.rc and init.<platform>.rc
zygote
这个是占用时间最多的,重点修理对象
preloads classes
装载了一千多个类,妈呀!!!
starts package manager 扫描package(下面详细介绍)
service manager
start services (启动多个服务)
从实际的测试数据来看,有两个地方时最耗时间的,一个是zygote的装载一千多个类和初始化堆栈的过程,用了20秒左右。另一个是扫描
/system/app,
/system/framework,
/data/app,
/data/app-private.
这几个目录下面的package用了大概10秒,所以我们重点能够修理的就是这两个老大的。
一、首先是调试工具的使用,可以测试哪些类和那些过程占用了多少时间,
主要工具为
stopwatch
Message loggers
grabserial
printk times
logcat
Android自带
bootchart
strace
AOSP的一部分(Eclair及以上版本)
使用例子
在init.rc中为了调试zygote
F. reboot+recovery,quiescent
摘要 项目中需要处理Android的原生开机动画,一定条件下还需要做到静默重启(android系统启动进入到桌面前,屏幕保持完全没有亮度的状态)。因为项目使用的rom是MTK平台支持,一开始并不知道Android 的QUIESCENT_REBOOT模式,所以自己想办法实现了此功能,详细见博客:基于Q的Android开机动画。因为后续Linux启用了SELinux增强了权限限制,原有的方案因为权限限制了文件的执行和读写,需要进行比较大的变动。后来,学习了下Android 的QUIESCENT_REBOOT模式,并把它用到了项目中解决了问题。这里介绍下QUIESCENT_REBOOT模式原理。
G. Android之Activity全面解析,有些知识点容易忘记
Activity作为安卓四大组件之一,是最重要也是用得最多的组件,涉及的知识点非常多,有些知识点平时开发很少用到,但在某些场景下需要特别注意,本文详细整理了Activity涉及的知识点,供开发参考。
针对Activity可以提出很多问题,如:
Activity 的生命周期?
Activity 之间的通信方式?
Activity 各种情况下的生命周期?
横竖屏切换时 Activity 的生命周期?
前台切换到后台,然后再回到前台时 Activity 的生命周期?
弹出 Dialog 的时候按 Home 键时 Activity 的生命周期?
两个Activity之间跳转时的生命周期?
下拉状态栏时 Activity 的生命周期?
Activity 与 Fragment 之间生命周期比较?
Activity 的四种 LaunchMode(启动模式)的区别?
Activity 状态保存与恢复?
Activity的转场动画有哪些实现方式?
Activity的生命周期中怎么获取控件宽高?
onNewIntent的执行时机?
如何连续退出多个Activity?
如何把Acitivty设置成Dialog样式 ,android:theme="@android:style/Theme.Dialog"
关于横竖屏切换的生命周期,对应不同的手机,由于厂商定制的原因,会有不同的效果,如设置了configChanges="orientation”在有些手机会执行各个生命周期,但有些手机却不会执行。
网上常见的结论如下:
但实际的测试如下:
可以看出,不同厂商的手机切屏生命周期会有差异。
从API 13以上,当设备在横竖切屏时,“屏幕尺寸”也会发生变化,因此为了杜绝切屏导致页面销毁重建,需要加上screenSize,使用设置4,即 android:configChanges="orientation|keyboardHidden|screenSize" .
Activity的四种状态如下:
在activity处于paused或者stoped状态下,如果系统内存紧张,可能会被销毁,当重回该activity时会重建,正常返回和被回收后返回的生命周期如下:
如果是回收后返回,onCreate的参数savedInstanceState不为空。
有哪些场景会触发onNewIntent回调呢?跟启动模式有关,首先该Activity实例已经存在,再次启动才可能触发。一种情况是启动模式是singleTask或者singleInstance,无论该activity在栈中哪个位置,都会触发onNewIntent回调,并且把上面其他acitivity移除,另一种情况是启动模式是singleTop或者以FLAG_ACTIVITY_SINGLE_TOP启动,并且该activity实例在栈顶,会触发onNewIntent,如果不在栈顶是重新创建的,不会触发。
在实际业务开发中,往往碰到需要连续退出多个activity实例,下面整理了几种常见方法:
● 发送特定广播
1、在需要处理连续退出的activity注册该特定广播;
2、发起退出的activity发送该特定广播;
3、接收到该广播的activity 调用finish结束页面。
● 递归退出
1、用startActivityForResult启动新的activity;
2、前一个页面finish时,触发onActvityResult回调,再根据requestCode和resultCode处理是否finish,达到递归退出的效果。
● FLAG_ACTIVITY_CLEAR_TOP
通过intent.setFlag(Intent.FLAG_ACTIVITY_CLEAR_TOP)启动新activity,如果栈中已经有该实例,则会把该activity之上的所有activity关闭,达到singleTop启动模式的效果。
● 自定义activity栈
1、自定义activity列表,新打开activity则加入栈中,关闭则移除栈;
2、需要退出多个activity时,则循环从栈中移除activity实例,并调用finish。
在讨论Activity启动模式经常提到任务栈,那到底什么是任务栈?
任务是一个Activity的集合,它使用栈的方式来管理其中的Activity,这个栈又被称为返回栈(back stack),栈中Activity的顺序就是按照它们被打开的顺序依次存放的。返回栈是一个典型的后进先出(last in, first out)的数据结构。下图通过时间线的方式非常清晰地向我们展示了多个Activity在返回栈当中的状态变化:
taskAffinity 任务相关性,可以用于指定一个Activity更加愿意依附于哪一个任务,在默认情况下,同一个应用程序中的所有Activity都具有相同的affinity, 名字为应用的包名。当然了,我们可以为每个 Activity 都单独指定 taskAffinity 属性(不与包名相同)。taskAffinity 属性主要和 singleTask 启动模式和 allowTaskReparenting 属性配对使用,在其他情况下没有意义。
taskAffinity 有下面两种应用场景:
分为显示启动和隐式启动。
(1)显示启动
直接指定待调整的Activity类名。
(2)隐式启动
Intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息,如果不匹配将无法启动目标 Activity。IntentFilter 的过滤信息有 action、category、data。
IntentFilter 需要注意的地方有以下:
● 一个 Activity 中可以有多个 intent-filter
● 一个 intent-filter 同时可以有多个 action、category、data
● 一个 Intent 只要能匹配任何一组 intent-filter 即可启动对应 Activity
● 新建的 Activity 必须加上以下这句,代表能够接收隐式调用
<category android:name="android.intent.category.DEFAULT" />
只要匹配一个action即可跳转,注意的是action要区分大小写。
规则:如果intent中有category,则所有的都能匹配到intent-filter中的category,intent中的category数量可用少于intent-filter中的。另外,单独设置category是无法匹配activity的,因为category属性是一个执行Action的附加信息。
intent不添加category会匹配默认的,即 “android:intent.category.DEFAULT”
如果上面例子,如果去掉intent.setAction("action_name"),则会抛出异常:
规则:类似action,但data有复杂的结构,只要匹配一个data并且与data中所有属性都一致就能匹配到Activity,只要有1个属性不匹配,都无法找到activity。
data的结构:
data 主要是由 URI 和 mimeType 组成的。
URI 可配置很多信息,的结构如下:
与url类似,例如:
mineType:指资源类型包括文本、图片、音视频等等,例如:text/plain、 image/jpeg、video/* 等
下面看下data匹配的例子:
只匹配scheme
只匹配scheme也是能匹配到activity的。
匹配scheme、host、port
将上面的data改为
匹配mineType
如果有mineType,则不能仅设置setData或setMineType了,因为setData会把mineType置为null,而setMineType会把data置为null,导致永远无法匹配到activity,要使用setDataAndType。
使用scheme的默认值contentfile
注意该方法需要在startAtivity方法或者是finish方法调用之后立即执行,不能延迟,但可以在子线程执行。
而在windowAnimationStyle中存在四种动画:
activityOpenEnterAnimation // 打开新的Activity并进入新的Activity展示的动画
activityOpenExitAnimation // 打开新的Activity并销毁之前的Activity展示的动画
activityCloseEnterAnimation //关闭当前Activity进入上一个Activity展示的动画
activityCloseExitAnimation // 关闭当前Activity时展示的动画
overridePendingTransition的方式比较生硬,方法也比较老旧了,不适用于MD风格,google提供了新的转场动画ActivityOptions,并提供了兼容包ActivityOptionsCompat。
我们知道在onCreate和onResume里面直接获取到控件宽高为0,那有什么办法获取到控件的实际宽高?只要有onWindowFocusChanged、view.post、ViewTreeObserver三种方式获取。
当用户点击桌面图标启动APP时,背后的流程如下:
我们看到的手机桌面是Launch程序的界面,点击应用图标会触发点击事件,调用startActivity(intent),然后通过Binder IPC机制,与ActivityManagerService(AMS)通讯,AMS执行一系列操作,最终启动目前应用,大概流程如下:
通过PackageManager的resolveIntent()收集跳转intent对象的指向信息,然后通过grantUriPermissionLocked()方法来验证用户是否有足够的权限去调用该intent对象指向的Activity。如果有权限,则在新的task中启动目标activity,如果发现没有进程,则先创建进程。
如果进程不存在,AMS会调用startProcessLocked创建新的进程,在该方法中,会通过socket的通讯方式通知zygote进程孵化新的进程并返回pid,在新的进程中会初始化ActivityThread,并依次调用Looper.prepareLoop()和Looper.loop()来开启消息循环。
创建好进程后下一步要将Application和进程绑定起来,AMS会调用上一节创建的ActivityThread对象的bindAppliction方法完成绑定工作,该方法会发送一条BIND_APPLICATION的消息,最终会调用handleBindApplication方法处理消息,并调用makeApplication方法处理消息,加载APP的classes到内存中。
通过前面的步骤,系统已经拥有了该Application的进程,后续的启动则是从已存在其他进程中启动Acitivity,即调用realStartAcitvityLocked,该方法会调用Application的主线程对象ActivityThread的sheleLaunchActivity方法,在方法中会发送LAUNCH_ACTIVITY到消息队列,最终通过handleLaunchActivity处理消息,完成Acitivty的启动。
Activity
Activity 的 36 大难点,你会几个?“建议收藏”
[译]Android Application启动流程分析
H. 全面解析Activity: Activity的工作过程
本文将对Activity的工作过程进行分析。
主要学习以下内容:
(1)系统内部是如何启动一个Activity的?
(2)新Activity的对象是何时创建的?
(3)Activity的各个生命周日是被系统何时回调的?
Activity启动流程分两种,一种是启动正在运行的app的Activity,即启动子Activity。如无特殊声明默认和启动该activity的activity处于同一进程。如果有声明在一个新的进程中,则处于两个进程。另一种是打开新的app,即为Launcher启动新的Activity。后边启动Activity的流程是一样的,区别是前边判断进程是否存在的那部分。
Activity的启动流程整体如下:
一.Activity启动阶段
(一)涉及到的概念
进程:Android系统为每个APP分配至少一个进程
IPC:跨进程通信,Android中采用Binder机制。
(二)涉及到的类
ActivityStack:Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。
ActivitySupervisor:管理 activity 任务栈
ActivityThread:ActivityThread 运行在UI线程(主线程),App的真正入口。
ApplicationThread:用来实现AMS和ActivityThread之间的交互。
ApplicationThreadProxy:ApplicationThread 在服务端的代理。AMS就是通过该代理与ActivityThread进行通信的。
IActivityManager:继承与IInterface接口,抽象出跨进程通信需要实现的功能
AMN:运行在server端(SystemServer进程)。实现了Binder类,具体功能由子类AMS实现。
AMS:AMN的子类,负责管理四大组件和进程,包括生命周期和状态切换。AMS因为要和ui交互,所以极其复杂,涉及window。
AMP:AMS的client端代理(app进程)。了解Binder知识可以比较容易理解server端的stub和client端的proxy。AMP和AMS通过Binder通信。
Instrumentation:仪表盘,负责调用Activity和Application生命周期。测试用到这个类比较多。
(三)涉及到的进程
(1)Launcher所在的进程
(2)AMS所在的SystemServer进程
(3)要启动的Activity所在的app进程
如果是启动根Activity,就涉及上述三个进程。
如果是启动子Activity,那么就只涉及AMS进程和app所在进程。
(四)具体流程
Launcher:Launcher通知AMS要启动activity。
startActivitySafely->startActivity->Instrumentation.execStartActivity()(AMP.startActivity)->AMS.startActivity
AMS:PMS的resoveIntent验证要启动activity是否匹配。如果匹配,通过ApplicationThread发消息给Launcher所在的主线程,暂停当前Activity(即Launcher)。
暂停完,在该activity还不可见时,通知AMS,根据要启动的Activity配置ActivityStack。然后判断要启动的Activity进程是否存在?
存在:发送消息LAUNCH_ACTIVITY给需要启动的Activity主线程,执行handleLaunchActivity
不存在:通过socket向zygote请求创建进程。进程启动后,ActivityThread.attach
判断Application是否存在,若不存在,通过LoadApk.makeApplication创建一个。在主线程中通过thread.attach方法来关联ApplicationThread。
在通过ActivityStackSupervisor来获取当前需要显示的ActivityStack。
继续通过ApplicationThread来发送消息给主线程的Handler来启动Activity (handleLaunchActivity)。
handleLauchActivity:调用了performLauchActivity,里边Instrumentation生成了新的activity对象,继续调用activity生命周期。
IPC过程:
双方都是通过对方的代理对象来进行通信。
1.app和AMS通信:app通过本进程的AMP和AMS进行Binder通信
2.AMS和新app通信:通过ApplicationThreadProxy来通信,并不直接和ActivityThread通信
(五)参考函数流程
Activity启动流程(从Launcher开始):
第一阶段: Launcher通知AMS要启动新的Activity(在Launcher所在的进程执行)
第二阶段:AMS先校验一下Activity的正确性,如果正确的话,会暂存一下Activity的信息。然后,AMS会通知Launcher程序pause Activity(在AMS所在进程执行)
第三阶段:pause Launcher的Activity,并通知AMS已经paused(在Launcher所在进程执行)
第四阶段:检查activity所在进程是否存在,如果存在,就直接通知这个进程,在该进程中启动Activity;不存在的话,会调用Process.start创建一个新进程(执行在AMS进程)
第五阶段: 创建ActivityThread实例,执行一些初始化操作,并绑定Application。如果Application不存在,会调用LoadedApk.makeApplication创建一个新的Application对象。之后进入Loop循环。(执行在新创建的app进程)
第六阶段:处理新的应用进程发出的创建进程完成的通信请求,并通知新应用程序进程启动目标Activity组件(执行在AMS进程)
第七阶段: 加载MainActivity类,调用onCreate声明周期方法(执行在新启动的app进程)
从另一个角度下图来概括:
下面简要介绍一下启动的过程:
Step 1. 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;
Step 2. ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;
Step 3. ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;
Step 4. ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
Step 5. 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;
Step 6. ActivityManagerServic调用ApplicationThread.scheleLaunchActivity接口,通知相应的进程执行启动Activity的操作;
Step 7. ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。
I. Android项目启动的具体流程
先分析需求,确定要有什么功能和要求,项目不大的话可以直接编代码,如果比较的的项目最后先用UML设计下,想清楚思路再动手写,编码过程中当然也少不了单元测试,调试程序的功夫。顺便提醒一下,Android3.0现在的份额还不大,多数都是2.2版本的,1.6的也不在少数,建议如果不是需要用到3.0的功能的话最好还是基于1.6版本的开发,增加兼容性
J. 怎样提高android启动速度
首先看一下Android系统的启动流程:
bootloader
引导程序
kernel
内核
init
init初始化(这个大家都比较熟悉了,不要多说)
loads several daemons and services, including zygote
see /init.rc and init.<platform>.rc
zygote
这个是占用时间最多的,重点修理对象
preloads classes
装载了一千多个类,妈呀!!!
starts package manager 扫描package(下面详细介绍)
service manager
start services (启动多个服务)
从实际的测试数据来看,有两个地方时最耗时间的,一个是zygote的装载一千多个类和初始化堆栈的过程,用了20秒左右。另一个是扫描
/system/app,
/system/framework,
/data/app,
/data/app-private.
这几个目录下面的package用了大概10秒,所以我们重点能够修理的就是这两个老大的。
一、首先是调试工具的使用,可以测试哪些类和那些过程占用了多少时间,
主要工具为
stopwatch
Message loggers
grabserial
printk times
logcat
Android自带
bootchart
strace
AOSP的一部分(Eclair及以上版本)
使用例子
在init.rc中为了调试zygote
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server改为
service zygote /system/xbin/strace -tt -o/data/boot.strace /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
method tracer*
ftrace*
详细使用可看提供的文档和网页介绍
上面的工具如果不用详细的分析不一定都用到,也可以使用logcat就可以,在代码中加一点计算时间和一些类的调试信息也可以达到很好效果。
二、zygote 装载1千多个类
首先,我们可以添加一点调试信息,以获得具体转载情况。
diff --git a/core/java/com/Android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 404c513..f2b573c 100644
--- a/core/java/com/Android/internal/os/ZygoteInit.java
+++ b/core/java/com/Android/internal/os/ZygoteInit.java
@@ -259,6 +259,8 @@ public class ZygoteInit {
} else {
Log.i(TAG, "Preloading classes...");
long startTime = SystemClock.uptimeMillis();
+ long lastTime = SystemClock.uptimeMillis();
+ long nextTime = SystemClock.uptimeMillis();
// Drop root perms while running static initializers.
setEffectiveGroup(UNPRIVILEGED_GID);
@@ -292,12 +294,24 @@ public class ZygoteInit {
if (Config.LOGV) {
Log.v(TAG, "Preloading " + line + "...");
}
+ //if (count%5==0) {
+ // Log.v(TAG, "Preloading " + line + "...");
+ //}
+ Log.v(TAG, "Preloading " + line + "...");
Class.forName(line);
+ nextTime = SystemClock.uptimeMillis();
+ if (nextTime-lastTime >50) {
+ Log.i(TAG, "Preloading " + line + "... took " + (nextTime-lastTime) + "ms.");
+ }
+ lastTime = nextTime;
+
if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
if (Config.LOGV) {
Log.v(TAG,
" GC at " + Debug.getGlobalAllocSize());
}
+ Log.i(TAG,
+ " GC at " + Debug.getGlobalAllocSize());
runtime.gcSoftReferences();
runtime.runFinalizationSync();
Debug.resetGlobalAllocSize();
上面+代表添加的代码,这样就可以很容易的得到在装载类的过程中具体装载了哪些类,耗费了多久。具体装载的类在文件platform/frameworks/base/ preloaded-classes
内容类似:
Android.R$styleable
Android.accounts.AccountMonitor
Android.accounts.AccountMonitor$AccountUpdater
Android.app.Activity
Android.app.ActivityGroup
Android.app.ActivityManager$MemoryInfo$1
Android.app.ActivityManagerNative
Android.app.ActivityManagerProxy
Android.app.ActivityThread
Android.app.ActivityThread$ActivityRecord
Android.app.ActivityThread$AppBindData
Android.app.ActivityThread$ApplicationThread
Android.app.ActivityThread$ContextCleanupInfo
Android.app.ActivityThread$GcIdler
Android.app.ActivityThread$H
Android.app.ActivityThread$Idler
而这个文件是由文件WritePreloadedClassFile.java中的WritePreloadedClassFile类自动生成
/**
* Writes /frameworks/base/preloaded-classes. Also updates
* {@link LoadedClass#preloaded} fields and writes over compiled log file.
*/
public class WritePreloadedClassFile
/**
* Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us.
*/
static final int MIN_LOAD_TIME_MICROS = 1250;//这个代表了装载时间小于1250us即1.25ms的类将不予装载,也许可以改这个参数减少一下类的装载
//这里可以看到什么样的类会被装载
A:启动必须装载的类,比如系统级的类
B:刚才说的装载时间大于1.25ms的类
C:被使用一次以上或被应用装载的类
仔细看看筛选类的具体实现,可以帮助我们认识哪些类比较重要,哪些可以去掉。
筛选规则是
第一 isPreloadable,
/**Reports if the given class should be preloaded. */
public static boolean isPreloadable(LoadedClass clazz) {
return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name);
}
意思是指除了EXCLUDED_CLASSES包含的类之外的所有系统装载的类。
EXCLUDED_CLASSES包含
/**
* Classes which we shouldn't load from the Zygote.
*/
private static final Set<String> EXCLUDED_CLASSES
= new HashSet<String>(Arrays.asList(
// Binders
"Android.app.AlarmManager",
"Android.app.SearchManager",
"Android.os.FileObserver",
"com.Android.server.PackageManagerService$AppDirObserver",
// Threads
"Android.os.AsyncTask",
"Android.pim.ContactsAsyncHelper",
"java.lang.ProcessManager"
));
目前是跟Binders跟Threads有关的不会被预装载。
第二 clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS装载时间大于1.25ms。
第三 names.size() > 1 ,既是被processes一次以上的。
上面的都是指的system class,另外还有一些application class需要被装载
规则是fromZygote而且不是服务
proc.fromZygote() && !Policy.isService(proc.name)
fromZygote指的除了com.Android.development的zygote类
public boolean fromZygote() {
return parent != null && parent.name.equals("zygote")
&& !name.equals("com.Android.development");
}
/除了常驻内存的服务
/**
* Long running services. These are restricted in their contribution to the
* preloader because their launch time is less critical.
*/
// TODO: Generate this automatically from package manager.
private static final Set<String> SERVICES = new HashSet<String>(Arrays.asList(
"system_server",
"com.google.process.content",
"Android.process.media",
"com.Android.bluetooth",
"com.Android.calendar",
"com.Android.inputmethod.latin",
"com.Android.phone",
"com.google.Android.apps.maps.FriendService", // pre froyo
"com.google.Android.apps.maps:FriendService", // froyo
"com.google.Android.apps.maps.LocationFriendService",
"com.google.Android.deskclock",
"com.google.process.gapps",
"Android.tts"
));
好了。要转载的就是这些类了。虽然preloaded- classes是在下载源码的时候已经确定了的,也就是对我们来说WritePreloadedClassFile类是没用到的,我们可以做的就是在 preloaded-classes文件中,把不预装载的类去掉,试了把所有类去掉,启动确实很快跳过那个地方,但是启动HOME的时候就会很慢了。所以最好的方法就是只去掉那些没怎么用到的,不过要小心处理。至于该去掉哪些,还在摸索,稍后跟大家分享。有兴趣的朋友可以先把preloaded- classes这个文件里面全部清空,启动快了很多,但在启动apk的时候会慢了点。当然了,也可以把Android相关的类全部去掉,剩下java的类,试过了也是可以提高速度。
三,系统服务初始化和package 扫描
在启动系统服务的init2()时会启动应用层(Java层)的所有服务。
public static void main(String[] args) {
System.loadLibrary("Android_servers");
init1(args); //init1 初始化,完成之后会回调init2()
}
在init2()中会启动一个线程来启动所有服务
public static final void init2() {
Log.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("Android.server.ServerThread");
thr.start();
}
class ServerThread extends Thread {
。。。
public void run() {
。。。
关键服务:
ServiceManager.addService("entropy", new EntropyService());
ServiceManager.addService(Context.POWER_SERVICE, power);
context = ActivityManagerService.main(factoryTest);
ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
PackageManagerService.main(context,
factoryTest != SystemServer.FACTORY_TEST_OFF);//apk扫描的服务
ServiceManager.addService(Context.ACCOUNT_SERVICE,
new AccountManagerService(context));
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
battery = new BatteryService(context);
ServiceManager.addService("battery", battery);
hardware = new HardwareService(context);
ServiceManager.addService("hardware", hardware);
AlarmManagerService alarm = new AlarmManagerService(context);
ServiceManager.addService(Context.ALARM_SERVICE, alarm);
ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context));
WindowManagerService.main(context, power,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);