Android应用程序启动过程(一)——进程建立

app进程建立

在这张简图中能够看到,从Launcher点击图标启动进程涉及到了3个角色。 其中Launcher是发起请求进程(caller),AMS接收到Launcher的请求并处理,若是要启动的Activity的进程不存在,则经过本地套接字链接到Zygote,向Zygote发起建立进程的请求。Zygote接收该请求并fork出app进程。java

整个过程涉及到的细节比较多,咱们这里只关注核心部分,分红几个小节来讲。linux

1. Zygote

Zygote是android系统中的一个重要的守护进程,它的主要做用是:
① 建立VM实例、预加载类和资源等。
② 启动systemserver。
③ 建立本地套接字,等待AMS的fork请求,完成app进程的建立工做。android

下面咱们简单看下它的源码:数据结构

// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, const char* const argv[])
{
    AppRuntime runtime;
    ...
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", 
                     startSystemServer ? "start-system-server" : "");
    }
    ...
}

AppRuntime的start()函数继承自基类AndroidRuntime,即上述代码将跳到app

// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const char* options) {
    ...
    JNIEnv* env;
    // 启动虚拟机
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    // 注册android须要的jni函数
    if (startReg(env) < 0) {
        LOGE("Unable to register all android natives\n");
        return;
    }
    ...
    // className是com.android.internal.os.ZygoteInit
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            LOGE("JavaVM unable to find main() in '%s'\n", className);
        } else {
            // 调用ZygoteInit的main(String[])方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    free(slashClassName);
    ...
}

好了,到这一步,虚拟机已经启动起来了,开始加载并运行主类(ZygoteInit)的main()函数了。socket

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
    try {
        // 建立本地套接字
        registerZygoteSocket();
        // 预加载类和资源等
        preload();
        ...
        if (argv[1].equals("start-system-server")) {
            // 启动system server进程
            startSystemServer();
        } else if (!argv[1].equals("")) {
            throw new RuntimeException(argv[0] + USAGE_STRING);
        }
        ...
        // 建立一个本地套接字,等待客户端的请求
        runSelectLoopMode();
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        // fork()出来的子进程最终会走到这
        // 在这个里面经过反射调用对应主类(即ActivityThread)的main()方法
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}
private static void runSelectLoopMode() throws MethodAndArgsCaller {
    // fds--peers 每一项是一一对应的,即<文件描述符,已创建的链接>构成一个二元组
    ArrayList<FileDescriptor> fds = new ArrayList();
    ArrayList<ZygoteConnection> peers = new ArrayList();
    FileDescriptor[] fdArray = new FileDescriptor[4];

    // 第一个二元组是<socket监听描述符,null>
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        ...
        try {
            fdArray = fds.toArray(fdArray);
            // native方法,使用了select io多路复用机制
            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) { 
            // index为0的是socket监听描述符,selectReadable()返回0表示来了个新链接
            ZygoteConnection newPeer = acceptCommandPeer();
            // 将创建好的新链接的二元组添加到集合中
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            // index>0表示已链接描述符有收到数据了
            boolean done;
            // 让对应的链接来处理数据
            done = peers.get(index).runOnce();

            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

到这一步,Zygote的大致启动流程咱们已经分析完了。关于Zygote如何建立app进程,咱们放到后面AMS那块再说。函数

2. AMS

ActivityManagerService,简称AMS。见名知意,它是用来管理Activity的系统服务。就像linux内核使用task_struct来管理进程同样,AMS要管理Activity,它确定须要用某种数据结构来记录当前系统上Activity的信息。oop

  • ActivityRecord 记录每一个Activity的运行时信息
final class ActivityRecord extends IApplicationToken.Stub {
    final ActivityManagerService service;
    // 从AndroidManifest.xml解析出来的关于Activity的信息
    final ActivityInfo info;
    // 触发生成这个ActivityRecord的Intent
    final Intent intent;
    // 当前activity所属的任务栈
    TaskRecord task;
    // 当前Activity所属进程的信息
    ProcessRecord app;
    ...
}
  • ProcessRecord 记录当前正在运行的某个进程的完整信息
class ProcessRecord {
    // 进程名和进程id
    final String processName;
    int pid;
    // AMS经过该Binder接口向app进程发请求
    IApplicationThread thread;
    ...
}

Launcher向AMS发起startActivity请求后,AMS会作一系列处理,这里咱们只关心下面2个要点:
① AMS会建立一个ActivityRecord对象来记录该Activity的信息。
② 若是进程不存在,即对应的ProcessRecord对象不存在,则建立ProcessRecord来记录要新建的进程的信息,并向Zygote请求建立新进程。进程建立成功后,在ProcessRecord中记录下Zygote返回新进程的pid。ui

// frameworks/base/services/java/com/android/server/am/ActivityStack.java
final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType,
            Uri[] grantedUriPermissions,
            int grantedMode, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, boolean onlyIfNeeded,
            boolean componentSpecified, ActivityRecord[] outActivity) {
    ...
        // 建立即将要启动的Activity的相关信息,并保存在r变量中
        ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
                intent, resolvedType, aInfo, mService.mConfiguration,
                resultRecord, resultWho, requestCode, componentSpecified);
    ...
}
// frameworks/base/services/java/com/android/server/am/ActivityStack.java
private final void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
    // AMS维护了一个ProcessMap<ProcessRecord> mProcessNames,用来记录经过AMS启动并运行的app进程
    // 在这个map里没查到说明该app进程不存在
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid);
    ...
    if (app != null && app.thread != null) {
        // 应用进程存在,则启动对应的Activity
        try {
            app.addPackage(r.info.packageName);
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
        }
    }

    // 应用进程不存在,先建立进程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false);
}
// frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
    ...
    if (app == null) {
        // 建立一个ProcessRecord,用来记录要启动的进程的信息
        app = newProcessRecordLocked(null, info, processName);
        // 将ProcessRecord存入map中
        mProcessNames.put(processName, info.uid, app);
    }
    ...
    startProcessLocked(app, hostingType, hostingNameStr);
    ...
}

