开启生长之旅!这是我参与「日新方案 12 月更文应战」的第25天,点击检查活动概况

1.Activity的发动流程

当咱们点击桌面的图标时,其实就是发动对应使用的入口Activity。发动Activity主要有两个流程,一个是对应的使用进程存在,一个是对应的进程不存在,以下的流程是对应的进程不存在的流程。

Activity的启动流程
如上图所示,当发动一个activity时,会将恳求发送至AMS,AMS会判别方针进程是否存在,若不存在,则先发音讯给zygote进程,然后从zygote进程傍边fork出方针进程,接着方针进程会发音讯给AMS,告诉AMS方针进程现已发动,然后AMS会调用bindApplication,告诉使用端创建Application,然后调用scheduleTransaction,发动对应的Activity。 下图为具体的调用时序图
Activity的启动流程
有几个当地咱们能够重点重视一下

1.startSpecificActivityLocked方法,判别当时进程是否存在,若存在,则直接发动对应的activity,若不存在,则发动进程

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    ......
    if (app != null && app.thread != null) {
        try {
            ......
            //1.若进程存在,则直接发动activity
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
    }
   //2.发动进程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

2.startProcessLocked,AMS发动进程如注释1所示,在发动进程的一起,会发送一个进程timeout的推迟音讯,推迟的时刻依据参数为12秒或者10秒,若在这段时刻内进程未发动,则会触发这个音讯执行,将会铲除改进程相关内容。这儿咱们能够看出,进程发动的这个timeout机制和ANR的原理是一模一样的。

private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {
      ......
      try {
         //1.发动进程
          final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                  uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                  invokeWith, startTime);
          //2.进程发动timeout音讯
          handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                  startSeq, false);
      } catch (RuntimeException e) {
         ......
      }
      ......
}

3.attachApplicationLocked,使用进程发动之后,会立马调用attachApplication,然后最终会走到attachApplicationLocked方法,这儿就将进程发动阶段设置的推迟音讯remove掉了。 此刻使用进程现已发动了,接着就能够处理activity了,如注释3所示。

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
   ......
   //1.remove timeout音讯
   mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
   ......
   //2.让使用进程初始化
   thread.bindApplication(processName, appInfo, providers,
                        app.instr.mClass,
                        profilerInfo, app.instr.mArguments,
                        app.instr.mWatcher,
                        app.instr.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, isAutofillCompatEnabled);
    //3.发动activity
    mStackSupervisor.attachApplicationLocked(app);
    //4.处理service
    mServices.attachApplicationLocked(app, processName);
    //5.处理broadcast
    sendPendingBroadcastsLocked(app);
   ......
}

4.realStartActivityLocked,如注释1所示,创建activity的发动transaction,然后将其发送到使用端。

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
   ......
  //1. 创建activity launch transaction.
  final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
          r.appToken);
  clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
          System.identityHashCode(r), r.info,
          // TODO: Have this take the merged configuration instead of separate global
          // and override configs.
          mergedConfiguration.getGlobalConfiguration(),
          mergedConfiguration.getOverrideConfiguration(), r.compat,
          r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
          r.persistentState, results, newIntents, mService.isNextTransitionForward(),
          profilerInfo));
  // Set desired final state.
  final ActivityLifecycleItem lifecycleItem;
  if (andResume) {
      lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
  } else {
      lifecycleItem = PauseActivityItem.obtain();
  }
  clientTransaction.setLifecycleStateRequest(lifecycleItem);
  // 2.Schedule transaction
  mService.getLifecycleManager().scheduleTransaction(clientTransaction);
......
}

5.使用端收到恳求会调用ActivityThread的handleLaunchActivity,然后调用performLaunchActivity,此方法会创建Activity,并调用对应的周期函数。

2.总结

1.冷发动优化

冷发动的时刻咱们能够大致分成两个阶段, 第一阶段:AMS调度+zygote进程发动+进程初始化 第二阶段:Application初始化+Activity的初始化和实际+本身业务的任务 通常咱们测验冷发动的时刻是从手指脱离使用图标开始到使用进程完全显示且图像静止,而这个时刻包含上述两段时刻,第一个阶段是使用层很难去影响的,对于单个使用来说,尽可能的去优化第二个阶段。

2.本身使用所占用的内存

当咱们在测验本身使用所占内存时,有时候会发现,分明没有做什么占用内存的修正,怎么这个版别比上个版别所占内存添加了这么多呢?这时咱们能够通过相关东西比照一下是否是zygote进程占用内存添加了,由于所有的使用进程均从zygote进程继承而来,所以若zygote进程占用内存添加,那么使用的内存也会相应地添加。