Android应用程序进程启动过程(后篇)

刘望舒 等级 408 2 0

本文首发于微信公众号「后厂技术官」

前言

在前篇中我们讲到了Android应用程序进程启动过程,这一篇我们来讲遗留的知识点:在应用程序进程创建过程中会启动Binder线程池以及在应用程序进程启动后会创建消息循环。

1.Binder线程池启动过程

我们首先来看RuntimeInit类的zygoteInit函数,如下所示 frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

  public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();
        commonInit();
        nativeZygoteInit();//1
        applicationInit(targetSdkVersion, argv, classLoader);
    }

注释1处会在新创建的应用程序进程中创建Binder线程池,来查看nativeZygoteInit函数:

 private static final native void nativeZygoteInit();

很明显nativeZygoteInit是一个jni方法,它对应的函数是什么呢。在 AndroidRuntime.cpp的JNINativeMethod数组中我们得知它对应的函数是com_android_internal_os_RuntimeInit_nativeZygoteInit,如下所示。 frameworks/base/core/jni/AndroidRuntime.cpp

static const JNINativeMethod gMethods[] = {
    { "nativeFinishInit", "()V",
        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
    { "nativeZygoteInit", "()V",
        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
    { "nativeSetExitWithoutCleanup", "(Z)V",
        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};

接着来查看 com_android_internal_os_RuntimeInit_nativeZygoteInit函数: frameworks/base/core/jni/AndroidRuntime.cpp

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

gCurRuntime是在AndroidRuntime初始化就创建的。如下所示。 frameworks/base/core/jni/AndroidRuntime.cpp

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
   ...
    gCurRuntime = this;
}

Android系统启动流程(二)解析Zygote进程启动过程这篇文章我们得知AppRuntime继承AndroidRuntime,AppRuntime创建时就会调用AndroidRuntime的构造函数,gCurRuntime就会被初始化,它指向的是AppRuntime,因此我们来查看AppRuntime的onZygoteInit函数,AppRuntime的实现在app_main.cpp中,如下所示。 frameworks/base/cmds/app_process/app_main.cpp

 virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

最后一行会调用ProcessState的startThreadPool函数: frameworks/native/libs/binder/ProcessState.cpp

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

支持Binder通信的进程中都有一个ProcessState类,它里面有一个mThreadPoolStarted 变量,来表示Binder线程池是否已经被启动过,默认值为false。在每次调用这个函数时都会先去检查这个标记,从而确保Binder线程池只会被启动一次。如果Binder线程池未被启动则设置mThreadPoolStarted为true,最后调用spawnPooledThread函数来创建线程池中的第一个线程,也就是线程池的main线程,如下所示。 frameworks/native/libs/binder/ProcessState.cpp

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());//1
    }
}

可以看到Binder线程为一个PoolThread。注释1调用PoolThread的run函数来启动一个启动一个新的线程。来查看PoolThread类里做了什么: frameworks/native/libs/binder/ProcessState.cpp

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

PoolThread类继承了Thread类。注释1处会将调用IPCThreadState的joinThreadPool函数,将当前线程注册到Binder驱动程序中,这样我们创建的线程就加入了Binder线程池中,这样新创建的应用程序进程就支持Binder进程间通信了,Binder线程池启动过程就讲到这,接下来我们来学习消息循环创建过程。

2.消息循环创建过程

首先我们回到上篇最后讲到的RuntimeInit的invokeStaticMain函数,代码如下所示。 frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
  ...
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

invokeStaticMain函数在上篇已经讲过,这里不再赘述,主要是看最后一行,会抛出一个MethodAndArgsCaller异常,这个异常会被ZygoteInit的main函数捕获,如下所示。 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

  public static void main(String argv[]) {
     ...
        try {
           ...
        } catch (MethodAndArgsCaller caller) {
            caller.run();//1
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

注释1处捕获到MethodAndArgsCaller 时会执行caller的run函数,如下所示。 frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

 public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        private final Method mMethod;
        private final String[] mArgs;
        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }
        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });//1
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            }
            ...
                throw new RuntimeException(ex);
            }
        }
    }

根据上一篇文章我们得知,mMethod指的就是ActivityThread的main函数,mArgs 指的是应用程序进程的启动参数。在注释1处调用ActivityThread的main函数,代码如下所示。 frameworks/base/core/java/android/app/ActivityThread.java

 public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();
...
        Looper.prepareMainLooper();//1
        ActivityThread thread = new ActivityThread();//2
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();//3
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

注释1处在当前应用程序进程中创建消息循环,注释2处创建ActivityThread,注释3处调用Looper的loop,使得Looper开始工作,开始处理消息。可以看出,系统在应用程序进程启动完成后,就会创建一个消息循环,用来方便的使用Android的消息处理机制。

收藏
评论区

相关推荐

