浅谈Android应用程序进程启动过程

浅谈Android应用程序进程启动过程

1 应用程序进程简介

要想启动一个应用程序,首先要保证这个应用程序所需要的应用程序进程已经启动。AMS在启动应用程序时会检查这个应用程序需要的应用程序进程是否存在,不存在就会请求Zygote进程启动需要的应用程序进程。
在Zygote的java框架中会创建一个Server端的Socket,这个Socket用来等待AMS请求Zygote来创建新的应用程序进程。Zygote进程通过fork自身创建应用程序进程,这样应用程序进创建过程中除了获取虚拟机实例外,还创建了binder线程池和消息循环,这样运行在应用进程中的应用程序就可以方便地使用Binder进行进程间通信以及消息处理。

2.应用程序启动过程

  • AMS发送启动应用程序进程请求
  • Zygote接收请求并创建应用程序进程

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

AMS如果想要启动应用程序进程,就需要向Zygote进程发送创建应用程序进程的请求,AMS会通过调用startProcessLocked方法向Zygote进程发送请求。

2.1.1 startProcessLocked

    1. 得到创建应用程序进程的用户ID,对用户组ID就行赋值
    1. 给entryPoint赋值为android.app.ActivityThread
    1. 最终调用Process.start()方法,主要讲上述参数传递进去
   private final boolean startProcessLocked(ProcessRecord app, String hostingType,
          String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
      if (app.pendingStart) {
          return true;
      }
      long startTime = SystemClock.elapsedRealtime();
      if (app.pid > 0 && app.pid != MY_PID) {
          checkTime(startTime, "startProcess: removing from pids map");
          synchronized (mPidsSelfLocked) {
              mPidsSelfLocked.remove(app.pid);
              mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
          }
          checkTime(startTime, "startProcess: done removing from pids map");
          app.setPid(0);
      }

      if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
              "startProcessLocked removing on hold: " + app);
      mProcessesOnHold.remove(app);

      checkTime(startTime, "startProcess: starting to update cpu stats");
      updateCpuStats();
      checkTime(startTime, "startProcess: done updating cpu stats");

      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;
          int[] gids = null;
          int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
          if (!app.isolated) {
              int[] permGids = null;
              try {
                  checkTime(startTime, "startProcess: getting gids from package manager");
                  final IPackageManager pm = AppGlobals.getPackageManager();
                  permGids = pm.getPackageGids(app.info.packageName,
                          MATCH_DEBUG_TRIAGED_MISSING, app.userId);
                  StorageManagerInternal storageManagerInternal = LocalServices.getService(
                          StorageManagerInternal.class);
                  mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
                          app.info.packageName);
              } catch (RemoteException e) {
                  throw e.rethrowAsRuntimeException();
              }

              /*
               * Add shared application and profile GIDs so applications can share some
               * resources like shared libraries and access user-wide resources
               */
              if (ArrayUtils.isEmpty(permGids)) {
                  gids = new int[3];
              } else {
                  gids = new int[permGids.length + 3];
                  System.arraycopy(permGids, 0, gids, 3, permGids.length);
              }
              gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
              gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
              gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));

              // Replace any invalid GIDs
              if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
              if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
          }
          checkTime(startTime, "startProcess: building args");
          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;
              }
          }
          int runtimeFlags = 0;
          if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
              runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
              runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
              // Also turn on CheckJNI for debuggable apps. It's quite
              // awkward to turn on otherwise.
              runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
          }
          // Run the app in safe mode if its manifest requests so or the
          // system is booted in safe mode.
          if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
              mSafeMode == true) {
              runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
          }
          if ("1".equals(SystemProperties.get("debug.checkjni"))) {
              runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
          }
          String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
          if ("1".equals(genDebugInfoProperty) || "true".equals(genDebugInfoProperty)) {
              runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
          }
          String genMiniDebugInfoProperty = SystemProperties.get("dalvik.vm.minidebuginfo");
          if ("1".equals(genMiniDebugInfoProperty) || "true".equals(genMiniDebugInfoProperty)) {
              runtimeFlags |= Zygote.DEBUG_GENERATE_MINI_DEBUG_INFO;
          }
          if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
              runtimeFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
          }
          if ("1".equals(SystemProperties.get("debug.assert"))) {
              runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;
          }
          if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {
              // Enable all debug flags required by the native debugger.
              runtimeFlags |= Zygote.DEBUG_ALWAYS_JIT;          // Don't interpret anything
              runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
              runtimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE;   // Disbale optimizations
              mNativeDebuggingApp = null;
          }

          if (app.info.isPrivilegedApp() &&
                  DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
              runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
          }

          if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) {
              app.info.maybeUpdateHiddenApiEnforcementPolicy(
                      mHiddenApiBlacklist.getPolicyForPrePApps(),
                      mHiddenApiBlacklist.getPolicyForPApps());
              @HiddenApiEnforcementPolicy int policy =
                      app.info.getHiddenApiEnforcementPolicy();
              int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
              if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
                  throw new IllegalStateException("Invalid API policy: " + policy);
              }
              runtimeFlags |= policyBits;
          }

          String invokeWith = null;
          if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
              // Debuggable apps may include a wrapper script with their library directory.
              String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
              StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
              try {
                  if (new File(wrapperFileName).exists()) {
                      invokeWith = "/system/bin/logwrapper " + wrapperFileName;
                  }
              } finally {
                  StrictMode.setThreadPolicy(oldPolicy);
              }
          }

          String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
          if (requiredAbi == null) {
              requiredAbi = Build.SUPPORTED_ABIS[0];
          }

          String instructionSet = null;
          if (app.info.primaryCpuAbi != null) {
              instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
          }

          app.gids = gids;
          app.requiredAbi = requiredAbi;
          app.instructionSet = instructionSet;

          // the per-user SELinux context must be set
          if (TextUtils.isEmpty(app.info.seInfoUser)) {
              Slog.wtf(TAG, "SELinux tag not defined",
                      new IllegalStateException("SELinux tag not defined for "
                      + app.info.packageName + " (uid " + app.uid + ")"));
          }
          final String seInfo = app.info.seInfo
                  + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
          // Start the process.  It will either succeed and return a result containing
          // the PID of the new process, or else throw a RuntimeException.
          final String entryPoint = "android.app.ActivityThread";

          return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                  runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                  startTime);
      } catch (RuntimeException e) {
          Slog.e(TAG, "Failure starting process " + app.processName, e);

          // Something went very wrong while trying to start this process; one
          // common case is when the package is frozen due to an active
          // upgrade. To recover, clean up any active bookkeeping related to
          // starting this process. (We already invoked this method once when
          // the package was initially frozen through KILL_APPLICATION_MSG, so
          // it doesn't hurt to use it again.)
          forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
                  false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
          return false;
      }
  }
  
  ...
      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 {
              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});
          }

