小夜曲:晓说ActivityThread

该篇是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创建三部分内容。内容都是整理之前资料得到的,网上关于这部分内容的资料也很多,但都比较零散。这里把这部分内容整理出来,一来备忘,二来抛砖引玉。本人才疏学浅,大部分内容都是自己理解加注释,有不当错误之处,恳请指正~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容