Android深入浅出之Binder机制
Android深入浅出之Binder机制 一 说明 Android系统最常见也是初学者最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制来和客户端通讯交互的。所以搞明白Binder的话,在很大程度上就能理解程序运行的流程。 我们这里将以MediaService的例子来分析Binder的使用: ServiceMan
Android应用程序进程启动过程(后篇)
本文首发于微信公众号「后厂技术官」 前言在前篇中我们讲到了Android应用程序进程启动过程,这一篇我们来讲遗留的知识点:在应用程序进程创建过程中会启动Binder线程池以及在应用程序进程启动后会创建消息循环。<more 1.Binder线程池启动过程我们首先来看RuntimeInit类的zygoteInit
Android Binder原理(一)学习Binder前必须要了解的知识点
本文首发于微信公众号「刘望舒」 前言Binder原理是掌握系统底层原理的基石,也是进阶高级工程师的必备知识点,这篇文章不会过多介绍Binder原理,而是讲解学习Binder前需要的掌握的知识点。 1.Linux和Android的IPC机制种类IPC全名为interProcess Communication,含义为进程间
Android Binder原理(二)ServiceManager中的Binder机制
Binder原理 Android框架层本文首发于微信公众号「刘望舒」<more 前言在上一篇文章中,我们了解了学习Binder前必须要了解的知识点,其中有一点就是Binder机制的三个部分:Java Binder、Native Binder、Kernel Binder,其中Java Binder和Native
Binder Driver缺陷导致定屏的案例
本文讲解异步binder call是如何阻塞整个系统的,通过ramdump信息以及binder通信协议来演绎并还原定屏现场。 一、背景知识点解决此问题所涉及到的基础知识点有:Trace、CPU调度、Ramdump推导、Crash工具、GDB工具、Ftrace, 尤其深入理解binder IPC机制。 1.1 工具简介 Trace:分析死锁
Android 操作系统架构开篇
版权声明: 本站所有博文内容均为原创,转载请务必注明作者与原文链接,且不得篡改原文内容。为便于日常查阅本博客,可通过 方便检索文章 一、引言众所周知,Android是谷歌开发的一款基于Linux的开源操作系统,从诞生至今已有10余年,这一路走来Android遇到哪些问题?大版本升级朝着什么方向演进?Android的未来如何?我的公号 讲解了Android一
Android四大组件与进程启动的关系
一. 概述Android系统将进程做得很友好的封装,对于上层app开发者来说进程几乎是透明的. 了解Android的朋友,一定知道Android四大组件,但对于进程可能会相对较陌生. 一个进程里面可以跑多个app, 一个app也可以跑在多个进程里,通过配置Android:process属性来决定所运行在哪个进程。再进一步进程是如何创建的, 可能很多人不知道f
Android Binder原理(三)系统服务的注册过程
Binder原理 Android框架层本文首发于微信公众号「刘望舒」<!more 前言在上一篇文章中,我们学习了ServiceManager中的Binder机制,有一个问题由于篇幅问题没有讲完,那就是MediaPlayerService是如何注册的。通过了解MediaPlayerService是如何注册的,可以得知系统服务的注册过程。 1.从调用链角度说明M
Android Binder原理(四)ServiceManager的启动过程
Binder原理 Android框架层本文首发于微信公众号「刘望舒」<!more 前言在上一篇文章中,我们以MediaPlayerService为例,讲解了系统服务是如何注册的(addService),既然有注册就势必要有获取,但是在了解获取服务前,我们最好先了解ServiceManager的启动过程,这样更有助于理解系统服务的注册和获取的过程。另外还有一点
Android Binder原理(五)系统服务的获取过程
Binder原理 Android框架层本文首发于微信公众号「后厂技术官」<!more 前言在本系列的此前文章中,以MediaPlayerService为例,讲解了系统服务是如何注册的(addService),既然有注册那肯定也要有获取,本篇文章仍旧以MediaPlayerService为例,来讲解系统服务的获取过程(getService)。文章会分为两个部分
Android Binder原理(六)Java Binder的初始化
Binder原理 Android框架层本文首发于微信公众号「刘望舒」<!more 前言在这篇文章中,我根据Android系统的分层,将Binder机制分为了三层:1. Java Binder (对应Framework层的Binder)2. Native Binder(对应Native层的Binder)3. Kernel Binder(对应Kernel层的Bi
Android Binder原理(七)Java Binder中系统服务的注册过程
Binder原理 Android框架层本文首发于微信公众号「后厂技术官」<!more 前言在这篇文章中,我介绍的是Native Binder中的系统服务的注册过程,这一过程的核心是ServiceManager,而在Java Binder中,也有一个ServiceManager,只不过这个ServiceManager是Java文件。既然要将系统服务注册到Ser
Android解析ActivityManagerService(一)AMS启动流程和AMS家族
Android框架层 Android系统服务 ActivityManagerService Android框架层本文首发于微信公众号「刘望舒」 前言此前在Android系统启动流程、应用进程以及深入四大组件这三个系列文章中,都提及到了AMS,但都没有系统的来讲解它,本文就以AMS为主来进行讲解,其中会有一些知识点与这些系列文章有所重合,这里会尽量做到详尽讲解
面试官突击一问:深入理解mysql技术
京东Java研发岗一面(基础面,约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和springboot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作用范围? 索引是什么概念有什么作用?MySQL里主要有哪些索引结构?哈希索引和B+树索引比较? Java线程池的原理?线程池有哪些?线程池
JNI 基础 - Android 共享内存的序列化过程
1. 进程间的通信方式有哪些2. binder 和 socket 通信的区别有哪些3. Android 为什么在大部分场景下用 Binder 进行进程间通信4. Serializable 和 Parcelable 之间的区别5. Parcelable 序列化和反序列化的具体过程不知道大家在面试中的过程中,有没有碰到上面类似的问题,我在腾讯和 oppo 面试的