Android進階知識樹——應用進程的啓動過程

程序的啓動是從進程啓動開始的,換句話說只有程序進程啓動後,程序纔會加載和執行,在AMS啓動程序時首先會判斷當前進程是否啓動,對未啓動的進程會發送請求,Zygote在收到請求後創建新的進程;

1、Zygote監聽客戶端請求

Android進階知識樹——Android系統的啓動過程知道,系統的啓動會執行到ZygoteInit.main()方法;

public static void main(String argv[]) {
   ZygoteServer zygoteServer = new ZygoteServer();//1
   zygoteServer.registerServerSocketFromEnv(socketName);
   caller = zygoteServer.runSelectLoop(abiList); //2
}

在main中創建並註冊了服務端的Socket,然後執行runSelectLoop()循環等待AMS的請求創建進程;

  • registerServerSocketFromEnv()
void registerServerSocketFromEnv(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;//1
            try {
                String env = System.getenv(fullSocketName);//2
                fileDesc = Integer.parseInt(env);
            } 
            try {
                FileDescriptor fd = new FileDescriptor();//3
                fd.setInt$(fileDesc);
                mServerSocket = new LocalServerSocket(fd);//4
                mCloseSocketFd = true;
            } catch (IOException ex) {
        }
    }

在registerServerSocketFromEnv中,首先使用ANDROID_SOCKET_PREFIX拼接Socket名稱,最終的名稱爲ANDROID_SOCKET_zygote,然後將fullSocketName轉換爲環境變量的值,註釋3處創建文件描述符,然後根據文件描述符創建LocalServerSocket對象

  • zygoteServer.runSelectLoop()
    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
177        fds.add(mServerSocket.getFileDescriptor());//1
178        peers.add(null);
179
180        while (true) { //2
181            StructPollfd[] pollFds = new StructPollfd[fds.size()];
182            for (int i = 0; i < pollFds.length; ++i) {
183                pollFds[i] = new StructPollfd();
184                pollFds[i].fd = fds.get(i);
185                pollFds[i].events = (short) POLLIN;
186            }
187            try {
188                Os.poll(pollFds, -1);
189            } catch (ErrnoException ex) {
190                throw new RuntimeException("poll failed", ex);
191            }
192            for (int i = pollFds.length - 1; i >= 0; --i) {
193                if ((pollFds[i].revents & POLLIN) == 0) {
194                    continue;
195                }
197                if (i == 0) { // 3
198                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
199                    peers.add(newPeer);
200                    fds.add(newPeer.getFileDesciptor());
201                } else {
202                    try {
203                        ZygoteConnection connection = peers.get(i);
204                        final Runnable command = connection.processOneCommand(this); // 4
205
206                        if (mIsForkChild) {
213                            return command;
214                        } else {
223                            if (connection.isClosedByPeer()) {
224                                connection.closeSocket();
225                                peers.remove(i);
226                                fds.remove(i);
227                            }
228                        }
229                    } catch (Exception e) {
230                        if (!mIsForkChild) {
241                            ZygoteConnection conn = peers.remove(i);
242                            conn.closeSocket();
244                            fds.remove(i);
245                        } else {
250                            throw e;
251                        }
252                    } finally {
256                        mIsForkChild = false;
257                    }
258                }
259            }
260        }
261    }

在runSelectLoop方法中,首先獲取註冊Socket的文件描述符fd,並將其保存在fds集合中,然後開啓循環監聽AMS的請求,在註釋3處判斷i ==0,若i=0表示Socket已連接,否則表示接收到AMS的請求信號,調用connection.processOneCommand(this)創建新的進程,創建完成後清除對應的peers集合和fds集合;

2、AMS發送創建進程請求

AMS會檢查目標程序進程,如果進程未啓動則調用startProcessLocked()方法啓動進程

   int uid = app.uid; //1
   ......
