Android 系统源码分析——系统的启动

https://rainmonth.github.io/posts/A191019.html

Android系统的启动

先看启动相关进程的关系图

Android系统进程关系图

[TOC]

相关的文件

  • init.cpp
  • app_main.cpp
  • ZygoteInit.java
  • SystemServer.java

init进程

init.main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
int main(int argc, char** argv) {
// 根据argv参数进行判断,分别执行不同的main函数
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}

if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}

// Clear the umask.
umask(0);

add_environment("PATH", _PATH_DEFPATH);

// 是否处于启动的第一阶段
bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);

// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
if (is_first_stage) {
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
}

// We must have some place other than / to create the device nodes for
// kmsg and null, otherwise we won't be able to remount / read-only
// later on. Now that tmpfs is mounted on /dev, we can actually talk
// to the outside world.
open_devnull_stdio();
klog_init();// 初始化kernel log
klog_set_level(KLOG_NOTICE_LEVEL);// 设置log输出级别

NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");

if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));

property_init();// 创建一块共属性服务使用的内存空间

// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
process_kernel_dt();
process_kernel_cmdline();

// Propogate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
}

// Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
selinux_initialize(is_first_stage);

// If we're in the kernel domain, re-exec init to transition to the init domain now
// that the SELinux policy has been loaded.
if (is_first_stage) {
if (restorecon("/init") == -1) {
ERROR("restorecon failed: %s\n", strerror(errno));
security_failure();
}
char* path = argv[0];
char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
if (execv(path, args) == -1) {
ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
security_failure();
}
}

// These directories were necessarily created before initial policy load
// and therefore need their security context restored to the proper value.
// This must happen before /dev is populated by ueventd.
INFO("Running restorecon...\n");
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
restorecon_recursive("/sys");

epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
ERROR("epoll_create1 failed: %s\n", strerror(errno));
exit(1);
}

signal_handler_init();

property_load_boot_defaults();
start_property_service();// 启动属性服务

init_parse_config_file("/init.rc");// 解析init.rc文件
// 执行rc文件中触发器为on early-init的语句
action_for_each_trigger("early-init", action_add_queue_tail);

// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");

// 执行rc文件中触发器为on init的语句
action_for_each_trigger("init", action_add_queue_tail);

// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

// Don't mount filesystems or start core system services in charger mode.
char bootmode[PROP_VALUE_MAX];
if (property_get("ro.bootmode", bootmode) > 0 && strcmp(bootmode, "charger") == 0) {
// 执行rc文件中触发器为on charger
action_for_each_trigger("charger", action_add_queue_tail);
} else {
// 执行rc文件中触发器为on late-init
action_for_each_trigger("late-init", action_add_queue_tail);
}

// Run all property triggers based on current state of the properties.
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");

while (true) {
if (!waiting_for_exec) {
execute_one_command();
restart_processes();
}

int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}

if (!action_queue_empty() || cur_action) {
timeout = 0;
}

bootchart_sample(&timeout);

epoll_event ev;
// 循环等待事件发生
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
if (nr == -1) {
ERROR("epoll_wait failed: %s\n", strerror(errno));
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}

return 0;
}

根据上面的源码,来分析init进程干了些啥?

  • 提供属性服务(包括初始化服务和启动属性服务);
  • 解析init.rc文件;
  • 根据init.rc文件生成设备驱动节点;
  • 提供无限循环来处理事件,同时提供了子进程的终止方式;

我们说Zygote进程由init进程创建,那么init进程是在什么时候启动Zygote进程的呢?

上面说到init进程会解析init.rc文件,在init.rc文件的头部,它引入了Zygote相关的.rc文件

1
2
3
4
5
6
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc // zygote相关的配置
import /init.trace.rc

这里Zygote相关的文件有:

  • init.zygote64_32.rc
  • init.zygote32_64.rc
  • init.zygote64.rc

个人猜测存在三个版本可能是为了32位机器与64位机器间的转换。

init.zygote64.rc文件内容如下:

1
2
3
4
5
6
7
8
service zygote /system/bin/app_process64 -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

当init进程解析到上面的内容时便会进行zygote进程的创建。

init进程会根据是否是oneshot来决定在Zygote进程退出后是否会重新创建(oneshot为true则不重新创建,为false则重新创建,默认为false,所以Zygote进程一旦被杀死会立即有init进程重新创建出来)