2.1.2 Process的start

在Process的start方法中调用了ZygoteProcess的start方法,其中zygoteProcess用于保持与Zygote进程的通信状态。

   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);
   }

2.1.3 ZygoteProcess 的 start

    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);
       } catch (ZygoteStartFailedEx ex) {
           Log.e(LOG_TAG,
                   "Starting VM process through Zygote failed");
           throw new RuntimeException(
                   "Starting VM process through Zygote failed", ex);
       }
   }

2.1.4 ZygoteProcess的startViaZygote

将对用应用程序进程启动的参数放在 argsForZygote当中,最终走zygoteSendArgsAndGetResult

  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
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--runtime-flags=" + runtimeFlags);
        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
            argsForZygote.add("--mount-external-default");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
            argsForZygote.add("--mount-external-read");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
            argsForZygote.add("--mount-external-write");
        }
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

   …………

        synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

2.1.5 ZygoteProcess的zygoteSendArgsAndGetResult

主要作用就是将传入的应用进程的启动参数argsForZygote写入ZygoteState中,Zygote是ZygoteProcess的静态内部类,用于表示与Zygote进程通信的窗台。

    /**
向合子进程发送一个参数列表,该进程启动一个新的子进程并返回子进程的pid。请注意:当前的实现用空格替换了参数列表中的换行。
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */
    @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();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }

            /**
             * See com.android.internal.os.SystemZygoteInit.readArgumentList()
             * Presently the wire format to the zygote process is:
             * a) a count of arguments (argc, in essence)
             * b) a number of newline-separated argument strings equal to count
             *
             * After the zygote process reads these it will write the pid of
             * the child or -1 on failure, followed by boolean to
             * indicate whether a wrapper process was used.
             */
            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?
            Process.ProcessStartResult result = new Process.ProcessStartResult();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            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);
        }
    }

2.1.6 ZygoteProcess的openZygoteSocketIfNeeded(abi)

进程间通信,主要与Zygote的Socket建立连接

   /**
    *如果尚未打开,则尝试打开Socket到Zygote进程。如果已经打开,什么也不做。可能阻塞和重试。要求持有mLock。
     */
    @GuardedBy("mLock")
    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
        }
        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

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

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

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