if (ArrayUtils.isEmpty(permGids)) { //2
           gids = new int[3];
        } else {
            gids = new int[permGids.length + 3];
            System.arraycopy(permGids, 0, gids, 3, permGids.length);
        }
          gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
          gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
          gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
.....
final String entryPoint = "android.app.ActivityThread"; //3
return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,startTime); //4

startProcessLocked執行一下邏輯:

  1. 獲取當前程序的uid
  2. 對用戶組gids創建並賦值
  3. entryPoint賦值爲ActivityThread的路徑,ActivityThread就是進程啓動時要初始化的類
  4. 調用startProcessLocked()啓動進程

在startProcessLocked()中又調用startProcess(),startProcess()中調用Process.start()方法,start中調用ZygoteProcess.startViaZygote()啓動進程,

  • ZygoteProcess.startViaZygote()
private Process.ProcessStartResult startViaZygote(final String processClass,
   ......String[] extraArgs)throws ZygoteStartFailedEx {
   ArrayList<String> argsForZygote = new ArrayList<String>();
   argsForZygote.add("--runtime-args");
   argsForZygote.add("--setuid=" + uid);
   argsForZygote.add("--setgid=" + gid);
   argsForZygote.add("--runtime-flags=" + runtimeFlags);

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

在startViaZygote中首先創建ArrayList集合,然後添加創建進程的啓動參數,最後調用zygoteSendArgsAndGetResult()執行啓動進程,在zygoteSendArgsAndGetResult的第一個參數中首先調用了openZygoteSocketIfNeeded()方法,它的作用其實就是連接Zygote 中服務端的Socket

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(mSocket); //1
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
           maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
        }
        if (primaryZygoteState.matches(abi)) { //2
            return primaryZygoteState;
        }
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);//3
            } 
           maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
           maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
        }
        if (secondaryZygoteState.matches(abi)) { //4
            return secondaryZygoteState;
        }
 }

在openZygoteSocketIfNeeded()中ZygoteState.connect()連接Zygote進程中的Socket,連接成功後返回連接的主模式,用此主模式和傳入的abi比較是否匹配,如果匹配則直接返回ZygoteState,否則連接zygote輔模式;

  • zygoteSendArgsAndGetResult()
 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
281            ZygoteState zygoteState, ArrayList<String> args)
282            throws ZygoteStartFailedEx {
283        try {
286            int sz = args.size();
287            for (int i = 0; i < sz; i++) {
288                if (args.get(i).indexOf('\n') >= 0) {
289                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
290                }
291            }
303            final BufferedWriter writer = zygoteState.writer;
304            final DataInputStream inputStream = zygoteState.inputStream;
306            writer.write(Integer.toString(args.size()));
307            writer.newLine();
309            for (int i = 0; i < sz; i++) {
310                String arg = args.get(i);
311                writer.write(arg);
312                writer.newLine();
313            }
315            writer.flush();
323            result.pid = inputStream.readInt();
324            result.usingWrapper = inputStream.readBoolean();
326            if (result.pid < 0) {
327                throw new ZygoteStartFailedEx("fork() failed");
328            }
329            return result;
330        } catch (IOException ex) {
331            zygoteState.close();
332            throw new ZygoteStartFailedEx(ex);
333        }
334    }

在zygoteSendArgsAndGetResult中獲取連接Socket返回的ZygoteState,利用ZygoteState內部的BufferedWriter將請求參數寫入Zygote進程中;

3、Zygote接收信息並創建進程

由第一部分知道,在AMS發送請求後zygote進程會接收請求,並調用ZygoteConnection.processOneCommand()方法處理請求,在ZygoteInit.main()方法中有以下代碼

  final Runnable caller;
  caller = zygoteServer.runSelectLoop(abiList);
  if (caller != null) {
      caller.run();
  }

