深入浅出 - Android系统移植与平台开发(九)- Android系统system_server及Home启动
3.3 Zygote守护进程与system_server进程
Android的执行环境和Java执行环境有着本质的差别,在Android系统中每一个应用程序都是一独立的进程,当一个进程死掉时,不会影响其他进程的执行,这能极大的保证Android系统的稳定。 Zygote守护进程的启动是Android执行环境启动的開始阶段, Zygote进程通过Linux系统特有的Fork机制分裂克隆出全然相同的执行环境,全部的Android应用程序都是Zygote进程的子进程,system_server进程作为Zygote进程的嫡长子进程,对Android系统服务又有着重要意义。本节内容是我们研究Android系统启动的開始,让我们从Zygote守护进程的启动開始分析吧。
3.3.1 Zygote守护进程的启动
在init.rc中,通过init进程启动了Zygote服务:
service zygote/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
……
通过上面init.rc的代码可知。Zygote服务相应程序为/system/bin/app_process。服务名为zygote,參数列表为:-Xzygote/system/bin --zygote --start-system-server。
在启动zygote 服务时,在/dev/socket/文件夹下建立一个streamsocket文件:zygote。权限为666。
我们能够通过以下的命令来查找Zygote进程的源代码:
find ./ -nameAndroid.mk -exec grep -l app_process {}\;
注:find命令用于查找一个文件,-exec xxx {} \;表示:在前面命令的结果里执行grep 命令。
由上述命令结果可知,Zygote进程代码为frameworks/base/cmds/app_process/app_main.cpp
找到该程序的main入口函数:
118 int main(int argc,const char* const argv[])
119 {
120 // These are global variables inProcessState.cpp
121 mArgC = argc;
122 mArgV = argv;
123
124 mArgLen = 0;
125 for (int i=0; i<argc; i++) {
126 mArgLen += strlen(argv[i]) + 1;
127 }
128 mArgLen--;
129
130 AppRuntimeruntime;
131 const char *arg;
132 const char *argv0;
133
134 argv0 = argv[0];
135
136 // Process command line arguments
137 // ignore argv[0]
138 argc--;
139 argv++;
141 // Everything up to '--' or first non '-'arg goes to the vm
142 // 在zygote服务的參数列表中:/system/bin–zygote--start-system-server
// 以“--”和非“-”开头的參数,是dalvik的參数,交给Vm来处理
143 int i = runtime.addVmArguments(argc, argv);
144
145 // 找到zygote的文件夹:/system/bin
146 if (i < argc) {
147 runtime.mParentDir = argv[i++];
148 }
149
150 // 假设接下来的參数是:--zygote --start-system-server的话,
// 设置argv0=“zygote”,startSystemServer= true,启动java VM
151 if (i < argc) {
152 arg = argv[i++];
153 if (0 == strcmp("--zygote",arg)) {
154 bool startSystemServer = (i <argc) ?
155 strcmp(argv[i],"--start-system-server") == 0 : false;
156 setArgv0(argv0,"zygote");
157 set_process_name("zygote");
158 runtime.start("com.android.internal.os.ZygoteInit",
159 startSystemServer);
160 } else {
161 set_process_name(argv0);
162
163 runtime.mClassName = arg;
164
165 // Remainder of args get passed tostartup class main()
166 runtime.mArgC = argc-i;
167 runtime.mArgV = argv+i;
168
169 LOGV("App process is startingwith pid=%d, class=%s.\n",
170 getpid(), runtime.getClassName());
171 runtime.start();
172 }
173 } else {
174 LOG_ALWAYS_FATAL("app_process: noclass name or --zygote supplied.");
175 fprintf(stderr, "Error: no classname or --zygote supplied.\n");
176 app_usage();
177 return 10;
178 }
179
180 }
依据service zygote的參数,启动Android执行时环境:
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer),依据前面的分析可知:startSystemServer= true,runtime是AppRuntime的对象。AppRuntime是AndroidRuntime的子类,如图xx-xx所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbXJfcmFwdG9y/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
图 xx-xx AndroidRuntime与AppRuntime类关系图
由上面类图可知,runtime.start方法在AndroidRuntime里实现:
@frameworks/base/core/jni/AndroidRuntime.cpp
883 void AndroidRuntime::start(const char*className, const bool startSystemServer)
884{
// logcat里最显眼的字样
885 LOGD("\n>>>>>> AndroidRuntime START %s<<<<<<\n",
886 className != NULL ? className : "(unknown)");
887
888 char* slashClassName = NULL;
889 char* cp;
890 JNIEnv* env;
891
// 启动Dalvik虚拟机。在AndroidRuntime::startVm方法中。设置了大量VM的启动參数。
// 最后通过JNI调用JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs)函数启动虚拟机
918 /* start the virtual machine */
919 if (startVm(&mJavaVM, &env) != 0)
920 goto bail;
921
922 /*
923 * Register android functions. //注冊系统使用的JNI函数
924 */
925 if (startReg(env) < 0) {
926 LOGE("Unable to register all android natives\n");
927 goto bail;
928 }
930 /*
931 * We want to call main() with a String array with arguments in it.
932 * At present we only have one argument, the class name. Create an
933 * array to hold it.
934 */
935 jclass stringClass;
936 jobjectArray strArray;
937 jstring classNameStr;
938 jstring startSystemServerStr;
939
// 从虚拟机执行环境里,查找到String类
940 stringClass = env->FindClass("java/lang/String");
941 assert(stringClass != NULL);
// 创建一个String数组,有两个元素(strArray = new String[2])
942 strArray = env->NewObjectArray(2, stringClass, NULL);
943 assert(strArray != NULL);
// 创建一个Java String对象,初始值为:className的值,
// 即:“com.android.internal.os.ZygoteInit”
944 classNameStr = env->NewStringUTF(className);
945 assert(classNameStr != NULL);
// 设置strArray 第一个元素的值为:classNameStr(strArray[0] = classNameStr)
946 env->SetObjectArrayElement(strArray, 0, classNameStr);
// 创建一个Java String对象,初始值为:startSystemServer的值,即:“true”
947 startSystemServerStr = env->NewStringUTF(startSystemServer ?
948 "true" : "false");
// 设置strArray 第二个元素的值为:strArray[1]=startSystemServerStr
949 env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
// 依据上面的解释。我们能够用以下的Java代码来表示:
// String[] strArray = new strArray[2];
// strArray[0] ="com.android.internal.os.ZygoteInit"
// strArray[1] = "true"
950
951 /*
952 * Start VM. This thread becomesthe main thread of the VM, and will
953 * not return until the VM exits.
954 */
955 jclass startClass;
956 jmethodID startMeth;
957
958 slashClassName = strdup(className);
959 for (cp = slashClassName; *cp != '\0'; cp++)
960 if (*cp == '.')
961 *cp = '/';
// 将com.android.internal.os.ZygoteInit中的包分隔符“.”换成“/”
// 即:slashClassName ="com/android/internal/os/ZygoteInit"
962
963 startClass = env->FindClass(slashClassName);
// 从VM中查找ZygoteInit类。难道它要在VM里执行这个它?
964 if (startClass == NULL) {
965 LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
966 /* keep going */
967 } else {
968 startMeth = env->GetStaticMethodID(startClass, "main",
969 "([Ljava/lang/String;)V");
// 从ZygoteInit类中查找名字为main的静态方法。
// 而且main方法有一个參数String[]。返回值为void。
// 这不就是Java应用程序的main函数的签名吗?难道要调用它??
970 if (startMeth == NULL) {
971 LOGE("JavaVM unable to find main() in '%s'\n", className);
972 /* keep going */
973 } else {
974 env->CallStaticVoidMethod(startClass, startMeth, strArray);
// 果然,调用了ZygoteInit类里的main方法。
这不就是在VM里执行ZygoteInit程序吗。!
980 }
981 }
... 省略部分代码...
991 }
由上面的分析简单总结下:
从源代码的角度在AndroidRuntime::start方法实现了以下功能:
1>通过startVm来启动Dalvik虚拟机(简称DVM),而且注冊了一些本地JNI函数,因为这个时候DVM里还没有程序,仅仅是个空的DVM执行环境
2>通过AndroidRuntime::start的參数,在JNI代码里执行第一个Java程序ZygoteInit,将其作为DVM的主线程,同一时候给它传递两个在JNI中构建的參数:
"com/android/internal/os/ZygoteInit"和"true"
我们再从进程的角度来分析下:
Zygote进程由init进程作为Service启动。在Zygote进程里通过startVm启动了VM执行环境(如图xx-xx中①所看到的),通过JNI代码在VM环境中执行ZygoteInit.java。作为VM中的主线程。
图 xx-xx Zygote进程与Dalvik虚拟机
3.3.2 ZygoteInit类的功能与system_server进程的创建
Zygote将DVM执行环境准备好了。而且開始调用执行ZygoteInit.java代码。
以下我们分析下ZygoteInit.java代码。
@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
554 public static void main(String argv[]) {
555 try {
... 省略部分代码...
561 registerZygoteSocket(); // 注冊ZygoteSocket。创建一个Socket的服务端
... 省略部分代码...
564 preloadClasses(); // 预载入类
565 //cacheRegisterMaps();
566 preloadResources(); // 预资源类
... 省略部分代码...
// 假设ZygoteInit的第二个參数为"true"。则调用startSystemServer()
581 if(argv[1].equals("true")) {
582 startSystemServer();
583 } else if(!argv[1].equals("false")) {
584 throw newRuntimeException(argv[0] + USAGE_STRING);
585 }
... 省略部分代码...
603 }
依据main函数的第二个參数。调用了startSystemServer:
508 private static boolean startSystemServer()
511 String args[] = {
512 "--setuid=1000",
513 "--setgid=1000",
514"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
515 "--capabilities=130104352,130104352",
516 "--runtime-init",
517 "--nice-name=system_server",
518 "com.android.server.SystemServer",
519 };
520 ZygoteConnection.Arguments parsedArgs= null;
521
522 int pid;
523
524 try {
// 创建ZygoteConnection的内部类Arguments,它是ZygoteSocketclient的參数封装类
// 在Arguments的构造方法里对args[]进行了解析,以下Zygote.forkSystemServer会用到。
525 parsedArgs = newZygoteConnection.Arguments(args);
... 省略部分代码...
536 /* Request to fork the system server process*/
537 pid = Zygote.forkSystemServer(
538 parsedArgs.uid,parsedArgs.gid,
539 parsedArgs.gids,debugFlags, null,
540 parsedArgs.permittedCapabilities,
541 parsedArgs.effectiveCapabilities);
// 调用Zygote的静态方法forkSystemServer()。用来创建了一个
// 名字为system_server的进程。该方法是一个本地方法
// 在libcore/dalvik/src/main/java/dalvik/system/Zygote.java里定义。
// 本地实如今dalvik/vm/native/dalvik_system_Zygote.c中
542 } catch (IllegalArgumentException ex){
543 throw new RuntimeException(ex);
544 }
545
546 /* For child process */
547 if (pid == 0) {
548 handleSystemServerProcess(parsedArgs);
549 }
550
551 return true;
552 }
通过Zygote.forkSystemServer方法克隆了一个新的进程system_server。除了进程ID号pid它和Zygote进程的代码和数据全然一样,关于克隆具体内容,请查看fork系统调用相关知识。
在新创建的子进程system_server中调用handleSystemServerProcess:
491 private static voidhandleSystemServerProcess(
492 ZygoteConnection.ArgumentsparsedArgs)
493 throwsZygoteInit.MethodAndArgsCaller {
494
// 在新创建的子进程里将ZygoteSocket关闭
495 closeServerSocket();
... 省略部分代码...
// 将"--nice-name=system_server,com.android.server.SystemServer"传递给RuntimeInit.zygoteInit()
// 在RuntimeInit.zygoteInit方法里,调用了SystemServer的main方法,即在新进程里执行SystemServer.java
501 RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
502 /* should never reach here */
503 }
至此。Zygote的第一个嫡长子进程system_server创建完成,而且開始执行其main方法,我们做下总结,如图xx-xx所看到的。
图 xx-xx system_server进程的创建
①:在Zygote进程通过startVm启动Dalvik虚拟机(简称DVM)。在DVM里通过JNI调用ZygoteInit.main(),启动DVM里第一个主线程。
②:在ZygoteInit.java中绑定了ZygoteSocket并预载入类和资源。
③:通过Zygote.forkSystemServer()本地方法。在Linux中分裂fork出Zygote的第一个子进程。取名为system_server,该进程中的代码和数据与父进程Zygote全然一样。
④:在Zygote进程中通过RuntimeInit.zygoteInit(),调用SystemServer.main()。从而在system_server中执行SystemServer.java代码。
在Zygote进程创建时,init.rc脚本中创建了/dev/socket/zygote文件,它在ZygoteInit中被绑定为服务器端,用来接收克隆Zygote进程的请求,它相应用程序的创建有着重要的意义,其创建步骤例如以下图所看到的:
图 xx-xx 应用程序的创建
① Zygote进程绑定并通过select监听ZygoteSocket(/dev/socket/zygote)
② 其他进程发出socket连接请求,用于创建新应用程序
③ Zygote和请求发起者建立新连接用于通信。接收待创建应用程序信息
④:Zygote进程依据client数据请求Fork出新的子进程
在ZygoteInit中预载入类和预加资源对Android整个执行环境有着至关重要的意义,预载入的类是指大量的Android框架层代码。这些类有数千个,当Android应用程序执行时都要载入这些类,相同的预载入资源是指一些系统的图片、图标、字符串资源。
假设这些类和资源推迟到Android应用程序启动时。那么应用程序的启动速度会大大减少,会直接影响用户体验,Android充分利用了Linux中fork进程时会克隆父进程数据和代码的特点。将类和资源提前载入到父进程里,从而大大提高了启动速度。
3.3.3 system_server进程的执行
@frameworks/base/services/java/com/android/server/SystemServer.java
596 native public static void init1(String[] args); // init1方法为本地方法
598 public static void main(String[] args) {
... 省略部分代码...
// 载入本地库android_servers,添头加尾后本地库文件名称为:libandroid_servers.so
624 System.loadLibrary("android_servers");
625 init1(args);
626 }
在system_server进程里载入了libandroid_servers.so本地库。依据JNI机制,当Java代码中通过System.load载入一个本地动态库时,会自己主动调用该动态库中的JNI_Onload方法。通常在JNI_Onload方法中注冊本地函数与Java方法映射关系:
@frameworks/base/services/jni/onload.cpp
20 extern "C" jint JNI_OnLoad(JavaVM*vm, void* reserved)
21 {
22 JNIEnv* env = NULL;
23 jint result = -1;
24
25 if (vm->GetEnv((void**) &env,JNI_VERSION_1_4) != JNI_OK) {
26 LOGE("GetEnv failed!");
27 return result;
28 }
29 LOG_ASSERT(env, "Could not retrievethe env!");
30
31 register_android_server_PowerManagerService(env);
32 register_android_server_InputManager(env);
33 register_android_server_LightsService(env);
34 register_android_server_AlarmManagerService(env);
35 register_android_server_BatteryService(env);
36 register_android_server_UsbService(env);
37 register_android_server_VibratorService(env);
38 register_android_server_SystemServer(env);// 它实如今com_android_server_SystemServer.cpp中
39 register_android_server_location_GpsLocationProvider(env);
40
41 return JNI_VERSION_1_4;
42 }
@frameworks/base/services/jni/com_android_server_SystemServer.cpp
22namespace android {
23
24 extern"C" int system_init();
25
26 staticvoid android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
27 {
28 system_init();// 被SystemServer.java调用。在frameworks/base/cmds/system_server/library/system_init.cpp中实现
// system_init.cpp被编译成libsystem_server.so库。被libandroid_servers.so引用
29 }
30
31 /*
32 * JNI registration.
33 */
// 由此可见。SystemServer.java中调用的init1方法,映射到了android_server_SystemServer_init1方法
34 staticJNINativeMethod gMethods[] = {
35 /* name, signature, funcPtr */
36 { "init1","([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1},
37 };
38 // 该方法被frameworks/base/services/jni/onload.cpp回调,用来注冊本地方法与Java方法的映射
39 intregister_android_server_SystemServer(JNIEnv* env)
40 {
41 return jniRegisterNativeMethods(env,"com/android/server/SystemServer",
42 gMethods, NELEM(gMethods));
43 }
44
45 }; //namespace android
在register_android_server_SystemServer方法中注冊本地方法与Java方法,通过映射关系可知,Java层的init1方法调用了本地的system_init方法:
@frameworks/base/cmds/system_server/library/system_init.cpp
54 extern"C" status_t system_init()
55 {
56 LOGI("Entered system_init()");
... 省略部分代码...
66 char propBuf[PROPERTY_VALUE_MAX];
67 property_get("system_init.startsurfaceflinger", propBuf,"1");
68 if (strcmp(propBuf, "1") == 0) {
69 // Start the SurfaceFlinger
70 SurfaceFlinger::instantiate(); // 启动SurfaceFlinger本地系统服务
71 }
72
73 // Start the sensor service
74 SensorService::instantiate(); // 启动SensorService本地系统服务
... 省略部分代码...
99 LOGI("System server: starting Android runtime.\n");
100
101 AndroidRuntime* runtime = AndroidRuntime::getRuntime();
102
103 LOGI("System server: starting Android services.\n");
104 runtime->callStatic("com/android/server/SystemServer","init2"); // 调用Java环境中SystemServer.java的init2方法
... 省略部分代码...
115 return NO_ERROR;
116 }
在system_init方法里开启了几个本地系统服务:SurfaceFlinger和SensorService,然后从本地又调回了Java执行环境中的SystemServer.java中的init2方法。之所以这么做,原因是上层Android系统服务的执行要依赖于本地系统服务的执行。所以system_server先保障本地服务的执行,然后再回执行Android系统服务。
SystemServer.java中的init2方法执行:
628 public static final void init2() {
629 Slog.i(TAG, "Entered the Android system server!");
630 Thread thr = new ServerThread();
631 thr.setName("android.server.ServerThread");
632 thr.start();
633 }
在init2中创建并开启了一个线程ServerThread,在线程的Run方法中
59 class ServerThread extends Thread {
... 省略部分代码...
80 @Override
81 public void run() {
// 开启主线程消息队列
85 Looper.prepare();
... 省略部分代码...
131 // Critical services...
132 try {
//加入Android系统服务
133 Slog.i(TAG, "Entropy Service");
134 ServiceManager.addService("entropy", new EntropyService());
//加入Android系统服务
136 Slog.i(TAG, "Power Manager");
137 power = new PowerManagerService();
138 ServiceManager.addService(Context.POWER_SERVICE, power);
//加入Android系统服务
140 Slog.i(TAG, "Activity Manager");
141 context = ActivityManagerService.main(factoryTest);
//加入Android系统服务
143 Slog.i(TAG, "TelephonyRegistry");
144 ServiceManager.addService("telephony.registry", newTelephonyRegistry(context));
145
... 省略部分代码。加入了大量Android系统服务...
473 // It is now time to start up the app processes...
474
475 if (devicePolicy != null) {
476 devicePolicy.systemReady();
477 }
478
479 if (notification != null) {
480 notification.systemReady();
481 }
482
483 if (statusBar != null) {
484 statusBar.systemReady();
485 }
486 wm.systemReady();
487 power.systemReady();
488 try {
489 pm.systemReady();
490 } catch (RemoteException e) {
491 }
... 省略部分代码...
507 // We now tell the activitymanager it is okay to run third party
508 // code. It will call back intous once it has gotten to the state
509 // where third party code can really run (but before it has actually
510 // started launching the initial applications), for us to complete our
511 // initialization.
512 ((ActivityManagerService)ActivityManagerNative.getDefault())
513 .systemReady(new Runnable(){ // 调用ActivityManagerService的systemReady。通知系统准备就绪。
...省略部分代码...
});
542 Looper.loop(); // system_service主线程队列開始循环等待消息
543 Slog.d(TAG, "System ServerThread is exiting!");
544 }
545 }
由前面分析可知,system_server进程的主要作用就是启动并执行Android系统服务,这些服务执行在system_server进程中,由此可见其重要性。
图x-x system_server进程
Android系统中服务分为两种:本地服务和Android系统服务,我们将Android2.3系统中这些服务分别罗列出来。以供參考。
Ø 本地服务主要包括:
服务名 |
作用 |
SurfaceFlinger |
显示层混合器 |
SensorService |
传感器服务 |
AudioFlinger |
音频管理 |
MediaPlayerService |
多媒体播放器服务 |
CameraService |
摄像头服务 |
AudioPolicyService |
音频策略管理服务 |
Ø Android系统服务:
服务名 |
作用 |
EntropyService |
提供熵服务。用于产生随机数 |
PowerManagerService |
电源管理服务 |
ActivityManagerService |
管理Activity画面 |
TelephonyRegistry |
注冊电话模块的事件响应 |
PackageManagerService |
程序包管理服务 |
AccountManagerService |
联系人账户管理服务 |
ContentService |
ContentProvider服务。提供跨进程数据共享 |
BatteryService |
电池管理服务 |
LightsService |
自然光强度感应传感器服务 |
VibratorService |
震动器服务 |
AlarmManagerService |
定时器管理服务 |
WindowManagerService |
窗体管理服务 |
BluetoothService |
蓝牙服务 |
DevicePolicyManagerService |
提供一些系统级别的设置及属性 |
StatusBarManagerService |
状态栏管理服务 |
ClipboardService |
系统剪切板服务 |
InputMethodManagerService |
输入法管理服务 |
NetStatService |
网络状态服务 |
NetworkManagementService |
网络管理服务 |
ConnectivityService |
网络连接管理服务 |
ThrottleService |
节流阀控制服务 |
AccessibilityManagerService |
辅助管理程序截获全部的用户输入。并依据这些输入给用户一些额外的反馈,起到辅助的效果,View的点击、焦点等事件分发管理服务 |
MountService |
磁盘载入服务 |
NotificationManagerService |
通知管理服务,通常和StatusBarManagerService |
DeviceStorageMonitorService |
存储设备容量监听服务 |
LocationManagerService |
位置管理服务 |
SearchManagerService |
搜索管理服务 |
DropBoxManagerService |
系统日志文件管理服务 |
WallpaperManagerService |
壁纸管理服务 |
AudioService |
AudioFlinger上层的封装的音量控制管理服务 |
UsbService |
USB Host和device管理服务 |
UiModeManagerService |
UI模式管理服务,监听车载、座机等场合下UI的变化 |
BackupManagerService |
备份服务 |
AppWidgetService |
应用桌面部件服务 |
RecognitionManagerService |
身份识别服务 |
DiskStatsService |
磁盘统计服务 |
3.3.4Home桌面的启动
当Android系统服务启动完成后。system_service进程会通知Android系统服务系统启动完成,在ActivityManagerService.systemReady方法里会启动Android系统桌面应用程序:launcher。
@frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
386 public ActivityStack mMainStack;
... 省略部分代码...
6089 public void systemReady(final Runnable goingCallback) {
... 省略部分代码...
6254 synchronized (this) {
... 省略部分代码...
6288 mMainStack.resumeTopActivityLocked(null); // 在Activity栈中显示栈顶的Activity画面
6289 }
6290 }
在ActivityManagerService中维护了一个ActivityStack,它用来管理Activity的执行状态,在栈顶的Activity即是正在执行的画面,当ActivityManagerService准备就绪后。显示ActivityStack中栈顶画面。
@frameworks/base/services/java/com/android/server/am/ActivityStack.java
125 final ActivityManagerService mService;
...省略部分代码...
1051 final boolean resumeTopActivityLocked(ActivityRecord prev) {
1052 // Find the first activity that is not finishing.
// 返回ActivityStack栈顶的Activity,因为刚启动Android系统,所以返回null
1053 ActivityRecord next = topRunningActivityLocked(null);
...省略部分代码...
1060 if (next == null) {
1061 // There are no more activities! Let's just start up the
1062 // Launcher...
1063 if (mMainStack) {
1064 return mService.startHomeActivityLocked(); // 假设Activity栈顶没有Activity,则启动Launcher。即:HOME
1065 }
1066 }
因为Android系统刚启动,ActivityStack栈中还没有不论什么执行的Activity,所以这时要启动HOME应用程序作为主画面,从而显示桌面应用程序。
在Android中,启动一个Activity有两种方式:显示Intent启动和隐式Intent启动。
显示Intent启动:在Intent对象中指定Intent对象的接收者。是点对点的启动方式。
隐式Intent启动:相似于广播机制。在发送的Intent中通过Action和Category来匹配接收者,因此在Android系统中同意发出的Intent对象启动多个Activity,这样的方式保证了Android中全部应用程序的公平性。
Android的HOME应用程序的启动是通过隐式Intent启动的,我们能够查看HOME应用程序的AndroidManifest.xml文件来确定它的Intent对象的匹配内容:
@packages/apps/Launcher2/AndroidManifest.xml
1<?xml version="1.0" encoding="utf-8"?>
... 省略部分代码...
20 <manifest
21 xmlns:android="http://schemas.android.com/apk/res/android"
22 package="com.android.launcher"
23 android:sharedUserId="@string/sharedUserId"
24 >
65 <application
66 android:name="com.android.launcher2.LauncherApplication"
67 android:process="@string/process"
68 android:label="@string/application_name"
69 android:icon="@drawable/ic_launcher_home">
70
71 <activity
72 android:name="com.android.launcher2.Launcher"
73 android:launchMode="singleTask"
74 android:clearTaskOnLaunch="true"
75 android:stateNotNeeded="true"
76 android:theme="@style/Theme"
77 android:screenOrientation="nosensor"
78 android:windowSoftInputMode="stateUnspecified|adjustPan">
79 <intent-filter>
80 <actionandroid:name="android.intent.action.MAIN" />
81 <categoryandroid:name="android.intent.category.HOME" />
82 <categoryandroid:name="android.intent.category.DEFAULT" />
83 <categoryandroid:name="android.intent.category.MONKEY"/>
84 </intent-filter>
85 </activity>
在Android系统启动的终于阶段通过Intent对象启动HOME应用程序,该Intent中封装了两个基本的属性:action=”android.intent.action.MAIN”。category=“android.intent.category.HOME”。通过上面的代码能够看出来,launcher2应用程序的intent-filter匹配项里包括了HOME应用程序启动的“必要条件”。
深入浅出 - Android系统移植与平台开发(九)- Android系统system_server及Home启动的更多相关文章
- 深入浅出 - Android系统移植与平台开发(一)
深入浅出 - Android系统移植与平台开发(一) 分类: Android移植2012-09-05 14:16 16173人阅读 评论(12) 收藏 举报 androidgitgooglejdkub ...
- 深入浅出-Android系统移植与平台开发(一)- Android4.0系统的下载与编译
作者:唐老师,华清远见嵌入式学院讲师. 一.Android4.0系统的下载与编译 Android系统的下载与编译,Google的官方网站上已经给出了详细的说明,请参照Android的官方网址: htt ...
- 深入浅出 - Android系统移植与平台开发(三)- 编译并运行Android4.0模拟器
作者:唐老师,华清远见嵌入式学院讲师. 1. 编译Android模拟器 在Ubuntu下,我们可以在源码里编译出自己的模拟器及SDK等编译工具,当然这个和在windows里下载的看起来没有什么区别 ...
- 深入浅出 - Android系统移植与平台开发(五)- 编译Android源码(转)
2.3编译Android源码 Android源码体积非常庞大,由Dalvik虚拟机.Linux内核.编译系统.框架代码.Android定制C库.测试套件.系统应用程序等部分组成,在编译Android源 ...
- 深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)
第四章.Android编译系统与定制Android平台系统 4.1Android编译系统 Android的源码由几十万个文件构成,这些文件之间有的相互依赖,有的又相互独立,它们按功能或类型又被放到不同 ...
- 深入浅出 - Android系统移植与平台开发(十一)- Android系统的定制(瘋耔修改篇一)
首先非常感谢原文作者为我们提供的知识库,因为有你们的贡献,我们的开发难度更显简单 原文 : http://blog.csdn.net/mr_raptor/article/details/30113 ...
- 深入浅出 - Android系统移植与平台开发(六)- 为Android启动加速
作者:唐老师,华清远见嵌入式学院讲师. Android的启动速度一直以来是他的诟病,虽然现在Android设备的硬件速度越来越快,但是随着新 版本的出现,其启动速度一直都比较慢,当然,作为程序员,我们 ...
- 深入浅出 - Android系统移植与平台开发(七)- 初识HAL
作者:唐老师,华清远见嵌入式学院讲师. 1. HAL的module与stub HAL(Hardware AbstractLayer)硬件抽象层是Google开发的Android系统里上层应用对底层硬件 ...
- 深入浅出 - Android系统移植与平台开发(七)- 初识HAL【转】
本文转载自:http://blog.csdn.net/mr_raptor/article/details/8069588 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] ...
随机推荐
- numpy.clip(a, a_min, a_max, out=None)(values < a_min are replaced with a_min, and those > a_max with a_max.)
numpy.clip(a, a_min, a_max, out=None) Clip (limit) the values in an array. Given an interval, values ...
- 【Luogu】P1410子序列(DP)
题目链接 我DP是真的菜啊啊啊啊啊! f[i][j]表示考虑前i个数,有i-j+1个数组成一个上升子序列,且不以i结尾的尾端最小值. 设a为j个数组成的序列,且以i结尾:b为i-j+1个数组成的序列, ...
- BZOJ1925 [Sdoi2010]地精部落 【dp】
题目 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中Hi是1到N ...
- VS链接错误: LNIK1123
问题:编译一个VS工程程序,出现连接错误:"LNK1123: 转换到 COFF 期间失败: 文件无效或损坏" 原因分析:连接器LNK是通过调用cvtres.exe完成文件向coff ...
- P1282 多米诺骨牌 (差值DP+背包)
题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中,S1=6+1+1+1=9, ...
- 【前端学习笔记】ajax与php之间的互动
ajax通常会牵扯到跨域问题,所以我们通常的解决方案是,通过ajax将参数传到后台php文件中 在后台通过php文件进行跨域访问api,再将结果返回到ajax响应中.需要注意一下几点: 1.可以通过& ...
- 解决 IDEA 中src下xml等资源文件无法读取的问题
该问题的实质是,idea对classpath的规定. 在eclipse中,把资源文件放在src文件夹下,是可以找到的: 但是在idea中,直接把资源文件放在src文件夹下,如果不进行设置,是不能被找到 ...
- 【索引】理解MySQL——索引与优化
MySQL 索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索 ...
- perl学习之精髓中的精髓
1.是函数就有返回值: 比如:chomp函数,其可以除去换行符,但其也有返回值 chomp($xx) #这是去除xx的换行符 $yy=chomp($xx) #这是看这次除去了几个换行符,也就是函数运 ...
- python实现显示安装进度条
一直很好奇那种安装进度条,或者启动程序时候显示的进度条是怎么实现的,学习了python之后,sys模块中有个方法可以实现,代码如下: 1 2 3 4 5 6 import sys,time ...