AMS-启动Activity之二



在上一篇文章中写到了Zygote派生了子进程给整个app的第一个启动的Activity并创建了一个完整的进程环境。那在这个

进程的第一个线程(主线程)中,入口函数是什么。这是一个静态方法,ActivityThread#main(String[] args).

ActivityThread#main(String[] args)

public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);//和调试及strickmode有关

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");//设置进程名为"<pre-initialized>"

        Looper.prepareMainLooper();//准备主线程消息循环

        ActivityThread thread = new ActivityThread();//创建一个ActivityThread对象。
        thread.attach(false);//调用attach函数,注意其参数为false

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    

      在面函数内部,将创建一个ActivityThread实例和一个消息循环Loop,接着调用

ActivityThread#attach(...),这是用于和AMS交互 ,最后loop(),启动主线程的消息循环。

      应用进程是由消息循环去驱动的,就是说主线程的运行主线是不断的去查询消息队列有

没有消息,有的话,就拿出来执行。触摸事件就是分发在消息队列中。


ActivityThread#attach(boolean system)

* 获取和AMS跨进程通信的IBinder,IActivityManager = ActivityManagerNative.getDefault();

* 执行mgr.attachApplication(mAppThread),其中mAppThread是ActivityThread.ApplicationThread

  (extends ApplicationThreadNative)类型,它是AMS与ActivityThread通信,即与应用进程通信

  的接口。目前进程好像创建了,ActivityThread代表着进程主线程的,也创建了,但是目前这个

  ActivityThread实例和进程间根本没有什么实际,ActivityThread对进程信息一无所知。

  attachApplication(mAppThread)可以让我们获得我们进程的信息

ActivityManagerService#attachApplicationLocked(IApplication thread,int pid)

* 因为当一个进程宣布结束后,pid就可以重用,他的ProcessRecord也将被重用,进程宣布结束后,

  并不意味着,关于这个旧进程的所有清理工作都完成了,因为多线程的原因,pid被重用时,清理

  工作还没有完成。此时就需要作出判断和相应的处理。

* 设置ProcessRecord的一些参数,如用于和;应用进程交互的thread对象,进度调度优先级及oom_adj

  从消息队列中撤销PROC_START_TMEOUT_MSG消息,至此,进程启动成功

  

        app.makeActive(thread, mProcessStats);//ProcessRecord绑定ActivityThread
        app.curAdj = app.setAdj = -100;//跟oom_adj有关,值越低优先级越高,则越不容易被杀掉
        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;//跟进程调度优先级有关
        app.forcingToForeground = null;
        updateProcessForegroundLocked(app, false, false);
        app.hasShownUi = false;
        app.debugging = false;
        app.cached = false;
        app.killedByAm = false;

        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);//启动成功,撤销PROC_...消息

* 执行List providers = normalMode?generateApplicationProvidersLocked(app):null;在该函数内部将查询

  (根据进程名和uid确定)PKMS以获得需运行在该进程中的ContentProvider。

* 通过ApplicationThread和应用进程交互,调用其bindApplication函数

   

 thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());

  这样就在ActivityThread中持有了进程相关的信息。那么就真正打通了AMS和应用进程主线程之间的通道了

* 终于调用了跟启动Activity和Service直接相关的方法了

  

Activity hr = mMainStack.topRunningActivityLocked(null);
//...
//启动Activity,最后两个参数为true
mMainStack.realStartActivityLocked(hr, app, true,true);
//...
ServiceRecord sr = null;
//mPendingServices存储那些因目标进程还未启动而处于等待状态的ServiceRecord
for(int i = 0 ;i < mPendingservices.size(); i++){
//...
   sr = mPendingServices.get(i);
//该Service将运行在目标进程,所以从mPendingService中移除
    mPendingServices.remove(i);
    i--;
   realStartServiceLocked(sr, app);//启动该Service
} 


ActivityThread.ApplicationThread#bindApplication(...)

