您的位置:首页 > 移动开发 > Android开发

Android内核解读-Android系统的开机启动过程(先MARK后学习学习)

2014-02-19 12:10 716 查看
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/19302593

转自singwhatiwanna大牛,膜拜膜拜

前言

当长按手机的power键,Android手机就会开机,那么Android系统的开机启动过程到底是怎么样的呢,本文将要介绍这一过程。简单来说,Android系统的开机启动过程大致是这样的:首先linux系统会启动一个叫做zygote(可以称为受精卵、母体)的linux程序,这个程序实际上就是android系统的内核,zygote启动的时候会建立socket服务端并加载大量的类和资源。接着zygote会孵化第一个dalvik进程SystemServer,在SystemServer中会创建一个socket客户端,后续AMS(ActivityManagerService)会通过此客户端和zygote通信,zygote再根据请求孵化出新的dalvik进程即启动一个新的apk同时把新进程的socket连接关闭。SystemServer初始化完毕后会启动一个位于桟顶的activity,由于系统刚开机,所以task桟顶没有activity,于是接着它会发送一个隐式的intent(category:CATEGORY_HOME),也就是launcher了,即Android系统的桌面程序,launcher启动以后,我们就可以通过桌面启动各种应用了,可以发现,launcher可以有多个,第三方应用只要加入launcher所需要的intent-filter即可。下面一一分析各个流程。(注:本文分析基于Android4.3源码)



zygote的启动过程

zygote是一个linux程序,其对应的可执行文件位于/system/bin/app_process,它在/init.rc中定义,如下

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

可以发现,zygote创建了一个流式套接字(即采用TCP协议),并监听660端口,并且当zygote重启的时候需要对唤醒电源并重启Media、netd服务。下面看zygote的源码,其路径为frameworks\base\cmds\app_process\app_main.cpp中:

[cpp] view
plaincopy





int main(int argc, char* const argv[])

{

#ifdef __arm__

/*

* b/7188322 - Temporarily revert to the compat memory layout

* to avoid breaking third party apps.

*

* THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.

*

* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
* changes the kernel mapping from bottom up to top-down.

* This breaks some programs which improperly embed

* an out of date copy of Android's linker.

*/

char value[PROPERTY_VALUE_MAX];

property_get("ro.kernel.qemu", value, "");

bool is_qemu = (strcmp(value, "1") == 0);

if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {

int current = personality(0xFFFFFFFF);

if ((current & ADDR_COMPAT_LAYOUT) == 0) {

personality(current | ADDR_COMPAT_LAYOUT);

setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);

execv("/system/bin/app_process", argv);

return -1;

}

}

unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");

#endif

// These are global variables in ProcessState.cpp

mArgC = argc;

mArgV = argv;

mArgLen = 0;

for (int i=0; i<argc; i++) {

mArgLen += strlen(argv[i]) + 1;

}

mArgLen--;

//注意,这里持有了一个AppRuntime对象,其继承自AndroidRuntime

AppRuntime runtime;

const char* argv0 = argv[0];

// Process command line arguments

// ignore argv[0]

argc--;

argv++;

// Everything up to '--' or first non '-' arg goes to the vm

int i = runtime.addVmArguments(argc, argv);

// Parse runtime arguments. Stop at first unrecognized option.

bool zygote = false;

bool startSystemServer = false;

bool application = false;

const char* parentDir = NULL;

const char* niceName = NULL;

const char* className = NULL;

//这里是解析init.rc中定义的zygote的启动参数

while (i < argc) {

const char* arg = argv[i++];

if (!parentDir) {

parentDir = arg;

} else if (strcmp(arg, "--zygote") == 0) {

zygote = true;

niceName = "zygote";

} else if (strcmp(arg, "--start-system-server") == 0) {

startSystemServer = true;

} else if (strcmp(arg, "--application") == 0) {

application = true;

} else if (strncmp(arg, "--nice-name=", 12) == 0) {

niceName = arg + 12;

} else {

className = arg;

break;

}

}

