From 42e3500b4fc6972feb4c16ee2ae354fab84eee4b Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Tue, 17 Mar 2020 21:13:43 +0800 Subject: [PATCH] add some files --- .../Framework/Android 系统的启动流程.md | 163 ++++++++++++++++++ blogs/Android/Framework/Choreographer.md | 23 +++ blogs/Android/Framework/Zygote 的理解.md | 139 +++++++++++++++ .../SurfaceFlinger.md | 12 ++ blogs/Android/Framework/添加系统服务.md | 127 ++++++++++++++ 5 files changed, 464 insertions(+) create mode 100644 blogs/Android/Framework/Android 系统的启动流程.md create mode 100644 blogs/Android/Framework/Choreographer.md create mode 100644 blogs/Android/Framework/Zygote 的理解.md create mode 100644 blogs/Android/Framework/深入理解 Android 内核设计思想/SurfaceFlinger.md create mode 100644 blogs/Android/Framework/添加系统服务.md diff --git a/blogs/Android/Framework/Android 系统的启动流程.md b/blogs/Android/Framework/Android 系统的启动流程.md new file mode 100644 index 0000000..00c4e89 --- /dev/null +++ b/blogs/Android/Framework/Android 系统的启动流程.md @@ -0,0 +1,163 @@ +--- +Android 系统的启动流程 +--- + +#### Android 有哪些主要的系统进程? + +在 init.rc 启动配置文件中定义了很多 Service,这些 Service 就是要单独启动的系统服务进程。 + +```ini +service zygote /system/bin/app_process ... +service servicemanager /system/bin/servicemanager ... +service surfaceflinger /system/bin/surfaceflinger ... +service media /system/bin/mediaserver ... +... +``` + +#### 这些系统进程是怎么启动的?以及做了什么事? + +Zygote 启动: + +1. init 进程 fork 出 zygote 进程 +2. 启动虚拟机,注册 jni 函数,为进入 Java 世界做准备 +3. 预加载系统资源 +4. 启动 SystemServer +5. 进入 Socket Loop + +Zygote 工作流程就是执行 runOnce 函数的过程。 + +SystemServer 启动: + +```java +private static boolean startSystemServer(...) { + String args[] = { + ... + "com.android.server.SystemServer", + } + int pid = Zygote.forkSystemServer(...); + if(pid == 0){ + handlerSystemServerProcess(parsedArgs); + } + return true; +} +``` + +```java +void handlerSystemServerProcess(Arguments parsedArgs) { + RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, ...); +} +``` + +```java +void zygoteInit(String[] argv, ...) { + commonInit(); + nativeZygoteInit(); + applicationInit(argv, ...); +} +``` + +```java +// 启动 Binder 机制 +void nativeZygoteInit() { + sp proc = ProcessState::self(); + proc->startThreadPool(); +} +``` + +```java +// 执行 SystemServer 的 main 函数 +void applicationInit() { + invokeStaticMain(args, ...); +} +``` + +```java +public static void main() { + new SystemServer().run(); +} +``` + +```java +// SystemServer#run + +``` + +```java +private void run() { + Looper.prepareMainLooper(); + + System.loadLibrary("android_servers"); + createSystemContext(); + + startBootstrapServcies(); + startCoreServices(); + startOtherServices(); + + Looper.loop(); +} +``` + + + +#### 两个问题: + +1. 系统服务是怎么启动的? +2. 怎么解决系统服务之间的相互依赖? + +第一个问题,系统服务是怎么启动的? + +我们只需要关注两个问题: + +1. 系统服务怎么发布,让应用程序可见? + + ```java + void publishBinderService(String name, IBiner service, ...) { + ServiceManager.addService(name, service, allowlsolated); + } + ``` + + 也就是把系统服务的 Binder 注册到 ServiceManager 中。 + +2. 系统服务跑在什么线程? + +3. + +课堂作业: + +1. 为什么系统服务不都跑在 binder 线程里呢? +2. 为什么系统服务不都跑在自己私有的工作线程里呢? +3. 跑在 binder 线程和跑在工作线程,如何取舍? + +第二个问题,怎么解决系统服务之间的相互依赖? + +1. 分批启动(AMS、PMS、PKMS) +2. 分阶段启动(阶段1、阶段2...) + +#### 桌面启动 + +在 AMS 服务就绪的时候,会调用以下函数: + +```java +public void systemReady(final Runnable goingCallback) { + //... + startHomeActivityLocked(mCurrentUserId, "systemReady"); +} +``` + +在 Launcher2 Activity 的 onCreate 里面会启动一个 LoaderTask: + +```java +mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags); +``` + +这个 LoaderTask 会向 PMS 去查询已经安装的应用: + +``` +mPm.queryIntentActivitiesAsUser +``` + +#### 说说 Android 系统的启动流程? + +1. Zygote 是怎么启动的? +2. systemServer 是怎么启动的? +3. 系统服务是怎么启动的? \ No newline at end of file diff --git a/blogs/Android/Framework/Choreographer.md b/blogs/Android/Framework/Choreographer.md new file mode 100644 index 0000000..c59d4c0 --- /dev/null +++ b/blogs/Android/Framework/Choreographer.md @@ -0,0 +1,23 @@ +--- +Choreographer +--- + +#### 概述 + +Choreographer 是用来控制同步处理输入(Input)、动画(Animation)、绘制(Draw)三个操作(UI 显示的时候每一帧要完成的事情只有这三种)。其内部维护着一个 Queue,使用者可以通过 postXxx 来把一系列待运行的 UI 操作放到 Queue 中。这些事件会在 Choreographer 接收 VSYNC 信号后执行这些操作,比如 ViewRootImpl 对于 ViewTree 的更新事件: + +```java +// ViewRootImpl +void scheduleTraversals() { + ... + mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); +} +``` + +#### 对 Vsync 信号的监听 + + + +#### 参考 + +[Choreographer工作逻辑总结](https://github.com/SusionSuc/AdvancedAndroid/blob/master/Rabbit%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E5%89%96%E6%9E%90/Choreographer%E5%B7%A5%E4%BD%9C%E9%80%BB%E8%BE%91%E6%80%BB%E7%BB%93.md) \ No newline at end of file diff --git a/blogs/Android/Framework/Zygote 的理解.md b/blogs/Android/Framework/Zygote 的理解.md new file mode 100644 index 0000000..b4dc0db --- /dev/null +++ b/blogs/Android/Framework/Zygote 的理解.md @@ -0,0 +1,139 @@ +--- +谈谈你对 Zygote 的理解? +--- + +#### 了解 Zygote 的作用 + +1. 启动 SystemServer +2. 孵化应用进程 + +#### 熟悉 Zygote 的启动流程 + +启动三段式: + +进程启动 -> 准备工作 -> LOOP + +Zygote 的启动可以分为两块: + +1. 进程是怎么启动的? +2. 进程启动之后做了什么? + +第一个问题:进程是怎么启动的? + +Init 进程是 Linux 启动之后,用户空间的第一个进程。加载了一个 init.rc 配置文件,里面配置了很多系统服务。通过 fork+execev 系统调用。 + +```ini +// Service Name: zygote, 可执行路径 + 参数 +service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server +class main +socket zygote stream 660 root system +onrestart write /sys/android_power/request_state wake +onrestart write /sys/power/state on +onrestart restart media +onrestart restart netd +writepid /dev/cpuset/foreground/tasks +``` + +启动进程有两种方式: + +第一种是 fork + handle: + +```c +pid_t pid = fork(); +if(pid == 0){ + // child process +} else { + // parent process +} +``` + +第二种是 fork + execve: + +```c +pid_t pid = fork(); +if(pid == 0){ + // child process + execve(path, argv, env); +} else { + // parent process +} +``` + +调用 fork 函数创建子进程,它会返回两次,子进程返回的 pid == 0,父进程返回的 pid 等于子进程的 pid。 + +默认情况下,子进程继承了父进程创建的所有资源,如果调用了系统调用 execve 去加载另一个二进程程序的话,那么继承父进程的资源就会被清掉。 + +信号处理,SIGCHLD 信号: + +父进程 fork 出了子进程,如果子进程挂了,那么它的父进程就会收到 SIGCHLD 信号,然后就可以重启。 + +第二个问题:Zygote 进程启动之后做了什么? + +* Zygote 的 Native 世界 +* Zygote 的 Java 世界 + +Native 世界其实就是为了进入 Java 世界做准备,有以下三件事: + +1. 启动虚拟机 +2. 注册 Android 的 JNI 函数 +3. 进入 Java 世界 + +```c +int main(int argc, char *argv[]) { + JavaVM *jvm; + JNIEnv *env; + // 1 + JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); + // 2 + jclass clazz = env->FindClass("ZygoteInit"); + jmethodID method = env->GetStaticMethodID(clazz, "Main", "(Ljava/lang/String;)V"); + env->CallStaticVoidMethod(clazz, method, args); + jvm->DestoryJavaVM(); +} +``` + +Java 虚拟机在 Zygote 都已经创建好了,应用程序都是由 Zygote 创建而来的,就直接继承了它的虚拟机。 + +再来看一下 Zygote 的世界,做了以下事情: + +1. 通过 registerServerSockert 方法来创建一个 Server 端的 Socket,这个 name 为 zygote 的 socket 用于等待 AMS 请求 Zygote 来创建新的应用程序进程 +2. 预加载资源,Preload Resources,在 Zygote 进程预加载系统资源后,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样大幅度提高应用程序的启动和运行速度 +3. 启动 System Server +4. 进入 Loop 循环,执行 runSelectLoop 方法等待消息去创建应用进程 + +Zygote 处理请求的关键代码: + +```java +boolean runOnce() { + // 1. 读取参数列表 + String[] args = readArgumentList(); + // 2. 启动子进程 + int pid = Zygote.forkAndSpecialize(); + if(pid == 0){ + // 3. 在进程里面干活,其实就是执行了一个 java 类的 main 函数,java 类名就是上面读取的参数列表,参数列表是 AMS 跨进程发过来的,类名其实就是 ActivityThread + // in child + handleChildProc(args, ...); + return true; + } +} +``` + +注意细节: + +1. Zygote 在 fork 的时候要保证是单线程的,为了避免造成死锁和状态不一致等问题 +2. Zygote 的 IPC 没有采用 Binder,而是本地 Socket + +问题: + +1. 孵化应用进程这种事为什么不交给 SystemServer 来做,而专门设计一个 Zygote ? + +> 我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类资源系统等等,这些都是非常耗时的,如果能在 zygote 里就给这些必要的初始化工作做好,子进程在 fork 的时候就能直接共享,那么这样的话效率就会非常高。这个就是 zygote 存在的价值,这一点 SystemServer 是替代不了的,主要是因为 SystemServer 里跑了一堆系统服务,这些是不能继承到应用程序的。而且我们应用程序在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一些乱七八糟的东西,所以呢,不如给 SystemServer 和应用进程里都要用到的资源抽出来单独放到一个进程里,也就是这个 zygote 进程,然后 zygote 进程在分别孵化出 SystemServer 进程和应用进程。孵化出来之后,SystemServer 进程和应用程序进程就可以各干各事了。 + +1. Zygote 的 IPC 通信机制为什么不采用 Binder?如果采用 Binder 的话会有什么问题呢? + +> https://www.zhihu.com/question/312480380 +> +> https://blog.csdn.net/qq_39037047/article/details/88066589 + +#### 深刻理解 Zygote 的工作原理 + diff --git a/blogs/Android/Framework/深入理解 Android 内核设计思想/SurfaceFlinger.md b/blogs/Android/Framework/深入理解 Android 内核设计思想/SurfaceFlinger.md new file mode 100644 index 0000000..e9933be --- /dev/null +++ b/blogs/Android/Framework/深入理解 Android 内核设计思想/SurfaceFlinger.md @@ -0,0 +1,12 @@ +--- +SurfaceFlinger +--- + +#### 概述 + +SurfaceFlinger 是负责绘制应用 UI 的核心,从名字上可以看出其功能是将所有的 Surface 合成工作。不论使用什么渲染 API,所有的东西最终都是渲染到 Surface 上,Surface 代表 BufferQueue 的生产者端,并且由 SurfaceFlinger 消费。Android 平台所创建的 Window 都由 Surface 所支持,所有可见的 Surface 渲染到显示设备都是通过 SurfaceFlinger来完成的。 + +SurfaceFlinger 进程是由 init 进程创建的,运行在独立的 SurfaceFlinger 进程。Android 应用程序必须跟 SurfaceFlinger 进程交互,才能完成将应用 UI 绘制到 FrameBuffer(帧缓冲区)。这个交互便涉及到进程间的通信,采用 Binder IPC 方式,名为 "SurfaceFlinger" 的 Binder 服务端运行在 SurfaceFlinger 进程。 + + + diff --git a/blogs/Android/Framework/添加系统服务.md b/blogs/Android/Framework/添加系统服务.md new file mode 100644 index 0000000..32d45b8 --- /dev/null +++ b/blogs/Android/Framework/添加系统服务.md @@ -0,0 +1,127 @@ +--- +怎么添加一个系统服务? +--- + +1. 了解如何使用系统服务? +2. 了解系统服务调用的基本原理 +3. 了解服务的注册原理 + +#### 如何使用系统服务以及基本原理 + +```java +// ContextImpl +public Object getSystemServer(String name) { + return SystemServiceRegistry.getSystemService(this, name); +} + +// SystemServiceRegistry + +SYSTEM_SERVICE_FETCHERS = new ArrayMap>(); +public static Object getSystemService(ContextImpl ctx, String name) { + ServiceFetcher fetcher = SYSTEM_SERVICE_FETCHERS.get(name); + return fetcher != null ? fetcher.getService(ctx) : null; +} + +// 具体实现 + public final T getService(ContextImpl ctx) { + final Object[] cache = ctx.mServiceCache; + T service = (T) cache[mCacheIndex]; + if (service != null) { + return service; + } else { + service = createService(ctx); + cache[mCacheIndex] = service; + } + } +``` + +然后看一下 createService 是如何实现的,这里以 Power Service 为例: + +```java +registerService(Context.POWER_SERVICE, PowerManager.class, new CachedServiceFetcher()) { + @Override + public PowerManager createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(Context.POWER_SERVICE); + IPowerManager service = IPowerManager.Stub.asInterface(b); + return new PowerManager(ctx.getOuterContext(), service, ctx.mMainThread.getHandler()); + } +} +``` + +```java + // ServiceManager#getService + public static IBinder getService(String name) { + try { + IBinder service = sCache.get(name); + if (service != null) { + return service; + } else { + return Binder.allowBlocking(rawGetService(name)); + } + } catch (RemoteException e) { + Log.e(TAG, "error in getService", e); + } + return null; + } +``` + +#### 服务的注册原理 + +```java +public static void addService(String name, IBinder service) { + getIServiceManager().addService(name, service, false); +} +``` + +什么时候注册的系统服务? + +就是在 SystemServer 启动时注册。它的主要流程是:启用 binder 机制 -> 启动各类系统服务 -> 进去 Loop 循环。 + +需要注意的是,并不是所有的系统服务都是在 SystemServer 进程里的,有一些服务·是单开一个进程的,比如 ServiceManager、SurfaceFlinger、MediaService 等,但是同样需要注册到 ServiceManager 中。 + +独立进程的系统服务实现,以 SurfaceFlinger 为例: + +```ini +service surfaceflinger /system/bin/surfaceflinger +class core +user system +group graphics drmrpc +onrestart restart zygote +writepid /dev/cpuset/system-background/tasks +``` + +```c +int main(int, char**) { + sp ps(ProcessState::self()); + // 启动 binder 线程池 + ps->startThreadPool(); + + sp flinger = new SurfaceFlinger(); + flinger->init(); + + // 注册 SurfaceFlinger 服务 + sp sm(defaultServiceManager()); + sm->addService(serviceName, flinger, false); + + flinger->run(); + return 0; +} +``` + +ProcessState 是一个进程内的单例,它的构造函数里面会启动 binder 机制,包括打开 binder 驱动,映射内存,分配缓冲区等等。 + +最后看一下defaultServiceManager 函数: + +```c +sp defaultServiceManager() { + if(gDefaultServiceManager != null) { + return gDefaultServiceManager; + } + while(gDefaultServiceManager == null) { + gDefaultServiceManager = getContextObject(); + if(gDefaultServiceManager==null) sleep(1); + } +} +``` + +因为 ServiceManager 和 SurfaceFlinger 都是由 init 进程启动的,所以这里如果是独立线程启动,可能在注册服务时,ServiceManager 还未来得及向 binder 驱动注册,所以如果拿不到 ServiceManager 就睡眠不停循环获取。 \ No newline at end of file