void bindApplication(String packageName,//应用包名
 ApplicationInfo info,、、该进程对应的ApplicationInfo
List<ProviderInfo> providers,//在该package中声明的provider信息
 ComponentName testName,//和Instrumentation有关
//下面三个和性能统计有关
 ProfilerInfo profilerInfo,
 Bundle testArguments,
  IInstrumentationWatcher testWatcher, 
  IUiAutomationConnection uiAutomationConnection,
  int debugMode,
 boolean openGlTrace,
 boolean restrictedBackupMode,
 boolean persistent,//该进程是否为persitent进程
  Configuration config,//当前的配置信息,如屏幕大小和语言
 CompatibilityInfo compatInfo,//兼容信息
 Map<String, IBinder> services,//WMS及AlarmmanagerService
  Bundle coreSettings//核心配置参数)

      该方法是在上面的ActivityManagerService#attachApplicationLocked(IApplication thread,int pid)

中调用的,因为要说的比较多,所以放到了后面补充。

     ApplicationThread接收到AMS的指令后(binder调用),会将指令中的参数封装到一个数据结构中,

然后通过发消息的方式转交给主线程去处理(因为binder服务端的调用的函数是在Binder线程中执行的)。

BIND_APPLICATION最终将由handleBindApplication()处理。


ActivityThread#handleBindApplication(AppBindData data)

做的都是跟启动Activity没有直接关系的,都是在跟搭建进程环境有关。

* 设置进程名,就是之前记录在ProcessRecord的那个processName,而不是临时的<pre_initialized>

  Process.setArg0(data.processName);

* 启动性能统计:mProfiler.startProfiling();

* 设置timezone:TimeZone.setDefaut(null);

* 设置资源及兼容模式

* 对于系统APK,如果当前熊为eng版本,则需要使用dropbox的日志记录

* 如果目标SDK版本大于9,则不允许在主线程使用网络操作(如socket、connect等)否则抛异常;

  这么做的目的是防止应用程序在主线程中因网络操作执行时间过长影响用户体验。

* 如果package中声明了FLG_LARGE_HEAP,则可跳过虚拟机的内存限制。

* 创建一个Application,data.info为LoadedApk类型,在其内部会通过java反射机制创建

  一个在APK的Manifest.xml中声明的Applicatiolication对象。

  Application app = data.info.makeApplication(data.restrictedBackupjMode, null);

  mInitialApplication = app;

*  调用Application的onCreate函数

   mInstrumentation。mInstrumentationApplicationOncreate(app);

  ActivityStack#bindApplication(...)其中有一个参数是List<Provider>,如果该Application有ContentProvider,

  则应该安装它们。


   AMS#attachApplication(...)和ActivityStack#bindApplication(..)的调用,让AMS和应用进程互相熟悉,

完成了通信道路的搭建和完善进程环境,创建了和初始化了该有的东西。ContentProvider也安装好了。


ActivityStackVisor#realStartAcitivtyLocked(ActivityRecord r,ProcessRecord app, boolean andResume,

   boolean checkConfig) throws RemoteException   (低版本是ActivityStack的方法)

* 通知应用进程启动Activity(跨进程)

  app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identifyHasClode(r), r.info,

   mService.mConfiguation, r.compat, r.icicle, results, newIntents, !andResume,

   mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop);

* 添加该Activity对应的task到近期任务列表中

  if(mMainStack) mService.addRecentTaskLocked(r.task)

* 调用completeResumeLocked(r);继续AMS的处理流程。

* 启动系统设置向导Activity,当系统更新或初次使用时需要进行配置

  if(mMainStack) mService.startSetupActivityLocked();


scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
                ProfilerInfo profilerInfo)


* 执行该方法时,是作为Binder服务端执行的,应该是在Binder线程中执行的。该方法会把

  ActivityStackVisor传过来的参数打包,然后向主线程发消息,然后该消息会在handleLaunchActivity()

  中处理。

 queueOrSendmessage(H.LAUNCH_ACTIVITY, r);


ActivityThread#handleLaunchActivity(ActivityClientRecord r, Intent customIntent)

* 创建Activity,通过Java反射机制创建目标Activity,将在内部完成Activity生命周期,

  的前两步,即调用onCreate和onStart函数。Activity终于创建了

  Activity a = performLaunchActivity(r, customIntent);

* 调用handleResumeActivity(r.token, false, r.isFsorward);并不只是调用回调onResume那么简单


ActivityThread#handleResumeActivity(IBinder token, boolean clearHide, boolean isForward)

* 调用Activity的onResume

  ActivityClientRecord r = performResumeActivity(token, clearHide)

* 向主线程消息队列中添加一个Idler对象

  Looper.myQueue().addIdleHandler(new Idler());

  当消息队列没有其他要处理的消息时,将处理通过addIdleHandler添加的idler对象,也就是说Idler对象

的优先级最低。


ActivityThread#Idler implements MessageQueue.IdleHandler

* 调用AMS的activityIdle

  am.activityIdle(a,token, a.createdConfig, stopProfiling)


ActivityStack#completeResumeLocked(ActivityRecord next)

* 发送一个超时处理消息,默认为10.IDLE_TIMEOUT-MSG是针对activityIdle

  的。AMS给Acitivty的启动设了个超时限定。取消该消息发送的代码在

  ActivityStack#activityIdleInternal(...)中。AMS#activityIdle()->

   ActivityStack#activityIdleInternal(...)


ActivityStack#activityIdleInternal(IBinder token, boolean fromTimeout, Configuration config)

* 如果应用进程在超时时间内调用了该方法,则fromTimeOut参数只为false,否则,一旦超时,在

  IDLE_TIME_MSG的消息处理也会调用该方法,并设置fromTimeOut为true。

* 从消息队列中撤销IDLE_TIMEOUT_MSG

  if(token != null) mHandler.removeMessages(IDLE_TIME_MSG, token);

* processStoppingActivitiesLocked函数返回那些因本次Activity启动而被暂停(pause)的Activity

  stops = processStoppingActivitiesLocked(true);

* 处理那些因为本次Activity启动而被暂停的Activity。有两种情况:

  如果被暂停的Activity处于finishing状态(如Activity在其onPause中调用了finish()函数),

   则调用finishCurrentActivityLocked。否则,要调用stopActivityLocked处理暂停的Activity;

  if(r.finishing) finishCurrentActivityLocked(r FINISH_IMMEDIATELY);

  else  stopActivityLocked(r);




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值