以下内容为原创,欢迎转载,转载请注明

来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5013863.html

Android系统启动流程源码分析

首先我们知道,Android是基于Linux的,当Linux内核加载完成时就会自动启动一个init的进程。

又因为我们每当我们启动一个App时,就会生成一个新的dalvik实例,并处于一个新的进程(当然一个App也可能是多进程的)。

当我们打开第一个App的时候,就会通过init进程fork出一个zygote进程。之后打开新的App的时候都会fork之前的zygote进程。

fork一个zygote进程时,会进入com.android.internal.os.ZygoteInitmain方法进行初始化操作:

  • 预加载资源
// ...
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
// ...
  • 从第一个zygote进程forkSystemServer进程,这个进程提供各种ManagerService
startSystemServer(abiList, socketName);

private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
int pid;
// ...
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",
};
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
// ...
}
  • Fork完SystemServer进程之后,继续接下来在handleSystemServerProcess方法中传入参数到SystemServer
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

注意,这里传入的参数是forkSystemServer进程后剩下的参数(parsedArgs.remainingArgs),其实只剩下了com.android.server.SystemServer这个参数了。

接下来继续调用applicationInit ,传入参数:

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
final Arguments args;
// ...
args = new Arguments(argv);
// ...
}

解析成Arguments后,得到了一个startClass对象,这个startClass其实就是刚刚的那个com.android.server.SystemServer

接下来,继续调用 invokeStaticMain

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
// ...
cl = Class.forName(className, true, classLoader);
// ...
m = cl.getMethod("main", new Class[] { String[].class });
// ...
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

就是调用通过反射得到com.android.server.SystemServer(也就是上面的startClass)的main(argv[])方法,然后手动抛一个携带了这个main(argv[])方法的MethodAndArgsCaller异常,但是这个异常是在ZygoteInit.main()方法中被catch,然后去调用它的run()方法,当然这个run()方法中会再去通过反射调用携带的main()方法(这个绕法真是有点坑爹--。):

public static class MethodAndArgsCaller extends Exception implements Runnable {
// ...
public void run() {
// ...
mMethod.invoke(null, new Object[] { mArgs });
// ...
}
// ...
}

绕了这么一大圈,终于通过MethodAndArgsCaller调用SystemServermain()方法了,代码很简单,直接new了之后run

new SystemServer().run();

接着,我们看SystemServerrun方法:

// ... (省略初始化当前的language、locale、country、指纹、用户等信息的初始化准备工作)
// 设置当前进程设置优先级为THREAD_PRIORITY_FOREGROUND(-2)
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
// 初始化主线程Looper
Looper.prepareMainLooper();
// ...
// 启动消息循环
Looper.loop()

然后调用createSystemContext()方法创建初始化system context,这个待会再展开。

创建SystemServiceManager

mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

使用SystemServiceManager去通过以下方法创建启动各个Service

  1. startBootstrapServices():
  • com.android.server.pm.Installer:提供安装、卸载App等服务
  • com.android.server.am.ActivityServiceManager:提供Activity等组件的管理的服务,这个比较复杂暂且再挖个坑。
  • com.android.server.power.PowerManagerService:电源管理的服务。
  • com.android.server.lights.LightsService:LED管理和背光显示的服务。
  • com.android.server.display.DisplayManagerService:提供显示的生命周期管理,根据物理显示设备当前的情况决定显示配置,在状态改变时发送通知给系统和应用等服务。
  • com.android.server.pm.PackageManagerService:管理所有的.apk
  • com.android.server.pm.UserManagerService:提供用户相关服务。
  • 通过startSensorService()本地方法启动Sensor服务。
  1. startCoreServices();
  • com.android.server.BatteryService:电量服务,需要LightService
  • com.android.server.usage.UsageStatsService:提供收集统计应用程序数据使用状态的服务。
  • com.android.server.webkit.WebViewUpdateService:私有的服务(@hide),用于WebView的更新。
  1. startOtherServices();
  • com.android.server.accounts.AccountManagerService:提供所有账号、密码、认证管理等等的服务。
  • com.android.server.content.ContentService:用户数据同步的服务。
  • com.android.server.VibratorService:震动服务。
  • IAlarmManager:提醒服务。
  • android.os.storage.IMountService:存储管理服务。
  • com.android.server.NetworkManagementService:系统网络连接管理服务。
  • com.android.server.net.NetworkStatsService:收集统计详细的网络数据服务。
  • com.android.server.net.NetworkPolicyManagerService:提供低网络策略规则管理服务。
  • com.android.server.ConnectivityService:提供数据连接服务。
  • com.android.server.NetworkScoreServiceandroid.net.NetworkScoreManager的备份服务。
  • com.android.server.NsdService:网络发现服务(Network Service Discovery Service)。
  • com.android.server.wm.WindowManagerService:窗口管理服务。
  • com.android.server.usb.UsbService:USB服务。
  • com.android.server.SerialService:串口服务。
  • com.android.server.NetworkTimeUpdateService:网络时间同步服务。
  • com.android.server.CommonTimeManagementService:管理本地常见的时间配置的服务,当网络配置变化时会重新配置本地服务。
  • com.android.server.input.InputManagerService:事件传递分发服务。
  • com.android.server.TelephonyRegistry:提供电话注册管理的服务。
  • com.android.server.ConsumerIrService:远程控制服务。
  • com.android.server.audio.AudioService:音量、铃声、声道等管理服务。
  • com.android.server.MmsServiceBrokerMmsService的代理,因为MmsService运行在电话进程中,可能随时crash,它会通过一个connectionMmsService建立一个桥梁,MmsService实现了公开的SMS/MMS的API。
  • TelecomLoaderService
  • CameraService
  • AlarmManagerService
  • BluetoothService
  • 还有其它很多很多Service,这方法竟然有近1000行……

