android7.0应用冷启动流程分析(代码片段)

江湖人称小白哥 江湖人称小白哥     2022-11-28     191

关键词:

最近在为自己Moto G定制Rom,顺便重新读了一遍Android 7.0的相关源码,特此记录当做笔记.

在开始正文之前,首先要明白冷启动和热启动.所谓冷启动就是启动该应用时,后台没有该应用的进程,此时系统会创建一个进程分配给它(AMS通过Socket和Zygote通信,Zygote通过forkAndSpecialize()方法向Linux内核申请新进程),之后会创建和初始化Application,然后通过反射执行ActivityThread中的main方法.而热启动则是,当启动应用的时候,后台已经存在该应用的进程,比如按home键返回主界面再打开该应用,此时会从已有的进程中来启动应用,这种方式下,不会重新走Application这一步.

那今天我们主要分析的是应用冷启动的过程.在分析过程中,我发现从Android 2.3到Android 7.0的启动流程总体变化不大,所以,无论你目前是用何版本,下文多是通用的.另外,在本文中,我省略掉了有关Binder这一部分,以便大部分人都能顺利阅读.


从Launcher点击开始

Launcher就是我们所说的桌面,它本质也是一个apk,当我们点击桌面上的图标时,会调用Activity的startActivity(),最终调用startActivityForResult():

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) 
        if (mParent == null) 
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            // 省略多行代码
         else 
           // 省略多行代码
        
    

startActivityForResult将创建过程委托给Instrumenttation的execStartActivity():

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) 
        //重点关注IApplicationThread
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) 
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        
        if (mActivityMonitors != null) 
            synchronized (mSync) 
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) 
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) 
                        am.mHits++;
                        if (am.isBlocking()) 
                            return requestCode >= 0 ? am.getResult() : null;
                        
                        break;
                    
                
            
        
        try 
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            // 重点关注ActivityManagerNative
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
         catch (RemoteException e) 
            throw new RuntimeException("Failure from system", e);
        
        return null;
    

在该方法签名中,我们看到第二个参数contextThread是IBinder类型,继续往下看,发现contextThread实则是IApplicationThread的实现类.简单来看IApplicationThread的定义:

public interface IApplicationThread extends IInterface 
    void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving,
            int configChanges, boolean dontReport) throws RemoteException;
    void scheduleStopActivity(IBinder token, boolean showWindow,
            int configChanges) throws RemoteException;
    void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException;
    void scheduleSleeping(IBinder token, boolean sleeping) throws RemoteException;
    void scheduleResumeActivity(IBinder token, int procState, boolean isForward, Bundle resumeArgs)
            throws RemoteException;
    void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
    void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
            int procState, Bundle state, PersistableBundle persistentState,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException;
    void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
            List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
            Configuration config, Configuration overrideConfig) throws RemoteException;
    void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
    void scheduleDestroyActivity(IBinder token, boolean finished,
            int configChanges) throws RemoteException;
    void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
            int resultCode, String data, Bundle extras, boolean sync,
            int sendingUser, int processState) throws RemoteException;
    // 省略多个方法
    void scheduleBindService(IBinder token,
            Intent intent, boolean rebind, int processState) throws RemoteException;
    void scheduleUnbindService(IBinder token,
            Intent intent) throws RemoteException;
    //省略多个方法
    void scheduleStopService(IBinder token) throws RemoteException;
    //省略多个方法
    void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
            ComponentName testName, ProfilerInfo profilerInfo, Bundle testArguments,
            IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
            int debugMode, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
            Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
            Bundle coreSettings) throws RemoteException;
    void scheduleExit() throws RemoteException;
    // 省略多行代码
    void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String data, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException;
    void scheduleLowMemory() throws RemoteException;
    void scheduleActivityConfigurationChanged(IBinder token, Configuration overrideConfig)
            throws RemoteException;
  //省略多个方法
    void scheduleTrimMemory(int level) throws RemoteException;
  //省略多个方法

通过大体的阅读IApplicationThread中代码,我们隐约有些熟悉,比如schedulePauseActivity方法应该就是负责Activity中Pause()执行的,scheduleLaunchActivity()应该是负责Activity创建的,scheduleBindService()负责Service绑定的,到现在,我们心里应该会想到IApplicationThread的真正实现类ApplicationThread(位于ActivityThread.java中)就是负责Activity,Service等的创建或其他操作,先来简单的看起其类关系图:

