AMS对象随系统进程启动而构建,随着系统进程退出而消亡,能够说,AMS与系统进程共存亡。java
先上一张总的启动时序图:android
上图分为三个步骤:git
SystemServer是咱们理解Android系统进程的入口,它的初始化是从Native层开始的:Zygote从Native层调用SystemServer的main()函数,便开始了SystemServer的初始化。初始化很重要的一个步骤就是建立系统进程的运行环境,即建立一个SystemContext,调用关系以下所示:github
SystemServer.main() // Zygote会从Native层调用该方法,进入SystemServer的执行代码
└── SystemServer.run() // SystemServer一旦运行起来,就一直循环处理消息队列中的消息
└── SystemServer.createSystemContext() // 建立SystemContext
SystemContext究竟是什么呢?说到底,它仍是一个Context类型的对象,须要借助于ActivityThread才能获取到:shell
// SystemServer.createSystemContext() private void createSystemContext() { ActivityThread activityThread = ActivityThread.systemMain(); mSystemContext = activityThread.getSystemContext(); mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); }
ActivityThread.systemMain()函数用于建立系统进程的主线程,方法主体很简单,建立了一个新的ActivityThread对象,并调用了attach()方法,输入参数是true,表示须要将其绑定到系统进程。数据库
应用进程建立ActivityThread对象是经过ActivityThread.main()函数完成的。因为系统进程的特殊性,专辟了一个systemMain()函数给系统进程。编程
public static ActivityThread systemMain() { ... // 省略硬件渲染相关配置的代码 ActivityThread thread = new ActivityThread(); thread.attach(true); return thread; }
接下来,咱们来着重分析一下ActivityThread.attach()函数:数据结构
private void attach(boolean system) { sCurrentActivityThread = this; mSystemThread = system; if (!system) { ... // 绑定应用进程,本例仅讨论绑定系统进程,故省略之 } else { // 设置进程名为system_process android.ddm.DdmHandleAppName.setAppName("system_process", UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( this, getSystemContext().mPackageInfo); mInitialApplication = context.mPackageInfo.makeApplication(true, null); mInitialApplication.onCreate(); } catch (Exception e) { ... // 省略抛出异常的代码 } } // 设置与输出日志相关的Dropbox DropBox.setReporter(new DropBoxReporter()); ViewRootImpl.addConfigCallback( ... // ); }
在上面的函数实现中,会建立几个很重要的对象:多线程
mInstrumentation: 工具类,主要用于测试,与AndroidManifest.xml中<instrumentation>对应;app
context: Application的运行环境,建立它的目的是为了建立下面的Application对象。建立这个context须要传入一个LoadedApk类型的对象,经过ActivityThread.getSystemContext()函数即可获取:
public ContextImpl getSystemContext() { synchronized (this) { if (mSystemContext == null) { mSystemContext = ContextImpl.createSystemContext(this); } return mSystemContext; } }
这里是第一次调用getSystemContext()函数,因此mSystemContext为null,进而会经过ContextImpl.createSystemContext()函数建立一个新的对象:
// ContextImpl.createSystemContext() static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetricsLocked()); return context; }
上述函数首先会建立一个LoadedApk的对象,LoadedApk表示一个装载到内存的Apk,对于SystemContext,这个Apk就是framework-res.apk; 而后,建立一个ContextImpl的对象,进一步初始化资源相关的配置; 最终,返回的context就是SystemContext。
兜兜转转弄了一圈,终于把SystemContext给建立好了,系统进程好好运行就行了,为何要大费周张的搞一个运行环境Context出来呢? 操做系统运行基本单位是进程,咱们写的任何Android代码最终都要落到一个实际的进程中去执行。然而,Android有意弱化了进程的概念,咱们在写Android应用程序的时候,基础的概念都是运行环境(Context),而不是去考虑进程中有什么可使用。 Android对待系统进程,也像对待普通的应用进程同样,都须要构建一个运行环境,就是Context。在构建AMS对象时,会将SystemContext传入,经过这个特殊的Context,AMS就能获取运行时所须要各类信息。
咱们经过一张类图来总结一下,与系统进程运行环境初始化相关的各个类之间的关系:
总结初始化环境的三个步骤:
Android要为应用进程创造一个运行环境,一样也须要为系统进程创造一个运行环境,在系统进程启动伊始,这个运行环境就须要建立完毕,这个环境就是咱们所说的SystemContext;
SystemServer会建立一个ActivityThread对象,表明系统进程的主线程,系统进程的入口为SysMain(),在ActivityThread对象构建的过程当中,又会建立Instrumentation对象和framework-res.apk的LoadedApk对象,再经过LoadedApk建立Application对象;
在ActivityThread对象构建完毕后,SystemServer即可获取到系统进程的运行环境了,即SystemContext,这是ActivityThread经过ContextImpl建立而成的。
在Android起机的过程当中,系统服务是相互影响的,因此有启动顺序的前后之分,譬如BatteryService,WindowManagerService就须要在ActivityManagerService建立以后才能建立。还有一些系统事件,譬如BOOT_COMPLETED广播,须要在系统彻底启动以后才能发出。 Android为系统服务封装了SystemService类,设计了系统服务的生命周期:
public abstract class SystemService { // 阶段 1: 等待显示设备准备完毕 // 这个阶段,Installer, AMS, PowerManagerService, DisplayManagerService已经构建完毕 public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // 阶段 2: 锁屏服务已经准备完毕 // 这个阶段,大部分系统服务已经构建完毕。其余服务能够获取锁屏相关的数据了,譬如锁屏密码等 public static final int PHASE_LOCK_SETTINGS_READY = 480; // 阶段 3: 系统服务已经准备完毕 // 这个阶段,大部分系统服务已经构建完毕,PackageManagerService,PowerManagerService已经可以提供服务 public static final int PHASE_SYSTEM_SERVICES_READY = 500; // 阶段 4: ActivityManagerService已经可以提供服务了 // 这个阶段,获取ContentProvider、发送广播等AMS相关的功能已经能够用了 public static final int PHASE_ACTIVITY_MANAGER_READY = 550; // 阶段 5: 已经能够启动应用程序了 // 这个阶段,用户界面已经启动,数据链接、音频等服务都已可用 public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600; // 阶段 6: 系统起机完成 public static final int PHASE_BOOT_COMPLETED = 1000; public abstract void onStart(); public void onBootPhase(int phase) {} // ... 省略其余函数 }
部分系统服务的初始化依赖于当前系统已经起机到什么阶段,当系统服务启动时,onStart()函数会被调用; 系统启动到必定的阶段,onBootPhase()函数会被调用。全部系统服务的建立和生命周期的管理都是由SystemServiceManager这个类完成的。
本文中要分析的AMS,它并无直接继承SystemService,而是经过内部类Lifecycle来继承实现的, AMS.Lifecycle很是简单,就是调用了AMS的构造函数和start()函数,是一个间接初始化AMS的过程。
咱们经过类图来总结一下SystemServiceManager, SystemService以及AMS三者之间的关系:public static final class Lifecycle extends SystemService { private final ActivityManagerService mService; // 构造函数会被SystemServiceManager反射调用 public Lifecycle(Context context) { super(context); mService = new ActivityManagerService(context); } // 在Lifecycle对象构造完成后,这个函数会被回调 @Override public void onStart() { mService.start(); } public ActivityManagerService getService() { return mService; } }
SystemService是系统服务的抽象类,封装了onStart()和onBootPhase()等生命周期函数供SystemServiceManager回掉;
AMS并非直接继承SystemService,而是经过内部类Lifecycle间接完成了系统服务启动的生命周期;
SystemServiceManager管理了多个SystemService。
SystemServer在完成一些简单的初始化后,就须要启动系统服务了,最重要的一系列服务是在SystemServer.startBootstrapServices() 这个函数中启动的,BootstrapServices的命名也很贴切,表示要启动一些”引导服务”,这些服务直接影响到其余服务的启动。
启动AMS以前,须要先链接installd进程。在系统进程(system_process)中,对应的服务就Installer, 经过Installer这个服务,就能完成一些重要目录的建立,譬如/data/user。
启动AMS。因而可知AMS的重要性,Android第二个启动的系统服务就是AMS。 实际上,这里经过SystemServcieManager来启动的是AMS.Lifecycle,AMS的真正初始化工做是由AMS.Lifecyle间接完成的。
启动PowerManagerService,这也是很是重要的一个系统服务。AMS也须要使用PowerManagerService的服务, 譬如,在启动Activity时,要避免系统进入休眠状态,就须要获取WakeLock。
这一步启动Lights、 DisplayManager、 PackageManager这些系统服务。
调用AMS.setSystemProcess()将当前进程设置为系统进程。为何在SystemServer中须要调用AMS的方法来设置当前进程的信息呢? 由于AMS的职责之一就是维护全部进程的状态,不论是应用进程仍是系统进程,都是AMS的管辖范围。
上面第2条AMS对象构建时,要初始化的内容很是多,大体能够分红两类:
在第5步中, 经过AMS对象调用了setSystemProcess()函数,目的是为了将当前进程(system_process)设置为系统进程:
经过ServiceManager向系统注册一些重要的服务。诸如meminfo、gfxinfo、dbinfo等信息都是由系统进程维护的, 能够经过adb shell dumpsys
命令输出。
ApplicationInfo包含了一个应用程序的信息,这些信息从AndroidManifest.xml的<application>标签中解析出来,譬如进程名、版本号、使用的主题等,那么,经过android这个包名,获取的ApplicationInfo天然就是Android系统这个应用程序的信息。
每个普通的应用程序都会有一个AndroidManifest.xml文件,这个应用程序运行的环境,就是咱们所说的”应用进程”; 有一个特殊的应用程序,具有更多的特权,这个应用程序的运行环境就是”系统进程”。 android就是这个特殊应用程序的包名,其所对应的<application>标签订义在frameworks/base/core/res/AndroidManifest.xml中,最终会编译在framework-res.apk中。
不管是应用进程仍是系统进程,都有主线程,ActivityThread就是Android定义的主线程类。 AMS中的mSystemThread对象就是ActivityThread的实例,表示这是系统进程的主线程。 经过mSystemThread.installSystemApplicationInfo()这个函数调用,ApplicationInfo和ClassLoader就被设置到了 LoadedApk中,ApplicationInfo与LoadedApk的关系咱们后文再描述。
ProcessRecord这个类用于描述一个运行的进程,AMS管理着全部ProcessRecord的状态,包括系统进程的ProcessRecord。 系统进程的ProcessRecord几个重要的属性值:
AMS经过mPidSelfLocked这个映射表来记录全部的ProcessRecord,(键 => 值)关系是(PID => ProcessRecord)。 在建立一个ProcessRecord以后,就须要集中对进程的信息进行调整了,AMS中管理进程的函数就两类:updateLruProcessLocked()用于更新最近使用进程列表,updateOomAdjLocked()用户更新进程的OOM ADJ。
在引导服务(BootstrapServices)启动完毕后,SystemServer就开始启动核心服务(CoreServices),包括电池服务(BatteryService),用户行为统计服务(UsageStatsService)等; 最后,就是启动其余服务了,很是之多,再也不此列举。部分服务在启动时,仍须要与AMS关联,譬如: AMS须要与WindowManagerService关联。AMS在这个过程之中有两个关键的步骤:
3.1 对于installSystemProviders的分析
关键函数 generateApplicationProvidersLocked()
该函数基于AndroidManifest.xml文件的定义, 生成一个应用程序的Provider信息, 以方便AMS对Provider进行管理,
AMS对Provider的管理方式:
AMS中使用ContentProviderRecord来管理一个ContentProvider。ProviderInfo, ApplicationInfo, 运行ContentProvider的ProcessRecord等信息都保存在ContentProviderRecord中。
AMS维护了一个ProviderMap, 支持从Authority或CompnentName到ContentProviderRecord的映射; AMS也维护了各类各样的ProcessRecord, 譬如: 前台进程, 内存常驻进程, 最近使用的进程等。 当一个ContentProvider绑定到具体的进程时, 就会添加到ProcessRecord中维护的mPubProviders的映射表中。因此, ProcessRecord.mPubProviders就表示进程所拥有的ContentProvider。
如今,咱们再来看这块函数的逻辑:
首先, 须要确保ProcessRecord可以容纳必定数量的Provider, 前面经过PackageManager找到的ProviderInfo可能会关联到ProcessRecord中,因此, 在mPubProvider上已有容量的基础上, 再扩容的大小为找到的ProviderInfo的数量。
而后, 对找到的ProviderInfo列表进行遍历, 若有须要, 则新建一个ContentProviderRecord对象, 将其添加到mProviderMap中以方便AMS管理;同时, 也须要将其添加到PrcoessRecord.mPubProviders中。
最后, 因为可能新增其余APK中的ProviderInfo, 因此须要确保对APK进行dex优化。
关键函数: ActivityThread.installSystemProviders()
将一个ProviderInfo绑定到ProcessRecord后, AMS中就有了Provider的信息了, 但这时Provider还不能工做, 由于真正的ContentProvider还未建立, 该函数的就是将上面找到的ProviderInfo装载到系统进程之中
全部ContentProvider的建立都须要通过installContentProvider()函数, 它接收两个参数, 一个是进程的运行环境Context, 一个是 ProviderInfo列表; 对系统进程而言, 运行环境就是mInitialApplication。该函数中使用了ContentProviderHodler这个类,它实现了Parcelable接口, 一般表示这类数据结构须要跨进程传递, 应用进程中生成的ContentProvider须要向系统进程注册后才能使用, 因此, 须要将ContentProvider的信息从应用进程传递到系统进程, 这就用到了ContentProviderHolder进行数据封装。
基于ProviderInfo生成的ContentProviderHolder的函数实现是installProvider():
3.2对于systemReady的分析
mSystemReady表示系统进程是否准备完毕, 因为systemReady()函数会被屡次调用到,并且多线程并行,因此一旦mSystemReady为true,表示再也不须要执行下面的逻辑了,直接回调函数入参goingCallback,这个回调函数咱们放到后面分析;
进入这一步,表示mSystemReady为false,第一次进入systemReady()函数时,就是这种场景。这里会恢复最近任务列表;
涉及到PRE_BOOT_COMPLETED广播的处理。这个广播在BOOT_COMPLETED广播以前发送,并且只发给系统应用。系统应用收到该广播后,也应该标注已经处理过该广播,下次不用再派发过来。设计PRE_BOOT_COMPLETED广播的目的,是为了应对系统升级的场景:当从旧的版本升级时,系统应用可能有一些清除数据的须要,系统升级后的第一次起机时,就会向接收者派发这个广播。
PRE_BOOT_COMPLETED的派发实如今deliverPreBootCompleted()函数中,本文不展开分析。须要知道这里有两个控制变量:
通过这3步mSystemReady就被设置为true了,再次调用该systemReady()函数,就会进入第1步的逻辑
在AMS彻底准备就绪以前,就可能有一些进程已经启动,在这里须要进行一个检查,若是非peristent的进程先于AMS启动,那么就须要杀掉这些进程。 注意,这里所指的进程是AMS管理的进程(系统进程和应用进程),Native进程并不在AMS的管辖范围。
在该代码片断的最后,输出了一行Event Log:
boot_process_ams_ready: xxx
进行日志分析时,能够根据这行日志信息断定AMS已经准备就绪,其余应用进程能够启动了。由于只有当AMS就绪后,才能开始管理应用进程。
AMS准备就绪是个关键节点,在此以后,不少其余服务就能够开始进入准备就绪的状态了,其实就是调用这些系统服务的systemReady()函数。
systemReady()函数的最后部分,一部分工做是发送通知:“当前用户已经进入使用状态了”; 另外一部分工做就是启动桌面,有两处关键调用: startHomeActivityLocked()和mStackSupervisor.resumeTopActivitiesLocked()
至此,systemReady()函数的执行逻辑已经分析完了,一共经历了4个步骤
systemReady()函数调用完成以后,桌面就可见了,用户就真正见到了Android系统的可操做界面
在桌面启动后,桌面进程主线程的消息队列进入空闲状态,此时会发起跨进程调用AMS.activityIdle(),紧接着会引起下面的调用关系:
AMS.finishBooting()函数主要进行ABI检查,注册一些系统广播,启动以前被抑制启动的进程,发送ACTION_BOOT_COMPLETED广播,调度性能统计功能。
总结:AMS.activityIdle()
└── ActivityStackSupervisor.activityIdleInternalLocked()
└── ActivityStackSupervisor.checkFinishBootingLocked()
└── AMS.postFinishBooting() // 向主线程抛出FINISH_BOOTING_MSG消息
└── AMS.MainHandler.handleMessage(FINISH_BOOTING_MSG)
└── AMS.finishBooting()
系统进程启动过程当中与AMS相关的逻辑,整体而言,能够分为三步:
初始化系统进程的运行环境。所谓运行环境,就是指的Context,Context蕴含了代码执行过程当中所须要的信息,包括进程信息、包信息、资源信息等等。Android有意弱化进程的概念,强化Context的概念,在Android编程时,必定避免不了与Context打交道。对于系统进程而言,Context有必定的特殊性,因此单独造了一个SystemContext。
初始化AMS对象。AMS对象在系统进程构建,做为最重要的系统服务,AMS初始化要作的事情很是多。因为各类系统服务耦合在一块,相互影响,Android设计了“系统进程启动阶段”这个概念,就像一个简单的状态机,只有进入的某个阶段,才能作某些操做。譬如,只有进入PHASE_ACTIVITY_MANAGER_READY,AMS才能正常工做,这时才能够进行派发广播、管理进程等操做。
由于系统进程也在AMS的管辖范围以内,因此,AMS对象构建后有一个重要的任务,就是设置系统进程的一些属性。这时,会将第一个启动的应用frameworks-res.apk的信息装载到系统进程中,建立一个系统进程的ProcessRecord对象以便AMS管理。
AMS初始化的配套工做。这里所谓配套工做是指,系统要彻底运行起来,还须要经由AMS进行一系列的运做:系统设置SettingsProvider会经由AMS装载到系统进程中;其余系统服务在AMS准备就绪后,也会进入就绪状态,表示能够正常工做;桌面会经由AMS启动,最终ACTION_BOOT_COMPLETED广播发出。
参考文章:http://duanqz.github.io/2016-07-15-AMS-LaunchProcess#3-%E6%80%BB%E7%BB%93