Zygote进程

Zygote进程启动后会执行到frameworks/base/cmds/app_process/app_main.cpp文件的main()方法. 整个调用流程如下:

1
2
3
4
5
6
7
8
9
app_main.main
AndroidRuntime.start
AndroidRuntime.startVm
AndroidRuntime.startReg
ZygoteInit.main(进入java层)
registerZygoteSocket
preload
startSystemServer
runSelectLoop

app_main.main方法部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int main(int argc, char* const argv[])
{
...

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
...
while (i < argc) {
// 参数解析
...
}
// 参数解析
...

// 设置进程名
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}

if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}

如果zygote为true,就执行ZygoteInit的main方法,否则执行RuntimeInit的main方法

AndroidRuntime的start()方法中先后分别调用了startVm()(创建Java虚拟机)和startReg()(JNI 方法注册),最后调用env->CallStaticVoidMethod(startClass, startMeth, strArray);通过反射来找到ZygoteInit.java的main方法并执行,并因此从C和C++世界进入到了了Java世界。

ZygoteInit.main方法干了什么呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public static void main(String argv[]) {
try {
RuntimeInit.enableDdms();
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();

boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
// 参数解析
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}

if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
// Socket注册
registerZygoteSocket(socketName);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 预加载,包括常用的类、常用的资源(便于进程间的共享)、如果OpenGL属性没有关闭还要预加载OpenGL、共享的库文件、共享的文本资源
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());

// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();

// Do an initial gc to clean up after startup
gcAndFinalize();

// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// 启动system_server进程(Zygote和system_server间通过socket通信)
if (startSystemServer) {
// 在该方法中fork出system_server进程
startSystemServer(abiList, socketName);
}

Log.i(TAG, "Accepting command socket connections");
runSelectLoop(abiList);

closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}

ZygoteInit.startSystemServer()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

/* fork system_server进程 */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}

/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}

handleSystemServerProcess(parsedArgs);
}

return true;
}

小结

Zygote 进程完成了JVM的创建、JNI方法的注册,并作为Java进程的鼻祖,用于孵化Java进程,再创建完system_server进程后,调用runSelectLoop(),随时待命,当接收到创建新进程请求时立即唤醒并重新工作。

system_server

在Zygote进程条用startSystemServer()孵化出system_server进程后,会调用handleSystemServerProcess()方法,该方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* 完成新近创建的system_server进程创建后的善后工作
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {

closeServerSocket();

// set umask to 0077 so new files and directories will default to owner-only permissions.
Os.umask(S_IRWXG | S_IRWXO);

if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}

final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
performSystemServerDexOpt(systemServerClasspath);
}

if (parsedArgs.invokeWith != null) {
String[] args = parsedArgs.remainingArgs;
// If we have a non-null system server class path, we'll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process.
if (systemServerClasspath != null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
}

WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
// 创建PathClassLoader类加载器
cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(cl);
}

/*
* Pass the remaining arguments to SystemServer.
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}

/* should never reach here */
}

根据上面的代码,可以看出:

  • 如果system_server已经存在,会有一个argument合并的过程,合并之后交由ART(Android Runtime)处理;

  • system_server 完成了PathClassLoader类加载器的创建;

  • 会调用RuntimeInit.zygoteInit方法;

RuntimeInit.zygoteInit

1
2
3
4
5
6
7
8
9
10
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(); // 调用c/c++层的Zygote Init方法
applicationInit(targetSdkVersion, argv, classLoader);
}

