码迷,mamicode.com
首页 > 其他好文 > 详细

AMS

时间:2016-04-16 18:22:25      阅读:285      评论:0      收藏:0      [点我收藏+]

标签:

 1    以桌面启动一个应用Activity为例,onClick事件后,会调用startActivityForResult(Intent, int)
public void startActivityForResult(Intent intent, int requestCode, Bundle options) { 2 if (mParent == null) {
 //Activity启动执行交由Instrumentation对象去处理
3 Instrumentation.ActivityResult ar = 4 mInstrumentation.execStartActivity(
   //mMainThread 在attach方法中被设置,当ActivityThread PerformLauchActivity,调用attach把ActivityThread.this传送过来
               //mMainThread.getApplicationThread()它是一个进程通信服务端存根对象,提供了很多操作ActivityThread的方法,它继承了ApplicationThreadNative       
5 this, mMainThread.getApplicationThread(), mToken, this, 6 intent, requestCode, options); 7 if (ar != null) { 8 mMainThread.sendActivityResult( 9 mToken, mEmbeddedID, requestCode, ar.getResultCode(), 10 ar.getResultData()); 11 } 12 if (requestCode >= 0) { 13 // If this start is requesting a result, we can avoid making 14 // the activity visible until the result is received. Setting 15 // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the 16 // activity hidden during this time, to avoid flickering. 17 // This can only be done when a result is requested because 18 // that guarantees we will get information back when the 19 // activity is finished, no matter what happens to it. 20 mStartedActivity = true; 21 } 22 23 final View decor = mWindow != null ? mWindow.peekDecorView() : null; 24 if (decor != null) { 25 decor.cancelPendingInputEvents(); 26 } 27 // TODO Consider clearing/flushing other event sources and events for child windows. 28 } else { 29 if (options != null) { 30 mParent.startActivityFromChild(this, intent, requestCode, options); 31 } else { 32 // Note we want to go through this method for compatibility with 33 // existing applications that may have overridden it. 34 mParent.startActivityFromChild(this, intent, requestCode); 35 } 36 } 37 }

技术分享

 技术分享

AMS由ActivityManagerNative(以后简称AMN)类派生,并实现Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,实现了IActivityManager接口。

 客户端使用ActivityManager类。由于AMS是系统核心服务,很多API不能开放供客户端使用,所以设计者没有让ActivityManager直接加入AMS家族。在ActivityManager类内部通过调用AMN的getDefault函数得到一个ActivityManagerProxy对象,通过它可与AMS通信。

1.1 初识ActivityManagerService

AMS由SystemServer的ServerThread线程创建,提取它的调用轨迹,代码如下:

[-->SystemServer.java::ServerThread的run函数]

//①调用main函数,得到一个Context对象

context =ActivityManagerService.main(factoryTest);

 

//②setSystemProcess:这样SystemServer进程可加到AMS中,并被它管理

ActivityManagerService.setSystemProcess();

 

//③installSystemProviders:将SettingsProvider放到SystemServer进程中来运行

ActivityManagerService.installSystemProviders();

 

//④在内部保存WindowManagerService(以后简称WMS)

ActivityManagerService.self().setWindowManager(wm);

 

//⑤和WMS交互,弹出“启动进度“对话框

ActivityManagerNative.getDefault().showBootMessage(

             context.getResources().getText(

               //该字符串中文为:“正在启动应用程序”

               com.android.internal.R.string.android_upgrading_starting_apps),

              false);

 

//⑥AMS是系统的核心,只有它准备好后,才能调用其他服务的systemReady

//注意,有少量服务在AMS systemReady之前就绪,它们不影响此处的分析

ActivityManagerService.self().systemReady(newRunnable() {

    publicvoid run() {

   startSystemUi(contextF);//启动systemUi。如此,状态栏就准备好了

    if(batteryF != null) batteryF.systemReady();

    if(networkManagementF != null) networkManagementF.systemReady();

    ......

    Watchdog.getInstance().start();//启动Watchdog

    ......//调用其他服务的systemReady函数

}

 

1.1.1  ActivityManagerService main分析

[-->ActivityManagerService.java::main]

 AThread thr = new AThread();//①创建一个AThread线程对象
    thr.start();
    ......//等待thr创建成功
    ActivityManagerService m = thr.mService;
    mSelf =m;
    //②调用ActivityThread的systemMain函数
    ActivityThread at = ActivityThread.systemMain();
    mSystemThread= at;
 
    //③得到一个Context对象,注意调用的函数名为getSystemContext,何为System Context
    Context context = 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);
       
   return context;
}

 在main函数中,我们又列出了4个关键函数,分别是:

  创建AThread线程。虽然AMS的main函数由ServerThread线程调用,但是AMS自己的工作并没有放在ServerThread中去做,而是新创建了一个线程,即AThread线程。

·  ActivityThread.systemMain函数。初始化ActivityThread对象。

·  ActivityThread.systemMain函数。初始化ActivityThread对象。

·  ActivityThread.getSystemContext函数。用于获取一个Context对象,从函数名上看,该Context代表了System的上下文环境。

·  AMS的startRunning函数。

注意,main函数中有一处等待(wait)及一处通知(notifyAll),原因是:

·  main函数首先需要等待AThread所在线程启动并完成一部分工作。

·  AThread完成那一部分工作后,将等待main函数完成后续的工作。

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类型)等成员变量赋值。

2.  ActivityThread.systemMain函数分析

 

ActivityThread是Android Framework中一个非常重要的类,它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中运行的四大组件。

注意应用进程指那些运行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
   return thread;
 }

 

在分析ActivityThread的attach函数之前,先提一个问题供读者思考:前面所说的ActivityThread代表应用进程(其上运行了APK)的主线程,而SystemServer并非一个应用进程,那么为什么此处也需要ActivityThread呢?

·  还记得在PackageManagerService分析中提到的framework-res.apk吗?这个APK除了包含资源文件外,还包含一些Activity(如关机对话框),这些Activity实际上运行在SystemServer进程中[②]。从这个角度看,SystemServer是一个特殊的应用进程。

·  另外,通过ActivityThread可以把Android系统提供的组件之间的交互机制和交互接口(如利用Context提供的API)也拓展到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类

Instrumentaion是一个工具类。当它被启用时,系统先创建它,再通过它来创建其他组件。另外,系统和组件之间的交互也将通过Instrumentation来传递,这样,Instrumentation就能监测系统和这些组件的交互情况了。在实际使用中,我们可以创建Instrumentation的派生类来进行相应的处理。读者可查询Android中Junit的使用来了解Intrstrumentation的作用。

Application类保存了一个全局的application状态。Application由AndroidManifest.xml中的<application>标签声明。在实际使用时需定义Application的派生类。

Context是一个接口,通过它可以获取并操作Application对应的资源、类,甚至包含于Application中的四大组件。

 

Context是一个抽象类,而由AMS创建的将是它的子类ContextImpl。如前所述,Context提供了Application的上下文信息,这些信息是如何传递给Context的呢?此问题包括两个方面:

·  Context本身是什么?

·  Context背后所包含的上下文信息又是什么?

下面来关注上边代码中调用的getSystemContext函数。

(2) getSystemContext函数分析

 [-->ActivityThread.java::getSystemContext]

 

public ContextImpl getSystemContext() {
  synchronized(this) {
   if(mSystemContext == null) {//单例模式
       ContextImpl context =  ContextImpl.createSystemContext(this);
       //LoadedApk是2.3引入的一个新类,代表一个加载到系统中的APK
       LoadedApk info = 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对象
      }
   }
    return mSystemContext;
}

 

以上代码无非是先创建一个ContextImpl,然后再将其初始化(调用init函数)。为什么函数名是getSystemContext呢?因为在初始化ContextImp时使用了一个LoadedApk对象。如注释中所说,LoadedApk是Android 2.3引入的一个类,该类用于保存一些和APK相关的信息(如资源文件位置、JNI库位置等)。在getSystemContext函数中初始化ContextImpl的这个LoadedApk所代表的package名为“android”,其实就是framework-res.apk,由于该APK仅供SystemServer使用,所以此处叫getSystemContext。

上面这些类的关系比较复杂,可通过图6-2展示它们之间的关系。

技术分享

Android运行环境是构建在进程之上的。有Android开发经验的读者可能会发现,在应用程序中,一般只和Android运行环境交互。基于同样的道理,SystemServer希望它内部的那些Service也通过Android运行环境交互,因此也需为它创建一个运行环境。由于SystemServer的特殊性,此处调用了systemMain函数,而普通的应用进程将在主线程中调用ActivityThread的main函数来创建Android运行环境。

另外,ActivityThread虽然本意是代表进程的主线程,但是作为一个Java类,它的实例到底由什么线程创建,恐怕不是ActivityThread自己能做主的,所以在SystemServer中可以发现,ActivityThread对象由其他线程创建,而在应用进程中,ActivityThread将由主线程来创建。

技术分享

·  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。

[-->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中调用
}

 

5.  ActivityManagerService的main函数总结

AMS的main函数的目的有两个:

·  首先也是最容易想到的目的是创建AMS对象。

·  另外一个目的比较隐晦,但是非常重要,那就是创建一个供SystemServer进程使用的Android运行环境。

根据目前所分析的代码,Android运行环境将包括两个成员:ActivityThread和ContextImpl(一般用它的基类Context)。

图6-4展示了在这两个类中定义的一些成员变量,通过它们可看出ActivityThread及ContextImpl的作用。

 技术分享

ActivityThread中有一个mLooper成员,它代表一个消息循环。这恐怕是ActivityThread被称做“Thread”的一个直接证据。另外,mServices用于保存Service,Activities用于保存ActivityClientRecord,mAllApplications用于保存Application。关于这些变量的具体作用,以后遇到时再说。

·  对于ContextImpl,其成员变量表明它和资源、APK文件有关。

 

由于framework-res.apk是一个APK文件,和其他APK文件一样,它应该运行在一个进程中。而AMS是专门用于进程管理和调度的,所以运行APK的进程应该在AMS中有对应的管理结构。因此AMS下一步工作就是将这个运行环境和一个进程管理结构对应起来并交由AMS统一管理。

AMS中的进程管理结构是ProcessRecord。

AMS如何与应用进程交互?例如AMS启动一个位于其他进程的Activity,由于该Activity运行在另外一进程中,因此AMS势必要和该进程进行跨进程通信。

答案自然是通过Binder进行通信。为此,Android提供了一个IApplicationThread接口,该接口定义了AMS和应用进程之间的交互函数,如图6-5所示为该接口的家族图谱。

 技术分享

·  ApplicationThreadNative实现了IApplicationThread接口。从该接口定义的函数可知,AMS通过它可以和应用进程进行交互,例如,AMS启动一个Activity的时候会调用该接口的scheduleLaunchActivity函数。

·  ActivityThread通过成员变量mAppThread指向它的内部类ApplicationThread,而ApplicationThread从ApplicationThreadNative派生。

 

IApplicationThread的Binder服务端在应用进程中还是在AMS中?

提示如果读者知道Binder系统支持客户端监听服务端的死亡消息,那么这个问题的答案就简单了:服务端自然在应用进程中,因为AMS需要监听应用进程的死亡通知。

有了IApplicationThread接口,AMS就可以和应用进程交互了。例如,对于下面一个简单的函数:

 

IOPP

AMS

标签:

原文地址:http://www.cnblogs.com/zjx-4413/p/5398677.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!