2019独角兽企业重金招聘Python工程师标准>>>
声明
- 前阶段在项目中涉及到了Android系统定制任务,Android系统定制前提要知道Android系统是如何启动的。
- 本文参考了一些书籍的若干章节,比如《Android进阶解密-第2章-Android系统启动》、《深入理解Android虚拟机-第8/9/10章-init进程详解/Dalvik VM的进程系统/Dalvik VM运作流程详解》、《深入理解Android系统-第6/7/8章-init启动进程详解/Zygote进程详解/System进程详解》等
- 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
- 很多代码注释待详细写
0 写在前面的
在上一篇《[日更-2019.4.20、21] cm-14.1 Android系统启动过程分析(二)-Zygote进程启动过程》的第3.2节启动了SystemServer,Zygote让SystemServer启动是为了让它去创建Android的系统服务:AMS、WMS、PMS等。
Zygote启动SystemServer的时序图(盗一张图)
1 Zygote进程启动SystemServer
分析startSystemServer方法最终调用的方法handleSystemServerProcess,源码目录为:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中:
/**
* Finish remaining work for the newly forked system server process.
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
//关闭Zygote进程创建的Socket(SystemServer进程是由Zygote进程fork而来,所以拥有Zygote进程的地址空间,
//因此也会得到Zygote进程创建的Socket,这个Socket对SystemServer进程没用,所以要关闭它);
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,关于它将在后面介绍ClassLoader时分析;
cl = createSystemServerClassLoader(systemServerClasspath,
parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
* 调用ZygoteInit的zygoteinit方法;
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
}
分析zygoteinit方法,源码目录为:~/LineageOS/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java中:
/**
* The main function called when started through the zygote process. This
* could be unified with main(), if the native code in nativeFinishInit()
* were rationalized with Zygote startup.
*
* Current recognized args:
*
* -
[--] <start class name> <args>
*
*
* @param targetSdkVersion target SDK version
* @param argv arg strings
*/
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();
//1-1 调用Native层方法启动Binder线程池,这样SystemServer进程就可以使用Binder与其他进程进行通信了;
nativeZygoteInit();
//1.2 进入SystemServer的main方法
applicationInit(targetSdkVersion, argv, classLoader);
}
1.1 如何启动Binder线程池
在代码注释1-1处nativeZygoteInit方法是RuntimeInit.java的一个Native方法,其对应的Native层的JNI函数为com_android_internal_os_RuntimeInit_nativeZygoteInit函数,源码目录:~/LineageOS/frameworks/base/core/jni/AndroidRuntime.cpp中
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
其中,gCurRuntime为AndroidRuntime类型的指针,具体是AndroidRuntime类型的子类AppRuntime,其定义在源码目录:~/LineageOS/frameworks/base/cmds/app_process/app_main.cpp中
virtual void onZygoteInit()
{
sp proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
//1-1-1 启动一个Binder线程池,
proc->startThreadPool();
}
1.2 如何进入SystemServer的main方法
在代码注释1-2处调用了RuntimeInit的applicationInit方法,该方法在源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java中:
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
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);
// Remaining arguments are passed to the start class's static main
//1-2-1 application方法中主要调用了invokeStaticMain方法;
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
在代码注释1-2处调用了invokeStaticMain方法,在源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java中
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class> cl;
try {
//1-2-2 通过反射得到SystemServer类,ClassName为com.android.server.SystemServer,返回的的cl为SystemServer类;
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
//1-2-3 找到SystemServer的main方法;
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.
*/
//1-2-4 将找到的main函数传入到MethodAndArgsCaller异常中并抛出该异常(截获MethodAndArgsCaller异常的代码在ZygoteInit.java的main函数中)
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
在代码注释1-2-4 处截获MethodAndArgsCaller异常的代码在ZygoteInit.java的main函数中,这个main方法会调用SystemServer的main方法,源码目录:~/LineageOS/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中:
public static void main(String argv[]) {
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
try {
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
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.");
}
registerZygoteSocket(socketName);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
gcAndFinalize();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
//1-2-5 捕获到MethodAndArgsCaller异常时调用MethodAndArgsCaller的run方法,MethodAndArgsCaller是ZygoteInit.java的静态内部类;
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
在代码注释1-2-5 处的MethodAndArgsCaller是ZygoteInit.java的内部类:
/**
* Helper exception class which holds a method and arguments and
* can call them. This is used as part of a trampoline to get rid of
* the initial process setup stack frames.
*/
public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
//其中mMethod指的是SystemServer的main方法,调用了mMethod的invoke方法后,SystemServer的main方法就会被动态调用,SystemServer进程就进入了SystemServer的main方法中了;
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
有一个疑问了在代码注释1-2-4为什么要以这种抛出异常的形式代用SystemServer的main方法呢?
因为这种抛出异常的处理会清除所有的设置过程需要的堆栈帧,而让SystemServer的main方法看起来像是SystemServer进程的入口方法。在Zygote启动了SystemServer后,SystemServer进程已经做了很多准备工作,而这些工作都是在SystemServer的main方法调用之前做的,这使得SystemServer的main方法看起来不像是SystemServer进程的入口方法,而这种抛出异常交给ZygoteInit.java的main方法处理,会让SystemServer的main方法看起来像是SystemServer进程的入口方法;(可以参考下图)
Zygote启动SystemServer的时序图(盗一张图)
2 SystemServer进程都做了什么?
进入源码目录:~/LineageOS/frameworks/base/services/java/com/android/server/SystemServer.java中查看SystemServer的main方法:
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
//main方法中只调用了SystemServer的main方法;
new SystemServer().run();
}
private void run() {
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// Mmmmmm... more memory!
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Within the system server, any incoming Bundles should be defused
// to avoid throwing BadParcelableException.
BaseBundle.setShouldDefuse(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Increase the number of binder threads in system_server
BinderInternal.setMaxThreads(sMaxBinderThreads);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
//创建消息Looper
Looper.prepareMainLooper();
// Initialize native services.
//加载动态库libandroid_servers.so
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
//创建系统的Context
createSystemContext();
// Create the system service manager.
//创建SystemServiceManager对系统服务进行创建、启动、生命周期管理;
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
// Start services.
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
//启动引导服务;
startBootstrapServices();
//启动核心服务;
startCoreServices();
//启动其他服务,其他服务是一些非必须或不需要立即启动的服务;
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
参考文章:Android 系统服务一览表
cm14-1 引导服务 | 作用 |
---|---|
Installer | 系统安装APK时的一个服务类,启动完成Installer服务之后才能启动其他系统服务 |
ActivityManagerService | Android framework框架核心服务,管理整个框架中任务、进程管理, Intent解析等的核心实现,管理四大组建的生命周期。 |
PowerManagerService | 电源管理服务 |
LightsService | 光感应传感器服务 |
DisplayManagerService | 用于管理全局显示生命周期,决定在已连接的物理设备如何配置逻辑显示,并且通知系统和应用状态的改变 |
UserManagerService | 多用户模式管理 |
SensorService | 为系统提供各种感应服务 |
PackageManagerService | 用来对APK进行安装、解析、删除、卸载等操作 |
... | ... |
cm14-1 核心服务 | 作用 |
---|---|
BatteryService | 管理电池相关系统服务 |
UsageStatsService | 收集用户使用的每个App的频率及时长 |
WebViewUpdateService | WebView更新服务 |
cm14-1 其他服务 | 作用 |
---|---|
VibratorService | 振动器服务 |
NetworkStatsService | 网络统计相关 |
NetworkPolicyManagerService | 维护网络使用策略 |
ConnectivityService | 网络连接状态服务 |
NsdService | 网络服务搜索 |
WindowManagerService | Android framework框架核心服务,窗口管理服务 |
SerialService | 对串口的设备进行操作 |
NetworkTimeUpdateService | 监视网络时间,当网络时间变化时更新本地时间 |
CommonTimeManagementService | 管理本地常见的时间服务的配置,在网络配置变化时重新配置本地服务 |
InputManagerService | 以前在WindowManagerService中,现在独立了出来,用户处理事件分发 |
ConsumerIrService | 远程控制,通过红外等控制周围的设备(例如电视等) |
CameraService | 摄像头相关服务 |
AlarmManagerService | 全局定时器管理服务 |
LocationManagerService | 定位管理服务 |
AudioService | 音频相关管理服务 |
... | ... |
2.1 利用SystemServiceManager的startService方法启动
这些系统服务的启动逻辑是相似的,以DisplayManagerService为例分析,其代码为:
// Display manager is needed to provide display metrics before package manager
// starts up.
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
SystemServiceManager的startService方法启动了DisplayManagerService,其在源码目录:~/LineageOS/frameworks/base/services/core/java/com/android/server /SystemServiceManager.java
/**
* Creates and starts a system service. The class must be a subclass of
* {@link com.android.server.SystemService}.
*
* @param serviceClass A Java class that implements the SystemService interface.
* @return The service instance, never null.
* @throws RuntimeException if the service fails to start.
*/
@SuppressWarnings("unchecked")
public T startService(Class serviceClass) {
try {
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
// Create the service.
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
Constructor constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
// 注册Service,mServices是一个存储SystemService类型的ArrayList;
mServices.add(service);
// Start it.
try {
//启动Service,调用PowerManagerService的onStart方法完成启动PowerManagerService;
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
2.2 利用Service自身main方法启动
以PancakeManagerService为例:
// Start the package manager.
traceBeginAndSlog("StartPackageManagerService");
//直接调用PackageManagerService的main方法;
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
其main方法在源码目录:~/LineageOS/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java中
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
//自检初始的设置;
PackageManagerServiceCompilerMapping.checkProperties();
//先将Package管理服务PackageManagerService启动起来;
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
//将该Package管理服务注册到ServiceManager中,这样其它组件就可以通过ServiceManager来获取它的访问接口了,ServiceManager用来管理系统中各种Service,用于系统C/S架构中的Binder通信机制;
ServiceManager.addService("package", m);
return m;
}
2.3 SystemServer进程小结
SystemServer进程被Zygote创建后的主要用来:
- 启动Binder线程池,这样就可与其他进程通信;
- 创建SystemServiceManager,用于对系统的服务进行创建、启动、生命周期的管理;
- 启动各种系统服务(引导服务、核心服务、其他服务);
Enjoy it !!
下一篇分析下Launcher的启动过程