我们继续看Instrumentation的execStartActivity()方法:

int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

此时启动Activity这一操作交给了ActivityManagerNative.getDefault()的startActivity()方法.ActivityManagerNative是一个抽象类,继承了Binder,同时它又实现了IActivityManager接口,其实现类是ActivityManagerService(AMS).

ActivityManagerNative.getDefault()方法返回IActivityManager类型对象,其实现类是ActivityManagerProxy,其构造函数接受一个IBinder类型,其实就是ActivityManagerService对象,此时你应该发现ActivityManagerNative,IActivityManager以及ActivityManagerProxy三者之间的联系如下:

通过上图,我们看到这三者就是一个典型的代理模式:ActivityManagerProxy就是ActivityManagerService的远程代理,那么此时ActivityManagerNative的作用也就很明显:返回AMS的远程代理对象,这样Launcher应用就能和AMS服务通信了.

我们用一张图来简单的描述上述整个流程:

进入ActivityManagerService

现在我们跳到AMS的startActivity()方法继续往下看:

    @Override
        public int startActivity(IBinder whoThread, String callingPackage,
                Intent intent, String resolvedType, Bundle options) 
            checkCaller();

            int callingUser = UserHandle.getCallingUserId();
            TaskRecord tr;
            IApplicationThread appThread;
            synchronized (ActivityManagerService.this) 
                tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
                if (tr == null) 
                    throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                
                appThread = ApplicationThreadNative.asInterface(whoThread);
                if (appThread == null) 
                    throw new IllegalArgumentException("Bad app thread " + appThread);
                
            
          //交给mStackSupervisor继续
            return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent,
                    resolvedType, null, null, null, null, 0, 0, null, null,
                    null, options, false, callingUser, null, tr);
        

首先我们注意到该方法的第一个参数是IBinder类型,其实质就是前边ApplicationThread的实例,也就是ActivityThread中的mAppThread对象.接下来交给ActivityStackSupervisor实例的startActivityMayWait()继续启动:

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
            Bundle options, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) 
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors()) 
            throw new IllegalArgumentException("File descriptors passed in Intent");
        
        boolean componentSpecified = intent.getComponent() != null;

        // Don't modify the client's object!
        intent = new Intent(intent);

        // Collect information about the target of the Intent.
        ActivityInfo aInfo =
                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);

        ActivityContainer container = (ActivityContainer)iContainer;
        synchronized (mService) 
            //省略多行代码
            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);
            // 省略多行代码

            return res;
        
    

该方法看起来非常复杂,但是流程确实蛮清晰的,通过resolveActivity()方法来获取ActivityInfo,接下来是一些其他操作(在不影响流程的前提下,省略多行),然后继续调用startActivityLocked():

final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            ActivityContainer container, TaskRecord inTask) 
        int err = ActivityManager.START_SUCCESS;
        //省略多行代码
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);


        return err;
    

在该方法中,又继续调用了startActivityUncheckedLocked()方法,抛开其中细节,我们发现该方法中又继续调用了ActivityStack的resumeTopActivityLocked()来继续启动流程:

 final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) 
        if (mStackSupervisor.inResumeTopActivity) 
            // Don't even start recursing.
            return false;
        

        boolean result = false;
        try 
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) 
                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
                mService.updateSleepIfNeededLocked();
            
            //继续启动
            result = resumeTopActivityInnerLocked(prev, options);
         finally 
            mStackSupervisor.inResumeTopActivity = false;
        
        return result;
    

从上面的代码看出,resumeTopActivitiesLocked()方法继续调用了resumeTopActivityInnerLocked()方法,该方法内部又反过来调用了ActivityStackSupervisor的resumeTopActivitiesLocked()方法

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) 
                //省略多行代码

                mStackSupervisor.startSpecificActivityLocked(next, true, false);
                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                return true;
            

在上述代码中,由于应用是第一次启动,因此这里跳过了一些判断代码,最终又调用了ActivityStackSupervisor的startSpecificActivityLocked()来继续启动流程:

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) 
        // Is this activity's application already running?
        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);
                return;
             catch (RemoteException e) 
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            
        

        //该应用的进程尚未创建,调用AMS的startProcessLocked()
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    