startOtherServices()方法的最后:

mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
// 下面仍然是各种Service的启动...
}
}

调用这个方法用来告诉ActivityManagerService,此时可以运行第三方的代码了(注意:这里的Home界面、Launcher等内置的App也算是第三方的App)。

public void systemReady(final Runnable goingCallback) {
// ...
if (mSystemReady) {
// 回调到SystemServer,继续启动各种Service
if (goingCallback != null) {
goingCallback.run();
}
return;
}
// ... ResolveInfo ri = mContext.getPackageManager().resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST), STOCK_PM_FLAGS);
// ...
ActivityInfo ai = ri.activityInfo;
ApplicationInfo app = ai.applicationInfo;
// ...从PackageManager中获取要打开的HomeActivity
mTopComponent = new ComponentName(app.packageName, ai.name);
// ...
// 启动第一个Home界面
startHomeActivityLocked(mCurrentUserId, "systemReady"); // ...
// 广播通知启动完成
broadcastIntentLocked(/*...*/, mCurrentUserId);
broadcastIntentLocked(/*...*/, UserHandle.USER_ALL);
// ...
}

启动Home界面的startHomeActivityLocked方法,调用mStackSupervisor启动HomeActivity

boolean startHomeActivityLocked(int userId, String reason) {
// ...
Intent intent = getHomeIntent();
// ...
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mStackSupervisor.startHomeActivity(intent, aInfo, reason);
// ...
} Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
// 设置前面获取到的mTopComponent
intent.setComponent(mTopComponent);
// ...
intent.addCategory(Intent.CATEGORY_HOME);
// ...
}

到此为止,SystemServer start完毕,并且启动了Home界面。

然后我们再回过头去看看在我们前面创建系统级的ContextcreateSystemContext)的时候做了什么:

ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);

首先调用了ActivityThread的静态方法systemMain()

public static ActivityThread systemMain() {
// ...
ActivityThread thread = new ActivityThread();
thread.attach(true);
return thread;
}

创建一个ActivityThread,然后调用它的attach()方法:

thread.attach(true);

private void attach(boolean system) {
if (!system) {
// ...
}else{
// ...
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
// ...
}
}

参数system表示,是否是系统级的线程,现在我们是启动整个Android系统,显然当前传入的参数为true。所以进入else,首先,创建一个InstrumentationInstrumentation是什么?暂时先挖个坑。接着通过System Context创建一个ContextImpl,然后使用它的LoadedApk::makeApplication方法来创建整个应用的Application对象,然后调用ApplicationonCreate方法。

然后看下LoadedApk::makeApplication方法的实现:

public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
// 只有第一次调用makeApplication才会往下执行
if (mApplication != null) {
return mApplication;
}
// 初始化系统的Application,所以appClass是"android.app.Application"
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
// ...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
// ...
}

创建appContext,然后通过Instrumentation生成Application对象,并给appContext设置外部引用。

