Framework学习(六)应用程序进程启动过程

2023-05-16

概述

上篇文章Framework学习(五)应用程序启动过程我们讲解了应用程序启动过程,但是还有一个遗留知识点,那就是应用程序进程的启动。我们知道应用程序启动之前需要保证应用程序的进程先启动,本文我们就来看看应用程序进程的启动过程。

AMS在启动应用程序时会检查这个应用程序需要的应用程序进程是否存在,不存在就会请求Zygote进程将需要的应用程序进程启动。在Framework学习(二)Zygote进程启动过程这篇文章中,我分析了Zygote会创建一个Server端的Socket,这个Socket用来等待AMS来请求Zygote来创建新的应用程序进程的。我们知道Zygote进程通过fock自身创建应用程序进程,这样应用程序进程就会获得Zygote进程在启动时创建的虚拟机实例。当然,在应用程序创建过程中除了获取虚拟机实例外,还可以获得Binder线程池和消息循环,这样运行在应用进程中的应用程序就可以方便的使用Binder进行进程间通信以及消息处理机制了。

发送请求创建应用程序进程

先从上篇文章中ActivityStackSupervisor的startSpecificActivityLocked函数说起:

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

ActivityStackSupervisor#startSpecificActivityLocked()

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
        //1
        ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true);
        r.task.stack.setLaunchTime(r);
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !"android".equals(r.info.packageName)) {
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode, mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);  //2
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "  + r.intent.getComponent().flattenToShortString(), e);
            }
        } 
        //3
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true);
    }


    final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
        if (uid == Process.SYSTEM_UID) {
            // The system gets to run in any process.  If there are multiple
            // processes with the same uid, just pick the first (this
            // should never happen).
            SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
            if (procs == null) return null;
            ...
        }
        ...
    }

AMS启动应用程序时,会检查这个应用程序需要的应用程序进程是否存在。
注释1处获取当前Activity所在的进程的ProcessRecord,如果进程已经启动了,会执行注释2处的代码。否则执行注释3的代码,通过调用startProcessLocked函数来向Zygote进程发送请求。

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

ActivityManagerService#startProcessLocked()

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
      ...
      try {
          try {
              final int userId = UserHandle.getUserId(app.uid);
              AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
          int uid = app.uid; //1
          int[] gids = null;
          int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
          if (!app.isolated) {
            ...
              //2
              if (ArrayUtils.isEmpty(permGids)) {
                  gids = new int[2];
              } else {
                  gids = new int[permGids.length + 2];
                  System.arraycopy(permGids, 0, gids, 2, permGids.length);
              }
              gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
              gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
          }

         ...
          if (entryPoint == null) entryPoint = "android.app.ActivityThread"; //3
          Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName);
          checkTime(startTime, "startProcess: asking zygote to start proc");
          //4
          Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs);
         ...
      } catch (RuntimeException e) {
        ...
      }
  }
 ...
  }

注释1处的代码创建应用程序进程的用户ID。
注释2处对用户组ID:gids进行创建和赋值。
注释3处如果entryPoint 为null则赋为”android.app.ActivityThread”。
注释4处调用Process的start函数,将此前得到的应用程序进程用户ID、用户组ID和entryPoint 传进去。

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

Process#start()

    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            //1
            return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG, "Starting VM process through Zygote failed");
            throw new RuntimeException("Starting VM process through Zygote failed", ex);
        }
    }

Process#startViaZygote()