应用是第一次启动,此时系统尚未为其创建进程,因此调用AMS的startProcessLocked()方法,如果该应用已经存在,则调用realStartActivityLocked().由于这里我们的应用第一次启动,所以从startProcessLocked()往下看:

  final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) 
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,hostingName, allowWhileBooting, isolated, 0 , keepIfLarge,null , null , null,null);
    

该方法直接调用了其对应的重载方法,并在该其中继续调用了重载方法:

      private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) 
        long startTime = SystemClock.elapsedRealtime();
            //省略多行代码
            boolean isActivityProcess = (entryPoint == null);

            //默认情况下,entryPoint为null,此时虚拟机启动后默认从ActivityThread的main()方法执行
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);

            //要求Zygote进程为其创建进程
            checkTime(startTime, "startProcess: asking zygote to start proc");
            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);
            checkTime(startTime, "startProcess: returned from zygote!");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

           //省略多行代码
         catch (RuntimeException e) 
            //省略
        
    

到现在我们同样用一张图来描述这过程:

走进Zygote

这里通过Process的start()方法来请求Zygote进程为其生成新进程,在start()方法中又直接调用了startViaZygote():

//processClass是调用者传的android.app.ActivityThread
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) 
            ArrayList<String> argsForZygote = new ArrayList<String>();

            // --runtime-args, --setuid=, --setgid=,
            // and --setgroups= must go first
            //--runtime-agrs决定了新建进程执行方式,
            argsForZygote.add("--runtime-args");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
            if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) 
                argsForZygote.add("--enable-jni-logging");
            
            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) 
                argsForZygote.add("--enable-safemode");
            
            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) 
                argsForZygote.add("--enable-debugger");
            
            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) 
                argsForZygote.add("--enable-checkjni");
            
            if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0) 
                argsForZygote.add("--enable-jit");
            
            if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) 
                argsForZygote.add("--generate-debug-info");
            
            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) 
                argsForZygote.add("--enable-assert");
            
            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);

            //TODO optionally enable debuger
            //argsForZygote.add("--enable-debugger");

            // --setgroups is a comma-separated list
            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());
            

            if (niceName != null) 
                argsForZygote.add("--nice-name=" + niceName);
            

            if (seInfo != null) 
                argsForZygote.add("--seinfo=" + seInfo);
            

            if (instructionSet != null) 
                argsForZygote.add("--instruction-set=" + instructionSet);
            

            if (appDataDir != null) 
                argsForZygote.add("--app-data-dir=" + appDataDir);
            

            argsForZygote.add(processClass);

            if (extraArgs != null) 
                for (String arg : extraArgs) 
                    argsForZygote.add(arg);
                
            

            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        
    

上面的方法非常简单,设置一堆参数后然后又调用了zygoteSendArgsAndGetResult()向Zygote发送创建进程请求,该方法内部就是和Zygote进行Socket通信.Zygote接受到该请求,并将该请求封装为ZygoteConnection对象,具体代码在ZygoteInit.java当中,来看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());
        peers.add(null);

        while (true) 
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) 
                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) 
                if ((pollFds[i].revents & POLLIN) == 0) 
                    continue;
                
                if (i == 0) 
                  //接受来自AMS的请求
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                 else 
                    boolean done = peers.get(i).runOnce();
                    if (done) 
                        peers.remove(i);
                        fds.remove(i);
                    
                
            
        
    

此时Zygote作为服务端不断监听来自AMS的请求,通过acceptCommandPeer()将请求封装为ZygoteConection对象,并将Socket文件标识存在fds中,请求放在peers中.而runOnce()则在下一次循环中处理请求,具体代码如下:

   boolean runOnce() throws ZygoteInit.MethodAndArgsCaller 

        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try 
            //读取请求中的参数
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
         catch (IOException ex) 
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        
        //省略多行代码
        /** the stderr of the most recent request, if avail */

        PrintStream newStderr = null;

        if (descriptors != null && descriptors.length >= 3) 
            newStderr = new PrintStream(
                    new FileOutputStream(descriptors[2]));
        

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

        try 
            //将请求参数封装成Arguments对象
            parsedArgs = new Arguments(args);

            //省略多行代码
            //创建新进程或者说创建VM实例
            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 

            if (pid == 0) //pid=0表示刚才fork出的子进程
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                // should never get here, the child is expected to either
                // throw ZygoteInit.MethodAndArgsCaller or exec().
                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);
        
    

上面的代码比较简单主要是读取请求参数并将其封装为Arguments对象,Arguments包含一下参数:

--setuid=
--setgid=
--target-sdk-version=
--enable-debugger
--enable-safemode
--enable-checkjni
--enable-jit
--generate-debug-info
--enable-jni-logging
--enable-assert
--runtime-args
--seinfo=
--capabilities=
--rlimit=
--setgroups=
--invoke-with
--nice-name=
--mount-external-default
--mount-external-read
--mount-external-write
--query-abi-list
--instruction-set=
--app-data-dir=

并通过Zygote的forkAndSpecialize()来生成新进程,成功后pid的值为0,这里我们只关心创建成功的情况,接下来,在新的进程中关闭从Zygote继承来的Socket,然后通过handleChildProc()继续后续操作.

  private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller 
        //关闭AMS和Zygote之间的Socket连接   
        closeSocket();
        ZygoteInit.closeServerSocket();

        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);
                
                newStderr = System.err;
             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);
         else 
          //寻找相应目标类的main()方法并执行
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        
    

这里根据invokeWith参数决定使用哪种执行方式,invokeWith不为空则通过WrapperInit执行,否则通过RuntimeInit方式执行.对于这两者不做过多的解释,参数—runtime-args决定了新进程都是以RuntimeInit方式启动,目前就记住SystemServer和apk都是通过RuntimeInit来的即可.

走进RuntimeInit

现在来看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();
        applicationInit(targetSdkVersion, argv, classLoader);
    

commonInit()为VM设置默认了线程异常处理器,然后调用了本地方法nativeZygoteInit(),其具体实现在AndroidRuntime.cpp下,位于frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)

    gCurRuntime->onZygoteInit();

在该方法中又调用了其子类AppRutime的onZygoteInit()方法,AppRuntime位于frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit()
    
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\\n");
        proc->startThreadPool();
    

为了不影响后文,我们先回到RuntimeInit的applicationInit():

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

        nativeSetExitWithoutCleanup(true);
        //VM设置
        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;
        
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        //反射执行ActivityThread的main函数
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    

其中最关键的就是invokeStaticMain()方法:

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller 
        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);
        


        //该异常会在ZygoteInit.main()中被捕获,然后在异常处理中调用MethodAndArgsCaller的run()
        //方法,这样就清除了进程中所有的栈帧
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    

在上面的代码中,最终的执行是通过抛出MethodAndArgsCaller的方式,来看一下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 );
             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);
            
        
    

MethodAndArgsCaller继承Exception类并实现Runnable接口.但不管如何,现在最终开始执行ActivityThread的入口函数main():

    public static void main(String[] args) 
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();
        EventLogger.setReporter(new EventLoggingReporter());

        AndroidKeyStoreProvider.install();
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) 
            sMainThreadHandler = thread.getHandler();
        

        if (false) 
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    

当main()开始运行时,主线程正式开始运行,这也就是我们所说的UI线程.同样我们用一张简单的图来描述上述过程:

总结

到现在,我们已经完全走完应用冷启动的流程,上面的过程看起来繁琐,但是结合时序图来看应该是比较清晰的.抛开细节不看,那么上述的整个流程可以用下图概括:

最后为了方便系统理解整个流程,附上一张相对完整的时序图:

android7.0系统启动流程分析(代码片段)

...ndroid版本的升级,aosp项目中的代码也有了些变化,本文基于Android7.0分析Android系统启动流程.当我们按下电源键后,整个Android设备大体经过了一下过程:今天我们只想来分析init进程及其后的过程,也就是下图所示部分:init进程init进程会... 查看详情

android应用启动流程分析(代码片段)

...。2冷启动与热启动Activity启动过程中,一般会牵涉到应用启动的流程。应用启动又分为冷启动和热启动。冷启动:点击桌面图标,手机系统不存在该应用进程,这时系统会重新fork一个子进程来加载Application并启动A... 查看详情

android7.0系统启动流程分析(代码片段)

...ndroid版本的升级,aosp项目中的代码也有了些变化,本文基于Android7.0分析Android系统启动流程.当我们按下电源键后,整个Android设备大体经过了一下过程:今天我们只想来分析init进程及其后的过程,也就是下图所示部分:init进程init进程会... 查看详情

微信matrix源码分析-如何计算app启动耗时(代码片段)