[Android]Android系统启动流程源码分析的更多相关文章

  1. 面试必备:Android Activity启动流程源码分析

    最近大致分析了一把 Activity 启动的流程,趁着今天精神状态好,把之前记录的写成文章. 开门见山,我们直接点进去看 Activity 的 startActivity , 最终,我们都会走到 st ...

  2. [Android]从Launcher开始启动App流程源码分析

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5017056.html 从Launcher开始启动App流程源码 ...

  3. Android笔记--View绘制流程源码分析(二)

    Android笔记--View绘制流程源码分析二 通过上一篇View绘制流程源码分析一可以知晓整个绘制流程之前,在activity启动过程中: Window的建立(activit.attach生成), ...

  4. Android笔记--View绘制流程源码分析(一)

    Android笔记--View绘制流程源码分析 View绘制之前框架流程分析 View绘制的分析始终是离不开Activity及其内部的Window的.在Activity的源码启动流程中,一并包含 着A ...

  5. Android Activity启动流程源码全解析(1)

    前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...

  6. Android Activity启动流程源码全解析(2)

    接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...

  7. Spring加载流程源码分析03【refresh】

      前面两篇文章分析了super(this)和setConfigLocations(configLocations)的源代码,本文来分析下refresh的源码, Spring加载流程源码分析01[su ...

  8. Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)

    上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...

  9. Spark(四十九):Spark On YARN启动流程源码分析(一)

    引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...

随机推荐

  1. 优秀工具推荐:超实用的 CSS 库,样板和框架

    当启动一个新的项目,使用 CSS 框架或样板,可以帮助您节省大量的时间.在这篇文章中,我编译整理了我最喜欢的 CSS 样板,框架和库,帮助你在建立网站或应用程序时更加高效. 您可能感兴趣的相关文章 精 ...

  2. 白话Https

    本文试图以通俗易通的方式介绍Https的工作原理,不纠结具体的术语,不考证严格的流程.我相信弄懂了原理之后,到了具体操作和实现的时候,方向就不会错,然后条条大路通罗马.阅读文本需要提前大致了解对称加密 ...

  3. web前端学习笔记(CSS盒子的浮动)

    在标准流中,一个块级元素在水平方向会自动伸展,直到包含它的元素的边界:而在竖直方向和兄弟元素依次排列,不能并排.使用“浮动”方式后,块级元素的表现就会有所不同.      CSS中有一个float属性 ...

  4. 【大数据】Linux下Storm(0.9版本以上)的环境配置和小Demo

    一.引言: 在storm发布到0.9.x以后,配置storm将会变得简单很多,也就是只需要配置zookeeper和storm即可,而不再需要配置zeromq和jzmq,由于网上面的storm配置绝大部 ...

  5. Android中自定义属性(attrs.xml,TypedArray的使用)

    做Android布局是件很享受的事,这得益于他良好的xml方式.使用xml可以快速有效的为软件定义界面.可是有时候我们总感觉官方定义的一些基本组件不够用,自定义组件就不可避免了.那么如何才能做到像官方 ...

  6. [Azure附录]2.在Windows Server 2012中配置AD域服务

    <Windows Azure Platform 系列文章目录> 本章我们配置的AD域名为contoso.com 1.安装完AD域服务后,我们返回服务器管理器界面,点击"将此服务器 ...

  7. Elasticsearch——分词器对String的作用

    更多内容参考:Elasticsearch学习总结 关于String类型--分词与不分词 在Elasticsearch中String是最基本的数据类型,如果不是数字或者标准格式的日期等这种很明显的类型, ...

  8. 从C#到Objective-C,循序渐进学习苹果开发(5)--利用XCode来进行IOS的程序开发

    本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.前面几篇随笔主要介绍C#和O ...

  9. 现在就使用HTML5的十大原因

    你难道还没有考虑使用HTML5? 当然我猜想你可能有自己的原因: 它现在还没有被广泛的支持,在IE中不好使,或者你就是喜欢写比较严格的XHTML代码. HTML5是Web开发世界的一次重大的改变,事实 ...

  10. 【c#搬砖记】用Docx导出word格式的docx文件

    DocX开源网址:http://docx.codeplex.com/ 1.引入DocX.dll 调用ReplaceText()方法替换模板中的字符.只支持docx格式的word文档 using (Do ...