Android進(jìn)程創(chuàng)建


前言

啟動(dòng)一個(gè)Android組件時(shí)冻辩,當(dāng)App進(jìn)程還不存在蛋铆,應(yīng)先創(chuàng)建一個(gè)App進(jìn)程。追蹤Ams源碼诗芜,在棧監(jiān)管者startSpecificActivityLocked方法中有判斷進(jìn)程是否存在瞳抓。

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
    .....
    if (app != null && app.thread != null) {
        ...//進(jìn)程存在
        realStartActivityLocked()
    }
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

Ams#getProcessRecordLocked方法查找進(jìn)程ProcessRecord記錄秒紧。若未找到,創(chuàng)建進(jìn)程 挨下。
當(dāng)用戶第一次點(diǎn)擊App圖標(biāo),系統(tǒng)啟動(dòng)App的AndroidManifest中配置action為android.intent.action.MAIN的Activity組件脐湾。
ActivityStackSupervisor#startActivityMayWait方法臭笆。

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,..) {
    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.
    // 搜集目標(biāo)Intent的信息
    ActivityInfo aInfo =resolveActivity(intent, resolvedType, startFlags, 
                profilerInfo, userId);
    ...
}

棧監(jiān)管者resolveActivity方法解析Intent信息。注意秤掌,這是啟動(dòng)App第一個(gè)Activity組件愁铺,App進(jìn)程還未創(chuàng)建。

ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
            ProfilerInfo profilerInfo, int userId) {
    ActivityInfo aInfo;
    try {
        //AppGlobals獲取包管理器IPackageManager闻鉴。
        ResolveInfo rInfo = AppGlobals.getPackageManager().resolveIntent(
                        intent, resolvedType,
                        PackageManager.MATCH_DEFAULT_ONLY
                                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
        aInfo = rInfo != null ? rInfo.activityInfo : null;
    } catch (RemoteException e) {
        aInfo = null;
    }

    if (aInfo != null) {
        intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
        ...
    }
    return aInfo;
}

ActivityThread#getPackageManager*獲取包管理器茵乱,

public static IPackageManager getPackageManager() {
    if (sPackageManager != null) {    
        return sPackageManager;
    }
    //從ServiceManager獲取包服務(wù),僅初始化一次孟岛。
    IBinder b = ServiceManager.getService("package");
    //代理
    sPackageManager = IPackageManager.Stub.asInterface(b);
    return sPackageManager;
}

包管理器Pms#resolveIntent方法瓶竭,解析Intent,返回ResolveInfo渠羞。主要結(jié)構(gòu)包含ActivityInfo斤贰,ActivityInfo結(jié)構(gòu)圖。
ActivityInfo.PNG

進(jìn)程名processName次询,ActivityInfo內(nèi)部有一個(gè)ApplicationInfo對(duì)象荧恍。

進(jìn)程創(chuàng)建

進(jìn)程創(chuàng)建流程圖。
創(chuàng)建進(jìn)程流程圖.png

下面是Ams#startProcessLocked方法屯吊。

final ProcessRecord startProcessLocked(String processName, ApplicationInfo 
                info,boolean knownToBeDead, int intentFlags, String 
                hostingType, ComponentName hostingName,boolean 
                allowWhileBooting,boolean isolated, int isolatedUid, boolean 
                keepIfLarge,String abiOverride, String entryPoint, String[]
                entryPointArgs, Runnable crashHandler) {
    ProcessRecord app;
    if (!isolated) {//非孤立
        //根據(jù)進(jìn)程名查詢進(jìn)程記錄ProcessRecord
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
        if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
            ...
        } else {
            //當(dāng)用戶顯式啟動(dòng)進(jìn)程時(shí)送巡,清除其崩潰計(jì)數(shù)
            mProcessCrashTimes.remove(info.processName, info.uid);
           ...
        }
    } else {
        // 如果是孤立進(jìn)程,無法重用存在的進(jìn)程
        app = null;
    } 
    //如果app不空,說明存在進(jìn)程記錄盒卸,調(diào)用者不認(rèn)為該進(jìn)程已經(jīng)死掉或者沒有線程對(duì)象骗爆,
    //pid存在
    if (app != null && app.pid > 0) {
        if (!knownToBeDead || app.thread == null) {
            //app已經(jīng)開始運(yùn)行,則加入新包,返回ProcessRecord
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
            checkTime(startTime, "startProcess: done, added package to proc");
            return app;
        }
        //app記錄綁定了以前的進(jìn)程蔽介。清理淮腾,需要啟動(dòng)進(jìn)程
        killProcessGroup(app.info.uid, app.pid);
        handleAppDiedLocked(app, true, true);
    }

    if (app == null) {
        //創(chuàng)建ProcessRecord
        app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
        if (app == null) {
            return null;
        }
        app.crashHandler = crashHandler;
    } else {
        // ProcessRecord存在,則加入新包
        app.addPackage(info.packageName, info.versionCode, mProcessStats);
    }

    //創(chuàng)建進(jìn)程屉佳,Ams#startProcessLocked方法谷朝。
    startProcessLocked(app, hostingType, hostingNameStr, abiOverride, 
                entryPoint, entryPointArgs);
    return (app.pid != 0) ? app : null;
}

