原标题:应用程序进程启动过程

作者:慕涵盛华

链接:https://www.jianshu.com/p/b158615cc2ad

一.背景

首先注意的是:这里要说的是应用程序进程的启动过程,而不是应用程序的启动过程。启动一个应用程序首先要确保该应用程序的进程已经被启动。

AMS在启动应用程序的时候会先检查对应的应用程序进程是否存在,如果不存在,就请求Zygote进程启动需要的应用程序进程。(在分析Android系统启动过程中,我们知道在ZygoteInit的main方法中会调用zygoteServer.runSelectLoop方法来等待AMS的请求)

Zygote进程通过fork自身来创建子进程,这样应用程序进程就会获得Zygote进程在启动时创建的虚拟机实例。应用程序进程在启动过程中除了获取虚拟机实例,还创建了Binder线程池和消息循环,这样就可以进行进程间的通信了。

应用程序进程的启动过程可以分为两个部分,一个是AMS发送启动应用程序进程的请求,另一个是Zygote接受请求并创建应用程序进程。

下面分别看一下这两个步骤的具体实现。

二.AMS发送启动应用程序进程请求

AMS会通过startProcessLocked方法向Zygote进程发送请求,下面看一下该方法的实现:

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

1private finalvoidstartProcessLocked(ProcessRecord app, StringhostingType,

2StringhostingNameStr, StringabiOverride, StringentryPoint, String[] entryPointArgs) {

3......

4try{

5try{

6finalintuserId = UserHandle.getUserId(app.uid);

7AppGlobals.getPackageManager.checkPackageStartable(app.info.packageName, userId);

8} catch(RemoteException e) {

9throwe.rethrowAsRuntimeException;

10}

11//获取要创建应用程序进程的用户id

12intuid = app.uid;

13int[] gids = null;

14intmountExternal = Zygote.MOUNT_EXTERNAL_NONE;

15if(!app.isolated) {

16......

17//创建组id和赋值

18if(ArrayUtils.isEmpty(permGids)) {

19gids = newint[ 3];

20} else{

21gids = newint[permGids.length + 3];

22System.arraycopy(permGids, 0, gids, 3, permGids.length);

23}

24gids[ 0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));

25gids[ 1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));

26gids[ 2] = UserHandle.getUserGid(UserHandle.getUserId(uid));

27}

28......

29//ActivityThread

30if(entryPoint == null) entryPoint = "android.app.ActivityThread";

31Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: "+

32app.processName);

33checkTime(startTime, "startProcess: asking zygote to start proc");

34ProcessStartResult startResult;

35if(hostingType.equals( "webview_service")) {

36startResult = startWebView(entryPoint,

37app.processName, uid, uid, gids, debugFlags, mountExternal,

38app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,

39app.info.dataDir, null, entryPointArgs);

40} else{

41//启动应用程序进程

42startResult = Process.start(entryPoint,

43app.processName, uid, uid, gids, debugFlags, mountExternal,

44app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,

45app.info.dataDir, invokeWith, entryPointArgs);

46}

47......

48} catch(RuntimeException e) {

49......

50}

51}

在该方法中会调用Process.start方法来启动应用程序进程,注意该方法传递的第一个参数值为:android.app.ActivityThread,后面会用到。start方法只是调用了ZygoteProcess的start方法,该类是用于保持与Zygote进程的通信状态。在它的start方法中实际调用了startViaZygote方法,下面看一下该方法的实现:

/frameworks/base/core/java/android/os/ZygoteProcess.java

