Activity启动流程(五)请求并创建目标Activity进程

深入解析Android应用进程从AMS请求Zygote创建、进程初始化、注册system_server及Application实例创建的详细流程,涵盖Activity启动的请求到目标进程诞生的关键步骤。

         请求并创建目标Activity进程


Android四大组件源码实现详解系列博客目录:

Android应用进程创建流程大揭秘
[Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Activity启动流程(一)发起端进程请求启动目标Activity
Activity启动流程(二)system_server进程处理启动Activity请求
Activity启动流程(三)-Activity Task调度算法复盘分析
Activity启动流程(四)-Pause前台显示Activity,Resume目标Activity
Activity启动流程(五)请求并创建目标Activity进程
Activity启动流程(六)注册目标Activity进程到system_server进程以及创建目标Activity进程Application
Activity启动流程(七)初始化目标Activity并执行相关生命周期流程


本篇博客编写思路总结和关键点说明:
在这里插入图片描述
为了更加方便的读者阅读博客,通过导读思维图的形式将本博客的关键点列举出来,从而方便读者取舍和阅读!



引言

  还记得我们在前面博客Activity启动流程(四)Pause前台显示Activity,Resume目标Activity以及更前面一系列博客中做的艰苦卓越的斗争吗!这些战役之惨烈,战况之持久前所未有!虽然过程是疼苦的,但是战果也是显赫和令人满意的,通过上述战役我们不仅消灭了启动目标Activity落上的各种拦路虎圆满完成了启动目标Activity请求阶段的重任,并且更是取得了如下的阶段性成果(不是老王卖瓜自卖自夸啊!):

  • 为目标Activity创建了ActivityRecord,从而在AMS中目标Activity有了相关的信息档案
  • 为目标Activity安排好了TaskRecord任务栈以及Stack栈,并且为其在上述结构中安排好了合适的位置
  • Pause好了前台相关的Activity

但是上述的努力远远不过,如果我们把Activity的启动比喻为万里长征的话,我们还只完成了Activity的请求阶段,在本篇博客中我将会带领小伙们一起分析目标Activity所属进程的启动流程,其主要包括如下的相关子流程:

  • AMS请求Zygote创建目标Activity所属进程
  • Zygote孵化目标Activity所属进程
  • 初始化目标Activity所属进程
  • 注册目标Activity所属进程到system_server
  • 目标Activity所属进程创建Application实例对象

注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:

frameworks/base/services/core/java/com/android/server/am/
  --- ActivityManagerService.java
  --- ProcessRecord.java
  --- ActivityRecord.java
  --- ActivityResult.java
  --- ActivityStack.java
  --- ActivityStackSupervisor.java
  --- ActivityStarter.java
  --- TaskRecord.java 

frameworks/base/services/core/java/com/android/server/pm/
 --- PackageManagerService.java
 
frameworks/base/core/java/android/content/pm/
--- ActivityInfo.java

frameworks/base/core/java/android/app/
  --- IActivityManager.java
  --- ActivityManagerNative.java (内部包含AMP)
  --- ActivityManager.java
  --- AppGlobals.java
  --- Activity.java
  --- ActivityThread.java(内含AT)
  --- LoadedApk.java  
  --- AppGlobals.java
  --- Application.java
  --- Instrumentation.java  
  --- IApplicationThread.java
  --- ApplicationThreadNative.java (内部包含ATP)
  --- ActivityThread.java (内含ApplicationThread)
  --- ContextImpl.java


frameworks/base/core/java/com/android/internal/os/*
	---ZygoteConnection.java
	---Zygote.java
	---ZygoteInit.java
	---RuntimeInit.java
	
frameworks/base/core/java/android/os/Process.java


frameworks/base/core/jni/include/android_runtime/AndroidRuntime.h
frameworks/base/core/jni/AndroidRuntime.cpp
frameworks/base/cmds/app_process/App_main.cpp


libcore/libart/src/main/java/java/lang/Daemons.java
libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java

art/runtime/native/dalvik_system_ZygoteHooks.cc
art/runtime/runtime.cc
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
bionic/libc/bionic/fork.cpp
bionic/libc/bionic/pthread_atfork.cpp
art/runtime/native/dalvik_system_ZygoteHooks.cc
art/runtime/runtime.cc
art/runtime/signal_catcher.cc

并且在后续的源码分析过程中为了简述方便,会将做如下简述:

  • ApplicationThreadProxy简称为ATP
  • ActivityManagerProxy简称为AMP
  • ActivityManagerService简称为AMS
  • ActivityManagerNative简称AMN
  • ApplicationThreadNative简称ATN
  • PackageManagerService简称为PKMS
  • ApplicationThread简称为AT
  • ActivityStarter简称为AS,这里不要和ActivityServices搞混淆了
  • ActivityStackSupervisor简称为ASS

在正式开始今天博客相关源码分析前,还是先奉上Activity启动调用的整体时序图以便小伙们先从整体上有个清晰的概括,然后再从细节开撸!

在这里插入图片描述




一. Android应用进程创建流程整体概括

  关于Android应用进程创建我有写过一个专门的博客Android应用进程创建流程大揭秘 ,但是是以Android 9为原型开展的,虽然创建流程和Android 7的源码逻辑相差不是很大,但是其中还是有些差异的,并且本文是一个一系列的专题文章,所以感觉还是关于这部分还是花点时间对Android 7的版本重新梳理,花点时间重新来一遍。在这里先来奉上一张Android应用冷启动进程创建的完整流程图,内容比较多,有兴趣的可以跟着图走一圈看看。

在这里插入图片描述

  上图是Android应用进程创建的整个详细流程图,东西有点多!好吗,我们还是简化一下,从整体架构上入手来分析,这样可能会容易一些,也容易开啃一些!
在这里插入图片描述

  上面的图示涉及到了几个中要的角色,下面我们来分别介绍介绍:

  • 发起进程端:这里的的发起端通常指代我们的桌面Launhcer,如果是从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过Binder关联AMS服务发送消息给system_server进程

  • system_server进程:system_server进程在收到启动Activity/Service以后,其中的AMS服务经过一系列的处理,最终调用Process.start开启进程创建的流程,在这个阶段主要是和zygote进程建立socket连接,将要创建的进程的相关数据发送过去,在这个阶段system_server对于发起端进程来说扮演的是服务端,而对于zygote进程来说system_server扮演的客户端角色

  • zygote进程:通过前面的篇章分析我们知道,在Android终端启动过程中,Zygote进程就已经早早的启动了,然后会创建LocalServerSocket服务端等待客户端的请求,然后在runSelectLoop开启了一个死循环静候accept客户端的连接,当system_server进程收到发起端进程的请求之后,就会创建LocalSocket和zygote进程的LocalServerSocket通信从而进行send/recev数据了,此时将相关数据发送给LocalServerSocket告知我要创建一个进程。进程fork完成之后,返回结果给system_sever进程的AMS。

  • 新建进程:Zygote进程把进程fork出来之后,需要做进程的初始化操作,比如设置进程异常的捕获方式,开始Binder线程池等等,最后进入了ActivityThread的main方法,从而到这里一个有血有肉的进程正式被启动了




二. AMS请求Zygote创建目标Activity所属进程

  在前面的博客Activity启动流程(四)- Pause前台显示Activity,Resume目标Activity最后我们知道,在Resume目标Activity时如果目标Activity所在的App进程还没有创建,则会调用startSpecificActivityLocked来发起创建目标进程,让我们朝着目标发起猛烈跑火开干!

注意,注意,注意:
Activity的启动过程中,存在一种特殊情况就是假如目标Activity在AndroidManifest.xml中配置了android:process相关的属性,那怕目标Activity所属进程已经创建了依然会走startSpecificActivityLocked流程创建Activity专有的Process,这个一定要注意!

        <activity 
            android:name="com.example.test.BActivity"
            android:process=":process"
             >
        </activity>

2.1 ASS.startSpecificActivityLocked(…)

  当我们第一次启动目标Activity时,其所对应的进程肯定还没有创建则会进入此方法中。此方法命名很霸气啊Specific,那就让我们看看它有啥Specific的,难不成它是内裤外穿不成。

//[ActivityStackSupervisor.java]
    void startSpecificActivityLocked(ActivityRecord r, //目标Activity相关信息
            						 boolean andResume, //此时传递的参数值为true
            						 boolean checkConfig) //此时传递的参数值为false
   {
   
   
        //检查目标Activity所属的应用进程是否创建,假如是冷启动的情况当然是木有创建的
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);
		
		/*
			当目标Activity对应的App进程和进程对应的ApplicationThread被创建时,进入此分支,此时的我们是木有机会了
		*/
        if (app != null && app.thread != null) {
   
   //
            try {
   
   
            	/*
            		判断此Activity是否携带FLAG_MULTIPROCESS或者其对应的进程名是"android"
            	    那"android"对应的进程到底是啥呢,其实它是system_server,这个是在zygote孵化它时指定的
            	*/
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
   
   
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                //正式启动目标Activity,开启生命周期
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
   
   
				...
            }

        }
		//调用AMS开启startProcess处理流程
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);//详见章节2.2
    }