創(chuàng)建ProcessRecord,它當(dāng)?shù)膒id是0武花,startProcessLocked啟動(dòng)進(jìn)程圆凰。

private final void startProcessLocked(ProcessRecord app, String hostingType,
                String hostingNameStr, String abiOverride, String entryPoint, 
                String[] entryPointArgs) {
    ...
    if (entryPoint == null) entryPoint = "android.app.ActivityThread";
    ...
    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);
    ...
}

設(shè)置entryPoint為android.app.ActivityThread,ActivityThread類的main方法的是新進(jìn)程App啟動(dòng)入口体箕。
Process的start方法专钉,向zygote進(jìn)程發(fā)送創(chuàng)建新進(jìn)程的請(qǐng)求挑童,啟動(dòng)成功的結(jié)果是ProcessStartResult中包含新進(jìn)程pid。
Process#startViaZygote方法跃须,創(chuàng)建一個(gè)字符串參數(shù)列表站叼,調(diào)用Process#zygoteSendArgsAndGetResult方法,將參數(shù)列表發(fā)送給zygote進(jìn)程菇民。zygote進(jìn)程收到后尽楔,啟動(dòng)一個(gè)子進(jìn)程,將子進(jìn)程pid返回第练。
startViaZygote方法參數(shù)圖阔馋。

startViaZygote方法傳入?yún)?shù).PNG

private static ProcessStartResult startViaZygote(...String[] extraArgs)
                        throws ZygoteStartFailedEx {
    return zygoteSendArgsAndGetResult(
                        openZygoteSocketIfNeeded(abi), argsForZygote);
}

Process#openZygoteSocketIfNeeded方法,利用ZygoteState#connect返回ZygoteState娇掏。

private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
    try {
        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;

        writer.write(Integer.toString(args.size()));
        writer.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");
            }
            writer.write(arg);
            writer.newLine();
        }
        writer.flush();
        ProcessStartResult result = new ProcessStartResult();
        //讀取返回的pid    
        result.pid = inputStream.readInt();
        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
        }
        result.usingWrapper = inputStream.readBoolean();
        return result;
    } catch (IOException ex) {
    }
}

Process保存主ZygoteState和次ZygoteState兩個(gè)靜態(tài)對(duì)象呕寝,代表兩個(gè)與zygote進(jìn)程的socket連接。當(dāng)主ZygoteState連接可用婴梧,則直接使用下梢,否則利用次ZygoteState,若都不可用塞蹭,拋出異常怔球。

通過socket與zygote進(jìn)程通信,連接與數(shù)據(jù)流讀寫鏈路封裝在ZygoteState浮还。主ZygoteState定義的連接地址名稱是zygote竟坛,次ZygoteState定義的連接地址名稱是zygote_secondary
BufferedWriter和DataInputStream數(shù)據(jù)流钧舌,發(fā)送和讀取担汤。

與zygote進(jìn)程Socket通信

與zygote進(jìn)程的Socket通信結(jié)構(gòu)圖。
與zygote進(jìn)程的Socket通信結(jié)構(gòu)圖.jpg

創(chuàng)建ZygoteState的connect方法洼冻。

public static ZygoteState connect(String socketAddress) throws IOException {
    DataInputStream zygoteInputStream = null;
    BufferedWriter zygoteWriter = null;
    final LocalSocket zygoteSocket = new LocalSocket();
    try {
        //到zygote進(jìn)程的socket連接
        zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                        LocalSocketAddress.Namespace.RESERVED));
        //建立讀寫數(shù)據(jù)通道
        zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
        zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                        zygoteSocket.getOutputStream()), 256);
    } catch (IOException ex) {
        //socket關(guān)閉崭歧,拋出異常
    }
    ....
    return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
}

1.創(chuàng)建LocalSocket,委托LocalSocketImpl實(shí)現(xiàn)類撞牢,利用LocalSocketImpl的文件描述符FileDescriptor建立連接率碾。
2.建立讀寫數(shù)據(jù)通道,創(chuàng)建ZygoteState對(duì)象屋彪,封裝通道與連接所宰。
LocalSocket#connect方法。

public void connect(LocalSocketAddress endpoint) throws IOException {
    synchronized (this) {
        implCreateIfNeeded();//初始化連接描述符
        impl.connect(endpoint, 0);
        isConnected = true;
        isBound = true;
    }
}

建立連接畜挥。implCreateIfNeeded方法仔粥,通過LocalSocketImpl#create方法初始化連接描述符Fd。
利用Os.socket(OsConstants.AF_UNIX, osType, 0)
委托LocalSocketImpl#connect方法躯泰。