1private Process.ProcessStartResult startViaZygote( finalStringprocessClass,

2finalStringniceName, finalintuid, finalintgid, finalint[] gids, intdebugFlags, intmountExternal, inttargetSdkVersion, StringseInfo, Stringabi, StringinstructionSet,

3StringappDataDir, StringinvokeWith, String[] extraArgs)throws ZygoteStartFailedEx {

4//创建字符串列表,并将应用进程的启动参数保存在该列表中

5ArrayList< String> argsForZygote = newArrayList< String>;

6argsForZygote.add( "--runtime-args");

7argsForZygote.add( "--setuid="+ uid);

8argsForZygote.add( "--setgid="+ gid);

9if((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {

10argsForZygote.add( "--enable-jni-logging");

11}

12......

13synchronized(mLock) {

14returnzygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

15}

16}

该方法的主要作用就是将应用进程启动的参数保存在列表argsForZygote中,然后调用了zygoteSendArgsAndGetResult方法,注意该方法传递的第一个参数是调用openZygoteSocketIfNeeded方法返回的,下面先看一下zygoteSendArgsAndGetResult方法的实现:

1privatestaticProcess. ProcessStartResult zygoteSendArgsAndGetResult(

2ZygoteState zygoteState, ArrayList args)

3throwsZygoteStartFailedEx {

4try{

5......

6finalBufferedWriter writer = zygoteState.writer;

7finalDataInputStream inputStream = zygoteState.inputStream;

8writer.write(Integer.toString(args.size));

9writer.newLine;

10

11for( inti = 0; i < sz; i++) {

12String arg = args.get(i);

13writer.write(arg);

14writer.newLine;

15}

16writer.flush;

17Process.ProcessStartResult result = newProcess.ProcessStartResult;

18result.pid = inputStream.readInt;

19result.usingWrapper = inputStream.readBoolean;

20if(result.pid < 0) {

21thrownewZygoteStartFailedEx( "fork failed");

22}

23returnresult;

24} catch(IOException ex) {

25zygoteState.close;

26thrownewZygoteStartFailedEx(ex);

27}

28}

从该方法的具体实现可以看出主要作用就是将应用进程的启动参数写入ZygoteState中,它是ZygoteProcess的静态内部类,用于表示与Zygote进程通信的状态。ZygoteState是传参进来的,是由openZygoteSocketIfNeeded方法返回的,下面就看一个该方法的具体实现:

1privateZygoteState openZygoteSocketIfNeeded(String abi)throwsZygoteStartFailedEx{

2Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

3

4if(primaryZygoteState == null|| primaryZygoteState.isClosed) {

5try{

6//与Zygot进程建立连接 mSocket是一个字符串(private final String mSocket;)

7primaryZygoteState = ZygoteState.connect(mSocket);

8} catch(IOException ioe) {

9thrownewZygoteStartFailedEx( "Error connecting to primary zygote", ioe);

10}

11}

12if(primaryZygoteState.matches(abi)) {

13returnprimaryZygoteState;

14}

15if(secondaryZygoteState == null|| secondaryZygoteState.isClosed) {

16try{

17secondaryZygoteState = ZygoteState.connect(mSecondarySocket);

18} catch(IOException ioe) {

19thrownewZygoteStartFailedEx( "Error connecting to secondary zygote", ioe);

20}

21}

22if(secondaryZygoteState.matches(abi)) {

23returnsecondaryZygoteState;

24}

25thrownewZygoteStartFailedEx( "Unsupported zygote ABI: "+ abi);

26}

在分析Android系统启动过程分析中知道,在Zygote的main方法中会创建名字为zygote的Server端Socket。该方法中mSocket的值就是zygote,也就是说通过调用ZygoteState.connect(mSocket)方法与Zygote进程建立了Socket连接,并返回ZygoteState类型的对象。上面说到zygoteSendArgsAndGetResult方法会将启动应用进程的参数写入到ZygoteState中,这样Zygote进程就会收到一个创建新的应用程序进程的请求。

三.Zygote接收请求并创建应用程序进程

上面提到在Zygote进程中会调用ZygoteServer的runSelectLoop方法来等待AMS的 请求,下面就看一下该方法的具体实现:

/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

1voidrunSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller{

2ArrayList fds = newArrayList;

3ArrayList peers = newArrayList;

4fds. add(mServerSocket.getFileDeor);

5peers. add( null);

6while( true) {

7StructPollfd[] pollFds = newStructPollfd[fds.size];

8for( inti = 0; i < pollFds.length; ++i) {

9pollFds[i] = newStructPollfd;

10pollFds[i].fd = fds. get(i);

11pollFds[i].events = ( short) POLLIN;

12}

13try{

14Os.poll(pollFds, -1);

15} catch(ErrnoException ex) {

16thrownewRuntimeException( "poll failed", ex);

17}

18for( inti = pollFds.length - 1; i >= 0; --i) {

19if((pollFds[i].revents & POLLIN) == 0) {

20continue;

21}

22if(i == 0) {

23ZygoteConnection newPeer = acceptCommandPeer(abiList);

24peers. add(newPeer);

25fds. add(newPeer.getFileDesciptor);

26} else{

27boolean done = peers. get(i).runOnce( this);

28if(done) {

29peers. remove(i);

30fds. remove(i);

31}

32}

33}

34}

35}

从上述代码中看出实际上是调用ZygoteConnection的runOnce方法来处理请求数据的,下面就看一下该方法:

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

1booleanrunOnce(ZygoteServer zygoteServer)throwsZygote.MethodAndArgsCaller{

2

3String args[];

4Arguments parsedArgs = null;

5FileDeor[] deors;

6try{

7//获取应用程序进程的启动参数

8args = readArgumentList;

9deors = mSocket.getAncillaryFileDeors;

10} catch(IOException ex) {

11Log.w(TAG, "IOException on command socket "+ ex.getMessage);

12closeSocket;

13returntrue;

14}

15......

16try{

17parsedArgs = newArguments(args);

18......

19//创建应用程序进程

20pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,

21parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,

22parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,

23parsedArgs.appDataDir);

24} catch(ErrnoException ex) {

25......

26}

27try{

28if(pid == 0) {

29// in child

30zygoteServer.closeServerSocket;

31IoUtils.closeQuietly(serverPipeFd);

32serverPipeFd = null;

33//处理应用程序进程

34handleChildProc(parsedArgs, deors, childPipeFd, newStderr);

35returntrue;

36} else{

37// in parent...pid of < 0 means failure

38IoUtils.closeQuietly(childPipeFd);

39childPipeFd = null;

40returnhandleParentProc(pid, deors, serverPipeFd, parsedArgs);

41}

42} finally{

43IoUtils.closeQuietly(childPipeFd);

44IoUtils.closeQuietly(serverPipeFd);

45}

46}

在该方法中首先获取启动应用程序进程的参数后封装成Arguments类型的对象,然后调用Zygote.forkAndSpecialize方法,并把该对象传入来创建应用程序进程。如果pid = 0说明创建成功,则当前的代码运行在新创建的进程中,就会调用handleChildProc方法来处理应用程序进程,在该方法中实际调用了ZygoteInit的zygoteInit方法,下面就看一下该方法的实现:

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

1publicstaticfinalvoidzygoteInit(inttargetSdkVersion, String[] argv,

2ClassLoader classLoader)throwsZygote.MethodAndArgsCaller {

3if(RuntimeInit.DEBUG) {

4Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");

5}

6Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");

7RuntimeInit.redirectLogStreams;

8RuntimeInit.commonInit;

9//创建Binder线程池

10ZygoteInit.nativeZygoteInit;

11//最终会调用ActivityThread的main方法(应用程序进程的入口方法)

12RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);

13}