2.1.7AMS发送请求小结

  1. AMS ::startProcessLocked
  2. Process :: start
  3. ZygoteProcess :: start
  4. ZygoteProcess :: startViaZygote
  5. ZygoteProcess :: openZygoteSocketIfNeeded (与zygote的socket建立连接)
  6. ZygoteProcess :: zygoteSendArgsAndGetResult

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

Socket链接成功并匹配ABI后会返回ZygoteState类型对象,我们在zygoteSendArgsAndGetResult方法中可以看到会将相应应用进程的启动参数argsForZygote写到ZygoteState中国呢,这样Zygote进程就会收到一个创建新的应用程序进程的请求。

2.2.1 ZygoteInit 的 main

通过 registerServerSocket方法创建一个Server端的Socket,这个name为"zygote"的Socket用来等待AMS请求Zygote,以创建新的应用程序进程,preload(bootTimingsTraceLog)用来预加载类和资源。之后启动SystemServer进程,最后调用 caller = zygoteServer.runSelectLoop(abiList) 来等待AMS请求创建新的应用程序进程。

  public static void main(String argv[]) {
        ZygoteServer zygoteServer = new ZygoteServer();

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        
        …………

            zygoteServer.registerServerSocketFromEnv(socketName);
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit
            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false, 0);

            Zygote.nativeSecurityInit();

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();

            ZygoteHooks.stopZygoteNoThreadCreation();

            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

2.2.2 zygoteServer.runSelectLoop

当用AMS的请求数据到来时,会调用final Runnable command = connection.processOneCommand(this);

    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        fds.add(mServerSocket.getFileDescriptor());
        peers.add(null);

        while (true) {
           ……
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }

                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    try {
                        ZygoteConnection connection = peers.get(i);
                        final Runnable command = connection.processOneCommand(this);

                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at this
                            // stage if processOneCommand hasn't called "exec".
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run.
                            if (command != null) {
                                throw new IllegalStateException("command != null");
                            }

                            // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This shows up as
                            // a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(i);
                                fds.remove(i);
                            }
                        }
                    } catch (Exception e) {
                        if (!mIsForkChild) {
                            // We're in the server so any exception here is one that has taken place
                            // pre-fork while processing commands or reading / writing from the
                            // control socket. Make a loud noise about any such exceptions so that
                            // we know exactly what failed and why.

                            Slog.e(TAG, "Exception executing zygote command: ", e);

                            // Make sure the socket is closed so that the other end knows immediately
                            // that something has gone wrong and doesn't time out waiting for a
                            // response.
                            ZygoteConnection conn = peers.remove(i);
                            conn.closeSocket();

                            fds.remove(i);
                        } else {
                            // We're in the child so any exception caught here has happened post
                            // fork and before we execute ActivityThread.main (or any other main()
                            // method). Log the details of the exception and bring down the process.
                            Log.e(TAG, "Caught post-fork exception in child process.", e);
                            throw e;
                        }
                    } finally {
                        // Reset the child flag, in the event that the child process is a child-
                        // zygote. The flag will not be consulted this loop pass after the Runnable
                        // is returned.
                        mIsForkChild = false;
                    }
                }
            }
        }
    }

2.2.3ZygoteConnection的processOneCommand