分析一番下来,该方法并没有内裤外穿仅仅是做了一些常规检查和处理,其主要逻辑如下:

  • 在开启创建目标Activity对应的进程之前,再次检查目标Activity对应的ProcessRecord是否创建,如果已经创建则直接启动目标Activity
  • 如若木有,则交由AMS的startProcessLocked方法继续处理下一流程

2.2 AMS.startProcessLocked(String processName,…)

  在AMS中startProcessLocked方法被重载了很多次,所以在接下来的分析中一定得注意不要搞错了!而且startProcessLocked涉及的参数也很多,说实话其中有些参数的作用很多我也没有整明白,但是这并不妨碍我们对整体流程的分析!

//[ActivityManagerService.java]
    final ProcessRecord startProcessLocked(String processName,//目标Activity对应的进程名,通常上是包名
            							   ApplicationInfo info, //Activity所属App的Application信息
            							   boolean knownToBeDead, //这个参数具体意义不明,传递过来的值为true
            							   int intentFlags,//参数的值为0
            							   String hostingType, //这个参数意义不明,参数值为"activity"
            							   ComponentName hostingName, //启动目标Activity时解析intent时得到的ComponentName值
            							   boolean allowWhileBooting,//是否允许在开启启动时,参数未false
            							   boolean isolated, //参数为false,这个值的意思是该进程是否是以隔离模式启动
            							   boolean keepIfLarge) //参数意义不明,传递的值为true
     {
   
   
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    }