if (niceName && *niceName) {

setArgv0(argv0, niceName);

set_process_name(niceName);

}

runtime.mParentDir = parentDir;

if (zygote) {

//从init.rc中的定义可以看出,zygote为true,startSystemServer也为true

//最终这里会调用ZygoteInit的main方法

runtime.start("com.android.internal.os.ZygoteInit",

startSystemServer ? "start-system-server" : "");

} else if (className) {

// Remainder of args get passed to startup class main()

runtime.mClassName = className;

runtime.mArgC = argc - i;

runtime.mArgV = argv + i;

runtime.start("com.android.internal.os.RuntimeInit",

application ? "application" : "tool");

} 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;

}

}

说明:这句代码runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "")在AndroidRuntime中实现,其最终会调用ZygoteInit的main方法,请看env->CallStaticVoidMethod(startClass, startMeth, strArray);这里的startClass就是com.android.internal.os.ZygoteInit,而startMeth就是main,所以,我们直接看ZygoteInit的main方法,代码路径为:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java:

[java] view
plaincopy





public static void main(String argv[]) {

try {

// Start profiling the zygote initialization.

SamplingProfilerIntegration.start();

//这里注册流式socket,以便于fork新的dalvik进程

registerZygoteSocket();

EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,

SystemClock.uptimeMillis());

//这里预先加载一些类和资源

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

gc();

// Disable tracing so that forked processes do not inherit stale tracing tags from

// Zygote.

Trace.setTracingEnabled(false);

// If requested, start system server directly from Zygote

if (argv.length != 2) {

throw new RuntimeException(argv[0] + USAGE_STRING);

}

if (argv[1].equals("start-system-server")) {

//启动SystemServer,zygote通过SystemServer和上层服务进行交互

startSystemServer();

} else if (!argv[1].equals("")) {

throw new RuntimeException(argv[0] + USAGE_STRING);

}

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

//通过Select方式监听端口,即异步读取消息,死循环,没有消息则一直阻塞在那里

runSelectLoop();

closeServerSocket();

} catch (MethodAndArgsCaller caller) {

caller.run();

} catch (RuntimeException ex) {

Log.e(TAG, "Zygote died with exception", ex);

closeServerSocket();

throw ex;

}

}

下面看一下runSelectLoop方法,看看它是如何fork产生一个新的进程的:

[java] view
plaincopy





/**

* Runs the zygote process's select loop. Accepts new connections as

* they happen, and reads commands from connections one spawn-request's

* worth at a time.

*

* @throws MethodAndArgsCaller in a child process when a main() should

* be executed.

*/

private static void runSelectLoop() throws MethodAndArgsCaller {

ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();

ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

FileDescriptor[] fdArray = new FileDescriptor[4];

fds.add(sServerSocket.getFileDescriptor());

peers.add(null);

int loopCount = GC_LOOP_COUNT;

//死循环,没有消息则一直阻塞在这里

while (true) {

int index;

/*

* Call gc() before we block in select().

* It's work that has to be done anyway, and it's better

* to avoid making every child do it. It will also

* madvise() any free memory as a side-effect.

*

* Don't call it every time, because walking the entire

* heap is a lot of overhead to free a few hundred bytes.

*/

if (loopCount <= 0) {

gc();

loopCount = GC_LOOP_COUNT;

} else {

loopCount--;

}

try {

fdArray = fds.toArray(fdArray);

//通过select()函数来读取新的socket消息,其返回值有<0、0、>0三种

//分别代表:发生异常、继续读取新消息、首先处理当前消息

index = selectReadable(fdArray);

} catch (IOException ex) {

throw new RuntimeException("Error in select()", ex);

}

if (index < 0) {

throw new RuntimeException("Error in select()");

} else if (index == 0) {

//构造一个ZygoteConnection对象,并将其加入到peers列表中

ZygoteConnection newPeer = acceptCommandPeer();

peers.add(newPeer);

fds.add(newPeer.getFileDesciptor());

} else {

boolean done;

//这里处理当前socket消息,ZygoteConnection的runOnce会被调用,一个新的dalvik进程会被创建

done = peers.get(index).runOnce();

if (done) {

//处理完了以后删除此socket消息

peers.remove(index);

fds.remove(index);

}

}

}

}

