Android 系统启动流程

本文基于android8.0系统源码来分析

系统启动大致流程图分析,一图以蔽之:

system-start- analysis

其中,启动电源、引导程序Bootloaderlinux内核启动 部分读者自行了解,重点关注:init 进程启动过程,zygote进程启动过程,SystemServer进程启动过程,Launcher启动过程

init 进程启动过程

init 进程是Android系统创建的第一个进程,其职责之一:创建zygote进程和属性服务等。

  1. 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

  1. init.rc

    它是由Android Init Language介绍脚本编写的,它主要包含五种类型语句:
    ActionCommandsServicesOptionsImport,较为重要的语法介绍:

    on  [&& ]* //设置触发器           //动作触发之后要执行的命令

    截取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   [  ]*   //<执行程序路径><传递参数>     

    每一个服务对应一个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 后文会用到

  2. 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& 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 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框架层代码

  3. 属性服务初始化与启动

    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用来替换selectepoll最大的好处在于它不会随着监听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);     }     ...}

    上述源码注释,介绍属性修改的过程

  4. init进程启动过程总结

    init-conclusion.png

    大致做了三件事:

    1. 创建文件目录并挂载设备;
    2. 初始化和启动属性服务;
    3. 解析init.rc 文件,fork zygote进程

zygote 进程启动过程

zygote 译为“孵化器”,是一个进程名字,DVM、应用程序进程以及运行系统关键服务的SystemServer进程都是由它创建并启动,其他应用所在的进程都是zygote进程的子进程

  1. AppRuntime 分析
    从上文得知init启动zygote时主要是调用app_main.cppmain函数中的AppRuntimestart函数来启动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.rcInit脚本:

    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 class AppRuntime : public AndroidRuntime{     ...}

    AppRuntime 继承AndroidRuntime,即调用AndroidRuntime#start函数
    frameworks/base/core/jni/AndroidRuntime.cpp

    void AndroidRuntime::start(const char* className, const Vector& 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 得知,源码中提到的classNamecom.android.internal.os.ZygoteInit ,而ZygoteInit是java编写的,所以需要通过JNI的方式完成调用(c++ ->Java 反射实现)

  2. 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用于fork SystemServer进程,和执行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处fork SystemServer进程,注释3若pid为0 表示在新创建的子进程中执行,则执行注释4的handleSystemServerProcess 并返回Runnable对象。由于forkSystemServer 方法调用链较长,这里用UML时序图简略表示:

    forkSystemServer-Call-chain

  3. Zygote进程启动流程总结


    zygote-start-analyze.png

SystemServer进程启动过程

SystemServer 也是一个进程,从上文得知,它是zygote fork 出来的。ActivityMangerService PackageManagerService WindowManagerService 等这些重要的服务都是通过SystemServer进程启动的

  1. 启动服务过程
    结合上一节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:启动系统服务,官方把系统服务分成三种类型引导服务、和兴服务、其他服务,这里简单列举一下:

    start-service.png

大致统计了下SystemServer 在启动过程中会启动96个左右的服务

查看调用启动服务源码 e.g
SystemServer#startBootstrapServices

mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

启动服务是委托给com.android.server.SystemServiceManager

public SystemService startService(String className) {     ...     // 1. 反射构造服务实例     Constructor 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机制通信有极大的作用。

  1. 总结


    SystemServer-start-analyze.png

Launcher启动过程过程

作为Android系统启动流程的最后一步:Home应用程序启动,Home也即Launcher。应用程序在启动过程中会请求PMS 返回系统中已经安装的应用程序信息,并将这些信息转换成一个快捷启动图标显示在桌面上,这样用户就可以点击快捷图标启动程序了。源码地址

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

    要启动的actionIntent.ACTION_MAINcategoryIntent.CATEGORY_HOME。 Launcher应用程序Manifest

                                                                                       

    这样 桌面应用程序Launcher Activity#onCreate 就会执行

    Launcher-start.png

  1. 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

                                          ...         

    重点关注cell,每一个cell对应一个application
    workspace_screen.xml

    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 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 很关键,快捷方式的点击事件委托给LauncherActivity ,接着看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 , 这样目标程序就会被启动。

更多相关文章

  1. cocos2dx2.1.4FATAL EXCEPTION: GLThread 10, Class doesn't imp
  2. Android(安卓)创世纪 第二天
  3. Android中AsyncTask线程的使用
  4. android调节屏幕亮度(包括只修改应用程序和修改系统)
  5. Android(安卓)通信的桥梁 Intent
  6. android中实现JavaScript与Java之间实现互相调用
  7. Android(安卓)Service - EntropyService
  8. Android启动第三方应用程序
  9. Android之Service 的生命周期

随机推荐

  1. sql convert函数使用小结
  2. SQL 多表连接查询实现语句
  3. SQL Server 高速缓存依赖分析
  4. 将备份数据还原到数据库的步骤
  5. 隐藏在SQLServer 字段中的超诡异字符解决
  6. sql 服务器知识
  7. SQL语法 分隔符理解小结
  8. sql中all,any,some用法
  9. 最常用的SQL语句
  10. SqlServer 实用操作小技巧集合第1/2页