调用readArgumentList方法来获取应用程序进程的启动参数,并将readArgumentList方法返回的字符串数组args封装到Arguments类型的parseArgs对象中,紧接着调用Zygote.forkAndSpecialize方法来创建应用程序进程,参数为parsedArgs中存储的应用进程启动参数。Zygote.forkAndSpecialize方法主要是通过fork当前进程来创建一个子进程的,如果pid为0,则说明当前代码逻辑运行在新创建的子进程(即为应用程序进程)当中,这时就会调用handleChildProc方法来处理应用程序进程

    Runnable processOneCommand(ZygoteServer zygoteServer) {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            throw new IllegalStateException("IOException on command socket", ex);
        }

        // readArgumentList returns null only when it has reached EOF with no available
        // data to read. This will only happen when the remote socket has disconnected.
        if (args == null) {
            isEof = true;
            return null;
        }

        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;

        parsedArgs = new Arguments(args);

        if (parsedArgs.abiListQuery) {
            handleAbiListQuery();
            return null;
        }

        if (parsedArgs.preloadDefault) {
            handlePreload();
            return null;
        }

        if (parsedArgs.preloadPackage != null) {
            handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
                    parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
            return null;
        }

        if (parsedArgs.apiBlacklistExemptions != null) {
            handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
            return null;
        }

        if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
            handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
            return null;
        }

        if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
            throw new ZygoteSecurityException("Client may not specify capabilities: " +
                    "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
                    ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
        }

        applyUidSecurityPolicy(parsedArgs, peer);
        applyInvokeWithSecurityPolicy(parsedArgs, peer);

        applyDebuggerSystemProperty(parsedArgs);
        applyInvokeWithSystemProperty(parsedArgs);

        int[][] rlimits = null;

        if (parsedArgs.rlimits != null) {
            rlimits = parsedArgs.rlimits.toArray(intArray2d);
        }

        int[] fdsToIgnore = null;

        if (parsedArgs.invokeWith != null) {
            try {
                FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                childPipeFd = pipeFds[1];
                serverPipeFd = pipeFds[0];
                Os.fcntlInt(childPipeFd, F_SETFD, 0);
                fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
            } catch (ErrnoException errnoEx) {
                throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
            }
        }

        /**
         * In order to avoid leaking descriptors to the Zygote child,
         * the native code must close the two Zygote socket descriptors
         * in the child process before it switches from Zygote-root to
         * the UID and privileges of the application being launched.
         *
         * In order to avoid "bad file descriptor" errors when the
         * two LocalSocket objects are closed, the Posix file
         * descriptors are released via a dup2() call which closes
         * the socket and substitutes an open descriptor to /dev/null.
         */

        int [] fdsToClose = { -1, -1 };

        FileDescriptor fd = mSocket.getFileDescriptor();

        if (fd != null) {
            fdsToClose[0] = fd.getInt$();
        }

        fd = zygoteServer.getServerSocketFileDescriptor();

        if (fd != null) {
            fdsToClose[1] = fd.getInt$();
        }

        fd = null;

        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);

        try {
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;

                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.startChildZygote);
            } else {
                // In the parent. A pid < 0 indicates a failure and will be handled in
                // handleParentProc.
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

2.2.4 ZygoteConnection的handleChildProc

 private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
        /**
         * By the time we get here, the native code has closed the two actual Zygote
         * socket connections, and substituted /dev/null in their place.  The LocalSocket
         * objects still need to be closed properly.
         */

        closeSocket();
        if (descriptors != null) {
            try {
                Os.dup2(descriptors[0], STDIN_FILENO);
                Os.dup2(descriptors[1], STDOUT_FILENO);
                Os.dup2(descriptors[2], STDERR_FILENO);

                for (FileDescriptor fd: descriptors) {
                    IoUtils.closeQuietly(fd);
                }
            } catch (ErrnoException ex) {
                Log.e(TAG, "Error reopening stdio", ex);
            }
        }

        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);

            // Should not get here.
            throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
        } else {
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }
        }
    }

2.2.5 ZygoteInit的zygoteInit

在新创建的应用程序进程中创建Binder线程池

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

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

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

2.2.6 RuntimeInit.applicationInit

   protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
           ClassLoader classLoader) {
       // If the application calls System.exit(), terminate the process
       // immediately without running any shutdown hooks.  It is not possible to
       // shutdown an Android application gracefully.  Among other things, the
       // Android runtime shutdown hooks close the Binder driver, which can cause
       // leftover running threads to crash before the process actually exits.
       nativeSetExitWithoutCleanup(true);

       // We want to be fairly aggressive about heap utilization, to avoid
       // holding on to a lot of memory that isn't needed.
       VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
       VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

       final Arguments args = new Arguments(argv);

       // The end of of the RuntimeInit event (see #zygoteInit).
       Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

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

2.2.7 RuntimeInit的 findStaticMain

通过反射获得了android.app.ActivityThread类,接下来获得了ActivityThread的main方法,最终走到ActivityThread的main方法,到这里,应用程序进程就创建完成了并且运行了主线程的管理ActivityThread

 protected static Runnable findStaticMain(String className, String[] argv,
           ClassLoader classLoader) {
       Class<?> cl;

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

       Method m;
       try {
           m = cl.getMethod("main", new Class[] { String[].class });
       } 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();
       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.
        */
       return new MethodAndArgsCaller(m, argv);
   }

2.2.8Zygote接收请求并创建应用程序进程小结

  1. ZygoteInit :: main
  2. zygoteServer :: runSelectLoop
  3. ZygoteConnection :: processOneCommand
  4. ZygoteConnection :: handleChildProc
  5. ZygoteInit :: zygoteInit
  6. RuntimeInit :: applicationInit
  7. RuntimeInit :: findStaticMain

参考: 刘望舒《Android进阶解密》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值