小夜曲:晓说ActivityThread

作者: 空同定翁 | 来源:发表于2017-06-22 17:15 被阅读181次

    该篇是Android启动系列的最后一篇,本文从应用进程的创建启动角度出发,分析ActivityThread是如何创建的。相对于上篇,本文内容较少,阅读无压力~

    从接触Android的那一刻开始,看到最多的是:耗时任务不能在主线程执行,UI操作要在主线程执行……当时人傻无知,从来没有想过什么是主线程,为啥不能在主线程做耗时任务等等。
    大家都说ActivityThread是主线程,那它是线程吗?它为什么被称为主线程?它做啥了?

    回顾

    在上文《沉思曲:Activity启动》一文中,分析了Activity的启动过程。并在调用startSpecificActivityLocked方法时,提到这里会判断目的Activity进程是否存在,如果不存在,就会创建新进程,本文就从这个创建新进程的分支开始。

    创建应用进程


    先回顾下startSpecificActivityLocked方法

    该方法在ActivityStackSupervisor.java中

    void startSpecificActivityLocked(ActivityRecord r,
                boolean andResume, boolean checkConfig) {
            //获取待启动Activity的进程信息
            ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                    r.info.applicationInfo.uid, true);
    
            r.task.stack.setLaunchTime(r);
    
            //待启动Activity所在进程存在
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.info.packageName, mService.mProcessStats);
                    //接着往下执行
                    realStartActivityLocked(r, app, andResume, checkConfig);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting activity "
                            + r.intent.getComponent().flattenToShortString(), e);
                }
            }
    
            //待启动Activity所在进程不存在,为其创建新进程
            mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
        }
    
    • 上方法中,如果目的Activity所在进程不存在,调用AMS的startProcessLocked方法创建目的应用进程。

    1.1、startProcessLocked

    startProcessLocked定义在ActivityManagerService.java中,该方法会调用Process的start方法。

    // Start the process.  It will either succeed and return a result containing
    // the PID of the new process, or else throw a RuntimeException.
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, app.info.seinfo, null);
    
    • 该方法调用Process的start方法,注意传入参数:<u>"android.app.ActivityThread"</u>

    1.2、 start | Process.java

    /**
     * Start a new process.
     * 
     * <p>If processes are enabled, a new process is created and the
     * static main() function of a <var>processClass</var> is executed there.
     * The process will continue running after this function returns.
     * 
     * <p>If processes are not enabled, a new thread in the caller's
     * process is created and main() of <var>processClass</var> called there.
     * 
     * <p>The niceName parameter, if not an empty string, is a custom name to
     * give to the process instead of using processClass.  This allows you to
     * make easily identifyable processes even if you are using the same base
     * <var>processClass</var> to start them.
     * 
     * @param processClass The class to use as the process's main entry
     *                     point.
     * @param niceName A more readable name to use for the process.
     * @param uid The user-id under which the process will run.
     * @param gid The group-id under which the process will run.
     * @param gids Additional group-ids associated with the process.
     * @param debugFlags Additional flags.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SE Android information for the new process.
     * @param zygoteArgs Additional arguments to supply to the zygote process.
     * 
     * @return An object that describes the result of the attempt to start the process.
     * @throws RuntimeException on fatal start failure
     * 
     * {@hide}
     */
    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[] zygoteArgs) {
        try {
            //通过Zygote启动新进程
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
        }
    }
    

    从注释可知,该方法用来启动一个新进程:

    • 如果进程启动,则processClass(此处入参为“android.app.ActivityThread”)会运行在该新进程中,并且在该方法调用完成后,新进程会继续运行。
    • 如果进程未启动,则调用该start方法所在的进程会创建一个新的线程,然后processClass运行在该新线程中。

    方法调用startViaZygote方法,从方法名看出,进程创建似乎是要交给zygote。

    1.3、startViaZygote | Process.java

    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[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            //启动新进程的参数
            ArrayList<String> argsForZygote = new ArrayList<String>();
    
            //添加各种参数到argsForZygote
            argsForZygote.add("--runtime-init");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
            ...
    
            if (niceName != null) {
                argsForZygote.add("--nice-name=" + niceName);
            }
    
            if (seInfo != null) {
                argsForZygote.add("--seinfo=" + seInfo);
            }
            argsForZygote.add(processClass);
            
            ...
    
            //调用该方法,由zygote创建进程,并获取新进程信息
            return zygoteSendArgsAndGetResult(argsForZygote);
        }
    }
    

    这个方法设置启动新进程所需参数,并往下调用zygoteSendArgsAndGetResult方法。

    1.4、zygoteSendArgsAndGetResult | Process.java

    private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
            throws ZygoteStartFailedEx {
        //进程通信,连接到Zygote的Server Socket,交由Zygote创建
        openZygoteSocketIfNeeded();
    
        try {
            //sZygoteWriter将参数发送到Server Socket
            sZygoteWriter.write(Integer.toString(args.size()));
            sZygoteWriter.newLine();
    
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                if (arg.indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx(
                            "embedded newlines not allowed");
                }
                sZygoteWriter.write(arg);
                sZygoteWriter.newLine();
            }
    
            sZygoteWriter.flush();
    
            //sZygoteInputStream从Server Socket读取结果
            ProcessStartResult result = new ProcessStartResult();
            result.pid = sZygoteInputStream.readInt();
            ...
            result.usingWrapper = sZygoteInputStream.readBoolean();
            return result;
        ...
    }
    

    从方法名可以猜出该方法大致干啥了:发送启动参数给Zygote进程,交由Zygote进程启动,并获得启动结果。看下是否如此:
    1、调用openZygoteSocketIfNeeded方法。
    2、调用sZygoteWriter往ServerSocket写创建进程所需要的参数,ServerSocket是啥?
    3、创建ProcessStartResult,并写入从ServerSocket读取的数据,作为结果返回。
    看来重点在openZygoteSocketIfNeeded方法!

    1.5、openZygoteSocketIfNeeded | Process.java

    private static void openZygoteSocketIfNeeded() 
            throws ZygoteStartFailedEx {
    
        //重连次数
        int retryCount;
    
        if (sPreviousZygoteOpenFailed) {
            retryCount = 0;
        } else {
            retryCount = 10;            
        }
    
        for (int retry = 0
                ; (sZygoteSocket == null) && (retry < (retryCount + 1))
                ; retry++ ) {
            ...
    
            try {
                //client socket
                sZygoteSocket = new LocalSocket();
                //连接到Zygote的server socket
                sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, 
                        LocalSocketAddress.Namespace.RESERVED));
                //sZygoteInputStream负责读取server socket信息
                sZygoteInputStream
                        = new DataInputStream(sZygoteSocket.getInputStream());
                //sZygoteWriter发送信息到server socket
                sZygoteWriter =
                    new BufferedWriter(
                            new OutputStreamWriter(
                                    sZygoteSocket.getOutputStream()),
                            256);
                sPreviousZygoteOpenFailed = false;
                break;
            ...
    }
    

    详细大家都能一眼看懂,这不是Java中的Socket的连接吗,这不过这里是用来进程连接。
    1、创建Client Socket:sZygoteSocket
    2、ClientSocket连接到服务端,ServerSocket:ZYGOTE_SOCKET
    3、创建输入流负责从ServerSocket读数据,创建输出流向ServerSocket写数据。

    即:

    • openZygoteSocketIfNeeded方法负责连接到Zygote的Server Socket,并发送/读取Server Socket的信息。
    • ServerSocket即ZYGOTE_SOCKET,它有Zygote进程创建。

    既然client socket连接到Zygote的创建的ServerSocket了,那接下来看下Zygote是如何处理连接的。

    Zygote处理客户端连接


    Zygote进程由init进程启动,Zygote的实现在ZygoteInit.java中,其main方法调用标志着Zygote的启动。

    2.1、main | ZygoteInit.java

    public static void main(String argv[]) {
       try {
            //注册server socket
            //其它进程的创建,通过连接到该Socket后,由zygote孵化出来
            registerZygoteSocket();
            
            ...
            //预加载android framework类和资源
            preload();
            
            ...
            if (argv[1].equals("start-system-server")) {
                //启动SystemServer
                startSystemServer();
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }
    
            //死循环接收client socket连接,由此创建新进程
            runSelectLoop();
    
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {  //标注加红,这个异常捕获是重点!!!
            caller.run();
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }
    
    • Zygote进程启动时,注册了ServerSocket,即上面提到的ZYGOTE_SOCKET,就是它来处理client socket的连接。
    • Zygote进程启动时还启动了SystemServer,这在第一篇文章中已经分析过了。
    • 最后调用runSelectLoop方法,死循环处理client socket连接。

    最后需要注意的是:
    main方法采用了try-catch的方式,其中捕获了异常MethodAndArgsCaller。由后面代码可知,通过这种抛异常的方式,使进程跳出死循环,并执行caller.run方法。

    2.2、runSelectLoop | ZygoteInit.java

    上面方法调用runSelectLoop,死循环处理client连接,看下其内容。

    private static void runSelectLoop() throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        //client socket连接列表
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        
        FileDescriptor[] fdArray = new FileDescriptor[4];
        //将server socket添加到fds中
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
        int loopCount = GC_LOOP_COUNT;
        
        while (true) {
            int index;
            ...
    
            try {
                //将fds转换成数组
                fdArray = fds.toArray(fdArray);
                //在fdArray中找到可读的连接
                index = selectReadable(fdArray);
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }
    
            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                //第一个为Server socket,此时等待client socket连接
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
                //处理连接
                done = peers.get(index).runOnce();
                //处理完连接,从列表中移除
                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
        }
    }
    

    代码逻辑还是比较清楚:

    • Zygote死循环处理已连接的client socket,client的连接封装成ZygoteConnection 表示,并调用其的runOnce()方法。
    • 如果已连接的client socket都处理完成,那就等待新的client连接。

    2.3、runOnce | ZygoteConnection.java

    看下连接的处理方法runOnce():

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
    
        try {
            //读取client socket传入的参数列表
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } 
        ...
    
        try {
            //转换参数
            parsedArgs = new Arguments(args);
            ...
            
            //Zygote创建 新进程并负责虚拟机实例到该进程
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName);
        }
        ...
    
        try {
            //新进程
            if (pid == 0) {
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //新进程中调用
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            }
            ...
    }
    

    要划重点了:
    1、该方法读取client socket连接时传入的参数,并封装。
    2、调用Zygote的forkAndSpecialize创建指定进程。
    3、pid=0时即子进程,在子进程中调用handleChildProc方法。

    这里涉及到以下几点:

    • 应用进程的确是有Zygote进程创建的,包括前文提到的SystemServer进程
    • 新进程时如何与虚拟机关联的?
      在forkAndSpecialize方法中,Zygote会将创建的Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的Dalvik虚拟机实例。

    好了,新进程已经创建好了,但似乎还没解决问题,ActivityThread是如何运行在新进程中的呢?接着往下看handleChildProc方法。

    2.4、handleChildProc | ZygoteConnection.java

    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
      
        //子进程中关闭client/server socket
        closeSocket();
        ZygoteInit.closeServerSocket();
        ...
        if (parsedArgs.niceName != null) {
            //设置进程名
            Process.setArgV0(parsedArgs.niceName);
        }
    
        //是否设置了runtimeInit参数
        if (parsedArgs.runtimeInit) {
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        pipeFd, parsedArgs.remainingArgs);
            } else {
                //zygoteInit最后仍会创建ActivityThread实例,并调用其main方法
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs);
            }
        } else {
            String className;
            try {
                //传入的类全限定名,此处为:“android.app.ActivityThread”
                className = parsedArgs.remainingArgs[0];
            } 
            ...
                    
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execStandalone(parsedArgs.invokeWith,
                        parsedArgs.classpath, className, mainArgs);
            } else {
                ClassLoader cloader;
                if (parsedArgs.classpath != null) {
                    //ClassLoader
                    cloader = new PathClassLoader(parsedArgs.classpath,
                            ClassLoader.getSystemClassLoader());
                } else {
                    cloader = ClassLoader.getSystemClassLoader();
                }
    
                try {
                    //反射创建className(此处为ActivityThread)实例,并调用其main方法
                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
                } 
                ...
            }
        }
    }
    

    注意哦,现在已经是在新创建的子进程了哦:
    1、子进程关闭client/server socket连接,为什么呢?
    2、解析参数,根据前面传入的参数“android.app.ActivityThread”,调用ZygoteInit.invokeStaticMain方法,反射创建ActivityThread实例,并调用该实例main方法。

    回答两个问题:
    1、子进程为什么要关闭client/server socket连接,关闭client还好理解,server socket不是在Zygote进程吗?
    了解Linux的都知道,通过fork创建的子进程会继承父进程的代码、数据,也就是:子进程除了自己的堆栈地址跟父进程不同外,其它数据都是直接从父进程拷贝过来的。那新创建的子进程,肯定也是有一份ServerSocket实例拷贝,子进程在创建完成后当然需要关闭。

    2、为什么ActivityThread被称为主线程?
    首先,ActivityThread不是线程,被称为主线程是因为:它运行在新进程的主线程中(当然了,主线程就是进程中的第一个线程了,此处没有额外再创建新线程,那肯定是主线程了)。

    2.5、invokeStaticMain | ZygoteInit.java

    
        static void invokeStaticMain(ClassLoader loader,
                String className, String[] argv)
                throws ZygoteInit.MethodAndArgsCaller {
            Class<?> cl;
    
            try {
                cl = loader.loadClass(className);
            } 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.
             */
            throw new ZygoteInit.MethodAndArgsCaller(m, argv);
        }
    

    这个方法不写注释也能一眼看懂:
    1、反射获得入参对应的Class,此处入参为:“android.app.ActivityThread”
    2、反射获取main方法对应的Method
    3、新建MethodAndArgsCaller,并以异常形式抛出

    • 前面都好理解,关键是为什么要将main方法封装成异常的形式抛出呢?
      前面提到:子进程实际是从父进程将代码数据拷贝而来,父进程Zygote在死循环中创建了子进程,那子进程当然也存在这份死循环的代码。子进程通过异常抛出的形式,然后异常被捕获,跳出死循环,并在调用异常的run方法,在该run方法中调用被封装的方法main。

    ActivityThread


    至此,应用进程已经创建好了,并通过反射方式创建了ActivityThread的实例,然后调用该实例的main方法。那看下其main方法都做了啥:

    3.1、main | ActivityThread.java

    public static void main(String[] args) {
        SamplingProfilerIntegration.start();
        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);
    
        Environment.initForCurrentUser();
    
        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());
    
        Security.addProvider(new AndroidKeyStoreProvider());
    
        Process.setArgV0("<pre-initialized>");
        
        //为当前线程创建Looper,并未改Looper创建关联的MessageQueue
        Looper.prepareMainLooper();
        
        //创建实例
        ActivityThread thread = new ActivityThread();
        //入口
        thread.attach(false);
        
        //创建Handler,即:H
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
    
        AsyncTask.init();
    
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        
        //mainLooper循环从消息队列中取消息,并交给H处理
        Looper.loop();
    
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    

    有代码知,main方法创建了主线程关联的Looper已经H handler,这些相信大家都很熟了,但还是废话几句吧:

    • main方法在当前进程的主线程中运行,即主线程创建了Looper,并为Looper创建了关联的消息队列,以及handler H。创建完成后,调用Looper的loop方法,循环从消息队列中取出消息交给Looper处理。

      • 关于Looper、MessageQueue、Handler以及Message的关系,大致如下:
        • Looper与线程相关联,在Looper类中采用线程局部变量保存每个线程关联的Looper。主线程默认关联一个Looper,即MainLooper;当然也可以为子线程手动创建关联的Looper,即调用Looper.prepare()方法。
        • 每个Looper实例中,存在一个关联的MessageQueue实例,调用Looper的prepare方法时,会创建Looper实例,以及Looper关联的MessageQueue实例。调用Looper.loop()方法,Looper会循环去关联的MessageQueue中取出消息处理。
        • Handler,当构造Handler的实例时,会获取当前线程关联的Looper对象和MessageQueue对象引用。调用handler发送消息时,实际是将消息放入到MessageQueue中。
        • Message,每个Message对象都关联了一个target,该target就是发送该消息的Handler实例。当Looper从MessageQueue中取出消息时,会将消息发送给其关联的target进行处理。(why:因为一个MessageQueue可能被多个handler引用。)

    方法中另外创建了一个ActivityThread的实例,并调用其attach方法,开始应用的启动。

    3.2、attach | ActivityThread.java

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        //普通App进这里
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
                                                    
            //VM中保存该应用标志,用于上报错误
            //mAppThread是Binder对象,AMS通过该对象实现与该应用进程通信,ActivityThread初始化时会创建该实例
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            //AMS代理
            IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                //AMS保存该应用进程信息,通过该Binder实现与该应用进程通信
                mgr.attachApplication(mAppThread);  //入口
            } catch (RemoteException ex) {
                // Ignore
            }
        } else {
            ......
        }
        ......
    }
    
    • 该方法入参为false,即普通应用app。
    • 将应用进程Binder关联到VM,用于上报错误信息;
    • 将应用进程Binder关联到AMS,用于AMS与该应用进程通信;
    • 最后,通过AIDL调用AMS的attachApplication方法,所以此时又交由AMS来处理了。

    什么是应用进程Binder?
    在上文《沉思曲:Acitivity启动》中提到,AMS通过持有应用进程的Binder实现与应用进程的通信。该Binder实现了IApplicationThread接口,实现是ApplicaitonThread。

    3.3、attachApplication | ActivityManagerService.java

    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            //应用进程pid
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            //入口
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }
    
    • 该方法继续调用attachApplicationLocked方法。
    • attachApplicationLocked方法主要是应用进程进行校验,并调用thread的bindApplication方法。thread就是上一方法中的入参:应用进程Binder,实现为ApplicaitonThread,是Binder对象。
    • 由于thread是Binder对象,即应用进程在AMS中的Binder对象,所以此处又由AMS进程切换到应用进程中!!!

    3.4、bindApplication | ActivityThread.java

    note:ApplicaitonThread是ActivityThread的内部类。

    public final void bindApplication(String processName,
                ApplicationInfo appInfo, List<ProviderInfo> providers,
                ComponentName instrumentationName, String profileFile,
                ParcelFileDescriptor profileFd, boolean autoStopProfiler,
                Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                Bundle coreSettings) {
    
            if (services != null) {
                // Setup the service cache in the ServiceManager
                ServiceManager.initServiceCache(services);
            }
    
            setCoreSettings(coreSettings);
    
            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providers;
            data.instrumentationName = instrumentationName;
            data.instrumentationArgs = instrumentationArgs;
            data.instrumentationWatcher = instrumentationWatcher;
            data.instrumentationUiAutomationConnection = instrumentationUiConnection;
            data.debugMode = debugMode;
            data.enableOpenGlTrace = enableOpenGlTrace;
            data.restrictedBackupMode = isRestrictedBackupMode;
            data.persistent = persistent;
            data.config = config;
            data.compatInfo = compatInfo;
            data.initProfileFile = profileFile;
            data.initProfileFd = profileFd;
            data.initAutoStopProfiler = false;
            
            //发送消息到H,消息类型为H.BIND_APPLICATION
            queueOrSendMessage(H.BIND_APPLICATION, data);
        }
    

    该方法在应用进程中,调用H handler发送消息H.BIND_APPLICATION,看下H handler是如何处理该消息的。

    3.5、 H处理H.BIND_APPLICATION消息 | ActivityThread.java

    case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    //入口
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
    
    • 该方法接着调用 handleBindApplication

    3.6、 handleBindApplication | ActivityThread.java

        private void handleBindApplication(AppBindData data) {
            mBoundApplication = data;
            mConfiguration = new Configuration(data.config);
            mCompatConfiguration = new Configuration(data.config);
    
            mProfiler = new Profiler();
            mProfiler.profileFile = data.initProfileFile;
            mProfiler.profileFd = data.initProfileFd;
            mProfiler.autoStopProfiler = data.initAutoStopProfiler;
    
            //设置进程名
            Process.setArgV0(data.processName);
            android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                    UserHandle.myUserId());
            //是否开启硬件加速
            if (data.persistent) {
                if (!ActivityManager.isHighEndGfx()) {
                    HardwareRenderer.disable(false);
                }
            }
            
            if (mProfiler.profileFd != null) {
                mProfiler.startProfiling();
            }
    
            //Honeycomb MR1版本前,设置AsyncTask的底层由线程池实现
            if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
                AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }
    
            //设置TimeZone、Locale
            TimeZone.setDefault(null);
            Locale.setDefault(data.config.locale);
    
            //更新系统设置,AppBindData中配置默认是最新的
            mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
            mCurDefaultDisplayDpi = data.config.densityDpi;
            applyCompatConfiguration(mCurDefaultDisplayDpi);
            
            //获取Package信息,返回LoadedApk对象。先从缓存读,没有则创建。
            data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    
            //设置分辨率信息
            if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
                    == 0) {
                mDensityCompatMode = true;
                Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
            }
            updateDefaultDensity();
            
            //创建ContextImpl实例
            final ContextImpl appContext = new ContextImpl();
            appContext.init(data.info, null, this);
          
            if (!Process.isIsolated()) {
                final File cacheDir = appContext.getCacheDir();
                if (cacheDir != null) {
                    // Provide a usable directory for temporary files
                    System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
                    setupGraphicsSupport(data.info, cacheDir);
                } else {
                    Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
                }
            }
    
            //系统应用,开启debug log
            if ((data.appInfo.flags &
                 (ApplicationInfo.FLAG_SYSTEM |
                  ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
                StrictMode.conditionallyEnableDebugLogging();
            }
    
            //Honeycomb版本以后,不允许在主线程进行网络操作
            if (data.appInfo.targetSdkVersion > 9) {
                StrictMode.enableDeathOnNetwork();
            }
    
            //设置debug
            ......
    
            // 是否启动GL
            if (data.enableOpenGlTrace) {
                GLUtils.setTracingLevel(1);
            }
    
            // Allow application-generated systrace messages if we're debuggable.
            boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
            Trace.setAppTracingAllowed(appTracingAllowed);
    
            //设置time zone时,走http代理;通过ConnectivityManager设置
            IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
            if (b != null) {
                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
                try {
                    ProxyProperties proxyProperties = service.getProxy();
                    Proxy.setHttpProxySystemProperty(proxyProperties);
                } catch (RemoteException e) {}
            }
            
            //是否指定trumentation类名,难道可以指定?!
            if (data.instrumentationName != null) {
                InstrumentationInfo ii = null;
                try {
                    //获取Instrumentation信息
                    ii = appContext.getPackageManager().
                        getInstrumentationInfo(data.instrumentationName, 0);
                }
                ......
    
                mInstrumentationAppDir = ii.sourceDir;
                mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
                mInstrumentationAppPackage = ii.packageName;
                mInstrumentedAppDir = data.info.getAppDir();
                mInstrumentedAppLibraryDir = data.info.getLibDir();
                
                //创建ApplicationInfo,用来保存应用信息
                ApplicationInfo instrApp = new ApplicationInfo();
                instrApp.packageName = ii.packageName;
                instrApp.sourceDir = ii.sourceDir;
                instrApp.publicSourceDir = ii.publicSourceDir;
                instrApp.dataDir = ii.dataDir;
                instrApp.nativeLibraryDir = ii.nativeLibraryDir;
                
                //创建LoadedApk实例,保存应用APK信息
                LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                        appContext.getClassLoader(), false, true);
                //创建应用关联的CotextImpl
                ContextImpl instrContext = new ContextImpl();
                instrContext.init(pi, null, this);
    
                try {
                    java.lang.ClassLoader cl = instrContext.getClassLoader();
                    //为应用创建指定的Instrumentation实例
                    mInstrumentation = (Instrumentation)
                        cl.loadClass(data.instrumentationName.getClassName()).newInstance();
                }
                ......
                //init,保存应用信息到Instrumentation
                mInstrumentation.init(this, instrContext, appContext,
                       new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
                       data.instrumentationUiAutomationConnection);
                ......
            } else {
                //未指定Instrmentation名称,创建默认Instrumentation
                mInstrumentation = new Instrumentation();
            }
    
            if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
                dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
            }
    
            //允许application和provider启动时访问disk
            final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
            try {
                //创建Application实例
                Application app = data.info.makeApplication(data.restrictedBackupMode, null);
                mInitialApplication = app;
    
                //restricted模式下,c处理provider
                if (!data.restrictedBackupMode) {
                    List<ProviderInfo> providers = data.providers;
                    if (providers != null) {
                        installContentProviders(app, providers);
                        mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                    }
                }
    
                try {
                    //调用Instrumentation的onCreate方法,用于Applicaiton启动onCreate()启动前的操作
                    mInstrumentation.onCreate(data.instrumentationArgs);
                }
                ......  
              
                try {
                    //Instrumentation回调应用Applicaiton的onCreate,启动应用
                    mInstrumentation.callApplicationOnCreate(app);
                }
                ......
        }
    

    该方法负责启动应用:

    • 设置进程名、是否开启硬件加速
    • 设置AsyncTask的底层实现方式
    • 设置TimeZone、Locale
    • 设置分辨率、不允许主线程网络操作等
    • 为应用进程设置Instrumentation,用于管理应用进程
    • 通过Instrumentation调用应用Applicationde 的onCreate方法,实现应用的启动等
      • 设置timezone、openGl等信息后,创建Instrumentation用于管理该应用进程,最后并回调该应用的Application的onCreate方法启动应用。

    至此,本文内容就差不多结束了,后面应用的启动就不讲了,感兴趣的可以看源码,大同小异。

    总结


    三篇文章到此结束了,三文粗略的分析了Android系统启动、Activity启动、ActivityThread创建三部分内容。内容都是整理之前资料得到的,网上关于这部分内容的资料也很多,但都比较零散。这里把这部分内容整理出来,一来备忘,二来抛砖引玉。本人才疏学浅,大部分内容都是自己理解加注释,有不当错误之处,恳请指正~

    相关文章

      网友评论

      • 御风无忧:很棒,辛苦了! 一口气看完了三部曲,头有些晕,也有些醒悟。 下次了解更深了,再回来看一次

      本文标题:小夜曲:晓说ActivityThread

      本文链接:https://www.haomeiwen.com/subject/ljbfcxtx.html