Android 10 启动Init进程解析

目录
  • 按下电源键时,android做了啥?
  • init进程解析
    • FirstStageMain
    • SetupSelinux
    • SecondStageMain
    • init.rc 解析

按下电源键时,android做了啥?

当我们按下电源键时,手机开始上电,并从地址0x00000000处开始执行,而这个地址通常是Bootloader程序的首地址。

bootloader是一段裸机程序,是直接与硬件打交道的,其最终目的是“初始化并检测硬件设备,准备好软件环境,最后调用操作系统内核”。除此之外,bootloader还有保护功能,部分品牌的手机对bootloader做了加锁操作,防止boot分区和recovery分区被写入。

或许有人会问了,什么是boot分区,什么又是recovery分区?

我们先来认识一下Android系统的常见分区:

/boot

这个分区上有Android的引导程序,包括内核和内存操作程序。没有这个分区设备就不能被引导。恢复系统的时候会擦除这个分区,并且必须重新安装引导程序和ROM才能重启系统。

/recovery

recovery分区被认为是另一个启动分区,你可以启动设备进入recovery控制台去执行高级的系统恢复和管理操作。

/data

这个分区保存着用户数据。通讯录、短信、设置和你安装的apps都在这个分区上。擦除这个分区相当于恢复出厂设置,当你第一次启动设备的时候或者在安装了官方或者客户的ROM之后系统会自动重建这个分区。当你执行恢复出厂设置时,就是在擦除这个分区。

/cache

这个分区是Android系统存储频繁访问的数据和app的地方。擦除这个分区不影响你的个人数据,当你继续使用设备时,被擦除的数据就会自动被创建。

/apex

Android Q新增特性,将系统功能模块化,允许系统按模块来独立升级。此分区用于存放apex 相关的内容。

为什么需要bootloader去拉起linux内核,而不把bootloader这些功能直接内置在linux内核中呢?这个问题不在此做出回答,留给大家自行去思考。

bootloader完成初始化工作后,会载入 /boot 目录下面的 kernel,此时控制权转交给操作系统。操作系统将要完成的存储管理、设备管理、文件管理、进程管理、加载驱动等任务的初始化工作,以便进入用户态。

内核启动完成后,将会寻找init文件(init文件位于/system/bin/init),启动init进程,也就是android的第一个进程。

我们来关注一下内核的common/init/main.c中的kernel_init方法。

static int __ref kernel_init(void *unused)
{
    ...
    if (execute_command) {
        ret = run_init_process(execute_command);
        if (!ret)
            return 0;
    }
    if (CONFIG_DEFAULT_INIT[0] != '\0') {
    ret = run_init_process(CONFIG_DEFAULT_INIT);
    if (ret)
        pr_err("Default init %s failed (error %d)\n",CONFIG_DEFAULT_INIT, ret);
      else
        return 0;
    }
if (!try_to_run_init_process("/sbin/init") ||!try_to_run_init_process("/etc/init") ||
    !try_to_run_init_process("/bin/init") ||!try_to_run_init_process("/bin/sh"))
    return 0;
}

可以看到,在init_kernel的最后,会调用run_init_process方法来启动init进程。

static int run_init_process(const char *init_filename){
    const char *const *p;
    argv_init[0] = init_filename;
    return kernel_execve(init_filename, argv_init, envp_init);
}

kernel_execve是内核空间调用用户空间的应用程序的函数。

接下来我们来重点分析init进程。

init进程解析

我们从system/core/init/main.cpp 这个文件开始看起。

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;
            return SubcontextMain(argc, argv, &function_map);
        }
        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }
        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
    return FirstStageMain(argc, argv);
}

第一个参数argc表示参数个数,第二个参数是参数列表,也就是具体的参数。

main函数有四个参数入口:

  • 一是参数中有ueventd,进入ueventd_main
  • 二是参数中有subcontext,进入InitLogging 和SubcontextMain
  • 三是参数中有selinux_setup,进入SetupSelinux
  • 四是参数中有second_stage,进入SecondStageMain