此方法很懒,啥也没有干直接调用了另外一个重载的startProcessLocked方法!

//[ActivityManagerService.java]
	//这个参数够多的,真是够多的
    final ProcessRecord startProcessLocked(String processName, //目标Activity对应的进程名,通常上是包名
    									   ApplicationInfo info,//Activity所属App的Application信息
            							   boolean knownToBeDead, //这个参数具体意义不明,传递过来的值为true
            							   int intentFlags, //参数的值为0
            							   String hostingType, //这个参数意义不明,参数值为"activity"
            							   ComponentName hostingName,//启动目标Activity时解析intent时得到的
            							   boolean allowWhileBooting, //是否允许在开启启动时,参数未false
            							   boolean isolated, //参数为false,这个值的意思是该进程是否是隔离的
            							   int isolatedUid, //指定隔离进程的UID
            							   boolean keepIfLarge,//参数意义不明,传递的值为true
            							   String abiOverride, //是否覆盖目标Activity所属app安装时的abi,abi通常影响so库的选择,取值为null
            							   String entryPoint, //参数意义不明,取值为null
            							   String[] entryPointArgs, //参数意义不明,取值为null
            							   Runnable crashHandler) //参数意义不明,取值为null
    {
   
   
        ...
        ProcessRecord app;
        if (!isolated) {
   
   //当不是隔离进程时
        	/*
	        	获取AMS中是否存在目标Activity所属进进程的ProcessRecord记录,在非isolated模式下AMS可以重用先前的ProcessRecord记录
	        	这里小伙们肯定有个疑问就是为啥startSpecificActivityLocked中检查了一次,这里又检查一次,
	        	而和startSpecificActivityLocked处理不同的是这里并没有因为ProcessRecord的存在而停止后续的脚步呢
	        	好吗,此处的逻辑感觉有点不是很清晰啊
        	*/
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
			// 启动参数中,带有FLAG_FROM_BACKGROUND标志,表示进程需要后台启动
            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
   
   
            	// 后台启动一个BadProcess,直接退出
                if (mAppErrors.isBadProcessLocked(info)) {
   
   
                    return null;
                }
            } else {
   
   
                //清理进程Crash消息
                mAppErrors.resetProcessCrashTimeLocked(info);
                if (mAppErrors.isBadProcessLocked(info)) {
   
   
                	// 前台启动,则需要将宿主进程从坏的进程中剔除
                    mAppErrors.clearBadProcessLocked(info);
                    if (app != null) {
   
   
                        app.bad = false;
                    }
                }
            }
        } else {
   
   
            app = null;
        }
		
		/*
			此处涉及到了超自然现象,看注释的意思是对于大小核的架构的设备的话,此时使用cpuset将前台任务迁移到大核上
			这个已经超过本人的能力范畴之外了,pass
		*/
		nativeMigrateToBoost();
        mIsBoosted = true;
		...
		
		// 当进程已经被分配了PID时
        if (app != null && app.pid > 0) {
   
   
        	// 进程还处于启动的过程中
            if ((!knownToBeDead && !app.killed) || app.thread == null) {
   
   
                app.addPackage(info.packageName, info.versionCode, mProcessStats);
                return app;
            }

			/*
				这个地方要怎么理解呢,可能前面目标Activity所属App进程被创建过
				但是已经over了再启动时需要对其做一些清理工作
			*/
            killProcessGroup(app.uid, app.pid);
            handleAppDiedLocked(app, true, true);
        }

        String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;

        if (app == null) {
   
   
        	//在AMS中创建ProcessRecord信息记录
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);//详见章节2.3
            if (app == null) {
   
   
                return null;
            }
            //设置crashHandler
            app.crashHandler = crashHandler;
        } else {
   
   
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
        }

		// 如果系统还未启动,则需要将待启动进程先保持住,等系统启动后,再来启动这些进程
		//final ArrayList<ProcessRecord> mProcessesOnHold = new ArrayList<ProcessRecord>();
        if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
   
   
            if (!mProcessesOnHold.contains(app)) {
   
   
                mProcessesOnHold.add(app);
            }
            return app;
        }

        //又调用另外一个重载的startProcessLocked
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);//详见章节2.4
        
        return (app.pid != 0) ? app : null;
    }