...么是启动耗时分为两个角度:冷启动:就是点击应用图标到打开应用的冷启动响应时间,且前提是应用从未被创建过进程,热启动:测量点击应用图标到打开应用的热启动响应时间,被测应用之前已经被打... 查看详情

应用内部启动startactivity-android12(代码片段)

应用内部启动startActivity-Android12android12-release桌面冷启动查看AMS:startActivity桌面启动应用1.明确冷启动相关对象首先桌面冷启动查看AMS:startActivity桌面启动应用,明确几个对象:ActivityThread【ApplicationThread】已经fork主线程app&#... 查看详情

android应用启动流程分析(代码片段)

1前言网上看过很多Activity启动过程的源码解析,很多文章会贴上一大段代码,然后从startActivity()函数开始深究整个源码的调用栈。个人感觉这类文章代码细节太多,反而容易迷失在源码调用之中,从而忽略了Activit... 查看详情

activity的启动流程分析(代码片段)

Activity是Android应用程序的四大组件之一,负责管理Android应用程序的用户界面,一般一个应用程序中包含很多个Activity,他们可能运行在一个进程中,也可能运行在不同的进程中。我们主要通过启动在不同进程中的Activity,... 查看详情

android7.0-----directboot模式(appclock)(代码片段)

本文针对闹钟应用对于此次Android7.0增加DB模式所需要的应对方式。DirectBoot模式:设备已开机但用户尚未解锁设备时,Android7.0将在安全的“直接启动”模式下运行。简单来说,如果不做处理,在手机开机锁屏的情... 查看详情

android性能优化之启动速度优化(代码片段)

...案,甚至包含一些FW层的代码改动,有的可能是对应用开发者无效的,但是对于车载开发是有用的。一安卓APP启动完整流程分析(冷启动)图1:主要分为三个阶段:1.1桌面点击APP图标,通知到AMS去完成应... 查看详情

android系统启动流程分析(代码片段)

...探在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。launcher程序可以理解为作为其它应用app... 查看详情

android7.0分屏拖拽文字和图片的研究(代码片段)

一前提二实测一三实测二四分析1分屏拖拽实现分析-Activity间ViewstartDragAndDrop实现拖拽图片的例子2拖拽实现分析-Activity内一、前提1.同一个应用app;2.不同的activity(A和B)且支持分屏;3.两个activity共享屏幕(即... 查看详情

android7.0分屏拖拽文字和图片的研究(代码片段)

一前提二实测一三实测二四分析1分屏拖拽实现分析-Activity间ViewstartDragAndDrop实现拖拽图片的例子2拖拽实现分析-Activity内一、前提1.同一个应用app;2.不同的activity(A和B)且支持分屏;3.两个activity共享屏幕(即... 查看详情

contentprovider的启动流程分析(代码片段)

...件之一,主要用于向外部提供数据。不仅可以向自己应用进程提供数据,也可以向其他进程的提供数据。所以在分析ContentProvider的时候我们首先分析本进程的ContentProvider的启动过程,然后再分析调用其他进程的ContentPr... 查看详情

应用内部启动startactivity-android12(代码片段)

应用内部启动startActivity-Android12android12-release桌面冷启动查看AMS:startActivity桌面启动应用1.明确冷启动相关对象首先桌面冷启动查看AMS:startActivity桌面启动应用,明确几个对象:ActivityThread【ApplicationThread】已经fork主线程app&#... 查看详情

android系统启动流程分析(代码片段)

...探在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。launcher程序可以理解为作为其它应用app... 查看详情

android|activity启动流程分析(代码片段)

前言Activity类是android应用的关键组件,在日常开发中,绝对少不了组件。既然用了这么久,你知道他的启动流程🐴?作为一个应用层开发者,大多数人可能觉得学习这些对日常开发可能没有太大帮助。但... 查看详情

[oc学习笔记]启动流程(代码片段)

我们的app是如何从桌面图标被启动的嘞?这个问题值得探究。冷启动与热启动这两个启动的区别其实很简单,就看启动之前手机后台是否有app存活。名称区别冷启动启动时,App的进程不在系统里,需要开启新进程... 查看详情

android7.0通过fileprovider实现应用间文件共享(代码片段)

一、介绍对于Android7.0,提供了非常多的变化,详细的可以阅读官方文档Android7.0行为变更,记得当时做了多窗口支持、FileProvider以及7.1的3DTouch的支持,不过和我们开发者关联最大的,或者说必须要适配的就是... 查看详情