main的执行顺序如下:

  • FirstStageMain  启动第一阶段
  • SetupSelinux    加载selinux规则,并设置selinux日志,完成SELinux相关工作
  • SecondStageMain  启动第二阶段
  • ueventd_main    init进程创建子进程ueventd,并将创建设备节点文件的工作托付给ueventd。

FirstStageMain

我们来从FirstStageMain的源码看起,源码位于/system/core/init/first_stage_init.cpp

int FirstStageMain(int argc, char** argv) {
    boot_clock::time_point start_time = boot_clock::now();
#define CHECKCALL(x) \
    if (x != 0) errors.emplace_back(#x " failed", errno);
    // Clear the umask.
    umask(0);
    //初始化系统环境变量
    CHECKCALL(clearenv());
    CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
    // 挂载及创建基本的文件系统,并设置合适的访问权限
    CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
    CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
#undef MAKE_STR
    // 不要将原始命令行公开给非特权进程
    CHECKCALL(chmod("/proc/cmdline", 0440));
    gid_t groups[] = {AID_READPROC};
    CHECKCALL(setgroups(arraysize(groups), groups));
    CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
    CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
    CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
    if constexpr (WORLD_WRITABLE_KMSG) {
        CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
    }
    //创建linux随机伪设备文件
    CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
    CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
    //log wrapper所必须的,需要在ueventd运行之前被调用
    CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
    CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
    ...
    //将内核的stdin/stdout/stderr 全都重定向/dev/null,关闭默认控制台输出
    SetStdioToDevNull(argv);
    // tmpfs已经挂载到/dev上,同时我们也挂载了/dev/kmsg,我们能够与外界开始沟通了
    //初始化内核log
    InitKernelLogging(argv);
    //检测上面的操作是否发生了错误
    if (!errors.empty()) {
        for (const auto& [error_string, error_errno] : errors) {
            LOG(ERROR) << error_string << " " << strerror(error_errno);
        }
        LOG(FATAL) << "Init encountered errors starting first stage, aborting";
    }
    LOG(INFO) << "init first stage started!";
    auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
    if (!old_root_dir) {
        PLOG(ERROR) << "Could not opendir("/"), not freeing ramdisk";
    }
    struct stat old_root_info;
    ...
    //挂载 system、cache、data 等系统分区
    if (!DoFirstStageMount()) {
        LOG(FATAL) << "Failed to mount required partitions early ...";
    }
    ...
    //进入下一步,SetupSelinux
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    execv(path, const_cast<char**>(args));
    return 1;
}

我们来总结一下,FirstStageMain到底做了哪些重要的事情:

  • 挂载及创建基本的文件系统,并设置合适的访问权限
  • 关闭默认控制台输出,并初始化内核级log。
  • 挂载 system、cache、data 等系统分区

SetupSelinux

这个模块主要的工作是设置SELinux安全策略,本章内容主要聚焦于android的启动流程,selinux的内容在此不做展开。

int SetupSelinux(char** argv) {
   ...
    const char* path = "/system/bin/init";
    const char* args[] = {path, "second_stage", nullptr};
    execv(path, const_cast<char**>(args));
    return 1;
}

SetupSelinux的最后,进入了init的第二阶段SecondStageMain。

SecondStageMain

不多说,先上代码。

int SecondStageMain(int argc, char** argv) {
    // 禁止OOM killer 结束该进程以及它的子进程
    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
    }
    // 启用全局Seccomp,Seccomp是什么请自行查阅资料
    GlobalSeccomp();
    // 设置所有进程都能访问的会话密钥
    keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
    // 创建 /dev/.booting 文件,就是个标记,表示booting进行中
    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
    //初始化属性的服务,并从指定文件读取属性
    property_init();
     ...
    // 进行SELinux第二阶段并恢复一些文件安全上下文
    SelinuxSetupKernelLogging();
    SelabelInitialize();
    SelinuxRestoreContext();
    //初始化Epoll,android这里对epoll做了一层封装
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        PLOG(FATAL) << result.error();
    }
    //epoll 中注册signalfd,主要是为了创建handler处理子进程终止信号
    InstallSignalFdHandler(&epoll);
    ...
    //epoll 中注册property_set_fd,设置其他系统属性并开启系统属性的服务
    StartPropertyService(&epoll);
    MountHandler mount_handler(&epoll);
    ...
    ActionManager& am = ActionManager::GetInstance();
    ServiceList& sm = ServiceList::GetInstance();
    //解析init.rc等文件,建立rc文件的action 、service,启动其他进程,十分关键的一步
    LoadBootScripts(am, sm);
    ...
    am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
    //执行rc文件中触发器为 on early-init 的语句
    am.QueueEventTrigger("early-init");
    // 等冷插拔设备初始化完成
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    // 设备组合键的初始化操作
    Keychords keychords;
    am.QueueBuiltinAction(
        [&epoll, &keychords](const BuiltinArguments& args) -> Result<Success> {
            for (const auto& svc : ServiceList::GetInstance()) {
                keychords.Register(svc->keycodes());
            }
            keychords.Start(&epoll, HandleKeychord);
            return Success();
        },
        "KeychordInit");
    am.QueueBuiltinAction(console_init_action, "console_init");
   // 执行rc文件中触发器为on init的语句
    am.QueueEventTrigger("init");
    // Starting the BoringSSL self test, for NIAP certification compliance.
    am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    am.QueueBuiltinAction(InitBinder, "InitBinder");
    // 当设备处于充电模式时,不需要mount文件系统或者启动系统服务,充电模式下,将charger设为执行队列,否则把late-init设为执行队列
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }
    // 基于属性当前状态 运行所有的属性触发器.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
    while (true) {
        //开始进入死循环状态
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
        //执行关机重启流程
        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }
        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            if (!shutting_down) {
                auto next_process_action_time = HandleProcessActions();
                // If there's a process that needs restarting, wake up in time for that.
                if (next_process_action_time) {
                    epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                            *next_process_action_time - boot_clock::now());
                    if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
                }
            }
            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout = 0ms;
        }
        // 循环等待事件发生
        if (auto result = epoll.Wait(epoll_timeout); !result) {
            LOG(ERROR) << result.error();
        }
    }
    return 0;
}