这里可以看到上述方法的处理逻辑主要体现在三个方面:

  • 首先判断是否是以isolated模式启动的目标Activity所属App进程,那么这个solated模式是什么意思呢,网上说通过isolated来判断要启动的进程是否是隔离的,当为true时意味着这是一个隔离的进程(虽然这么说,但是本人是没有搞明白,这个隔离到底隔离的是啥,如果对此处有比较深入的小伙们可以告诉我)。

    对于隔离的进程而言,每次启动都是独立的,不能复用已有的进程信息。如果要启动一个非隔离的进程,那么就需要区分进程是在前台启动还是后台启动,这是用户体验相关的设计。在AMS中维护了一个badProcesses的结构体,用于保存一些“坏进程”,什么才是“坏进程”呢?如果一个进程在一分钟内连续崩溃两次,那就变成了一个“坏进程”。对于后台启动的进程而言(即启动参数中带有FLAG_FROM_BACKGROUND标识),如果进程崩溃了,会造成用户使用的困惑,因为进程崩溃时,会弹出一个对话框,而后台启动的进程是没有任何操作界面的,这时候弹一个框,用户会觉得自己什么都没干,却弹出了一个对话框。所以,后台启动一个“坏进程”时,会直接退出。

    当进程是在前台启动时,即便是一个"坏进程",那也应该宽恕这个进程以前的不良记录,因为这通常是用户通过界面主动要唤起的进程。本着用户是上帝的原则,还是得让用户达到启动进程的目的,即便这个进程可能再次崩溃。

  • 接着判断目标Activity所对应的ProcessRecord是否创建,如果还没有创建这时候会调用AMS.newProcessRecord来创建一个新的ProcessRecord

  • 接着调用AMS的另一个重载方法startProcessLocked继续目标Activity对应进程创建的处理流程


2.3 AMS.newProcessRecordLocked(…)在AMS中创建目标Activity对应的Process记录

//[ActivityManagerService.java]
    final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid) {
   
   
        String proc = customProcess != null ? customProcess : info.processName;
        //电量统计相关
        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
        final int userId = UserHandle.getUserId(info.uid);
        int uid = info.uid;
        //根据isolated模式调整uid,至于怎么具体调整的这块我还没有整明白,就忽略了
        if (isolated) {
   
   
            if (isolatedUid == 0) {
   
   
                int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
                while (true) {
   
   
                    if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
                            || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
   
   
                        mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
                    }
                    uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
                    mNextIsolatedProcessUid++;
                    if (mIsolatedProcesses.indexOfKey(uid) < 0) {
   
   
                        break;
                    }
                    stepsLeft--;
                    if (stepsLeft <= 0) {
   
   
                        return null;
                    }
                }
            } else {
   
   
                uid = isolatedUid;
            }
        }
        //根据传入的参数和获取到的uid信息构建ProcessRecord 
        final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
        if (!mBooted && !mBooting
                && userId == UserHandle.USER_SYSTEM
                && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
   
   
            r.persistent = true;
        }
        addProcessNameLocked(r);//将ProcessRecord信息在AMS中存储起来
        /*************************************************/
			    private final void addProcessNameLocked(ProcessRecord proc) {
   
   
			        ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
			        if (old == proc && proc.persistent) {
   
   			    
			        } else if (old != null) {
   
   
			        }
			        UidRecord uidRec = mActiveUids.get(proc.uid);
			        if (uidRec == null) {
   
   
			            uidRec = new UidRecord(proc.uid);
			            mActiveUids.put(proc.uid, uidRec);
			            noteUidProcessState(uidRec.uid, uidRec.curProcState);
			            enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
			        }
			        proc.uidRecord = uidRec;
			        uidRec.numProcs++;
			        mProcessNames.put(proc.processName, proc.uid, proc);
			        if (proc.isolated) {
   
   
			            mIsolatedProcesses.put(proc.uid, proc);
			        }
			    } 
        /*************************************************/
        return r;
    }

该方法无需动脑,逻辑也比较简单:

  • 根据isolated的情况,调试uid的取值(这个地方先忽略了)
  • 根据ApplicaitonInfo,uid等相关参数创建一个ProcessRecord,并将ProcessRecord加入AMS的管理范围,与此同时,与进程相关的电量统计也是在这一步被绑定上的

2.4 AMS.startProcessLocked(ProcessRecord app,…)依然范特西

  注意将此处的方法startProcessLocked和2.2章节中的区分开来,其参数是完全不同的!此时表示目标Activity对应的rocessRecord已经构建好了,但是仅此而已,此时只是在AMS中有了相关Process的记录但是对应的进程是没有创建的,所以革命尚未成功同志仍需努力啊!继续干!

//[ActivityManagerService.java]
private final void startProcessLocked(ProcessRecord app, 
									  String hostingType,
        							  String hostingNameStr, 
        							  String abiOverride, 
        							  String entryPoint, 
        							  String[] entryPointArgs) {
   
   
    if (app.pid > 0 && app.pid != MY_PID) {
   
   
        // 新启动进程了,清除超时消息设置
        synchronized (mPidsSelfLocked) {
   
   
            mPidsSelfLocked.remove(app.pid);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
        app.setPid(0);
    }
    // 在HoldProcess中移除app
    mProcessesOnHold.remove(app);
    updateCpuStats();
	...
	try {
   
   
            try {
   
   
 				// gid与进程的访问权限相关处理
            	//获取userId,通常为0
                final int userId = UserHandle.getUserId(app.uid);
                // 检查应用的package状态
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            } catch (RemoteException e) {
   
   
            }

            int uid = app.uid;
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
   
   
				...
            }
			...
			int debugFlags = 0;
			// debugFlags相关的处理,与进程的调试选项相关处理,不过多分析
			//我们为了调试通常会在AndroidManifest中配置android:debuggable="true"的参数
            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
   
   
                debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
                debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
            }
			


			//primaryCpuAbi的值在应用安装的时候已经确定了,这个牵涉到应用的安装解析apk包的问题了
            String requiredAbi 
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值