在runSelectLoop()中接收到AMS請求信息後,然後執行處理並返回Runnable對象並執行run()方法,

  Runnable processOneCommand(ZygoteServer zygoteServer) {
   String args[];
   Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        try {
            args = readArgumentList(); //1
            descriptors = mSocket.getAncillaryFileDescriptors();
        } 
         parsedArgs = new Arguments(args); //2
  pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,parsedArgs.instructionSet, parsedArgs.appDataDir);
 if (pid == 0) {
                zygoteServer.setForkChild();
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.startChildZygote); //3
            } else {
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }

  }

在processOneCommand()中首先調用readArgumentList讀取參數數組,然後將數組封裝在Arguments對象中,調用Zygote.forkAndSpecialize()方法fork子進程,子進程創建成功後調用handleChildProc()初始化進程

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd, boolean isZygote) {
        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }
        }
    }

在handleChildProc調用ZygoteInit.zygoteInit(),關於ZygoteInit.zygoteInit()方法的內容參考Android進階知識樹——Android系統的啓動過程,其最終會使用反射調用ActivityThread.main()方法,程序進入進程初始化,關於ActivityThread中的操作這裏不做分析,相信Android開發者應該瞭解;

4、啓動Binder線程池

本篇文章和上一篇Android進階知識樹——Android系統的啓動過程中都提到Binder線程池的創建,但都沒有詳細介紹,這裏補充一下,程序在啓動進程後會調用ZygoteInit.zygoteInit()方法,zygoteInit中調用本地方法nativeZygoteInit(),在ZygoteInit中聲明瞭nativeZygoteInit方法;

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
       RuntimeInit.commonInit();
       ZygoteInit.nativeZygoteInit();//
       return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
    
private static final native void nativeZygoteInit();

很明顯nativeZygoteInit()是JNI方法(關於JNI見另一篇文章Android進階知識樹——JNI和So庫開發),他在AndroidRuntime中完成方法動態註冊,nativeZygoteInit中對應c文件中com_android_internal_os_ZygoteInit_nativeZygoteInit()方法

int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

在com_android_internal_os_ZygoteInit_nativeZygoteInit()方法中調用gCurRuntime.onZygoteInit(),這裏的gCurRuntime是AppRuntime對象,它繼承AndroidRuntime,在AndroidRuntime的構造函數中被初始化,AppRuntime類在app_main中實現

class AppRuntime : public AndroidRuntime
{
virtual void onZygoteInit()    {
       sp<ProcessState> proc = ProcessState::self();
        proc->startThreadPool();
    }
}

在onZygoteInit()中調用ProcessState類的startThreadPool(),startThreadPool()中調用

void ProcessState::spawnPooledThread(bool isMain){
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}

在spawnPooledThread()中使用makeBinderThreadName()生成線程名稱,然後創建PoolThread線程並執行線程

class PoolThread : public Thread{
protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain); 
        return false;
    }
    const bool mIsMain;
};

PoolThread繼承Thread類,啓動PoolThread對象就創建了一個新的線程,在PoolThread的threadLoop()方法中調用IPCThreadState的joinThreadPool()方法將創建的線程加入Binder線程吃中,那麼新創建的應用進程就支持Binder進程通行了;

總結一下整個進程啓動的過程:

  1. AMS判斷當前進程是否啓動,對未啓動的進程發送請求
  2. 首先根據程序的pid設置並賦值用戶組gids
  3. 將entryPoint賦值爲ActivityThread的路徑,然後開始執行進程啓動
  4. 在與zygote交互中,首先根據設置的abi連接zygote進程中的socket,並判斷是匹配主模式還是輔模式,連接成功後返回zygoteState對象
  5. 使用zygoteState將請求參數寫入zygote的Socket中,zygote進程中讀取請求的信息保存在數組中
  6. 使用參數數組創建Argument對象,並fork出程序進程,從而啓動程序進程
  7. 進程啓動後調用ZygotezInit.zygoteInit()方法,內部初始化Binder線程池實現進程通信,然後反射獲取ActivityThread.main()方法,完成新進程的初始化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章