这个方法的调用完成了两件事情:

  • 完成了进程binder线程池的启动,nativeZygoteInit()最终会走到app_main.cpp的onZygoteInit()方法,该方法如下:

    1
    2
    3
    4
    5
    6
    virtual void onZygoteInit()
    {
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool(); // 启动Binder线程池
    }
  • 捕获特殊异常,applicationInit方法最终会抛出ZygoteInit.MethodAndArgsCaller(m, argv)异常,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    ...
    // 设置目标对利用率
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    // 设置tagetSDKVersion
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
    args = new Arguments(argv);
    } catch (IllegalArgumentException ex) {
    Slog.e(TAG, ex.getMessage());
    // let the process exit
    return;
    }

    // The end of of the RuntimeInit event (see #zygoteInit).
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    // 找到目标类的静态main方法并调用,同时抛出异常
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
    cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
    throw new RuntimeException(
    "Missing class when invoking static main " + className,
    ex);
    }

    Method m;
    try {
    m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
    throw new RuntimeException(
    "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
    throw new RuntimeException(
    "Problem getting static main on " + className, ex);
    }

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
    throw new RuntimeException(
    "Main method is not public and static on " + className);
    }

    /*
    * This throw gets caught in ZygoteInit.main(), which responds
    * by invoking the exception's run() method. This arrangement
    * clears up all the stack frames that were required in setting
    * up the process.
    */
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

    MethodAndArgsCaller相关说明:

    1. 该异常实现了Runnable接口;
    2. 该异常有ZygoteInit.main方法捕获;
    3. 该异常捕获后,其run方法会被调用,调用后会执行SystemServer的main方法;

    SystemServer

    SystemServer的main方法主要就是先创建SystemServer对象,然后调用其run方法。run方法干了啥?

    1. SystemProperties的设置;
    2. VMRuntime的设置;
    3. 准备主线程的Looper;
    4. android_servers.so库的加载;
    5. System Context的初始化;
    6. SystemServiceManager的创建;
    7. 各种服务的开启:
      • startBootstrapServices();
      • startCoreServices();
      • startOtherServices();
    8. 调用Looper.loop()开启循环;

​ SystemServer启动服务分几个不同的阶段,分别是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
* 这个阶段,开始一些服务的创建
*/
public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?

/**
* 进入这个阶段,可获取Lock Setting数据
*/
public static final int PHASE_LOCK_SETTINGS_READY = 480;

/**
* 进入这个阶段,可以安全掉调用系统的PowerManager和PackageManager提供的方法
*/
public static final int PHASE_SYSTEM_SERVICES_READY = 500;

/**
* 进入这个阶段,服务可以发送广播
*/
public static final int PHASE_ACTIVITY_MANAGER_READY = 550;

/**
* 进入这个阶段,可以绑定或启动第三方APP了
*/
public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;

/**
* 进入这个阶段,允许用户与系统机型交互
* This phase occurs when boot has completed and the home application has started.
* System services may prefer to listen to this phase rather than registering a
* broadcast receiver for ACTION_BOOT_COMPLETED to reduce overall latency.
*/
public static final int PHASE_BOOT_COMPLETED = 1000;
  • start,调用start方法,会先开启几个关键的服务,如AMS、PowerManagerService、LightService、DisplayManagerService;
  • phase100(即PHASE_WAIT_FOR_DEFAULT_DISPLAY):创建PKMS, WMS, IMS, DBMS, LockSettingsService, JobSchedulerService, MmsService等服务;
  • phase480 && 500(即PHASE_LOCK_SETTINGS_READYPHASE_ACTIVITY_MANAGER_READY): 进入Phase480, 调用WMS, PMS, PKMS, DisplayManagerService这4个服务的systemReady();
  • phase550: 进入phase550, 执行AMS.systemReady(), 启动SystemUI, WebViewFactory, Watchdog.
  • Phase600: 进入phase600, 执行AMS.systemReady(), 执行各种服务的systemRunning().
  • Phase1000: 进入1000, 执行finishBooting, 启动启动on-hold进程.

SystemServer的主线程在经过上面几个步骤后,主线程启动总算完毕,在Looper.loop()后开始等待其他线程通过Handler发送消息再处理

普通app进程

普通app的进程和system_server进程启动的流程类似,只是最后调用的main方法不同,普通app进程最后调用的是ActivityThread.main方法,而system_server调用的是SystemServer.main

总结

这里对系统启动时的一些进程做个总结性描述。

核心进程及其对应的main方法

进程名 对应的main方法
init进程 init.main()
zygote进程 ZygoteInit.main()
app_process进程 RuntimeInit.main()
SystemServer进程 SystemServer.main()
app进程 ActivityThread.main()

注意app_process进程是指通过/system/bin/app_process启动的进程,且后面跟的参数不带–zygote,即并非启动zygote进程。 比如常见的有通过adb shell方式来执行am,pm等命令,便是这种方式。

进程重启导致的关联性

重启的进程 关联重启的进程
zygote 触发media、netd以及zygote的子进程(system_server)重启
system_server 触发zygote重启
surfaceflinger 触发zygote重启
servicemanager 触发zygote、healthd、media、surfaceflinger、drm重启