总结一下,第二阶段做了以下这些比较重要的事情:

  • 初始化属性的服务,并从指定文件读取属性
  • 初始化epoll,并注册signalfd和property_set_fd,建立和init的子进程以及部分服务的通讯桥梁
  • 初始化设备组合键,使系统能够对组合键信号做出响应
  • 解析init.rc文件,并按rc里的定义去启动服务
  • 开启死循环,用于接收epoll的事件

在第二阶段,我们需要重点关注以下问题:

init进程是如何通过init.rc配置文件去启动其他的进程的呢?

init.rc 解析

我们从 LoadBootScripts(am, sm)这个方法开始看起,一步一部来挖掘init.rc 的解析流程。

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
   //初始化ServiceParse、ActionParser、ImportParser三个解析器
   Parser parser = CreateParser(action_manager, service_list);
   std::string bootscript = GetProperty("ro.boot.init_rc", "");
   if (bootscript.empty()) {
       //bootscript为空,进入此分支
       parser.ParseConfig("/init.rc");
       if (!parser.ParseConfig("/system/etc/init")) {
           late_import_paths.emplace_back("/system/etc/init");
       }
       if (!parser.ParseConfig("/product/etc/init")) {
           late_import_paths.emplace_back("/product/etc/init");
       }
       if (!parser.ParseConfig("/product_services/etc/init")) {
           late_import_paths.emplace_back("/product_services/etc/init");
       }
       if (!parser.ParseConfig("/odm/etc/init")) {
           late_import_paths.emplace_back("/odm/etc/init");
       }
       if (!parser.ParseConfig("/vendor/etc/init")) {
           late_import_paths.emplace_back("/vendor/etc/init");
       }
   } else {
       parser.ParseConfig(bootscript);
   }
}