该方法运行在应用程序进程中,主要做了两件事情:1.创建Binder线程池(nativeZygoteInit);2.执行ActivityThread的main方法(RuntimeInit.applicationInit)。RuntimeInit.applicationInit方法中会调用

invokeStaticMain(args.startClass, args.startArgs, classLoader);,第一个传入的参数就是上面提到的android.app.ActivityThread。/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

1private staticvoidinvokeStaticMain( StringclassName, String[] argv, ClassLoader classLoader)

2throws Zygote.MethodAndArgsCaller {

3Class> cl;

4

5try{

6//通过反射获取ActivityThread类

7cl = Class.forName(className, true, classLoader);

8} catch(ClassNotFoundException ex) {

9thrownewRuntimeException(

10"Missing class when invoking static main "+ className,

11ex);

12}

13Method m;

14try{

15//获取ActivityThread的main方法

16m = cl.getMethod( "main", newClass[] { String[]. class});

17} catch(NoSuchMethodException ex) {

18thrownewRuntimeException(

19"Missing static main on "+ className, ex);

20} catch(SecurityException ex) {

21thrownewRuntimeException(

22"Problem getting static main on "+ className, ex);

23}

24

25intmodifiers = m.getModifiers;

26if(! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {

27thrownewRuntimeException(

28"Main method is not public and static on "+ className);

29}

30//抛出异常,注意传入的参数

31thrownewZygote.MethodAndArgsCaller(m, argv);

32}

该方法最后会抛出异常,该异常的捕获是在ZygoteInit的main方法中:

1publicstaticvoidmain(String argv[]){

2......

3} catch(Zygote.MethodAndArgsCaller caller) {

4caller.run;

5} catch(Throwable ex) {

6Log.e(TAG, "System zygote died with exception", ex);

7zygoteServer.closeServerSocket;

8throwex;

9}

10}

可以看到捕获异常后会调用MethodAndArgsCaller的run方法,该类是Zygote的静态内部类,看一下该方法的实现:

1public voidrun {

2try{

3//反射调用方法

4mMethod.invoke( null, newObject[] { mArgs });

5} catch(IllegalAccessException ex) {

6thrownewRuntimeException(ex);

7} catch(InvocationTargetException ex) {

8Throwable cause = ex.getCause;

9if(cause instanceofRuntimeException) {

10throw(RuntimeException) cause;

11} elseif(cause instanceofError) {

12throw( Error) cause;

13}

14thrownewRuntimeException(ex);

15}

16}

mMethod指的就是上面传进来的ActivityThread的main方法,这样应用程序进程就进入了ActivityThread.main方法中。下面看一下main方法都做了那些事情:

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

1publicstaticvoidmain(String[] args){

2......

3//创建主线程Looper

4Looper.prepareMainLooper;

5ActivityThread thread = newActivityThread;

6thread.attach( false);

7//创建Handler

8if(sMainThreadHandler == null) {

9sMainThreadHandler = thread.getHandler;

10}

11if( false) {

12Looper.myLooper.setMessageLogging( new

13LogPrinter(Log.DEBUG, "ActivityThread"));

14}

15// End of event ActivityThreadMain.

16Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

17//开启消息轮询

18Looper.loop;

19thrownewRuntimeException( "Main thread loop unexpectedly exited");

20}

