Android系统源码情景分析-学习笔记-12

Android 应用程序的启动过程

     ActivityManangerService 再启动一个组件的时候,如果这个组件所在的应用程序还没有启动起来,它就会请求Zygote进程,将这个应用程序启动起来。
     Zygote进程通过复制自身的方式来创建一个新的应用程序。由于zygote进程在启动时会在内部创建一个虚拟机实例,因此,通过复制它而得到的应用程序进程就自然得到了一个应用程序实例拷贝。
     应用程序进程在启动过程中,还可以获得一个Binder线程池和一个消息循环,

应用程序进程的创建过程

     每当ActivityManagerService 需要创建一个新的应用程序来启动一个应用程序组件时,就是通过startProcessLocked 方法向Zygote进程发送一个创建应用程序的请求,

    private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
        
        try {
            int uid = app.info.uid;
            int[] gids = null;
            try {
                gids = mContext.getPackageManager().getPackageGids(
                        app.info.packageName);
            } catch (PackageManager.NameNotFoundException e) { ... }
            
            
            int pid = Process.start("android.app.ActivityThread",
                    mSimpleProcessManagement ? app.processName : null, uid, uid,
                    gids, debugFlags, null);
            
        } catch (RuntimeException e) { ... }
    }
Process#start
    public static final int start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags,
                                  String[] zygoteArgs)
    {
        if (supportsProcesses()) {  // 判断是否支持支持Binder进程间通信
            try {
                return startViaZygote(processClass, niceName, uid, gid, gids,
                        debugFlags, zygoteArgs);
            } catch (ZygoteStartFailedEx ex) { ... }
        } else {
            // 不支持Binder进程间通信机制,然后创建一个线程来模拟一个应用程序
            ...
        }
    }
Process#startViaZygote
    private static int startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        int pid;

        synchronized(Process.class) {
            ArrayList<String> argsForZygote = new ArrayList<String>();

            // --runtime-init, --setuid=, --setgid=,
            // and --setgroups= must go first
            argsForZygote.add("--runtime-init");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);

            //TODO optionally enable debuger
            //argsForZygote.add("--enable-debugger");

            // --setgroups is a comma-separated list
            if (gids != null && gids.length > 0) {
                StringBuilder sb = new StringBuilder();
                sb.append("--setgroups=");

                int sz = gids.length;
                for (int i = 0; i < sz; i++) {
                    if (i != 0) {
                        sb.append(',');
                    }
                    sb.append(gids[i]);
                }

                argsForZygote.add(sb.toString());
            }

            if (niceName != null) {
                argsForZygote.add("--nice-name=" + niceName);
            }

            argsForZygote.add(processClass);

            if (extraArgs != null) {
                for (String arg : extraArgs) {
                    argsForZygote.add(arg);
                }
            }
            
            pid = zygoteSendArgsAndGetPid(argsForZygote);
        }

        return pid;
    }
Process#zygoteSendArgsAndGetPid

向 zygote 进程发送一个参数列表,该进程启动一个新子进程并返回该子进程的 pid。

    private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
            throws ZygoteStartFailedEx {

        int pid;
        // 创建一个连接到Zygote进程的LocalSocket对象
        openZygoteSocketIfNeeded();

        try {
            // 将启动参数传递给Zygote进程
            sZygoteWriter.write(Integer.toString(args.size()));
            sZygoteWriter.newLine();

            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                
                sZygoteWriter.write(arg);
                sZygoteWriter.newLine();
            }

            sZygoteWriter.flush();

            // Should there be a timeout on this?
            pid = sZygoteInputStream.readInt();

            ...
        } catch (IOException ex) { ... }

        return pid;
    }
ZygoteInit#runSelectLoopMode

     Zygote进程在启动完成之后,会在一个名称为“zygote” 的Socket上等待ActivityManagerService 向它发送创建新的应用程序进程的请求。因此,这一步执行完成之后,Zygote进程就会在ZygoteInit类的静态成员函数runSelectLoopMode中接受到一个创建新的应用程序进程的请求

    private static void runSelectLoopMode() throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList();
        ArrayList<ZygoteConnection> peers = new ArrayList();
        FileDescriptor[] fdArray = new FileDescriptor[4];

        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);

        int loopCount = GC_LOOP_COUNT;
        while (true) {
            int index;


            try {
                fdArray = fds.toArray(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) {
                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);
                }
            }
        }
    }
ZygoteConnection # runOnce
    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            // 获取创建的应用程序进程的启动参数
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            ...
        }

        ...

        int pid;

        try {
            parsedArgs = new Arguments(args);

            ...

            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
        }

        if (pid == 0) {
            // in child
            handleChildProc(parsedArgs, descriptors, newStderr);
            // should never happen
            return true;
        } 
    }
ZygoteConnection # handleChildProc

通过调用handleChildProc来启动这个子进程

    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        // 存在参数 “--runtime-init” 参数
        if (parsedArgs.runtimeInit) {
            RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
        } else {
            ...
        }
    }
RuntimeInit # zygoteInit
    public static final void zygoteInit(String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {

        commonInit();
        // 启动一个Binder线程池
        zygoteInitNative();

        // 启动ActivityThread类的main函数中
        invokeStaticMain(startClass, startArgs);
    }

12.2 Binder线程池的启动过程

RuntimeInit类的zygoteInitNative的函数来启动一个Binder线程池

RuntimeInit # zygoteInitNative
    public static final native void zygoteInitNative();
AndroidRuntime # com_android_internal_os_RuntimeInit_zygoteInit
static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}
app_main.cpp # onZygoteInit
    virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        if (proc->supportsProcesses()) {
            LOGV("App process: starting thread pool.\n");
            proc->startThreadPool();
        }       
    }
ProcessState # startThreadPool
sp<ProcessState> ProcessState::self()
{
    if (gProcess != NULL) return gProcess;
    
    AutoMutex _l(gProcessMutex);
    if (gProcess == NULL) gProcess = new ProcessState;
    return gProcess;
}

ProcessState::ProcessState()
    : mDriverFD(open_driver())
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // mmap binder,提供一块虚拟地址空间来接收事务。
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
    }
}

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    // 每个支持Binder进程间通信机制的进程内部,只会启动一个Binder线程池,
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        int32_t s = android_atomic_add(1, &mThreadPoolSeq);
        char buf[32];
        
        sp<Thread> t = new PoolThread(isMain);
        t->run(buf);
    }
}

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

消息循环的创建过程

ActivityThread 的 main 函数中,会创建一个消息循环

    public static final void main(String[] args) {
        
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        Looper.loop();

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

推荐阅读更多精彩内容