private static ProcessStartResult startViaZygote(final String processClass,
                               final String niceName,
                               final int uid, final int gid,
                               final int[] gids,
                               int debugFlags, int mountExternal,
                               int targetSdkVersion,
                               String seInfo,
                               String abi,
                               String instructionSet,
                               String appDataDir,
                               String[] extraArgs)
                               throws ZygoteStartFailedEx {
     synchronized(Process.class) {
         //1
         ArrayList<String> argsForZygote = new ArrayList<String>();
         argsForZygote.add("--runtime-args");
         argsForZygote.add("--setuid=" + uid);
         argsForZygote.add("--setgid=" + gid);
       ...
         if (gids != null && gids.length > 0) {
             StringBuilder sb = new StringBuilder();
             sb.append("--setgroups=");
             int sz = gids.length;
             for (int i = 0; i < sz; i++) {
                 if (i != 0) {
                     sb.append(',');
                 }
                 sb.append(gids[i]);
             }
             argsForZygote.add(sb.toString());
         }
      ...
         argsForZygote.add(processClass);
         if (extraArgs != null) {
             for (String arg : extraArgs) {
                 argsForZygote.add(arg);
             }
         }
         return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
     }
 }

注释1处创建了字符串列表argsForZygote ,并将启动应用进程的启动参数保存在argsForZygote中,例如uid、gid等,这里需要注意processClass = android.app.ActivityThread,后文会用到。
注释2会调用zygoteSendArgsAndGetResult函数,需要注意的是,zygoteSendArgsAndGetResult函数中第一个参数中调用了openZygoteSocketIfNeeded函数,而第二个参数是保存应用进程的启动参数的argsForZygote。

Process#zygoteSendArgsAndGetResult()

    private static 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();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }
            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();

            // Should there be a timeout on this?
            ProcessStartResult result = new ProcessStartResult();
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

zygoteSendArgsAndGetResult函数主要做的就是将传入的应用进程的启动参数argsForZygote写入到ZygoteState中,结合上文我们知道ZygoteState其实是由openZygoteSocketIfNeeded函数返回的,那么我们接着来看openZygoteSocketIfNeeded函数。

Process#openZygoteSocketIfNeeded()

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); //1
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }

        if (primaryZygoteState.matches(abi)) { 
            return primaryZygoteState;
        }

        // The primary zygote didn't match. Try the secondary.
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);  //2
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }

        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }

        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

在之前讲Zygote进程启动过程时我们得知,在Zygote的main函数中会创建name为“zygote”的Server端Socket。
注释1处会调用ZygoteState的connect函数与名称为ZYGOTE_SOCKET的Socket建立连接,这里ZYGOTE_SOCKET的值为“zygote”。
注释2处如果连接name为“zygote”的Socket返回的primaryZygoteState与当前的abi不匹配,则会连接name为“zygote_secondary”的Socket。这两个Socket区别就是:name为”zygote”的Socket是运行在64位Zygote进程中的,而name为“zygote_secondary”的Socket则运行在32位Zygote进程中。既然应用程序进程是通过Zygote进程fock产生的,当要连接Zygote中的Socket时,也需要保证位数的一致。

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

Socket进行连接成功并匹配abi后会返回ZygoteState类型对象,我们在分析zygoteSendArgsAndGetResult函数中讲过,会将应用进程的启动参数argsForZygote写入到ZygoteState中,这样Zygote进程就会收到一个创建新的应用程序进程的请求,我们回到ZygoteInit的main函数。

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