我们可以看到这句话,Parse开始解析init.rc文件,在深入下去之前,让我们先来认识一下init.rc。

 parser.ParseConfig("/init.rc")

init.rc是一个可配置的初始化文件,负责系统的初步建立。它的源文件的路径为 /system/core/rootdir/init.rc

init.rc文件有着固定的语法,由于内容过多,限制于篇幅的原因,在此另外单独开了一篇文章进行讲解:

Android 10 启动分析之init语法

了解了init.rc的语法后,我们来看看init.rc文件里的内容。

import /init.environ.rc  //导入全局环境变量
import /init.usb.rc   //adb 服务、USB相关内容的定义
import /init.${ro.hardware}.rc  //硬件相关的初始化,一般是厂商定制
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc   //定义Zygote服务

我们可以看到,在/system/core/init目录下,存在以下四个zygote相关的文件

怎样才能知道我们当前的手机用的是哪个配置文件呢?

答案是通过adb shell getprop | findstr ro.zygote命令,看看${ro.zygote}这个环境变量具体的值是什么,笔者所使用的华为手机的ro.zygote值如下所示:

什么是Zygote,Zygote的启动过程是怎样的,它的启动配置文件里又做了啥,在这里我们不再做进一步探讨, 只需要知道init在一开始在这个文件中对Zygote服务做了定义,而上述的这些问题将留到 启动分析之Zygote篇 再去说明。

on early-init
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0
    # Set the security context of /adb_keys if present.
    restorecon /adb_keys
    # Set the security context of /postinstall if present.
    restorecon /postinstall
    mkdir /acct/uid
    # memory.pressure_level used by lmkd
    chown root system /dev/memcg/memory.pressure_level
    chmod 0040 /dev/memcg/memory.pressure_level
    # app mem cgroups, used by activity manager, lmkd and zygote
    mkdir /dev/memcg/apps/ 0755 system system
    # cgroup for system_server and surfaceflinger
    mkdir /dev/memcg/system 0550 system system
    start ueventd
    # Run apexd-bootstrap so that APEXes that provide critical libraries
    # become available. Note that this is executed as exec_start to ensure that
    # the libraries are available to the processes started after this statement.
    exec_start apexd-bootstrap

紧接着是一个Action,Action的Trigger 为early-init,在这个 Action中,我们需要关注最后两行,它启动了ueventd服务和apex相关服务。还记得什么是ueventd和apex吗?不记得的读者请往上翻越再自行回顾一下。

ueventd服务的定义也可以在init.rc文件的结尾找到,具体代码及含义如下:

service ueventd    //ueventd服务的可执行文件的路径为 /system/bin/ueventd
    class core    //ueventd 归属于 core class,同样归属于core class的还有adbd 、console等服务
    critical //表明这个Service对设备至关重要,如果Service在四分钟内退出超过4次,则设备将重启进入恢复模式。
    seclabel u:r:ueventd:s0 //selinux相关的配置
    shutdown critical  //ueventd服务关闭行为

然而,early-init 这个Trigger到底什么时候触发呢?

答案是通过init.cpp代码调用触发。

我们可以在init.cpp 代码中找到如下代码片段:

am.QueueEventTrigger("early-init");

QueueEventTrigger这个方法的实现机制我们稍后再进行探讨,目前我们只需要了解, ActionManager 这个类中的 QueueEventTrigger方法,负责触发init.rc中的Action。

我们继续往下看init.rc的内容。

on init
    ...
    # Start logd before any other services run to ensure we capture all of their logs.
    start logd
    # Start essential services.
    start servicemanager
    ...

在Trigger 为init的Action中,我们只需要关注以上的关键内容。在init的action中启动了一些核心的系统服务,这些服务具体的含义为 :

服务名 含义
logd Android L加入的服务,用于保存Android运行期间的日志
servicemanager android系统服务管理者,负责查询和注册服务

