🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
AMS的main函数将返回一个Context类型的对象,该对象在SystemServer中被其他服务大量使用。Context,顾名思义,代表了一种上下文环境(笔者觉得其意义和JNIEnv类似),有了这个环境,我们就可以做很多事情(例如获取该环境中的资源、Java类信息等)。那么AMS的main将返回一个怎样的上下文环境呢?来看以下代码: **ActivityManagerService.java::main** ~~~ publicstatic final Context main(int factoryTest) { AThreadthr = new AThread();//①创建一个AThread线程对象 thr.start(); ......//等待thr创建成功 ActivityManagerServicem = thr.mService; mSelf =m; //②调用ActivityThread的systemMain函数 ActivityThreadat = ActivityThread.systemMain(); mSystemThread= at; //③得到一个Context对象,注意调用的函数名为getSystemContext,何为System Context Contextcontext = at.getSystemContext(); context.setTheme(android.R.style.Theme_Holo); m.mContext= context; m.mFactoryTest= factoryTest; //ActivtyStack是AMS中用来管理Activity的启动和调度的核心类,以后再分析它 m.mMainStack = new ActivityStack(m, context,true); //调用BSS的publish函数,我们在第5章的BSS知识中介绍过了 m.mBatteryStatsService.publish(context); //另外一个service:UsageStatsService。后续再分析该服务 m.mUsageStatsService.publish(context); synchronized (thr) { thr.mReady = true; thr.notifyAll();//通知thr线程,本线程工作完成 } //④调用AMS的startRunning函数 m.startRunning(null, null, null, null); returncontext; } ~~~ 在main函数中,我们又列出了4个关键函数,分别是: - 创建AThread线程。虽然AMS的main函数由ServerThread线程调用,但是AMS自己的工作并没有放在ServerThread中去做,而是新创建了一个线程,即AThread线程。 - ActivityThread.systemMain函数。初始化ActivityThread对象。 - ActivityThread.getSystemContext函数。用于获取一个Context对象,从函数名上看,该Context代表了System的上下文环境。 - AMS的startRunning函数。 注意,main函数中有一处等待(wait)及一处通知(notifyAll),原因是: - main函数首先需要等待AThread所在线程启动并完成一部分工作。 - AThread完成那一部分工作后,将等待main函数完成后续的工作。 这种双线程互相等待的情况,在Android代码中比较少见,读者只需了解它们的目的即可。下边来分析以上代码中的第一个关键点。 1. AThread分析 (1) AThread分析 AThread的代码如下: **ActivityManagerService.java::AThread** ~~~ static class AThread extends Thread {//AThread从Thread类派生 ActivityManagerServicemService; booleanmReady = false; publicAThread() { super("ActivityManager");//线程名就叫“ActivityManager” } publicvoid run() { Looper.prepare();//看来,AThread线程将支持消息循环及处理功能 android.os.Process.setThreadPriority(//设置线程优先级 android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); //创建AMS对象 ActivityManagerService m = new ActivityManagerService(); synchronized (this) { mService= m;//赋值AThread内部成员变量mService,指向AMS notifyAll(); //通知main函数所在线程 } synchronized (this) { while (!mReady) { try{ wait();//等待main函数所在线程的notifyAll }...... } }...... Looper.loop();//进入消息循环 } } ~~~ 从本质上说,AThread是一个支持消息循环及处理的线程,其主要工作就是创建AMS对象,然后通知AMS的main函数。这样看来,main函数等待的就是这个AMS对象。 (2) AMS的构造函数分析 AMS的构造函数的代码如下: **ActivityManagerService.java::ActivityManagerService构造** ~~~ private ActivityManagerService() { FiledataDir = Environment.getDataDirectory();//指向/data/目录 FilesystemDir = new File(dataDir, "system");//指向/data/system/目录 systemDir.mkdirs();//创建/data/system/目录 //创建BatteryStatsService(以后简称BSS)和UsageStatsService(以后简称USS) //我们在分析PowerManageService时已经见过BSS了 mBatteryStatsService = new BatteryStatsService(new File( systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); mOnBattery = DEBUG_POWER ? true : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); //创建USS mUsageStatsService= new UsageStatsService(new File( systemDir, "usagestats").toString()); //获取OpenGl版本 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); //mConfiguration类型为Configuration,用于描述资源文件的配置属性,例如 //字体、语言等。后文再讨论这方面的内容 mConfiguration.setToDefaults(); mConfiguration.locale = Locale.getDefault(); //mProcessStats为ProcessStats类型,用于统计CPU、内存等信息。其内部工作原理就是 //读取并解析/proc/stat文件的内容。该文件由内核生成,用于记录kernel及system //一些运行时的统计信息。读者可在Linux系统上通过man proc命令查询详细信息 mProcessStats.init(); //解析/data/system/packages-compat.xml文件,该文件用于存储那些需要考虑屏幕尺寸 //的APK的一些信息。读者可参考AndroidManifest.xml中compatible-screens相关说明。 //当APK所运行的设备不满足要求时,AMS会根据设置的参数以采用屏幕兼容的方式去运行它 mCompatModePackages = new CompatModePackages(this, systemDir); Watchdog.getInstance().addMonitor(this); //创建一个新线程,用于定时更新系统信息(和mProcessStats交互) mProcessStatsThread = new Thread("ProcessStats") {...//先略去该段代码} mProcessStatsThread.start(); } ~~~ AMS的构造函数比想象得要简单些,下面回顾一下它的工作: - 创建BSS、USS、mProcessStats (ProcessStats类型)、mProcessStatsThread线程,这些都与系统运行状况统计相关。 - 创建/data/system目录,为mCompatModePackages(CompatModePackages类型)和mConfiguration(Configuration类型)等成员变量赋值。 AMS main函数的第一个关键点就分析到此,再来分析它的第二个关键点。 2. ActivityThread.systemMain函数分析 ActivityThread是Android Framework中一个非常重要的类,它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中运行的四大组件。 >[info] **注意**:应用进程指那些运行APK的进程,它们由Zyote 派生(fork)而来,上面运行了dalvik虚拟机。与应用进程相对的就是系统进程(包括Zygote和SystemServer)。 >另外,读者须将“应用进程和系统进程”与“应用APK和系统APK”的概念区分开来。APK的判别依赖其文件所在位置(如果apk文件在/data/app目录下,则为应用APK)。 该函数代码如下: **ActivityThread.java::systemMain** ~~~ public static final ActivityThread systemMain() { HardwareRenderer.disable(true);//禁止硬件渲染加速 //创建一个ActivityThread对象,其构造函数非常简单 ActivityThread thread = new ActivityThread(); thread.attach(true);//调用它的attach函数,注意传递的参数为true returnthread; } ~~~ 在分析ActivityThread的attach函数之前,先提一个问题供读者思考:前面所说的ActivityThread代表应用进程(其上运行了APK)的主线程,而SystemServer并非一个应用进程,那么为什么此处也需要ActivityThread呢? - 还记得在PackageManagerService分析中提到的framework-res.apk吗?这个APK除了包含资源文件外,还包含一些Activity(如关机对话框),这些Activity实际上运行在SystemServer进程中[^①]。从这个角度看,SystemServer是一个特殊的应用进程。 - 另外,通过ActivityThread可以把Android系统提供的组件之间的交互机制和交互接口(如利用Context提供的API)也拓展到SystemServer中使用。 * * * * * **提示**:解答这个问题,对于理解SystemServer中各服务的交互方式是尤其重要的。 * * * * * 下面来看ActivityThread的attach函数。 (1) attach函数分析 **ActivityThread.java::attach** ~~~ private void attach(boolean system) { sThreadLocal.set(this); mSystemThread= system;//判断是否为系统进程 if(!system) { ......//应用进程的处理流程 } else {//系统进程的处理流程,该情况只在SystemServer中处理 //设置DDMS时看到的systemserver进程名为system_process android.ddm.DdmHandleAppName.setAppName("system_process"); try { //ActivityThread的几员大将出场,见后文的分析 mInstrumentation = new Instrumentation(); ContextImpl context = new ContextImpl(); //初始化context,注意第一个参数值为getSystemContext context.init(getSystemContext().mPackageInfo, null, this); Application app = //利用Instrumentation创建一个Application对象 Instrumentation.newApplication(Application.class,context); //一个进程支持多个Application,mAllApplications用于保存该进程中 //的Application对象 mAllApplications.add(app); mInitialApplication = app;//设置mInitialApplication app.onCreate();//调用Application的onCreate函数 }......//try/catch结束 }//if(!system)判断结束 //注册Configuration变化的回调通知 ViewRootImpl.addConfigCallback(newComponentCallbacks2() { publicvoid onConfigurationChanged(Configuration newConfig) { ......//当系统配置发生变化(如语言切换等)时,需要调用该回调 } public void onLowMemory() {} public void onTrimMemory(int level) {} }); } ~~~ attach函数中出现了几个重要成员,其类型分别是Instrumentation类、Application类及Context类,它们的作用如下(为了保证准确,这里先引用Android的官方说明)。 - Instrumentation:Base class for implementingapplication instrumentation code. When running with instrumentation turned on,this class will be instantiated for you before any of the application code,allowing you to monitor all of the interaction the system has with the application.An Instrumentation implementation is described to the system through anAndroidManifest.xml's <instrumentation> tag。大意是:Instrumentaion是一个工具类。当它被启用时,系统先创建它,再通过它来创建其他组件。另外,系统和组件之间的交互也将通过Instrumentation来传递,这样,Instrumentation就能监测系统和这些组件的交互情况了。在实际使用中,我们可以创建Instrumentation的派生类来进行相应的处理。读者可查询Android中Junit的使用来了解Intrstrumentation的作用。本书不讨论Intrstrumentation方面的内容。 - Application:Base class for those who need tomaintain global application state. You can provide your own implementation byspecifying its name in your AndroidManifest.xml's <application> tag,which will cause that class to be instantiated for you when the process foryour application/package is created.大意是:Application类保存了一个全局的application状态。Application由AndroidManifest.xml中的<application>标签声明。在实际使用时需定义Application的派生类。 - Context:Interface to global informationabout an application environment. This is an abstract class whoseimplementation is provided by the Android system. It allows access toapplication-specific resources and classes, as well as up-calls forapplication-level operations such as launching activities, broadcasting andreceiving intents, etc.大意是:Context是一个接口,通过它可以获取并操作Application对应的资源、类,甚至包含于Application中的四大组件。 >[info] **提示**:此处的Application是Android中的一个概念,可理解为一种容器,它内部包含四大组件。另外,一个进程可以运行多个Application。 Context是一个抽象类,而由AMS创建的将是它的子类ContextImpl。如前所述,Context提供了Application的上下文信息,这些信息是如何传递给Context的呢?此问题包括两个方面: - Context本身是什么? - Context背后所包含的上下文信息又是什么? 下面来关注上边代码中调用的getSystemContext函数。 (2) getSystemContext函数分析 **ActivityThread.java::getSystemContext** ~~~ public ContextImpl getSystemContext() { synchronized(this) { if(mSystemContext == null) {//单例模式 ContextImplcontext = ContextImpl.createSystemContext(this); //LoadedApk是2.3引入的一个新类,代表一个加载到系统中的APK LoadedApkinfo = new LoadedApk(this, "android", context, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO); //初始化该ContextImpl对象 context.init(info, null, this); //初始化资源信息 context.getResources().updateConfiguration( getConfiguration(),getDisplayMetricsLocked( CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, false)); mSystemContext = context;//保存这个特殊的ContextImpl对象 } } returnmSystemContext; } ~~~ 以上代码无非是先创建一个ContextImpl,然后再将其初始化(调用init函数)。为什么函数名是getSystemContext呢?因为在初始化ContextImp时使用了一个LoadedApk对象。如注释中所说,LoadedApk是Android 2.3引入的一个类,该类用于保存一些和APK相关的信息(如资源文件位置、JNI库位置等)。在getSystemContext函数中初始化ContextImpl的这个LoadedApk所代表的package名为“android”,其实就是framework-res.apk,由于该APK仅供SystemServer使用,所以此处叫getSystemContext。 上面这些类的关系比较复杂,可通过图6-2展示它们之间的关系。 :-: ![](http://img.blog.csdn.net/20150803122554489?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图6-2 ContextImpl和它的“兄弟”们 由图6-2可知: - 先来看派生关系, ApplicationContentResolver从ConentResolver派生,它主要用于和ContentProvider打交道。ContextImpl和ContextWrapper均从Context继承,而Application则从ContextWrapper派生。 - 从社会关系角度看,ContextImpl交际面最广。它通过mResources指向Resources,mPackageInfo指向LoadedApk,mMainThread指向ActivityThread,mContentResolver指向ApplicationContentResolver。 - ActivityThread代表主线程,它通过mInstrumentation指向Instrumentation。另外,它还保存多个Application对象。 * * * * * **注意**:在函数中有些成员变量的类型为基类类型,而在图6-2中直接指向了实际类型。 * * * * * (3) systemMain函数总结 调用systemMain函数结束后,我们得到了什么? - 得到一个ActivityThread对象,它代表应用进程的主线程。 - 得到一个Context对象,它背后所指向的Application环境与framework-res.apk有关。 费了如此大的功夫,systemMain函数的目的到底是什么?一针见血地说: systemMain函数将为SystemServer进程搭建一个和应用进程一样的Android运行环境。这句话涉及两个概念。 - 进程:来源于操作系统,是在OS中看到的运行体。我们编写的代码一定要运行在一个进程中。 - Android运行环境:Android努力构筑了一个自己的运行环境。在这个环境中,进程的概念被模糊化了。组件的运行及它们之间的交互均在该环境中实现。 Android运行环境是构建在进程之上的。有Android开发经验的读者可能会发现,在应用程序中,一般只和Android运行环境交互。基于同样的道理,SystemServer希望它内部的那些Service也通过Android运行环境交互,因此也需为它创建一个运行环境。由于SystemServer的特殊性,此处调用了systemMain函数,而普通的应用进程将在主线程中调用ActivityThread的main函数来创建Android运行环境。 另外,ActivityThread虽然本意是代表进程的主线程,但是作为一个Java类,它的实例到底由什么线程创建,恐怕不是ActivityThread自己能做主的,所以在SystemServer中可以发现,ActivityThread对象由其他线程创建,而在应用进程中,ActivityThread将由主线程来创建。 3. ActivityThread.getSystemContext函数分析 该函数在上一节已经见过了。调用该函数后,将得到一个代表系统进程的Context对象。到底什么是Context?先来看如图6-3所示的Context家族图谱。 * * * * * **注意**:该族谱成员并不完全。另外,Activity、Service和Application所实现的接口也未画出。 * * * * * :-: ![](http://img.blog.csdn.net/20150803122622508?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图6-3 Context家族图谱 由图6-3可知: - ContextWrapper比较有意思,其在SDK中的说明为“Proxying implementation ofContext that simply delegates all of its calls to another Context. Can besubclassed to modify behavior without changing the original Context.”大概意思是:ContextWrapper是一个代理类,被代理的对象是另外一个Context。在图6-3中,被代理的类其实是ContextImpl,由ContextWrapper通过mBase成员变量指定。读者可查看ContextWrapper.java,其内部函数功能的实现最终都由mBase完成。这样设计的目的是想把ContextImpl隐藏起来。 - Application从ContextWrapper派生,并实现了ComponentCallbacks2接口。Application中有一个LoadedApk类型的成员变量mLoadedApk。LoadedApk代表一个APK文件。由于一个AndroidManifest.xml文件只能声明一个Application标签,所以一个Application必然会和一个LoadedApk绑定。 - Service从ContextWrapper派生,其中Service内部成员变量mApplication指向Application(在AndroidManifest.xml中,Service只能作为Application的子标签,所以在代码中Service必然会和一个Application绑定)。 - ContextThemeWrapper重载了和Theme(主题)相关的两个函数。这些和界面有关,所以Activity作为Android系统中的UI容器,必然也会从ContextThemeWrapper派生。与Service一样,Activity内部也通过mApplication成员变量指向Application。 对Context的分析先到这里,再来分析第三个关键函数startRunning。 4. AMS的startRunning函数分析 **ActivityManagerService.java::startRunning** ~~~ //注意调用该函数时所传递的4个参数全为null public final void startRunning(String pkg, Stringcls, String action, String data) { synchronized(this) { if (mStartRunning) return; //如果已经调用过该函数,则直接返回 mStartRunning = true; //mTopComponent最终赋值为null mTopComponent = pkg != null && cls != null ? new ComponentName(pkg, cls) : null; mTopAction = action != null ? action : Intent.ACTION_MAIN; mTopData = data; //mTopData最终为null if(!mSystemReady) return; //此时mSystemReady为false,所以直接返回 } systemReady(null);//这个函数很重要,可惜不在本次startRunning中调用 } ~~~ startRunning函数很简单,此处不赘述。 至此,ASM 的main函数所涉及的4个知识点已全部分析完。下面回顾一下AMS 的main函数的工作。 5. ActivityManagerService的main函数总结 AMS的main函数的目的有两个: - 首先也是最容易想到的目的是创建AMS对象。 - 另外一个目的比较隐晦,但是非常重要,那就是创建一个供SystemServer进程使用的Android运行环境。 根据目前所分析的代码,Android运行环境将包括两个成员:ActivityThread和ContextImpl(一般用它的基类Context)。 图6-4展示了在这两个类中定义的一些成员变量,通过它们可看出ActivityThread及ContextImpl的作用。 :-: ![](http://img.blog.csdn.net/20150803122653459?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图6-4 ActivityThread和ContextImpl的部分成员变量 由图6-4可知: - ActivityThread中有一个mLooper成员,它代表一个消息循环。这恐怕是ActivityThread被称做“Thread”的一个直接证据。另外,mServices用于保存Service,Activities用于保存ActivityClientRecord,mAllApplications用于保存Application。关于这些变量的具体作用,以后遇到时再说。 - 对于ContextImpl,其成员变量表明它和资源、APK文件有关。 AMS的main函数先分析到此,至于其创建的Android运行环境将在下节分析中派上用场。 接下来分析AMS的第三个调用函数setSystemProcess。 [^①]:实际上,SettingsProvider.apk也运行于system_server进程中。