ZygoteInit#main()

    public static void main(String argv[]) {
        ...
        try {
            String socketName = "zygote";
            /**注册Zygote用的Socket*/
            registerZygoteSocket(socketName); //1
            //预加载类和资源
            preload(); //2
            ...
            //启动SystemServer进程
            if (startSystemServer) {
                startSystemServer(abiList, socketName); //3
            }

            //监听socket,启动新的应用进程  
            runSelectLoop(abiList); //4
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            //通过反射调用SystemServer#main()
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

注释1处通过registerZygoteSocket函数来创建一个Server端的Socket,这个name为”zygote”的Socket用来等待AMS来请求Zygote来创建新的应用程序进程。
注释2处用来预加载类和资源。
注释3处用来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。
注释4处调用runSelectLoop函数来等待AMS的请求。

ZygoteInit#runSelectLoop()

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        fds.add(sServerSocket.getFileDescriptor()); //1
        peers.add(null);

        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {  //2
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {  //3
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);  //4
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    boolean done = peers.get(i).runOnce();  //5
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }


    private static ZygoteConnection acceptCommandPeer(String abiList) {
        try {
            return new ZygoteConnection(sServerSocket.accept(), abiList);
        } catch (IOException ex) {
            ...
        }
    }

注释1处中的sServerSocket就是我们在registerZygoteSocket函数中创建的服务端Socket,调用sServerSocket.getFileDescriptor()用来获得该Socket的fd字段的值并添加到fd列表fds中。接下来无限循环用来等待AMS请求Zygote进程创建新的应用程序进程。
注释2处通过遍历将fds存储的信息转移到pollFds数组中。
注释3处对pollFds进行遍历。
注释4如果i==0则说明服务端Socket与客户端连接上,也就是当前Zygote进程与AMS建立了连接,则通过acceptCommandPeer函数得到ZygoteConnection类并添加到Socket连接列表peers中,接着将该ZygoteConnection的fd添加到fd列表fds中,以便可以接收到AMS发送过来的请求。
注释5如果i的值大于0,则说明AMS向Zygote进程发送了一个创建应用进程的请求,则调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程。并在成功创建后将这个连接从Socket连接列表peers和fd列表fds中清除。

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

ZygoteConnection#runOnce()

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        try {
            args = readArgumentList(); //1
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
...
        try {
            parsedArgs = new Arguments(args);//2
        ...
            //3
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
          ....
        }
       try { 
            //4
            if (pid == 0) {
                // in child
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

注释1处调用readArgumentList函数来获取应用程序进程的启动参数。注释2处将readArgumentList函数返回的字符串封装到Arguments对象parsedArgs中。
注释3处调用Zygote的forkAndSpecialize函数来创建应用程序进程,参数为parsedArgs中存储的应用进程启动参数,返回值为pid。
注释4处forkAndSpecialize函数主要是通过fork当前进程来创建一个子进程的,如果pid等于0,则说明是在新创建的子进程中执行的,就会调用handleChildProc函数来启动这个子进程也就是应用程序进程。

ZygoteConnection#handleChildProc()

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
           throws ZygoteInit.MethodAndArgsCaller {
     ...
                   //1
                   if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
       }
   }

注释1处由于parsedArgs.invokeWith属性默认为null,最后调用RuntimeInit.zygoteInit函数。

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

RuntimeInit#zygoteInit()

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();

        commonInit();
        nativeZygoteInit(); //1
        applicationInit(targetSdkVersion, argv, classLoader); //2
    }

注释1处会在新创建的应用程序进程中创建Binder线程池。
注释2处调用了applicationInit函数。

RuntimeInit#applicationInit()

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        ...

        // 初始化虚拟机环境
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());
            // let the process exit
            return;
        }

        // Remaining arguments are passed to the start class's static main
        invokeStaticMain(args.startClass, args.startArgs, classLoader); //1
    }

注释1处applicationInit函数中主要调用了invokeStaticMain函数,需要注意的是第一个参数args.startClass,这里指的就是前面赋值的android.app.ActivityThread。

RuntimeInit#invokeStaticMain()

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader); //1
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException("Missing class when invoking static main " + className, ex);
        }

        Method m;
        try {
            // 获取main方法
            m = cl.getMethod("main", new Class[] { String[].class }); //2
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException("Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException("Problem getting static main on " + className, ex);
        }
        // 判断修饰符
        int modifiers = m.getModifiers(); //3
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException("Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv); //4
    }

注释1处通过反射来获得android.app.ActivityThread类。
注释2处来获得ActivityThread的main函数。
注释3判断修饰符,必须是static而且必须是public类型。
注释4将找到的main函数传入到MethodAndArgsCaller异常中并抛出该异常。这个异常在ZygoteInit#main()方法中捕获。这么做的作用是清除应用程序进程创建过程的调用栈。

ZygoteInit#main()

public static void main(String argv[]) {
    try {
        ...
        startSystemServer(abiList, socketName);
        ...
    } catch (MethodAndArgsCaller caller) {
        caller.run(); //1
    }
}

在注释1处调用了MethodAndArgsCaller的run函数。

MethodAndArgsCaller

public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs }); //1
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }

注释1处通过反射调用了android.app.ActivityThread#main(String[] args)。至此,Zygote进程fork出ActivityThread进程,并成功调用ActivityThread#main()。

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

ActivityThread#main()

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();
...
        Looper.prepareMainLooper();//1
        ActivityThread thread = new ActivityThread();//2
        thread.attach(false); //3
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler(); //4
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();//5
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

注释1处在当前应用程序进程中创建消息循环。
注释2处创建ActivityThread实例。
注释4处从ActivityThread获取handler,这样就将ActivityThread关联到Looper和MessageQueue了。
注释5处调用Looper的loop,使得Looper开始工作,开始处理消息。可以看出,系统在应用程序进程启动完成后,就会创建一个消息循环,用来方便的使用Android的异步消息处理机制。
关于Android的异步消息处理机制大家可以参考我这篇文章:Android 异步消息处理机制:Looper、Handler、Message。这里就不多说了。

如果你看过Framework学习(三)SyetemServer进程启动过程这篇文章,你肯定会发现创建应用程序进程和创建SyetemServer进程的步骤如此类似,其实他们都是通过Zygote进程fork自身来实现的,当然步骤差不多了。唯一区别是一个最终调用到SyetemServer的main函数,另一个最终调用到ActivityThread的main函数。

之前说过:在Android系统中,启动四大组件中的任何一个都可以启动应用程序。但实际上应用程序入口方法只有ActivityThread#main()一个。接着看ActivityThread#main()方法。
注释3处调用了ActivityThread#attach(false)。

ActivityThread#attach()

    final ApplicationThread mAppThread = new ApplicationThread();

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ...
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread); //1
            } catch (RemoteException ex) {
                // Ignore
            }
            ...
        }
        ...
    }

前面文章分析过AMS中的Binder机制:ActivityManagerNative.getDefault(),返回的其实是AMS。注释1其实调用的是AMS的attachApplication方法。

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

ActivityManagerService#attachApplication()

public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid); //1
            Binder.restoreCallingIdentity(origId);
        }
    }

注释1调用了两个参数的attachApplicationLocked()方法

ActivityManagerService#attachApplicationLocked()

    private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {
        ...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) { //1
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
        ...
    }

注释1调用ActivityStackSupervisor的attachApplicationLocked方法。

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

ActivityStackSupervisor#attachApplicationLocked()

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFrontStack(stack)) {
                    continue;
                }
                ActivityRecord hr = stack.topRunningActivityLocked(null);
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            ...
                        }
                    }
                }
            }
        }
        ...
        return didSomething;
    }

首先遍历所有stack,之后找到目前被置于前台的stack。之后通过topRunningActivityLocked()获取最上面的Activity。最后调用realStartActivityLocked()方法来真正的启动目标Activity。
之后就是应用程序启动过程了,具体请看Framework学习(五)应用程序启动过程这篇文章。

下面看看应用程序进程启动时序图:

这里写图片描述