private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
    // 使用Process.start来启动新进程
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags,
                    app.info.targetSdkVersion, null);
   ...
   app.pid = startResult.pid; // 记录新进程的pid
   ...
}
3. Zygote socket 链接的请求及响应

刚才上面咱们没有看到有关和Zygote socket相关的内容。这块实际上是由ZygoteProcess类实现的。Process.start()通过几层调用,来到ZygoteProcess.startViaZygote()`。this

Process.start()  
	--> ZygoteProcess.start() 
		--> ZygoteProcess.startViaZygote()
private Process.ProcessStartResult startViaZygote(...) {
    ... // 省略参数的组装过程
    synchronized(mLock) {
        return zygoteSendArgsAndGetResult(
                openZygoteSocketIfNeeded(abi), // 创建socket链接
                argsForZygote); // argsForZygote是要发给Zygote的参数,ArrayList类型
}
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
    ...
    // 写入流
    final BufferedWriter writer = zygoteState.writer;
    // 读取流
    final DataInputStream inputStream = zygoteState.inputStream;
    // 按照Zygote协议写数据
    // 先写入参数个数,格式:size\n
    writer.write(Integer.toString(args.size()));
    writer.newLine();
    // 写参数,每一个参数的格式:arg\n
    for (int i = 0; i < sz; i++) {
          String arg = args.get(i);
          writer.write(arg);
          writer.newLine();
    }
    writer.flush();
    Process.ProcessStartResult result = new Process.ProcessStartResult();
    // 读取Zygote返回回来的进程id
    result.pid = inputStream.readInt();
    if (result.pid < 0) { // 若是pid小于0,说明fork失败了
       throw new ZygoteStartFailedEx("fork() failed");
    }
    return result;
}

ProcessProcess向Zygote发送请求和接收请求的大体流程咱们已经看过了。那Zygote那边怎么接收和处理请求的呢?

// frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    try {
        // 读取client经过socket发过来的数据
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        Log.w(TAG, "IOException on command socket " + ex.getMessage());
        closeSocket();
        return true;
    }
    ...
    // 将获取的数据解析成Arguments类型
    parsedArgs = new Arguments(args);
    ...
    // 建立APP进程
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
    if (pid == 0) {
        ...
        // 走子进程的处理逻辑
        handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
        ...
    } else {
        ...
        // 走父进程的处理逻辑
        return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
    }
}

此时进程已经建立好了,须要将子进程的pid经过socket传回给AMS了。

// frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private boolean handleParentProc(int pid,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
    ...
   try {
        // 将fork出来的进程pid传给AMS
        mSocketOutStream.writeInt(pid);
        mSocketOutStream.writeBoolean(usingWrapper);
    } catch (IOException ex) {
        Log.e(TAG, "Error reading from command socket", ex);
        return true;
    }
    ...
}
4. ActivityThread的main方法的执行

上面的流程结束后,子进程已经成功建立,接下来子进程将进行自身的初始化,加载主类和执行main(String[])方法。

ZygoteConnection.handleChildProc() 
    --> RuntimeInit.zygoteInit()
        --> RuntimeInit.zygoteInitNative() 
        --> RuntimeInit.applicationInit()
            --> RuntimeInit.invokeStaticMain()
private static void invokeStaticMain(String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    // 加载主类(android.app.ActivityThread)
    cl = Class.forName(className); 
    Method m;
    // 获取main(String[])方法
    m = cl.getMethod("main", new Class[] { String[].class });
    // 检查main方法是不是public static的
    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()的catch块中继续执行
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

这段代码的最后将反射获得的Method对象和参数封装成ZygoteInit.MethodAndArgsCaller异常并抛出,这个异常被ZygoteInit的main()方法捕获。

// ZygoteInit.main()
catch (MethodAndArgsCaller caller) {
    // fork()出来的子进程最终会走到这
    // 在这个里面经过反射调用对应类的main()方法
    caller.run();
}

// MethodAndArgsCaller.run()
public void run() {
    try {
        // 最终经过反射调用main()方法
        mMethod.invoke(null, new Object[] { mArgs });
    } catch (IllegalAccessException ex) {
        throw new RuntimeException(ex);
    } catch (InvocationTargetException ex) {
        throw new RuntimeException(ex);
    }
}

最终,app进程的ActivityThread类的main()方法开始执行。

相关文章
相关标签/搜索