parent
16cec8ca89
commit
42e3500b4f
@ -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<ProcessState> 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. 系统服务是怎么启动的? |
@ -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) |
@ -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 的工作原理 |
||||||
|
|
@ -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 进程。 |
||||||
|
|
||||||
|
|
||||||
|
|
@ -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<String, ServiceFetcher<?>>(); |
||||||
|
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<PowerManager>()) { |
||||||
|
@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<ProcessState> ps(ProcessState::self()); |
||||||
|
// 启动 binder 线程池 |
||||||
|
ps->startThreadPool(); |
||||||
|
|
||||||
|
sp<SurfaceFlinger> flinger = new SurfaceFlinger(); |
||||||
|
flinger->init(); |
||||||
|
|
||||||
|
// 注册 SurfaceFlinger 服务 |
||||||
|
sp<IServiceManager> sm(defaultServiceManager()); |
||||||
|
sm->addService(serviceName, flinger, false); |
||||||
|
|
||||||
|
flinger->run(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
ProcessState 是一个进程内的单例,它的构造函数里面会启动 binder 机制,包括打开 binder 驱动,映射内存,分配缓冲区等等。 |
||||||
|
|
||||||
|
最后看一下defaultServiceManager 函数: |
||||||
|
|
||||||
|
```c |
||||||
|
sp<IServiceManager> defaultServiceManager() { |
||||||
|
if(gDefaultServiceManager != null) { |
||||||
|
return gDefaultServiceManager; |
||||||
|
} |
||||||
|
while(gDefaultServiceManager == null) { |
||||||
|
gDefaultServiceManager = getContextObject(); |
||||||
|
if(gDefaultServiceManager==null) sleep(1); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
因为 ServiceManager 和 SurfaceFlinger 都是由 init 进程启动的,所以这里如果是独立线程启动,可能在注册服务时,ServiceManager 还未来得及向 binder 驱动注册,所以如果拿不到 ServiceManager 就睡眠不停循环获取。 |
Loading…
Reference in new issue