总体流程

  • 1.AMS通知Process使用Socket和Zygote进程通信,请求创建一个新进程.
  • 2.Zygote收到Socket请求,fork出一个进程,会在新的进程中创建Binder线程池并反射调用ActivityThread#main().
  • 3.ActivityThread通过Binder通知AMS启动应用程序.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Framework学习(六)应用程序进程启动过程 的相关文章

  • 多段图的最短路径问题-----动态规划法

    对多段图 xff0c 求最短路径 xff0c 如图 xff1a 对其使用动态规划法 xff1a 阶段 xff1a 将图中的顶点划分5个阶段 xff0c k 状态 xff1a 每个阶段有几种供选择的点s 决策 xff1a 当前状态应在前一个状
  • Android 文件存储 和 权限管理

    转载请标明出处 xff1a xff1a http blog csdn net huaiyiheyuan article details 52473984 android SD卡主要有两种存储方式 Internal External Stor
  • Python 连接Linux服务器完成上传下载和执行命令及查询目录下的文件

    Python 连接Linux服务器完成上传下载和执行命令及查询目录下的文件 记录一些用于连接linux获取远端文件或者上传文件的小工具 xff0c 另外还有执行shell命令和查找linux目录下文件是否存在 span class toke
  • 【学习整理】Windows server 2019AD域之创建用户的三种形式

    内置工具程序csvde exe xff0c ldifde exe dsadd exe csvde exe xff1a 能利用它来新建用户账户 xff0c 但不能修改 需要将用户数据输入纯文本文件中ldifde exe xff1a 可以利用它
  • 邮件退信提示

    一般情况下 xff0c 当您发送的邮件无法正常到达收件人时 xff0c winmail 邮件系统将会自动给您发一封系统退信 xff0c 这封退信通知里面包含了无法正常发送到对方邮件地址的原因 xff0c 所以绝大多数情况下可以通过退信通知来
  • 学以致用--注解加反射实现Butterknife的View注入功能

    不知不觉更文挑战来到了第三天 xff0c 今天来写一篇反射和注解的应用篇 对反射不熟悉的同学 xff0c 请阅读 搞懂Java反射和JDK里的动态代理 对注解不熟悉的同学 xff0c 请阅读 搞懂Java高级特性 注解 首先这篇文章 xff
  • 百度试题---开发测试工程师

    一 问答题 说出常用的几种希哈函数 xff0c 其作用是什么 xff1f 描述OSI 的七层网络结构 xff0c HTTP 工作在哪一层 xff1f 描述一段C 语言代码程序能运行起来的代码要求和执行过程 二 算法设计 有一车苹果 xff0
  • 错误: Entry在LinkedHashMap中不是公共的; 无法从外部程序包中对其进行访问

    遇到了一个很奇怪的问题 xff0c 使用LinkedHashMap来做LRU缓存时 xff0c 重写protected boolean removeEldestEntry Entry lt String String gt eldest 方
  • 【安卓真机调试】较全面的Android真机调试详解

    目录 1 启动调试功能1 1 配置设备上的开发者选项1 2 运行可调试的 build 变体 2 开始调试2 1 设置断点2 2 选择设备2 3 在工具栏中点击Debug图标2 4 打开Debug窗口2 5 将调试程序连接到正在运行的应用上
  • 如何搭建ftp服务器实现文件共享

    这里以windows系统和linux系统为例 xff0c 简单介绍一下如何在这2种系统下搭建ftp服务器 xff0c 整个过程非常简单 xff0c 感兴趣的朋友可以自己尝试一下 xff1a windows windows系统自带有ftp服务
  • Rabbitmq—— 从入门到放弃

    文章目录 背景总体架构类与方法BlockingConnection init channel BlockingChannelqueue declarequeue deleteexchange declarebasic publishbasi
  • 使用electron-vue+go写一个处理excel表格小软件(2)

    目录 问题思路go部分主要流程遇到的坑 node部分主要流程遇到的坑 源码链接 问题 使用node xlsx处理excel一次最多能处理30M的文件 xff0c 所以来个80M的话就要手动拆成3个文件 xff0c 这看起来太蠢了 xff0c
  • Gradle project sync failed的解决方法

    开发工具android studio在运行项目的时候报如下错误 xff1a Error Gradle project sync failed Please fix your project and try again 编辑gradle wr
  • Mvp契约类实践

    MVP中关于契约的用法 契约类的好处 xff1a 低耦合 接口统一管理 业务逻辑清晰 易于后期维护 以最简单的登录为例 xff1a loginContract契约类 span class token comment 契约类 span spa
  • Ubuntu Wine deepin-Wechat生成方法

    转自https ywnz com linuxjc 5530 html 更新deepin中微信的方法 1 下载官方打包的xxx deb xff0c 放至 xff5e wine app文件夹中 2 创建文件夹extract xff0c 并在ex
  • 借助Redis Bitmap实现简单的布隆过滤器

    在之前的一篇文章中 xff0c 我们已经深入理解了布隆过滤器的基本原理 xff0c 并且了解到它在缓存系统中有较多的应用 Redis提供的Bitmap正好能够作为布隆过滤器所需要的位数组的基础 xff0c 本文先简要介绍Bitmap xff
  • AndroidStudio编写编译脚本Gradle文件时没有,没有代码提示,ctrl + 点击属性时提示Cannot find declaration to go to

    问题描述 AndroidStudio编写编译脚本Gradle文件时没有 xff0c 没有代码提示 xff0c ctrl 43 点击属性时提示Cannot find declaration to go to 原因分析 xff1a gradle
  • 在Ubuntu下最靠谱的键位修改方法 ,亲测有效

    本人刚入坑linux不久 我一直在windows下工作 同样linux我也当成windows来玩 也常有改键位的需求 我曾经百度无数改键位的方法 要么就是只能改左边的ctrol和大小写键交换 右边的alt和ctrol交换失败 有的教程能交换
  • svn怎么切换分支

    项目场景 xff1a svn切换不成功 问题描述 怎么切换都不成功 原因分析 xff1a 解决方案 xff1a 1查看当前所在的位置 2点击switch 3to path选中需要的路径 xff0c ok就可以了 重复1步骤就能查看当前路径是
  • android studio识别不到夜神模拟器怎么办

    问题描述 xff1a 正常运行情况下 xff0c 夜神模拟器突然找不到了 xff1b 解决方案 xff1a 1 找到夜神模拟器的目录bin目录下 xff0c 路径栏中输入cmd回车 xff0c 进入控制台页面 2 执行命令 nox adb