protected void connect(LocalSocketAddress address, int timeout)
                        throws IOException{        
    if (fd == null) {//Fd已在implCreateIfNeeded初始化谭羔。
        throw new IOException("socket not created");
    }
    connectLocal(fd, address.getName(), address.getNamespace().getId());
}

JNI#方法進(jìn)行連接,address就是上面提到過的主ZygoteState定義的zygote麦向。
LocalSocket#getInputStream方法瘟裸,getOutputStream方法委托LocalSocketImpl的方法創(chuàng)建讀寫數(shù)據(jù)流,SocketInputStream與SocketOutputStream诵竭,數(shù)據(jù)流封裝在LocalSocketImpl话告。
數(shù)據(jù)流返回后,再次封裝秀撇,BufferedWriter與DataInputStream
本質(zhì):BufferedWriter#write向族,利用SocketOutputStream向Fd發(fā)送數(shù)據(jù)呵燕,DataInputStream#read,利用SocketInputStream從Fd讀取數(shù)據(jù)件相。
最后再扭,進(jìn)程創(chuàng)建成功,pid保存在ProcessStartResult夜矗。

App入口方法

ActivityThread的main方法是新進(jìn)程入口泛范。

public static void main(String[] args) {
    .....
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    //ActivityThread內(nèi)部H對(duì)象,負(fù)責(zé)處理主線程消息紊撕,如AMS罢荡,WMS利用Binder發(fā)來的消息。
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    ...
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

初始化主線程消息隊(duì)列对扶,啟用主線程Looper区赵,等待消息,創(chuàng)建ActivityThread對(duì)象浪南,觸發(fā)ActivityThread#attach方法笼才。

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ...
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            //mAppThread是ApplicationThread類型
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
        }
        ...
    } else {
       ...
    }
}

非系統(tǒng)應(yīng)用時(shí),Ams#attachApplication方法络凿,Ams利用ApplicationThread訪問App進(jìn)程骡送,這是剛創(chuàng)建的進(jìn)程,此時(shí)主線程消息隊(duì)列已經(jīng)創(chuàng)建絮记,可向隊(duì)列插入消息摔踱,但Loop循環(huán)還未起來。
Ams#attachApplicationLocked方法中怨愤,先ApplicationThread#bindApplication回調(diào)App進(jìn)程昌渤,向主線程消息隊(duì)列發(fā)送BIND_APPLICATION消息,待Looper起來后憔四,就會(huì)執(zhí)行啦膀息。
后續(xù)般眉,還會(huì)觸發(fā)ActivityStackSupervisor#attachApplicationLocked方法潜支,進(jìn)入realStartActivityLocked方法,它就是剛開篇介紹過的,進(jìn)程存在時(shí)代碼執(zhí)行的選擇,在realStartActivityLocked繼續(xù)往下走,啟動(dòng)Activity組件。

總結(jié)

創(chuàng)建App進(jìn)程的核心知識(shí)點(diǎn)是建立一個(gè)與zygote進(jìn)程通信的Socket連接,通過向其發(fā)送參數(shù)大审,請(qǐng)求zygote創(chuàng)建App進(jìn)程根穷。


任重而道遠(yuǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末康栈,一起剝皮案震驚了整個(gè)濱河市悬荣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖弄捕,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拳芙,居然都是意外死亡察藐,警方通過查閱死者的電腦和手機(jī)皮璧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門舟扎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人悴务,你說我怎么就攤上這事睹限。” “怎么了讯檐?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵羡疗,是天一觀的道長。 經(jīng)常有香客問我别洪,道長叨恨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任挖垛,我火速辦了婚禮痒钝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痢毒。我一直安慰自己送矩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布哪替。 她就那樣靜靜地躺著栋荸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晌块,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天爱沟,我揣著相機(jī)與錄音,去河邊找鬼摸袁。 笑死钥顽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的靠汁。 我是一名探鬼主播蜂大,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼蝶怔!你這毒婦竟也來了奶浦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤踢星,失蹤者是張志新(化名)和其女友劉穎澳叉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沐悦,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡成洗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了藏否。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓶殃。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖副签,靈堂內(nèi)的尸體忽然破棺而出遥椿,到底是詐尸還是另有隱情,我是刑警寧澤淆储,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布冠场,位于F島的核電站,受9級(jí)特大地震影響本砰,放射性物質(zhì)發(fā)生泄漏碴裙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一点额、第九天 我趴在偏房一處隱蔽的房頂上張望舔株。 院中可真熱鬧,春花似錦咖楣、人聲如沸督笆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娃肿。三九已至咕缎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間料扰,已是汗流浹背凭豪。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晒杈,地道東北人嫂伞。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像拯钻,于是被迫代替她去往敵國和親帖努。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容