接着,我们还需要看下ZygoteConnection的runOnce方法,看看一个dalvik进程到底是如何产生的,我们知道每个apk都运行在一个独立的dalvik进程中,所以当启动一个apk的时候,zygote会孵化出一个新的进程,在这个进程中运行此apk。 在ZygoteConnection中,新进程是通过Zygote的静态方法forkAndSpecialize来产生的:

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,

parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);

具体的我们就不用多看了,内部肯定是通过linux系统的fork()函数来产生一个新进程的。当一个新的dalvik进程产生了以后,还需要做一些清场的工作,由于新进程是由zygote程序fork出来的,所以子进程具有zygote的一份拷贝,我们知道,zygote启动的时候创建了一个socket服务端,这个服务端只能有一个,由zygote孵化的子进程是不应该有的,所以子进程孵化出来以后,还必须关闭拷贝的socket服务端,这些操作在handleChildProc方法中完成:

[java] view
plaincopy





private void handleChildProc(Arguments parsedArgs,

FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)

throws ZygoteInit.MethodAndArgsCaller {

//关闭本地和服务端(如果有)的socket

closeSocket();

ZygoteInit.closeServerSocket();

if (descriptors != null) {

try {

ZygoteInit.r
1eaea
eopenStdio(descriptors[0],

descriptors[1], descriptors[2]);

for (FileDescriptor fd: descriptors) {

IoUtils.closeQuietly(fd);

}

newStderr = System.err;

} catch (IOException ex) {

Log.e(TAG, "Error reopening stdio", ex);

}

}

if (parsedArgs.niceName != null) {

Process.setArgV0(parsedArgs.niceName);

}

if (parsedArgs.runtimeInit) {

if (parsedArgs.invokeWith != null) {

WrapperInit.execApplication(parsedArgs.invokeWith,

parsedArgs.niceName, parsedArgs.targetSdkVersion,

pipeFd, parsedArgs.remainingArgs);

} else {

RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,

parsedArgs.remainingArgs);

}

} else {

String className;

try {

className = parsedArgs.remainingArgs[0];

} catch (ArrayIndexOutOfBoundsException ex) {

logAndPrintError(newStderr,

"Missing required class name argument", null);

return;

}

String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];

System.arraycopy(parsedArgs.remainingArgs, 1,

mainArgs, 0, mainArgs.length);

if (parsedArgs.invokeWith != null) {

WrapperInit.execStandalone(parsedArgs.invokeWith,

parsedArgs.classpath, className, mainArgs);

} else {

ClassLoader cloader;

if (parsedArgs.classpath != null) {

cloader = new PathClassLoader(parsedArgs.classpath,

ClassLoader.getSystemClassLoader());

} else {

cloader = ClassLoader.getSystemClassLoader();

}

try {

//这里子进程的main方法被调用,此时,子进程完全从zygote(母体)上脱离出来了

ZygoteInit.invokeStaticMain(cloader, className, mainArgs);

} catch (RuntimeException ex) {

logAndPrintError(newStderr, "Error starting.", ex);

}

}

}

}

同时在ZygoteInit中会预先加载一些类和资源,具体代码在preload方法中:
static void preload() {

preloadClasses();

preloadResources();

}

SystemServer的创建

