探索APP进程的启动流程(一)

对于APP的启动,可以分类为两种:冷启动和热启动。
通俗地解释就是,冷启动是内存中不存在这个app进程,需要先初始化该app进程,再启动activity;
热启动是直接启动activity。
对于这两种启动的区别是,内存中是否存在该app进程。
首先附上冷启动app时的流程鸟瞰图:

在这里插入图片描述
共有四个步骤:
1.launcher进程通过binder请求ams启动Activity,AMS进程查询内存中是否存在该进程。
2.内存中无相应进程,ams通过socket发送创建进程命令和相关资料到zygote进程。
3.zygote进程收到socket信息后,fork子进程,创建出ActivityThread的进程(目的进程)
4.ActivityThread通过binder把新建的进程信息与AMS进行相关联。

这博文中,我们一起从源码里探究学习(基于Android 9 ),AMS如何判断进程是否存在,和进程如何被实例化。(这里以点击首页launcher的app卡片,进去app作为例子)在本篇中,将介绍步骤1和步骤2.
先看看主要代码调用流程图:
在这里插入图片描述

开始从源码看看代码调度流程。
framework\frameworks\base\core\java\android\app\ContextImpl.java

 @Override
    public void startActivity(Intent intent) {
        warnIfCallingFromSystemProcess();
        startActivity(intent, null);
    }
    
 @Override
    public void startActivity(Intent intent, Bundle options) {
       ...
        //mMainThread是ActivityThread类型,用于维护该进程的生命周期
        //getInstrumentation返回Instrumentation实例,Instrumentation用于进程生命周期的执行工具类
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

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

  public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        //得到当前进程的IApplicationThread代理实例 whoThread
        IApplicationThread whoThread = (IApplicationThread) contextThread;
     ...
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            //调用ActivityManagerService的startActivity,并传入当前进程的IApplicationThread代理实例和目的intent
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
      ...
    }

在AMS中调度到startActivityAsUser(),代码如下:
framework\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

 public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivity");
        ...
        //mActivityStartController.obtainStarter返回ActivityStartController实例,obtainStarter()返回ActivityStarter实例
        //把数据存在ActivityStarter实例,然后调用 execute()进行执行,调用ActivityStarter的startActivityMayWait方法
        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();
    }
private int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
            int userId, TaskRecord inTask, String reason,
            boolean allowPendingRemoteAnimationRegistryLookup) {
            ...
		 //ResolveInfo 用于描述app的manifest的信息
		   ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
		                0 /* matchFlags */,
		                        computeResolveFilterUid(
		                                callingUid, realCallingUid, mRequest.filterCallingUid));
 ...
	 		// 收集关于目标Intent的信息,aInfo 
       		 ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
  ...
		           //新建  outRecord数组,用于activity启动后返回activity对应的 ActivityRecord        
			 final ActivityRecord[] outRecord = new ActivityRecord[1];
			 //startActivity传入前面的ResolveInfo、ActivityInfo 对象
            int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                    ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                    allowPendingRemoteAnimationRegistryLookup);
                    ...
 }

继续跟进startActivity()

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            SafeActivityOptions options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
            ...
            ProcessRecord callerApp = null;
	        //caller是发起StartActivity的进程,这里分析从launcher点击打开。
	        //所以caller是launcher进程的IApplicationThread
	        if (caller != null) {
	            //callerApp得到的是launcher对应的 ProcessRecord
	            //ProcessRecord是用于存储正在运行的特定进程的信息。
	            callerApp = mService.getRecordForAppLocked(caller);
	            if (callerApp != null) {
	                //获取当前进程的pid和 uid
	                callingPid = callerApp.pid;
	                callingUid = callerApp.info.uid;
	            }
	            ...
	             //创建即将启动的Activity的描述类 ActivityRecord
	        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
	                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
	                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
	                mSupervisor, checkedOptions, sourceRecord);
	        if (outActivity != null) {
	            //把 r 赋值给传进来的outActivity数组
	            outActivity[0] = r;
	        }
		   ...   
		   
		    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true /* doResume */, checkedOptions, inTask, outActivity);
    }

继续接着调用startActivity

 private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity) {
		...
		//startActivityUnchecked方法主要处理与栈相关的逻辑
		 result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
		...
}
      private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        //初始化ActivityStarter的各个配置, 把 r.intent 赋值给 mIntent
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor);
        //计算出 launcherMode
        computeLaunchingTaskFlags();

        computeSourceStack();
        //mIntent把mLaunchFlags赋值到mIntent.Flags
        mIntent.setFlags(mLaunchFlags);
        ...
        int result = START_SUCCESS;
        //设置目标任务栈
        // mAddingToTask 在computeLaunchingTaskFlags()算出并赋值
        // mLaunchFlags 为 FLAG_ACTIVITY_NEW_TASK
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
        //创建新的TaskRecord
            result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
        } else if (mSourceRecord != null) {
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            result = setTaskFromInTask();
        } else {
            // This not being started from an existing activity, and not part of a new task...
            // just put it in the top task, though these days this case should never happen.
            setTaskToCurrentTopOrCreateNewTask();
        }
        ...
          //传入的mDoResume为true
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
          ...
                //调用ActivityStackSupervisor.resumeFocusedStackTopActivityLocked()
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
        ...
   }

frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

 boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

    ...
        //获取要启动activity所在栈的栈顶的且不是处于停止状态的ActivityRecord
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || !r.isState(RESUMED)) {
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } 
        ...
        return false;
    }

执行ActivityStack.resumeTopActivityUncheckedLocked时再调用了resumeTopActivityInnerLocked(prev, options);
frameworks\base\services\core\java\com\android\server\am\ActivityStack.java

@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
			...
			//获取栈顶的activityRecord
        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        ...
         //执行上一个activity的pause
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
        ....
         //热启动
        if (next.app != null && next.app.thread != null) {
        ....
		}else {
            //冷启动
            // Whoops, need to restart this activity!
      		...
            //打开目的activity
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
      	...
    }

frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

  void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running? 
        //调用ams.getProcessRecordLocked()查询进程表内是否有该进程
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
                //进程存在
		 if (app != null && app.thread != null) {
      			...
		 }
      	  //进程不存在,调用ams的startProcessLocked进行开启进程
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
      	...
}

在这里先看看ams怎么实现查询进程表内是否有该进程
rameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
        //uid为系统进程,系统进程在开机时被启动
        if (uid == SYSTEM_UID) {
          		...
        }
        //根据uid,获取ProcessRecord   (mProcessNames是ProcessMap类型,存储所有的系统内的进程,key为包名)
        ProcessRecord proc = mProcessNames.get(processName, uid);
    		...
        return proc;
    }

再来看看,startProcessLocked()如何进行新建进程。在ams中有多个startProcessLocked方法,每个都有着自己的功能。

 @GuardedBy("this")
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
            //调用startProcessLocked(参数不一致)
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    }

在这次startProcessLocked(),主要是为冷启动的app新建ProcessRecord实例

    @GuardedBy("this")
    final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
		...
		ProcessRecord app;
		 if (!isolated) {
		 
        	//查看堆栈中是否有启动过该进程
				 app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
				...
		}
		...
		//冷启动时,app = null        	
        if (app == null) {
            checkTime(startTime, "startProcess: creating new process record");
            //新建目的 ProcessRecord对象
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
		...
        }
		...
		//调度到startProcessLocked(ProcessRecord app,  String hostingType, String hostingNameStr, String abiOverride)
		 final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
		...
}

在这次startProcessLocked(),主要是为即将发送新建进程的命令传入参数

    @GuardedBy("this")
    private final boolean startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
				//判断进程是否被加入到开启队列
        if (app.pendingStart) {
            return true;
        }
		...
		//组建发给zygote进程的命令参数,groupid,uid,apk文件路径等
            if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
                if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                        && mTopComponent != null
                        && app.processName.equals(mTopComponent.getPackageName())) {
                    uid = 0;
                }
                if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL
                        && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
                    uid = 0;
                }
            }
		...
		//把相关必要参数传到startProcessLocked
            return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                    runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                    startTime);		
		...
	}

把具体参数发送到startProcessLocked(),异步触发发送命令到Zygote进程:

@GuardedBy("this")
    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) {
    	//pendingStart是加入到开启队列的标识参数
        app.pendingStart = true;
		...
		   //异步进行开启进程
        if (mConstants.FLAG_PROCESS_START_ASYNC) {
      				...
                    //在startProcess方法里进行参数发送
                    final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                            app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                            requiredAbi, instructionSet, invokeWith, app.startTime);
						...
          }
		...
}

跟进到startProcess

  private ProcessStartResult startProcess(String hostingType, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
            ...
            //webview_service开启
            if (hostingType.equals("webview_service")) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else {
            	//Process.start实现发送
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            }
	...
}

frameworks\base\core\java\android\os\Process.java

public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

跟进到zygoteProcess.start
frameworks\base\core\java\android\os\ZygoteProcess.java

 public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                    zygoteArgs);
        ...
    }

 private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      final String niceName,
                                                      final int uid, final int gid,
                                                      final int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      boolean startChildZygote,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        //把参数放入startViaZygote
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
    		 ...
        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }

        synchronized(mLock) {
        //zygoteSendArgsAndGetResult()进行把参数发送
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

具体发送由socket实现

 @GuardedBy("mLock")
    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // Throw early if any of the arguments are malformed. This means we can
            // avoid writing a partial response to the zygote.
            int sz = args.size();
          ...
          //zygoteState.writer是socket 的输出流,直接往里面写数据即可发送
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }
            writer.flush();

在上面步骤中,介绍了从用户点开app到发送指令给zygote进程请求新建应用进程。

再往下就去到Zygote进程,Zygote接收到初始化进程指令,fork子进程。后面的步骤将在下面一篇博文继续介绍

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值