关注公众号,回复"flutter"获取flutter视频教程返回搜狐,查看更多

责任编辑:

android 启动app过程,应用程序进程启动过程相关推荐

  1. Android应用程序进程启动过程的源代码分析(1)

    Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实 ...

  2. Android应用程序进程启动过程

    相关文章 Android系统架构与系统源码目录 Android系统启动流程(一)解析init进程启动过程 Android系统启动流程(二)解析Zygote进程启动过程 Android系统启动流程(三) ...

  3. [日更-2019.4.26、27、28] cm-14.1 Android系统启动过程分析(四)-应用程序进程启动过程...

    2019独角兽企业重金招聘Python工程师标准>>> 声明 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的: 本文 ...

  4. Android 系统(14)---SystemServer进程启动过程

    SystemServer进程的启动 在上一篇文章Framework学习(二)Zygote进程启动过程中,我们已经知道Zygote进程会启动SystemServer进程,但具体启动流程还没有涉及,本文我 ...

  5. 应用程序进程启动过程

    --摘自<Android进阶解密> 1.AMS在启动应用程序时会检查者应用程序需要的应用进程是否存在,不存在就会请求Zygote进程启动需要的应用程序进程 2.Zygote的Java框架层 ...

  6. Android应用程序进程启动流程

    在学习应用程序进程启动流程前,先要弄清楚系统启动流程,如果有不清楚的同学,建议先看下以前博主的文章: Android系统启动(上篇)_AD钙奶-lalala的博客-CSDN博客 Android系统启动 ...

  7. Android音乐App桌面图标制作以及启动页面开发(简易音乐 一)

    Android音乐App桌面图标制作以及启动页面开发( 简易音乐 一 ) 关于 效果 第一步 第二步 第一步 修改SplashAcitivity的布局页面 第二步 修改androidmanifest. ...

  8. react native开发Android 篇——APP名称、图标、启动页

    react native开发Android 篇--APP名称.图标.启动页 设置APP名称 设置APP图标 设置启动页 隐藏启动页 设置APP名称 编辑 android/app/src/main/re ...

  9. cm-14.1 Android系统启动过程分析(8)-应用程序进程启动过程

    文章目录 声明 0 写在前面 1 什么应用程序进程? 2 应用程序进程的启动过程 2.1 AMS发送启动应用程序进程请求 2.2 Zygote接收AMS的请求并创建应用程序进程 3 启动线程池 4 创 ...

最新文章

  1. 写给将要参加软考的朋友们
  2. kubernetes1.4版本遇到的坑
  3. 【Tiny4412】 编译dnw源码报错 /lib/modules/2.6.32-431.el6.x86_64/build/: No such file or directory
  4. js代码自动排版_接口测试平台代码实现9:菜单常显
  5. Mybatis 在 insert 之后想获取自增的主键 id,但却总是返回1
  6. js布尔类型+数字判断_C ++中的布尔数据类型
  7. 书生中学计算机应用自费,浙江省台州市书生中学2016-2017学年高二上学期期中考试信息试题 Word版含答案.doc...
  8. 怎么用计算机测出来体脂,怎么测体脂比较科学
  9. APP支付模块设计分析
  10. 摄影测量——单片空间后方交会
  11. 大数据还是人工智能?哪个发展更好
  12. Electron安装报错解决办法
  13. macOS Big Sur 11.5.2 (20G95) 虚拟机 ISO 镜像
  14. 如何制作一个高转化的广告落地页(文末有福利)
  15. oracle安装点下一步退出,学习笔记:oracle之win10安装卸载oracle 11gR2步骤及常见问题解决...
  16. 怎么在视频中截取音频作为手机铃声?
  17. 基于SSM框架的图书馆借阅管理系统
  18. 【第四十三期】社招面经-后端开发 蚂蚁
  19. centos7代理设置
  20. 【Appium】如何配置真机连接及定位元素

热门文章

  1. 体脂秤方案——体脂秤的原理是什么?
  2. 什么是软考?计算机专业有没有必要考?
  3. JCA-Java加密框架
  4. HTML基础知识笔记-01
  5. CodeForces 1089 简要题解
  6. 基于单片机射频RFID卡公司考勤控制系统设计(毕设课设资料)
  7. 怎么把图片的分辨率调高?如何调整图片分辨率?
  8. 中秋赏月地图出炉,跟随锦江之星去赏月
  9. 不用找,你想要的手抄报 小报印刷模板素材都在这里
  10. Excel数据快速收集工具