接下来是late-init Action:

on late-init
    //启动vold服务(管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等)
    trigger early-fs
    trigger fs
    trigger post-fs
    trigger late-fs
    //挂载/data , 启动 apexd 服务
    trigger post-fs-data
    # 读取持久化属性或者从/data 中读取并覆盖属性
    trigger load_persist_props_action
    //启动zygote服务!!在启动zygote服务前会先启动netd服务(专门负责网络管理和控制的后台守护进程)
    trigger zygote-start
    //移除/dev/.booting 文件
    trigger firmware_mounts_complete
    trigger early-boot
    trigger boot  //初始化网络环境,设置系统环境和守护进程的权限

最后,我们用流程图来总结一下上述的启动过程:

以上就是Android 10 启动Init进程解析的详细内容,更多关于Android 10 启动Init进程的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Init进程对信号的处理流程详细介绍

    Android  Init进程对信号的处理流程 在Android中,当一个进程退出(exit())时,会向它的父进程发送一个SIGCHLD信号.父进程收到该信号后,会释放分配给该子进程的系统资源:并且父进程需要调用wait()或waitpid()等待子进程结束.如果父进程没有做这种处理,且父进程初始化时也没有调用signal(SIGCHLD, SIG_IGN)来显示忽略对SIGCHLD的处理,这时子进程将一直保持当前的退出状态,不会完全退出.这样的子进程不能被调度,所做的只是在进程列表中占据一个

  • 深入剖析Android中init进程实现的C语言源码

    概述 init是一个进程,确切的说,它是Linux系统中用户空间的第一个进程.由于Android是基于Linux内核的,所以init也是Android系统中用户空间的第一个进程.init的进程号是1.作为天字第一号进程,init有很多重要的工作: init提供property service(属性服务)来管理Android系统的属性. init负责创建系统中的关键进程,包括zygote. 以往的文章一上来就介绍init的源码,但是我这里先从这两个主要工作开始.搞清楚这两个主要工作是如何实现的,我

  • Android init.rc文件简单介绍

    Android init.rc文件简单介绍 init.rc脚本是由Android中linux的第一个用户级进程init进行解析的. init.rc 文件并不是普通的配置文件,而是由一种被称为"Android初始化语言"(Android Init Language,这里简称为AIL)的脚本写成的文件. 该文件在ROM中是只读的,即使有了root权限,可以修改该文件也没有.因为我们在根目录看到的文件只是内存文件的镜像.也就是说,android启动后,会将init.rc文件装载到内存.而修改

  • Android中init.rc文件的解析 分享

    对init.rc的解析是在parse_config(): [system/core/init/init_parser.c]中进行的.解析发生在init全过程中的哪个阶段,参看<Android init进程启动过程分析>. 一.解析过程 1.      扫描init.rc中的token 找到其中的 文件结束EOF/文本TEXT/新行NEWLINE,其中的空格' '.'\t'.'\r'会被忽略,#开头的行也被忽略掉: 而对于TEXT,空格' '.'\t'.'\r'.'\n'都是TEXT的结束标志.

  • Android init.rc文件详解及简单实例

    Android init.rc文件详解 本文主要来自$ANDROID_SOURCE/system/init/readme.txt的翻译. 1 简述 Android init.rc文件由系统第一个启动的init程序解析,此文件由语句组成,主要包含了四种类型的语句:Action,Commands,Services,Options.在init.rc文件中一条语句通常是占据一行.单词之间是通过空格符来相隔的.如果需要在单词内使用空格,那么得使用转义字符"\",如果在一行的末尾有一个反斜杠,那么

  • Android miniTwitter登录界面开发实例

    本文要演示的Android开发实例是如何完成一个Android中的miniTwitter登录界面,下面将分步骤讲解怎样实现图中的界面效果,让大家都能轻松的做出美观的登录界面. 先贴上最终要完成的效果图: miniTwitter登录界面的布局分析 首先由界面图分析布局,基本可以分为三个部分,下面分别讲解每个部分. 第一部分是一个带渐变色背景的LinearLayout布局,关于背景渐变色就不再贴代码了,效果如下图所示: 第二部分,红色线区域内,包括1,2,3,4 如图所示: 红色的1表示的是一个带圆

  • Android 10 启动Init进程解析

    目录 按下电源键时,android做了啥? init进程解析 FirstStageMain SetupSelinux SecondStageMain init.rc 解析 按下电源键时,android做了啥? 当我们按下电源键时,手机开始上电,并从地址0x00000000处开始执行,而这个地址通常是Bootloader程序的首地址. bootloader是一段裸机程序,是直接与硬件打交道的,其最终目的是“初始化并检测硬件设备,准备好软件环境,最后调用操作系统内核”.除此之外,bootloader

  • Android 10 启动分析之init语法详解

    目录 正文 Actions Services Options Triggers Commands Imports 正文 init.rc脚本包含5种类型,Action(动作),Commands(命令), Services(服务),Options(选项), Imports(导入). 以上这些都是基于“行”来解析的,并且用空格隔开关键字. 如果关键字中有空格,处理方法类似于C语言,使用/表示转义,使用""防止关键字被断开,另外需要注意/在末尾表示换行. #开头表示注释. 可以使用语法 ${p

  • Android 10 启动之servicemanager源码解析

    目录 正文 获取服务 注册服务 正文 上一篇文章: Android 10 启动分析之Init篇 (一) 在前文提到,init进程会在在Trigger 为init的Action中,启动servicemanager服务,这篇文章我们就来具体分析一下servicemanager服务,它到底做了哪些事情. servicemanager服务的源码位于/frameworks/native/cmds/servicemanager/service_manager.c,我们将从这个类的入口开始看起. int ma

  • Android Activity启动模式全面解析

    在android里,有4种activity的启动模式,分别为: "standard" (默认) "singleTop" "singleTask" "singleInstance" 在Android应用中, Activity是最核心的组件, 如何生成一个Activity实例, 可以选择不同的启动模式, 即LaunchMode. 启动模式主要包括: standard, singleTop, singleTask, singleIn

  • Android10 App 启动分析进程创建源码解析

    目录 正文 RootActivityContainer ActivityStartController 调用startActivityUnchecked方法 ActivityStackSupervisor 启动进程 RuntimeInit.applicationInit这个方法 正文 从前文# Android 10 启动分析之SystemServer篇 (四)中可以得知,系统在完成所有的初始化工作后,会通过 mAtmInternal.startHomeOnAllDisplays(currentU

  • Android后台启动Activity的实现示例

    目录 概述 原生Android ROM 定制化ROM 检测后台弹出界面权限 Android P后台启动权限 Android Q后台启动权限 总结 概述 前几天产品提了一个需求,想在后台的时候启动我们 APP 的一个 Activity,随着 Android 版本的更新,以及各家 ROM 厂商的无限改造,这种影响用户体验的功能许多都受到了限制,没办法,虽然是比较流氓的功能,但拿人钱财替人消灾,于是开启了哼哧哼哧的调研之路. 原生Android ROM 首先从 Android 的原生 ROM 开始,根

  • Android zygote启动流程详解

    对zygote的理解 在Android系统中,zygote是一个native进程,是所有应用进程的父进程.而zygote则是Linux系统用户空间的第一个进程--init进程,通过fork的方式创建并启动的. 作用 zygote进程在启动时,会创建一个Dalvik虚拟机实例,每次孵化新的应用进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面,从而使得每个应用程序进程都有一个独立的Dalvik虚拟机实例. zygote进程的主要作用有两个: 启动SystemServer. 孵化应用

  • Android AMS启动详解

    启动 在Android系统启动流程中中我们提到过,AMS是在system_service中启动的, //frameworks/base/services/java/corri/android/server/SystemServer.java //该方法主要启动服务 ActivityManagerService,PowerManagerService,LightsService,DisplayManagerService,PackageManagerService,UserManagerServi

随机推荐