Android 系统启动流程
本文基于android8.0系统源码来分析
系统启动大致流程图分析,一图以蔽之:
其中,启动电源、引导程序Bootloader
、linux
内核启动 部分读者自行了解,重点关注:init
进程启动过程,zygote
进程启动过程,SystemServer
进程启动过程,Launcher
启动过程
init 进程启动过程
init
进程是Android系统创建的第一个进程,其职责之一:创建zygote
进程和属性服务等。
- init 入口函数
init
进程的入口函数是main
system/core/init/init.cpp
源码
int main(int argc, char** argv){
...
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
...
// 1. 创建文件夹并挂载到 initramdisk
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
...
// 2. 初始化属性相关属性
property_init();
process_kernel_dt();
process_kernel_cmdline();
...
// 3. 启动属性服务
start_property_service();
set_usb_controller();
...
Parser& parser = Parser::GetInstance();
...
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
// 4. 解析init.rc 文件
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
parser.ParseConfig("/system/etc/init"));
parser.set_is_vendor_etc_init_loaded(parser.ParseConfig("/vendor/etc/init"));
parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
}
...
property_load_boot_defaults();
export_oem_lock_status();
}
init
main
函数做了很多事情,需要重点关注代码中的注释部分。注释4处解析init.rc
-
它是由Android Init Language介绍脚本编写的,它主要包含五种类型语句:
Action
、Commands
、Services
、Options
和Import
,较为重要的语法介绍:on <trigger> [&& <trigger>]* //设置触发器 <command> <command> //动作触发之后要执行的命令
截取init.rc 部分
Action
类型语句代码,如下所示:on init sysclktz 0 copy /proc/cmdline /dev/urandom copy /default.prop /dev/urandom ... mkdir /dev/stune/foreground mkdir /dev/stune/background mkdir /dev/stune/top-app
不难发现,
init.rc
组合了许多系统执行命令。为了分析如何创建zygote
,主要查看下Service
类型语句,格式如下service <name> <pathname> [ <argument> ]* //<service的名字><执行程序路径><传递参数> <option> //option是service的修饰词,影响什么时候、如何启动services <option>
每一个服务对应一个
rc
文件,相应的zygote服务的启动脚本则在init.zygoteXX.rc
中定义,切换到system/core/rootdir/
源码目录,存在多个形似zygote.rc
文件,这里,选取64位处理器为例,也即为system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main //1. zygote 进程的类名 priority -20 user root group root readproc socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks
结合
Init
脚本语言的Service
类型规范,可以得出init进程要启动的进程名称为zygote
,zygote
进程执行程序的路径为/system/bin/app_process64
。注释1 后文会用到 -
init进程fork zygote进程
从
zygote
启动脚本init.zygote64.rc
中得出zygote
的class name 为main
。 在init.rc
配置中... on nonencrypted class_start main class_start late_start ...
结合
Android Init Language
脚本Action
类型语句,class_start
是一个COMMAND
,用于启动还没有运行的指定服务,对应的函数是system/core/init/builtins.cpp#do_class_start
static int do_class_start(const std::vector<std::string>& args) { /* Starting a class does not start services * which are explicitly disabled. They must * be started individually. */ ServiceManager::GetInstance(). ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); }); // 调用了Service.StartIfNotDisabled return 0; }
system/core/init/service.cpp
的StartIfNotDisabled函数bool Service::StartIfNotDisabled() { if (!(flags_ & SVC_DISABLED)) { return Start(); // 执行Start函数 } else { flags_ |= SVC_DISABLED_START; } return true; }
执行
Start
函数:bool Service::Start() { flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); if (flags_ & SVC_RUNNING) { //1. 如果Service已经启动,则不启动 return false; } ... struct stat sb; // 2. 判断启动的Service对应的执行文件是否存在,不存在则不启动该Service if (stat(args_[0].c_str(), &sb) == -1) { PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'"; flags_ |= SVC_DISABLED; return false; } ... pid_t pid = -1; if (namespace_flags_) { pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr); } else { // 3. fork 函数创建子进程 pid = fork(); } if (pid == 0) { ... std::vector<char*> strs; ExpandArgs(args_, &strs); // 4. 通过execve 函数执行程序 if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { PLOG(ERROR) << "cannot execve('" << strs[0] << "')"; } } }
注释3处将zygote进程启动; 注释4处,在子进程中调用
execve
函数来执行/system/bin/app_process64
,这样就会进入framework/cmds/app_process/app_main.cpp
源码的main
的函数int main(int argc, char* const argv[]){ ... if (zygote) { // 1. 执行Zygote 进程Java框架层代码 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); } }
从注释1:调用
AppRuntime#start
执行Zygote 进程Java框架层代码 -
属性服务初始化与启动
init入口函数
system/core/init/init.cpp
源码注释2,property_init()
函数具体实现代码system/core/init/property_service.cpp
void property_init() { if (__system_property_area_init()) { LOG(ERROR) << "Failed to initialize property area"; exit(1); } }
其中
__system_property_area_init
函数用来初始化属性内存区域。init入口函数
system/core/init/init.cpp
源码注释3处start_property_service
函数具体实现代码void start_property_service() { property_set("ro.property_service.version", "2"); // 1. 创建非阻塞的socket property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0666, 0, 0, NULL); if (property_set_fd == -1) { PLOG(ERROR) << "start_property_service socket creation failed"; exit(1); } // 2. 对property_set_fd 进行监听,第二个参数代表属性服务最多可以同时为8个视图设置属性的用户提供服务 listen(property_set_fd, 8); // 3. 用epoll 监听property_set_fd属性,当property_set_fd属性设置时,init进程将用handle_property_set_fd函数来处理 register_epoll_handler(property_set_fd, handle_property_set_fd); }
在新
linux
内核中,epoll
用来替换select
,epoll
最大的好处在于它不会随着监听fd数目的增长而降低效率。因为内核中的select
实现是采用轮询来处理的,轮询的fd数目越多,自然耗时越多
当属性服务接受到客户端的请求,关注下handle_property_set_fd
函数static void handle_property_set_fd(){ ... switch (cmd) { case PROP_MSG_SETPROP:{ char prop_name[PROP_NAME_MAX]; char prop_value[PROP_VALUE_MAX]; if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) || !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) { PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket"; return; } prop_name[PROP_NAME_MAX-1] = 0; prop_value[PROP_VALUE_MAX-1] = 0; // 1. 处理属性设置 handle_property_set(socket, prop_value, prop_value, true); } } ... } static void handle_property_set(SocketConnection& socket, const std::string& name, const std::string& value, bool legacy_protocol){ ... // 2. 检查权限 if (check_mac_perms(name, source_ctx, &cr)) { // 3. 设置属性 uint32_t result = property_set(name, value); if (!legacy_protocol) { socket.SendUint32(result); } } else { LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name; if (!legacy_protocol) { socket.SendUint32(PROP_ERROR_PERMISSION_DENIED); } } ... } uint32_t property_set(const std::string& name, const std::string& value){ size_t valuelen = value.size(); //1. 校验属性键是否合法 if (!is_legal_property_name(name)) { LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name"; return PROP_ERROR_INVALID_NAME; } //2. 校验值是否合法 if (valuelen >= PROP_VALUE_MAX) { LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " << "value too long"; return PROP_ERROR_INVALID_VALUE; } //3. 加载属性元信息, prop_info* pi = (prop_info*) __system_property_find(name.c_str()); if (pi != nullptr) { // ro.* properties are actually "write-once". if (android::base::StartsWith(name, "ro.")) { // 属性ro.前缀开头,表示只读,不能修改 LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: " << "property already set"; return PROP_ERROR_READ_ONLY_PROPERTY; } // 更新属性值 __system_property_update(pi, value.c_str(), valuelen); } ... }
上述源码注释,介绍属性修改的过程
-
init进程启动过程总结
大致做了三件事:
- 创建文件目录并挂载设备;
- 初始化和启动属性服务;
- 解析
init.rc
文件,forkzygote
进程
zygote 进程启动过程
zygote
译为“孵化器”,是一个进程名字,DVM、应用程序进程以及运行系统关键服务的SystemServer
进程都是由它创建并启动,其他应用所在的进程都是zygote
进程的子进程
-
AppRuntime 分析
从上文得知init
启动zygote
时主要是调用app_main.cpp
的main
函数中的AppRuntime
的start
函数来启动zygote
服务的:
framework/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]){ ... AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); ... while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0){ // 1.启动SystemServer命令 startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } if (zygote) { //2. 将args(启动SystemServer命令)作为形参传入 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } }
main
函数第二个形参中包含--start-system-server
,因为上一节init
进程启动分析中提到过init.zygote64.rc
中Init
脚本:service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server ...
其中
--start-system-server
为携带参数,该参数传递到app_main.cpp#main()
函数 ,AppRuntime#start
启动zygote
进程,同时也会将SystemServer
进程启动#include <android_runtime/AndroidRuntime.h> class AppRuntime : public AndroidRuntime{ ... }
AppRuntime
继承AndroidRuntime
,即调用AndroidRuntime#start
函数
frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote){ ... JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; // 1. 开启虚拟机 if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env); // 2. 注册android native函数 if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } // 3. 将main函数的 形参options 转成 jobjectArray,作为注释5执行className 类的main函数 jclass stringClass; jobjectArray strArray; jstring classNameStr; ... stringClass = env->FindClass("java/lang/String"); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); classNameStr = env->NewStringUTF(className); for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName);// 反射获取类实例 ... // 4. 找到className 类对应的main函数 jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); //5. 注释3出生成的strArray 参数数组 传递给className 类的main 函数并执行它 env->CallStaticVoidMethod(startClass, startMeth, strArray); }
从源码
app_main.cpp
得知,源码中提到的className
为com.android.internal.os.ZygoteInit
,而ZygoteInit
是java编写的,所以需要通过JNI的方式完成调用(c++ ->Java 反射实现) -
Zygote的java 框架层
从上一节得知,
zygote
通过jni调用ZygoteInit.java
,
com.android.internal.os.ZygoteInit
public static void main(String argv[]) { ... boolean startSystemServer = false; String socketName = "zygote"; ... for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { // 1. 参数中携带start-system-server startSystemServer = true; } else if{...} } // 2. 注册zygote 用的Socket zygoteServer.registerServerSocketFromEnv(socketName); ... if (startSystemServer) { // 3. fork SystemServer进程(用于启动系统关键服务) 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) { //4. 执行SystemServer#run 方法 r.run(); return; } } }
注释2出的
registerServerSocketFromEnv
用来等待ActivityManagerService
来请求Zygote
创建应用程序进程,注释3、4用于forkSystemServer
进程,和执行run
方法。
com.android.internal.os.ZygoteServer
void registerServerSocketFromEnv(String socketName) { if (mServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); // 1. mServerSocket = new LocalServerSocket(fd); mCloseSocketFd = true; } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
注释1创建
LocalServerSocket
,也就是服务端的Socket, 当Zygote
进程将SystemServer
进程启动后,就会等待ActivityManagerService
请求Zygote
进程来启动新的应用程序进程。接着继续看forkSystemServer
方法private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) { ... //1. String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; ... //2. pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); //3. if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); //4. return handleSystemServerProcess(parsedArgs); } }
注释1处用于为启动
SystemServer
进程参数命令,可以得知启动的类名为com.android.server.SystemServer
,注释2处forkSystemServer
进程,注释3若pid
为0 表示在新创建的子进程中执行,则执行注释4的handleSystemServerProcess
并返回Runnable
对象。由于forkSystemServer
方法调用链较长,这里用UML时序图简略表示:
-
Zygote进程启动流程总结
SystemServer进程启动过程
SystemServer
也是一个进程,从上文得知,它是zygote
fork 出来的。ActivityMangerService
PackageManagerService
WindowManagerService
等这些重要的服务都是通过SystemServer
进程启动的
-
启动服务过程
结合上一节Zygote.forkSystemServer
方法 绘制的UML时序图,最终通过反射的方式调用SystemServer#main
方法
com.android.server.SystemServer
public static void main(String[] args) { // 1. 创建`SystemServer`实例并执行`run`方法,注意,它并不是`Runnable`对象 new SystemServer().run(); } ... private void run() { ... //2.注释2用于初始化系统配置(时区、语言...) SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); SystemProperties.set("persist.sys.timezone", "GMT"); SystemProperties.set("persist.sys.language", ""); ... // 3. 设置进程优先级并创建主线程`Looper` android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); Looper.prepareMainLooper(); Looper.getMainLooper().setSlowLogThresholdMs( SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS); // 4. 加载了`libandroid_servers.so` // Initialize native services. System.loadLibrary("android_servers"); ... // 5. 创建系统上下文 createSystemContext(); ... // 6. 创建SystemServiceManager:创建系统服务、管理服务生命周期,存取系统服务 // Create the system service manager. mSystemServiceManager = new SystemServiceManager(mSystemContext); mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // 为可以并行化的任务准备线程池 SystemServerInitThreadPool.get(); try { // 7. 启动核心关键服务 startBootstrapServices(); startCoreServices(); startOtherServices(); SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { ... } ... // 8. Looper.loop(); }
注释5创建系统上下文:
private void createSystemContext() { ActivityThread activityThread = ActivityThread.systemMain(); mSystemContext = activityThread.getSystemContext(); mSystemContext.setTheme(DEFAULT_SYSTEM_THEME); final Context systemUiContext = activityThread.getSystemUiContext(); systemUiContext.setTheme(DEFAULT_SYSTEM_THEME); }
得知
systemContext
是从ActivityThread#getSystemContext
;并设置了系统主题。重点关注注释7:启动系统服务,官方把系统服务分成三种类型引导服务、和兴服务、其他服务,这里简单列举一下:
大致统计了下SystemServer
在启动过程中会启动96个左右的服务
查看调用启动服务源码 e.g
SystemServer#startBootstrapServices
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
启动服务是委托给com.android.server.SystemServiceManager
public SystemService startService(String className) {
...
// 1. 反射构造服务实例
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
...
// Register it.
//2. 添加到动态数组中
mServices.add(service);
try {
//3. 执行服务的onStart方法
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
}
以上代码表述了一个服务启动的过程。其中SystemServerManager
用来管理(生死存亡、开启|关闭服务)系统各种服务,这对于后期学习系统C/S架构中的Binder机制通信有极大的作用。
-
总结
Launcher启动过程过程
作为Android系统启动流程的最后一步:Home应用程序启动,
Home
也即Launcher
。应用程序在启动过程中会请求PMS
返回系统中已经安装的应用程序信息,并将这些信息转换成一个快捷启动图标显示在桌面上,这样用户就可以点击快捷图标启动程序了。源码地址
-
Launcher 程序是如何启动的?
由上一节得知SystemServer
进程会启动AMS
PMS
等服务。其中Launcher
程序是通过AMS
启动的
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() { mActivityManagerService.systemReady(() -> { ... // MakeXXXServiceReady } }
调用了
AMS
systemReady
方法... String mTopAction = Intent.ACTION_MAIN; ... public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) { ... // Start up initial activity. mBooting = true; // Enable home activity for system user, so that the system can always boot. We don't // do this when the system user is not setup since the setup wizard should be the one // to handle home activity in this case. // 1. 启动HomeActivity startHomeActivityLocked(currentUserId, "systemReady"); } boolean startHomeActivityLocked(int userId, String reason){ if (mFactoryTest == FactoryTest.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; } // 2. 创建Home程序的启动Activity Intent Intent intent = getHomeIntent(); 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, true); if (app == null || app.instr == null) { //3. 设置启动模式为FLAG_ACTIVITY_NEW_TASK intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK); final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); // For ANR debugging to verify if the user activity is the one that actually // launched. final String myReason = reason + ":" + userId + ":" + resolvedUserId; // 4. 启动Activity mActivityStartController.startHomeActivity(intent, aInfo, myReason); } } else { Slog.wtf(TAG, "No home screen found for " + intent, new Throwable()); } return true; } 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) { // 2.1 设置Category为CATEGORY_HOME intent.addCategory(Intent.CATEGORY_HOME); } return intent; }
要启动的
action
为Intent.ACTION_MAIN
,category
为Intent.CATEGORY_HOME
。 Launcher应用程序Manifest
<application android:name="LauncherApplication" android:process="android.process.acore" android:label="@string/application_name" android:icon="@drawable/ic_launcher_home"> <activity android:name="Launcher" android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:theme="@style/Theme" android:screenOrientation="nosensor" android:windowSoftInputMode="stateUnspecified|adjustPan"> <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" /> </intent-filter> </activity> </application>
这样 桌面应用程序
Launcher Activity#onCreate
就会执行
-
Launcher中应用图标启动分析
紧接着分析下点击应用图标到底发生了什么?
Launcher.java
public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener{ @Override protected void onCreate(Bundle savedInstanceState) { ... // 1. setContentView(R.layout.launcher); ... } }
launcher.xml
<com.android.launcher.DragLayer xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher" android:id="@+id/drag_layer" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- The workspace contains 3 screens of cells --> <com.android.launcher.Workspace android:id="@+id/workspace" android:layout_width="fill_parent" android:layout_height="fill_parent" launcher:defaultScreen="1"> <include android:id="@+id/cell1" layout="@layout/workspace_screen" /> <include android:id="@+id/cell2" layout="@layout/workspace_screen" /> <include android:id="@+id/cell3" layout="@layout/workspace_screen" /> </com.android.launcher.Workspace> ... <com.android.launcher.DeleteZone android:id="@+id/delete_zone" android:layout_width="wrap_content" android:layout_height="49dip" android:scaleType="center" android:src="@drawable/ic_delete" android:background="@drawable/delete_zone_selector" android:layout_gravity="bottom|center_horizontal" android:visibility="invisible" launcher:direction="horizontal" /> </com.android.launcher.DragLayer>
重点关注
cell
,每一个cell
对应一个application
workspace_screen.xml
<com.android.launcher.CellLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher" android:layout_width="fill_parent" android:layout_height="fill_parent" launcher:cellWidth="80dip" launcher:cellHeight="100dip" launcher:longAxisStartPadding="0dip" launcher:longAxisEndPadding="55dip" launcher:shortAxisStartPadding="0dip" launcher:shortAxisEndPadding="0dip" launcher:shortAxisCells="4" launcher:longAxisCells="4" />
CellLayout
是一个自定义View,继承ViewGroup
,父控件为Workspace
。回到Launcher.java
:private static class DesktopBinder extends Handler implements MessageQueue.IdleHandler{ ... @Override public void handleMessage(Message msg) { Launcher launcher = mLauncher.get(); if (launcher == null || mTerminate) { return; } switch (msg.what) { case MESSAGE_BIND_ITEMS: { // 1.执行了bindAppWidgets launcher.bindItems(this, mShortcuts, msg.arg1, msg.arg2); break; } case MESSAGE_BIND_DRAWER: { launcher.bindDrawer(this, mDrawerAdapter); break; } case MESSAGE_BIND_APPWIDGETS: { launcher.bindAppWidgets(this, mAppWidgets); break; } } } } private void bindItems(Launcher.DesktopBinder binder, ArrayList<ItemInfo> shortcuts, int start, int count){ final Workspace workspace = mWorkspace; ... for ( ; i < end; i++) { final ItemInfo item = shortcuts.get(i); switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: // 2. 创建快捷方式View 并添加到 workspace子控件的cellLayout中 final View shortcut = createShortcut((ApplicationInfo) item); workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1, !desktopLocked); break; } } }
当从
PMS
获取到已经安装的应用程序后,将这些appinfo
绑定到Launcher
的界面中。注释2调用createShortcut
View createShortcut(int layoutResId, ViewGroup parent, ApplicationInfo info) { TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false); if (!info.filtered) { info.icon = Utilities.createIconThumbnail(info.icon, this); info.filtered = true; } favorite.setCompoundDrawablesWithIntrinsicBounds(null, info.icon, null, null); favorite.setText(info.title); favorite.setTag(info); // 1. favorite.setOnClickListener(this); return favorite; }
注释1 很关键,快捷方式的点击事件委托给
Launcher
Activity ,接着看Launcher#onClick
方法/** * Launches the intent referred by the clicked shortcut. * * @param v The view representing the clicked shortcut. */ public void onClick(View v) { Object tag = v.getTag(); if (tag instanceof ApplicationInfo) { // Open shortcut final Intent intent = ((ApplicationInfo) tag).intent; //1. startActivitySafely(intent); } else if (tag instanceof FolderInfo) { handleFolderClick((FolderInfo) tag); } } void startActivitySafely(Intent intent) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { // 2. startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { ... } }
注释1 & 2 调用了
startActivitySafely
也即调用了startActivity
, 这样目标程序就会被启动。