美文网首页
Android应用启动的实质(五)

Android应用启动的实质(五)

作者: 榕城歌者 | 来源:发表于2019-06-23 23:00 被阅读0次

    在上一篇文章讲述到了AMS最终通过Binder调用ActivityThread(应用程序线程)中的scheduleLaunchActivity方法,我们最后来看一下ActivityThread是怎么工作的。
    先来查看ActivityThread启动Activity的过程的时序图。

    ActivityThread启动Activity.png
    ApplicationThread是ActivityThread的内部类,应用程序进程创建后会运行代表主线程的实例ActivityThread,它管理着当前应用程序进程的线程。ApplicationThread的scheduleLaunchActivity方法如下所示。
    源码frameworks/base/core/java/android/app/ActivityThread.java
    @Override
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
            int procState, Bundle state, PersistableBundle persistentState,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
        updateProcessState(procState, false);
        ActivityClientRecord r = new ActivityClientRecord();
        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.referrer = referrer;
        ...
        updatePendingConfiguration(curConfig);
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }
    

    scheduleLaunchActivity方法会将启动Activity的参数封装成ActivityClientRecord ,sendMessage方法向H类发送类型为LAUNCH_ACTIVITY的消息,并将ActivityClientRecord 传递过去,最终调用的sendMessage方法。

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
         if (DEBUG_MESSAGES) Slog.v(
             TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
             + ": " + arg1 + " / " + obj);
         Message msg = Message.obtain();
         msg.what = what;
         msg.obj = obj;
         msg.arg1 = arg1;
         msg.arg2 = arg2;
         if (async) {
             msg.setAsynchronous(true);
         }
         mH.sendMessage(msg);
     }
    

    mH指的是H,它是ActivityThread的内部类并继承Handler,是应用程序进程中主线程的消息管理类。H的代码如下所示:

    private class H extends Handler {
          public static final int LAUNCH_ACTIVITY         = 100;
          public static final int PAUSE_ACTIVITY          = 101;
    ...
    public void handleMessage(Message msg) {
              if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
              switch (msg.what) {
                  case LAUNCH_ACTIVITY: {
                      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                      final ActivityClientRecord r = (ActivityClientRecord) msg.obj;//1
                      r.packageInfo = getPackageInfoNoCheck(
                              r.activityInfo.applicationInfo, r.compatInfo);//2
                      handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");//3
                      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                  } break;
                  case RELAUNCH_ACTIVITY: {
                      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                      ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                      handleRelaunchActivity(r);
                      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                  } break;
                ...
    }
    

    查看H的handleMessage方法中对LAUNCH_ACTIVITY的处理,在注释1处将传过来的msg的成员变量obj转换为ActivityClientRecord。
    在注释2处通过getPackageInfoNoCheck方法获得LoadedApk类型的对象并赋值给ActivityClientRecord 的成员变量packageInfo 。应用程序进程要启动Activity时需要将该Activity所属的APK加载进来,而LoadedApk就是用来描述已加载的APK文件。
    在注释3处调用handleLaunchActivity方法,代码如下所示。

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ...
        WindowManagerGlobal.initialize();
        //启动Activity
        Activity a = performLaunchActivity(r, customIntent);//1
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            //将Activity的状态置为Resume
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);//2
            if (!r.activity.mFinished && r.startsNotResumed) {
                performPauseActivityIfNeeded(r, reason);
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            }
        } else {
            try {
                //停止Activity启动
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
    

    注释1处的performLaunchActivity方法用来启动Activity ,注释2处的代码用来将Activity 的状态置为Resume。如果该Activity为null则会通知AMS停止启动Activity。
    重点看注释1处的performLaunchActivity方法。

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
           //获取ActivityInfo类
           ActivityInfo aInfo = r.activityInfo;//1
           if (r.packageInfo == null) {
           //获取APK文件的描述类LoadedApk
               r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                       Context.CONTEXT_INCLUDE_CODE);//2
           }
    
           ComponentName component = r.intent.getComponent();//3
           ...
           //创建要启动Activity的上下文环境
           ContextImpl appContext = createBaseContextForActivity(r);//4
           Activity activity = null;
           try {
               java.lang.ClassLoader cl = appContext.getClassLoader();
               //用类加载器来创建该Activity的实例
               activity = mInstrumentation.newActivity(
                       cl, component.getClassName(), r.intent);//5
             ...
           } catch (Exception e) {
             ...
           }
    
           try {
               //创建Application
               Application app = r.packageInfo.makeApplication(false, mInstrumentation);//6
               ...
               if (activity != null) {
                  ...
                   /**
                   *7 初始化Activity
                   */
                   activity.attach(appContext, this, getInstrumentation(), r.token,
                           r.ident, app, r.intent, r.activityInfo, title, r.parent,
                           r.embeddedID, r.lastNonConfigurationInstances, config,
                           r.referrer, r.voiceInteractor, window, r.configCallback);
    
                  ...
                   if (r.isPersistable()) {
                       mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//8
                   } else {
                       mInstrumentation.callActivityOnCreate(activity, r.state);
                   }
                  ...
               }
               r.paused = true;
               mActivities.put(r.token, r);
           } catch (SuperNotCalledException e) {
               throw e;
           } catch (Exception e) {
             ...
           }
    
           return activity;
       }
    

    注释1处用来获取ActivityInfo,ActivityInfo用于存储代码和AndroidManifes设置的Activity和receiver节点信息,比如Activity的theme和launchMode。
    注释2处获取APK文件的描述类LoadedApk。
    注释3处获取要启动的Activity的ComponentName类,ComponentName类中保存了该Activity的包名和类名。
    注释4处用来创建要启动Activity的上下文环境。
    注释5处根据ComponentName中存储的Activity类名,用类加载器来创建该Activity的实例。
    注释6处用来创建Application,makeApplication方法内部会调用Application的onCreate方法。
    注释7处调用Activity的attach方法初始化Activity,attach方法中会创建Window对象(PhoneWindow)并与Activity自身进行关联。
    注释8处会调用Instrumentation的callActivityOnCreate方法来启动Activity。
    值得注意的是注释5中通过类加载实例化Activity与注释8启动Activity的都是Instrumentation类。同时也可以知道创建Window对象是早于Activity的onCreate方法的。也因此我们可以在onCreate通过setContentView方法将自己的布局添加到window里面。

    frameworks/base/core/java/android/app/Instrumentation.java

    public void callActivityOnCreate(Activity activity, Bundle icicle,
              PersistableBundle persistentState) {
          prePerformCreate(activity);
          activity.performCreate(icicle, persistentState);//1
          postPerformCreate(activity);
      }
    

    注释1处调用了Activity的performCreate方法,最后回到了我们常用的Activity中。
    frameworks/base/core/java/android/app/Activity.java

    performCreate方法中会调用Activity的onCreate方法,讲到这里,根Activity就启动了,即应用程序就启动了。
    

    总结

    Instrumentation管理Activity的生命周期,包括实例化Activity以及回调Activity的各个生命周期方法,onCreate()之类的。

    AMS是Android系统全局应用调度器,Activity之间的跳转最终都是通过AMS去执行的。另一方面,因为AMS是在SystemServer进程里的,应用程序进入另一个应用程序,通过AMS去实现,就是一个多进程通信的过程,所以可以看出Binder的重要性。

    应用启动涉及到的进程.png

    首先Launcher进程向AMS请求创建根Activity,AMS会判断根Activity所需的应用程序进程是否存在并启动,如果不存在就会请求Zygote进程创建应用程序进程。应用程序进程准备就绪后会通知AMS,AMS会请求应用程序进程创建根Activity。上图中步骤2采用的是Socket通信,步骤1和步骤4采用的是Binder通信。
    时序图:


    sxt_s.png

    普通Activity启动过程不会涉及到Zygote进程,因为应用进程已经被创建了,并不需要Zygote去fork。

    整理出这个资料,其实更多的是自我学习和提升,对应用有本质上的认识。

    相关文章

      网友评论

          本文标题:Android应用启动的实质(五)

          本文链接:https://www.haomeiwen.com/subject/pvliqctx.html