SystemServer作为zygote孵化的第一个dalvik进程,其孵化过程在上面已经进行了描述,但是其和普通进程的启动略有不同,普通进程由Zygote.forkAndSpecialize来启动,而SystemServer由Zygote.forkSystemServer来启动,其次是SystemServer内部多创建了一个socket客户端。关于SystemServer内部的本地socket客户端,本文前面已经说过,外围的Service都是通过SystemServer和zygote交互的,比如要启动一个apk,首先AMS会发起一个新进程的创建请求,在startProcessLocked方法中会调用Process的start方法,其内部会调用startViaZygote方法,而在startViaZygote内部会创建一个本地socket和zygote通信,我们要知道,AMS是在SystemServer进程中创建的,所以说在SystemServer中创建一个本地socket和zygote通信是有道理的。SystemServer的一个很重要的作用是创建各种服务,包括大家常见的WindowManagerService 、AlarmManagerService、ActivityManagerService等,然后上层的各种manager通过binder和service进行交互,关于SystemServer创建各种服务的过程以及和binder的交互,请参考我之前写的一篇博客的其中一节,这里就不重复了:各种Manager和Binder服务的对应关系



系统桌面的启动

当SystemServer创建各种服务完毕后,其中的一个服务ActivityManagerService由于也创建完成,所以其事件回调方法systemReady会被调用,这个方法很长,注意到在这个方法的倒数第二句是mMainStack.resumeTopActivityLocked(null),它的意思是将桟顶的activity复位,看它的代码

[java] view
plaincopy





final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {

// Find the first activity that is not finishing.

//找到桟顶的activity记录

ActivityRecord next = topRunningActivityLocked(null);

// Remember how we'll process this pause/resume situation, and ensure

// that the state is reset however we wind up proceeding.

final boolean userLeaving = mUserLeaving;

mUserLeaving = false;

//由于系统刚启动,桟顶肯定没有activity,所以next为null

if (next == null) {

// There are no more activities! Let's just start up the

// Launcher...

if (mMainStack) {

ActivityOptions.abort(options);

//程序执行到这里,桌面就会被调起来

return mService.startHomeActivityLocked(mCurrentUser);

}

}

...此处省略

}

最后看看桌面是如何被调起来的:

[java] view
plaincopy





boolean startHomeActivityLocked(int userId) {

if (mHeadless) {

// Added because none of the other calls to ensureBootCompleted seem to fire

// when running headless.

ensureBootCompleted();

return false;

}

if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL

&& mTopAction == null) {

// We are running in factory test mode, but unable to find

// the factory test app, so just sit around displaying the

// error message and don't try to start anything.

return false;

}

Intent intent = new Intent(

mTopAction,

mTopData != null ? Uri.parse(mTopData) : null);

intent.setComponent(mTopComponent);

if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {

//其实就是为intent加上CATEGORY_HOME这个Category,接着就发送隐式intent来调起所有满足条件的桌面

//这也是第三方桌面存在的价值

intent.addCategory(Intent.CATEGORY_HOME);

}

ActivityInfo aInfo =

resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);

if (aInfo != null) {

intent.setComponent(new ComponentName(

aInfo.applicationInfo.packageName, aInfo.name));

// Don't do this if the home app is currently being

// instrumented.

aInfo = new ActivityInfo(aInfo);

aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);

ProcessRecord app = getProcessRecordLocked(aInfo.processName,

aInfo.applicationInfo.uid);

if (app == null || app.instrumentationClass == null) {

intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);

//这里启动桌面activity,到此为止,桌面被启动了,我们就可以认为手机开机完成了

mMainStack.startActivityLocked(null, intent, null, aInfo,

null, null, 0, 0, 0, null, 0, null, false, null);

}

}

return true;

}

到此为止,桌面已经启动了,也就意味着手机的开机启动过程已经完成,后续我们就可以通过桌面来启动各个应用了,根据本文的介绍,我们已经知道apk启动时dalvik进程的创建过程,关于单个activity的启动过程,请参看我之前写的另一篇文章Android源码分析-Activity的启动过程。到此为止,本文结束了,相信大家对Android系统的开机启动过程应该有了一个感性的认识了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: