Launch 桌面启动详解
Posted xyTianZhao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Launch 桌面启动详解相关的知识,希望对你有一定的参考价值。
Launch 桌面启动详解
不管是开机还是重启手机,相信我们大家都不陌生吧。大部分的 90 后都经历了从 android 2.* 的统一开机动画,到现在 Android 10 的各种定制开机动画。
为什么 Android 系统启动时需要播放一段开机动画呢,而且播放完成后有的性能比较差的机器或者定制度比较高的 Room 都需要在最后一帧动画定格一段时间,是因为 Android 系统启动时首先需要从 Linux 系统进程 fork 一个新的进程作为 Android 系统的运行环境。
在这个 Android 进程中需要启动大量的系统服务为上层应用提供相应的接口,以达到安全隔离的作用。其中最为主要的就是 SystemServer ,他是一切服务启动的入口。
public final class SystemServer
/**
* The main entry point from zygote.
*/
public static void main(String[] args)
new SystemServer().run();
private void run()
......
// Start services.
try
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
catch (Throwable ex)
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
finally
traceEnd();
......
// Loop forever.
Looper.loop();
......
从 main 函数的注释可以很清楚的看到,这个方法的进入点是 zygote 进程,有关 zygote 进程的启动,我们这里简单梳理一条调用链,大概了解一下。
这个 app_main 就相当于程序的主入口,这里找到 ZygoteInit 这个类的 main 方法,然后调用。
class AppRuntime : public AndroidRuntime
//这个是父类 AndroidRuntime 的方法,放倒这里为了方便查看
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
......
//通过 className 找到相应的 class
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
......
// 找到 class 的 main 方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
......
// 调用 static 的 main 方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
int main(int argc, char* const argv[])
......
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
......
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
......
到这里后就开始启动当前应用进程啦。ZygoteInit 会做一些进程的相关初始化工作。完成后调用 Zygote 的 forkSystemServer 启动 SystemServer。
public class ZygoteInit
public static void main(String argv[])
......
if (startSystemServer)
//这里 从 Zygote 进程 fork 出 system server进程
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// @code r == null in the parent (zygote) process, and @code r != null in the
// child (system_server) process.
if (r != null)
//标注①
r.run();
return;
......
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer)
......
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
......
if (pid == 0)
if (hasSecondZygote(abiList))
waitForSecondaryZygote(socketName);
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
......
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
......
// 找到 SystemServer 的 class
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
......
ClassLoader cl = null;
if (systemServerClasspath != null)
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
/*
* Pass the remaining arguments to SystemServer.
* 将其余参数传递给SystemServer
*/
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
......
//运行时相关的初始化
RuntimeInit.commonInit();
//初始化 ZygoteInit
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
public class RuntimeInit
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader)
......
//根据上面找的 SystemServer 的 class 找到相应的 main 函数,将 参数传递并调用
return findStaticMain(args.startClass, args.startArgs, classLoader);
//通过反射找到 main 函数
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader)
Class<?> cl = Class.forName(className, true, classLoader);
......
Method m = cl.getMethod("main", new Class[] String[].class );
......
// 这里返回的 runnable 对象会在上面的 标注① 出进行调用
return new MethodAndArgsCaller(m, argv);
//封装了 main 方法的签名 和 传递的参数。
//这里返回的是一个 Runnable 对象。
static class MethodAndArgsCaller 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()
......
mMethod.invoke(null, new Object[] mArgs );
......
这些就是有关 SystemServer 的调用链,上面这些代码执行完成后就调用到了 开始说的 SystemServer 的 main 函数。
回到 SystemServer 的 main 函数,发现里面直接new 了一个自己作为对象调用了他的 run 方法,run 方法中分别调用了三个方法,根据名字可以很直观的想到这三个方法对应的功能,启动引导服务、启动内核服务、启动其他服务。
public final class SystemServer
private void startOtherServices()
mActivityManagerService.systemReady(() ->
......
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog)
......
startHomeActivityLocked(currentUserId, "systemReady");
......
boolean startHomeActivityLocked(int userId, String reason)
......
Intent intent = getHomeIntent();
......
intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
......
mActivityStartController.startHomeActivity(intent, aInfo, myReason);
......
Intent getHomeIntent()
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL)
//public static final String CATEGORY_HOME = "android.intent.category.HOME";
//标注②
intent.addCategory(Intent.CATEGORY_HOME);
return intent;
可以看到当 其他服务启动完成时,会调用 AMS 的 systemReady 函数。在这里会调用 startHomeActivityLocked 启动 Home 界面,就是我们所说的 Launch 界面了。
通过 getHomeIntent 方法获取启动 Launch 界面的 Intent。后续流程就和 Activity 的启动流程相当了,具体流程可以查看 Activity 启动流程详解
这个 Launch 应用是一个系统应用,这里附上 Launch.apk 的源码,当然,不同的系统会定制不同的 Launch 应用。
标注② 中 添加的 Intent.CATEGORY_HOME
就是 Launch 应用的主界面中声明的 category。
<activity
android:name="com.android.launcher3.Launcher"
......
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
<category android:name="android.intent.category.LAUNCHER_APP" />
</intent-filter>
......
</activity>
至此,Launch 界面的启动就分析完成了。最后附上一个 SystemServer 的启动流程图。
以上是关于Launch 桌面启动详解的主要内容,如果未能解决你的问题,请参考以下文章
我的电脑每次开机就定格在一个画面上上面显示 ese f2 f12 下面是BIOS中的电脑启动项