随机推荐

  • Android 动态设置padding跟margin的问题

    padding view setPadding int left int top int right int bottom margin LayoutParams lp 61 LayoutParams view getLayoutParam
  • svn如何合并代码

    1 先提交本地代码 2 切换至要汇总代码的目标枝干 3 在目标枝干选择最外层的文件夹 xff0c 然后右击文件夹 merge 4 选择需要合并的分支 xff0c 和需要合并的日志 xff1b 5可以先test merge xff0c 然后选
  • android studio logcat 无日志 No connect devices

    解决 xff1a 去sdk tools中找到 google use driver xff0c 下载 xff0c 然后重启编译器 成功 连接不上夜神模拟器可以去夜神对应的bin目录下 xff0c 在目录框中输入cmd回车 输入nox adb
  • android findviewbyid 返回null

    findViewById返回Null 转自 xff1a http blog sina com cn s blog 5e58565701012q2d html 错误 xff1a findViewById返回Null xff0c 报nullpo
  • nox夜神模拟器连接不上android studio,用bat脚本快速输入命令

    不知道为什么android studio老是会识别不到夜神模拟器 xff1b 之前都是通过cmd 到夜神的bin目录下面 然后输入命令 xff0c 连接模拟器 现在发现一种更简单的做法 xff1b 1 创建一个文本文档 xff0c 改名的时
  • 微策略2017年秋招线下笔试+技术面+在线测评+主管面总结

    1 前言 微策略可能在国内的知名度比较小 xff0c 它是一家总部在美国 xff0c 在杭州设立研发中心 xff0c 主要做智能商用软件的外企 更多的信息 xff0c 请自行搜索 我是17年10月份面试微策略 xff0c 然后拿到的开发 x
  • Gradle Wrapper是什么

    Gradle提供了内置的Wrapper task帮助我们自动生成Wrapper所需要的目录文件 在一个项目中的根目录下执行 gradle wrapper即可生成 工程结构介绍 xff1a gradlew xff1a Linux下的可执行脚本
  • nginx上传文件失败,提示上传文件过大,怎么解决

    问题描述 xff1a 上传文件失败 xff0c 文件大小4M左右 上传程序为Java xff0c 通过nginx反向代理写入Fastdfs中 xff0c 但是一直失败 xff0c 查看nginx错误日志 xff0c 提示如下内容 xff1a
  • slf4j,log4j,logback之间的关系

    1 SLF4J Simple logging Facade for Java 意思为简单日志门面 xff0c 它是把不同的日志系统的实现进行了具体的抽象化 xff0c 只提供了统一的日志使用接口 xff0c 使用时只需要按照其提供的接口方法
  • 360笔试题2013

    编程题 传教士人数M xff0c 野人C xff0c M C xff0c 开始都在岸左边 xff0c 船只能载两人 xff0c 传教士和野人都会划船 xff0c 当然必须有人划船 两岸边保证野人人数不能大于传教士人数 把所有人都送过河 xf
  • 搜狗笔试题

    搜狗 xff1a 1 xff0c 有n n个正方形格子 xff0c 每个格子里有正数或者0 xff0c 从最左上角往最右下角走 xff0c 只能向下和向右走 一共走两次 xff0c 把所有经过的格子的数加起来 xff0c 求最大值 且两次如
  • WINDOWS VISTA 使用心得(二)

    WINDOWS VISTA 使用心得 xff08 二 xff09 前面谈了VISTA的版本介绍 xff0c 下面谈谈VISTA的安装 现在网上关于VISTA的文章已经很多了 xff0c 介绍也都很详细 我主要是谈谈自己安装VISTA的感受
  • 数据结构-----约瑟夫环问题

    据说著名犹太历史学家 Josephus有过以下的故事 xff1a 在罗马人占领乔塔帕特后 xff0c 39 个犹太人与Josephus及他的朋友躲到一个洞中 xff0c 39个犹太人决定宁愿死也不要被敌人抓到 xff0c 于是决定了一个自杀
  • Ubuntu错误之runitgit-daemon-runE

    使用apt install命令的错误信息如下所示 Use 39 apt get autoremove 39 to remove them 0 upgraded 0 newly installed 0 to remove and 228 no
  • E: 有未能满足的依赖关系。请尝试不指明软件包的名字来运行“apt --fix-broken install”(也可以指定一个解决办法)。

    提示 xff1a img alt src https img blog csdnimg cn 00ad6aa76f7b4b3083f5fd9dc0c5f826 png 问题描述 安装包缺少依赖关系时 xff0c 系统提示 您也许需要运行 a
  • Android7.0高级设置修改一级菜单分类和显示顺序并跳转第三方应用

    在android 盒子定制开发中 xff0c 时常会遇到需要修改高级设置Settings内容的需求 xff0c 比如在海思3798MV200方案中 xff0c 显示 菜单和 高级设置 菜单都是调整HDMI视频显示相关的设置 xff0c 但
  • Python 绘制散点图

    span class token keyword from span sklearn span class token punctuation span cluster span class token keyword import spa
  • springMVC之配置(context:component-scan) 详解

    lt context component scan base package 61 34 com wjx betalot 34 lt 扫描的基本包路径 gt annotation config 61 34 true 34 lt 是否激活属性
  • Android开发之design库学习

    Internal ForegroundLinearLayout 分割线性能优化 接触第一个类就是他了 xff0c 瞬间get到一点关于性能优化的 xff0c LinearLayout的divider相关属性 xff0c 平时开发需要分割线个
  • Framework学习(六)应用程序进程启动过程

    概述 上篇文章Framework学习 xff08 五 xff09 应用程序启动过程我们讲解了应用程序启动过程 xff0c 但是还有一个遗留知识点 xff0c 那就是应用程序进程的启动 我们知道应用程序启动之前需要保证应用程序的进程先启动 x