Android內核解讀-Android系統的開機啓動過程

轉載請註明出處:http://blog.csdn.net/singwhatiwanna/article/details/19302593java

前言

當長按手機的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源碼)linux

zygote的啓動過程

zygote是一個linux程序,其對應的可執行文件位於/system/bin/app_process,它在/init.rc中定義,以下android

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 netdgit

能夠發現,zygote建立了一個流式套接字(即採用TCP協議),並監聽660端口,而且當zygote重啓的時候須要對喚醒電源並重啓Media、netd服務。下面看zygote的源碼,其路徑爲frameworks\base\cmds\app_process\app_main.cpp中:app

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:less

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產生一個新的進程的:異步

/**
 * 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來產生的:socket

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);ide

具體的咱們就不用多看了,內部確定是經過linux系統的fork()函數來產生一個新進程的。當一個新的dalvik進程產生了之後,還須要作一些清場的工做,因爲新進程是由zygote程序fork出來的,因此子進程具備zygote的一份拷貝,咱們知道,zygote啓動的時候建立了一個socket服務端,這個服務端只能有一個,由zygote孵化的子進程是不該該有的,因此子進程孵化出來之後,還必須關閉拷貝的socket服務端,這些操做在handleChildProc方法中完成:函數

private void handleChildProc(Arguments parsedArgs,
		FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
		throws ZygoteInit.MethodAndArgsCaller {
	//關閉本地和服務端(若是有)的socket
	closeSocket();
	ZygoteInit.closeServerSocket();

	if (descriptors != null) {
		try {
			ZygoteInit.reopenStdio(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復位,看它的代碼
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);
		}
	}
	...此處省略
}

最後看看桌面是如何被調起來的:

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系統的開機啓動過程應該有了一個感性的認識了。

相關文章
相關標籤/搜索