启动流程(基于openharmony4.1
)
系统上电加载内核后,按照以下流程完成系统各个服务和应用的启动:
- 内核加载init进程,一般在bootloader启动内核时通过设置内核的cmdline来指定init的位置。
- init进程启动后,会挂载tmpfs,procfs,创建基本的dev设备节点,提供最基本的根文件系统。
- init也会启动ueventd监听内核热插拔设备事件,为这些设备创建dev设备节点。包括block设备各个分区设备都是通过此事件创建。
- init进程挂载block设备各个分区(system,vendor)后,开始扫描各个系统服务的init启动脚本,并拉起各个SA服务。
- samgr是各个SA的服务注册中心,每个SA启动时,都需要向samgr注册,每个SA会分配一个ID,应用可以通过该ID访问SA。
- foundation是一个特殊的SA服务进程,提供了用户程序管理框架及基础服务。由该进程负责应用的生命周期管理。
- 由于应用都需要加载JS的运行环境,涉及大量准备工作,因此appspawn作为应用的孵化器,在接收到foundation里的应用启动请求时,可以直接孵化出应用进程,减少应用启动时间。
启动子系统内部涉及以下组件:
-
init启动引导组件
init启动引导组件对应的进程为init进程,是内核完成初始化后启动的第一个用户态进程。init进程启动之后,读取init.cfg配置文件,根据解析结果,执行相应命令(见job解析接口说明)并依次启动各关键系统服务进程,在启动系统服务进程的同时设置其对应权限。
-
ueventd启动引导组件
ueventd负责监听内核设备驱动插拔的netlink事件,根据事件类型动态管理相应设备的dev节点。
-
appspawn应用孵化组件
负责接收用户程序框架的命令孵化应用进程,设置新进程的权限,并调用应用程序框架的入口函数。
-
bootstrap服务启动组件
提供了各服务和功能的启动入口标识。在SAMGR启动时,会调用bootstrap标识的入口函数,并启动系统服务。
图1 启动子系统上下文结构图
约束与限制
启动恢复子系统源代码目录和适配平台:
表1 启动恢复子系统源代码目录和适配平台
名称 | 适配平台 |
---|---|
base/startup/appspawne | 小型系统设备(参考内存≥1MB)、 标准系统,如Hi3516DV300 、Hi3518EV300、 RK3568 |
base/startup/bootstrap_lite | 轻量系统设备(参考内存≥128KB),如Hi3861V100 |
base/startup/init | 小型系统设备(参考内存≥1MB)、标准系统,如Hi3516DV300、Hi3518EV300、RK3568 |
-
init启动引导组件:
- 每个系统服务启动时都需要编写各自的启动脚本文件
init.cfg
,定义各自的服务名、可执行文件路径、权限和其他信息。 - 每个系统服务各自安装其启动脚本到
/system/etc/init
目录下,init进程统一扫码执行。
- 每个系统服务启动时都需要编写各自的启动脚本文件
-
新芯片平台移植时,平台相关的初始化配置需要增加平台相关的初始化配置文件
/vendor/etc/init/init.{hardware}.cfg
;该文件完成平台相关的初始化设置,如安装ko驱动,设置平台相关的/proc节点信息。说明:
配置文件init.cfg仅支持json格式。
-
bootstrap服务启动组件:需要在链接脚本中配置zInit代码段。
bootstrap服务启动组件实现了服务的自动初始化,即服务的初始化函数无需显式调用,而是将其使用宏定义的方式申明,就会在系统启动时自动被执行。实现原理是将服务启动的函数通过宏定义的方式申明之后,放在预定义好的zInit代码段中,系统启动的时候调用OHOS_SystemInit接口遍历该代码段并调用其中的函数。因此,需要在链接脚本中添加zInit段,并且在main函数里调用OHOS_SystemInit接口。
zInit段的添加可参考已有的Hi3861平台的链接脚本,文件路径为vendor/hisi/hi3861/hi3861/build/link/link.ld.S。
用于实现服务的自动初始化的宏定义接口请参见启动恢复子系统的API接口文档。
接口说明
bootstrap服务自动初始化宏如表1所述。
表1 主要的服务自动初始化宏
接口名 描述 SYS_SERVICE_INIT(func) 标识核心系统服务的初始化启动入口。 SYS_FEATURE_INIT(func) 标识核心系统功能的初始化启动入口。 APP_SERVICE_INIT(func) 标识应用层服务的初始化启动入口。 APP_FEATURE_INIT(func) 标识应用层功能的初始化启动入口。 开发实例
服务自动初始化宏使用实例:
void SystemServiceInit(void) { printf("Init System Service\n"); } SYS_SERVICE_INIT(SystemServiceInit); void SystemFeatureInit(void) { printf("Init System Feature\n"); } SYS_FEATURE_INIT(SystemFeatureInit); void AppServiceInit(void) { printf("Init App Service\n"); } APP_SERVICE_INIT(AppServiceInit); void AppFeatureInit(void) { printf("Init App Feature\n"); } APP_FEATURE_INIT(AppFeatureInit); // 日志打印顺序为: // Init System Service // Init System Feature // Init App Service // Init App Feature
启动引导OpenHarmony标准系统的详细流程
当前OpenHarmony标准系统默认支持以下几个镜像:
镜像名称 | 挂载点 | 说明 |
---|---|---|
boot.img | NA | 内核和ramdisk镜像,bootloader加载的第一个镜像 |
system.img | /system | 系统组件镜像,存放与芯片方案无关的平台业务 |
vendor.img | /vendor | 芯片组件镜像,存放芯片相关的硬件抽象服务 |
updater.img | / | 升级组件镜像,用于完成升级;正常启动时不加载次镜像 |
userdata.img | /data | 可写的用户数据镜像 |
每个开发板都需要在存储器上划分好分区来存放上述镜像,SOC启动时都由bootloader来加载这些镜像,具体过程包括以下几个大的步骤:
- bootloader初始化ROM和RAM等硬件,加载分区表信息。
- bootloader根据分区表加载
boot.img
,从中解析并加载ramdisk.img
到内存中。 - bootloader准备好分区表信息,ramdisk地址等信息,进入内核,内核加载ramdisk并执行init。
- init准备初始文件系统,挂载
required.fstab
(包括system.img
和vendor.img
的挂载)。 - 扫描
system.img
和vendor.img
中etc/init
目录下的启动配置脚本,执行各个启动命令。
u-boot启动
-
u-boot加载
支持了ramdisk的启动过程,此场景需要修改productdefine中的产品配置文件,通过"enable_ramdisk"开关开启ramdisk生成,这一部分与平台相关,不同的平台对于ramdisk的处理方式不一样。以Hi3516DV300平台为例,需要将u-boot中的原启动参数修改为
root=/dev/ram0 initrd=0x84000000,0x292e00
。
uboot引导内核启动
-
u-boot进入
u-boot启动进入内核时,可以通过bootargs传递关键信息给内核,这一部分内容是与平台相关的,主要信息如下:
名称 示例 说明 initrd 0x84000000,0x292e00 参考内核文档。 ramfs-rootfs-initramfs.rst initrd.rst init /init blkdevparts mmcblk0:1M(boot),15M(kernel),200M(system),200M(vendor), 2M(misc),20M(updater),-(userdata) 分区表信息,kernel会根据此信息创建物理分区。 hardware Hi3516DV300、rk3568等 (必要信息)硬件平台。 root /dev/ram0(Hi3516DV00)、root=PARTUUID=614e0000-0000 rw(rk3568) kernel加载的启动设备。 rootfstype ext4 根文件系统类型。 default_boot_device soc/10100000.himci.eMMC (建议配置信息)默认启动设备,在启动第一阶段会根据这个参数创建required设备的软链接。 ohos.required_mount.xxx /dev/block/platform/soc/10100000.himci.eMMC/by-name/xxx@/usr@ext4@ro,barrier=1@wait,required 现支持从cmdline中读取fstab信息,获取失败的情况下,会继续尝试从fstab.required文件中读取
图 内核启动流程图
表 启动框架层级
层级 | 说明 |
---|---|
LOS_INIT_LEVEL_EARLIEST | 最早期初始化 说明:不依赖架构,单板以及后续模块会对其有依赖的纯软件模块初始化 例如:Trace模块 |
LOS_INIT_LEVEL_ARCH_EARLY | 架构早期初始化 说明:架构相关,后续模块会对其有依赖的模块初始化,如启动过程中非必需的功能,建议放到LOS_INIT_LEVEL_ARCH层 |
LOS_INIT_LEVEL_PLATFORM_EARLY | 平台早期初始化 说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化,如启动过程中必需的功能,建议放到LOS_INIT_LEVEL_PLATFORM层 例如:uart模块 |
LOS_INIT_LEVEL_KMOD_PREVM | 内存初始化前的内核模块初始化 说明:在内存初始化之前需要使能的模块初始化 |
LOS_INIT_LEVEL_VM_COMPLETE | 基础内存就绪后的初始化 说明:此时内存初始化完毕,需要进行使能且不依赖进程间通讯机制与系统进程的模块初始化 例如:共享内存功能 |
LOS_INIT_LEVEL_ARCH | 架构后期初始化 说明:架构拓展功能相关,后续模块会对其有依赖的模块初始化 |
LOS_INIT_LEVEL_PLATFORM | 平台后期初始化 说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化 例如:驱动内核抽象层初始化(mmc、mtd) |
LOS_INIT_LEVEL_KMOD_BASIC | 内核基础模块初始化 说明:内核可拆卸的基础模块初始化 例如:VFS初始化 |
LOS_INIT_LEVEL_KMOD_EXTENDED | 内核扩展模块初始化 说明:内核可拆卸的扩展模块初始化 例如:系统调用初始化、ProcFS初始化、Futex初始化、HiLog初始化、HiEvent初始化、LiteIPC初始化 |
LOS_INIT_LEVEL_KMOD_TASK | 内核任务创建 说明:进行内核任务的创建(内核任务,软件定时器任务) 例如:资源回收系统常驻任务的创建、SystemInit任务创建、CPU占用率统计任务创建 |
LOS_INIT_LEVEL_FINISH | 内核初始化完成 |
汇编阶段(LiteOS-A内核)
uboot引导LiteOS-A启动入口:
kernel\liteos_a\tools\build\liteos.ld
ENTRY(reset_vector)
INCLUDE board.ld
SECTIONS
{
_start = .;
.set_sysinit_set : {
__start_set_sysinit_set = ABSOLUTE(.);
KEEP (*(.set_sysinit_set))
__stop_set_sysinit_set = ABSOLUTE(.);
} > ram
.
.
.
}
reset_vector就是整个鸿蒙内核启动入口点,这是个符号,定义在:
kernel\liteos_a\arch\arm\arm\src\startup\reset_vector_mp.S, 这个文件是多核使用的,同目录下的reset_vector_up.S是单核使用的。
bl main
_start_hang:
b _start_hang
通过main函数进入内核的C语言阶段
c语言阶段(LiteOS-A内核)
kernel\liteos_a\kernel\common\main.c
/**
* @brief
* 内核入口函数,由汇编调用,见于reset_vector_up.S 和 reset_vector_mp.S
* up指单核CPU, mp指多核CPU bl main
* @return LITE_OS_SEC_TEXT_INIT
*/
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)//由主CPU执行,默认0号CPU 为主CPU
{
UINT32 ret = OsMain();
if (ret != LOS_OK) {
return (INT32)LOS_NOK;
}
CPU_MAP_SET(0, OsHwIDGet());//设置主CPU映射信息
OsSchedStart();//调度开始
while (1) {
__asm volatile("wfi");//WFI: wait for Interrupt 等待中断,即下一次中断发生前都在此hold住不干活
}
}
kernel\liteos_a\kernel\common\los_config.c
///由汇编调用,鸿蒙C语言层级的入口点
LITE_OS_SEC_TEXT_INIT UINT32 OsMain(VOID)
{
UINT32 ret;
#ifdef LOS_INIT_STATISTICS
UINT64 startNsec, endNsec, durationUsec;
#endif
ret = EarliestInit();//鸿蒙初开,天地混沌
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_EARLIEST);
ret = ArchEarlyInit(); //架构级初始化,包括硬中断
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_ARCH_EARLY);
ret = PlatformEarlyInit();//平台级初始化
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_PLATFORM_EARLY);
/* system and chip info */
OsSystemInfo();
PRINT_RELEASE("\nmain core booting up...\n");
#ifdef LOS_INIT_STATISTICS
startNsec = LOS_CurrNanosec();
#endif
//进程模块初始化
ret = OsProcessInit();
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_KMOD_PREVM);
ret = OsSysMemInit();//系统内存初始化
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_VM_COMPLETE);
ret = OsIpcInit();//进程间通讯模块初始化
if (ret != LOS_OK) {
return ret;
}
ret = OsSystemProcessCreate();//创建系统进程
if (ret != LOS_OK) {
return ret;
}
ret = ArchInit(); //MMU架构初始化
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_ARCH);
ret = PlatformInit();
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_PLATFORM);
ret = KModInit();
if (ret != LOS_OK) {
return ret;
}
OsInitCall(LOS_INIT_LEVEL_KMOD_BASIC);
OsInitCall(LOS_INIT_LEVEL_KMOD_EXTENDED);
#ifdef LOSCFG_KERNEL_SMP
OsSmpInit();
#endif
OsInitCall(LOS_INIT_LEVEL_KMOD_TASK);
#ifdef LOS_INIT_STATISTICS
endNsec = LOS_CurrNanosec();
durationUsec = (endNsec - startNsec) / OS_SYS_NS_PER_US;
PRINTK("The main core takes %lluus to start.\n", durationUsec);
#endif
return LOS_OK;
}
......
/*! 进程模块初始化,被编译放在代码段 .init 中*/
UINT32 OsProcessInit(VOID)
{
UINT32 index;
UINT32 size;
UINT32 ret;
g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT;//默认支持64个进程
size = (g_processMaxNum + 1) * sizeof(LosProcessCB);
g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);// 进程池,占用内核堆,内存池分配
if (g_processCBArray == NULL) {
return LOS_NOK;
}
(VOID)memset_s(g_processCBArray, size, 0, size);//安全方式重置清0
LOS_ListInit(&g_freeProcess);//进程空闲链表初始化,创建一个进程时从g_freeProcess中申请一个进程描述符使用
LOS_ListInit(&g_processRecycleList);//进程回收链表初始化,回收完成后进入g_freeProcess等待再次被申请使用
for (index = 0; index < g_processMaxNum; index++) {//进程池循环创建
g_processCBArray[index].processID = index;//进程ID[0-g_processMaxNum-1]赋值
g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;// 默认都是白纸一张,贴上未使用标签
LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList);//注意g_freeProcess挂的是pendList节点,所以使用要通过OS_PCB_FROM_PENDLIST找到进程实体.
}
/* Default process to prevent thread PCB from being empty */
g_processCBArray[index].processID = index;
g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;
ret = OsTaskInit((UINTPTR)&g_processCBArray[g_processMaxNum]);
if (ret != LOS_OK) {
(VOID)LOS_MemFree(m_aucSysMem1, g_processCBArray);
return LOS_OK;
}
#ifdef LOSCFG_KERNEL_CONTAINER
OsInitRootContainer();
#endif
#ifdef LOSCFG_KERNEL_PLIMITS
OsProcLimiterSetInit();
#endif
SystemProcessEarlyInit(OsGetIdleProcess());//初始化 0,1,2号进程
SystemProcessEarlyInit(OsGetUserInitProcess());
SystemProcessEarlyInit(OsGetKernelInitProcess());
return LOS_OK;
}
.
.
.
.
.
.
#ifndef LOSCFG_PLATFORM_ADAPT
STATIC VOID SystemInit(VOID)
{
PRINTK("dummy: *** %s ***\n", __FUNCTION__);
}
#else
extern VOID SystemInit(VOID);
#endif
#ifndef LOSCFG_ENABLE_KERNEL_TEST
///创建系统初始任务并申请调度
STATIC UINT32 OsSystemInitTaskCreate(VOID)
{
UINT32 taskID;
TSK_INIT_PARAM_S sysTask;
(VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit;//任务入口函数
sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16k
sysTask.pcName = "SystemInit";//任务名称
sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;//内核默认优先级10
sysTask.uwResved = LOS_TASK_STATUS_DETACHED;//任务分离模式
#ifdef LOSCFG_KERNEL_SMP
sysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
#endif
return LOS_TaskCreate(&taskID, &sysTask);
}
//系统任务初始化
STATIC UINT32 OsSystemInit(VOID)
{
UINT32 ret;
ret = OsSystemInitTaskCreate();
if (ret != LOS_OK) {
return ret;
}
return 0;
}
//在内核初始化的时候初始化该模块,则通过内核启动框架将该模块的初始化函数注册进内核启动流程
LOS_MODULE_INIT(OsSystemInit, LOS_INIT_LEVEL_KMOD_TASK);//模块初始化
#endif
通过上述调用最终调用到SystemInit任务,跳转到soc的SystemInit()做系统初始化。
device\soc\hisilicon\hi3516dv300\sdk_liteos\mpp\module_init\src\system_init.c
void SystemInit(void)
{
SystemInit_QuickstartInit();
SystemInit_IPCM();
SystemInit_RandomInit();
SystemInit_MMCInit();
SystemInit_MemDevInit();
SystemInit_GpioDevInit();
SystemInit_SDKInit();
SystemInit_HDFInit();
SystemInit_NetInit(); /* need to check later */
SystemInit_MountRootfs();
SystemInit_ConsoleInit();
#ifndef LOSCFG_DRIVERS_QUICKSTART
SystemInit1();
SystemInit2();
SystemInit3();
#endif
SystemInit_UserInitProcess();
}
void SystemInit_UserInitProcess(void)
{
if (OsUserInitProcess()) {//跳转回到内核创建1号init进程
PRINT_ERR("Create user init process faialed!\n");
return;
}
return;
}
kernel\liteos_a\kernel\base\core\los_process.c
LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID)
{
UINT32 ret;
UINT32 size;
TSK_INIT_PARAM_S param = { 0 };
VOID *stack = NULL;
//获取用户态进程的根进程,所有用户进程都是g_processCBArray[g_userInitProcess] fork来的
LosProcessCB *processCB = OsGetUserInitProcess();
ret = OsSystemProcessInit(processCB, OS_USER_MODE, "Init");// 进程创建初始化
if (ret != LOS_OK) {
return ret;
}
ret = OsLoadUserInit(processCB);
if (ret != LOS_OK) {
goto ERROR;
}
stack = OsUserInitStackAlloc(processCB, &size);//初始化堆栈区,分配栈内存
if (stack == NULL) {
PRINT_ERR("Alloc user init process user stack failed!\n");
goto ERROR;
}
//代码区开始位置,对应LITE_USER_SEC_ENTRY
param.pfnTaskEntry = (TSK_ENTRY_FUNC)(CHAR *)&__user_init_entry;
param.userParam.userSP = (UINTPTR)stack + size;//指向栈顶
param.userParam.userMapBase = (UINTPTR)stack;//栈底
param.userParam.userMapSize = size;//栈大小
param.uwResved = OS_TASK_FLAG_PTHREAD_JOIN;//能够被其他线程收回其资源和啥事
ret = OsUserInitProcessStart(processCB, ¶m);//用户进程开始初始化
if (ret != LOS_OK) {
(VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);
goto ERROR;
}
return LOS_OK;
ERROR:
OsDeInitPCB(processCB);
return ret;
}
STATIC UINT32 OsUserInitProcessStart(LosProcessCB *processCB, TSK_INIT_PARAM_S *param)
{
UINT32 intSave;
INT32 ret;
UINT32 taskID = OsCreateUserTask((UINTPTR)processCB, param);
if (taskID == OS_INVALID_VALUE) {
return LOS_NOK;
}
//设置进程优先级
ret = LOS_SetProcessPriority(processCB->processID, OS_PROCESS_USERINIT_PRIORITY);
if (ret != LOS_OK) {
PRINT_ERR("User init process set priority failed! ERROR:%d \n", ret);
goto EXIT;
}
SCHEDULER_LOCK(intSave);
processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;
SCHEDULER_UNLOCK(intSave);
//调度器:设置为抢占式调度和最低任务优先级(31级)
ret = LOS_SetTaskScheduler(taskID, LOS_SCHED_RR, OS_TASK_PRIORITY_LOWEST);
if (ret != LOS_OK) {
PRINT_ERR("User init process set scheduler failed! ERROR:%d \n", ret);
goto EXIT;
}
return LOS_OK;
EXIT:
(VOID)LOS_TaskDelete(taskID);
return ret;
}
__user_init_entry在编译链接文件
kernel\liteos_a\tools\build\liteos.ld 中
.user_init USER_INIT_VM_START : ALIGN(0x1000) {
. = ALIGN(0x4);
__user_init_load_addr = LOADADDR(.user_init);
__user_init_entry = .;
KEEP(libuserinit.O (.user.entry))//地址指向镜像的.user.entry
KEEP(libuserinit.O (.user.text))
KEEP(libuserinit.O (.user.rodata))
. = ALIGN(0X4);
__user_init_data = .;
KEEP(libuserinit.O (.user.data))
. = ALIGN(0X4);
__user_init_bss = .;
KEEP(libuserinit.O (.user.bss))
. = ALIGN(0x1000);
__user_init_end = .;
} > user_ram AT > ram
.user.entry通过宏定义在
kernel\liteos_a\kernel\user\include\los_user_init.h中
#ifndef LITE_USER_SEC_TEXT
#define LITE_USER_SEC_TEXT __attribute__((section(".user.text")))
#endif
#ifndef LITE_USER_SEC_ENTRY
#define LITE_USER_SEC_ENTRY __attribute__((section(".user.entry")))
#endif
#ifndef LITE_USER_SEC_DATA
#define LITE_USER_SEC_DATA __attribute__((section(".user.data")))
#endif
#ifndef LITE_USER_SEC_RODATA
#define LITE_USER_SEC_RODATA __attribute__((section(".user.rodata")))
#endif
#ifndef LITE_USER_SEC_BSS
#define LITE_USER_SEC_BSS __attribute__((section(".user.bss")))
#endif
init进程启动进入函数OsUserInit
kernel\liteos_a\kernel\user\src\los_user_init.c
#ifdef LOSCFG_QUICK_START
LITE_USER_SEC_RODATA STATIC CHAR *g_initPath = "/dev/shm/init";
#else
LITE_USER_SEC_RODATA STATIC CHAR *g_initPath = "/bin/init";//由Init_lite在编译后,生成
#endif
///将 sys_call3 链接在 section(".user.text")段
LITE_USER_SEC_TEXT STATIC UINT32 sys_call3(UINT32 nbr, UINT32 parm1, UINT32 parm2, UINT32 parm3)
{
register UINT32 reg7 __asm__("r7") = (UINT32)(nbr); //系统调用号给了R7寄存器
register UINT32 reg2 __asm__("r2") = (UINT32)(parm3);//R2 = 参数3
register UINT32 reg1 __asm__("r1") = (UINT32)(parm2);//R1 = 参数2
register UINT32 reg0 __asm__("r0") = (UINT32)(parm1);//R0 = 参数1
//SVC指令会触发一个特权调用异常。这为非特权软件调用操作系统或其他只能在PL1级别访问的系统组件提供了一种机制。
__asm__ __volatile__
(
"svc %1" //管理模式(svc) [10011]:操作系统使用的保护模式
: "=r"(reg0) //输出寄存器为R0
: "i"(SYS_CALL_VALUE), "r"(reg7), "r"(reg0), "r"(reg1), "r"(reg2)
: "memory", "r14"
);
//相当于执行了 reset_vector_mp.S 中的 向量表0x08对应的 _osExceptSwiHdl
return reg0;//reg0的值将在汇编中改变.
}
LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
{
#ifdef LOSCFG_KERNEL_DYNLOAD
sys_call3(__NR_execve, (UINTPTR)g_initPath, 0, 0);//发起系统调用,陷入内核态,对应 SysExecve ,加载elf运行
#endif
while (true) {
}
}
#endif
最终启动了/bin/init可执行程序
标准linux内核
kernel\linux\linux-5.10\init\main.c
各种模块的初始化
asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
char *command_line;
char *after_dashes;
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
cgroup_init_early();
local_irq_disable();
early_boot_irqs_disabled = true;
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them.
*/
boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
early_security_init();
setup_arch(&command_line);
setup_boot_config(command_line);
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
boot_cpu_hotplug_init();
build_all_zonelists(NULL);
page_alloc_init();
pr_notice("Kernel command line: %s\n", saved_command_line);
/* parameters may set static keys */
jump_label_init();
parse_early_param();
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, NULL, &unknown_bootoption);
if (!IS_ERR_OR_NULL(after_dashes))
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
NULL, set_init_arg);
if (extra_init_args)
parse_args("Setting extra init args", extra_init_args,
NULL, 0, -1, -1, NULL, set_init_arg);
/*
* These use large bootmem allocations and must precede
* kmem_cache_init()
*/
setup_log_buf(0);
vfs_caches_init_early();
sort_main_extable();
trap_init();
mm_init();
ftrace_init();
/* trace_printk can be enabled here */
early_trace_init();
/*
* Set up the scheduler prior starting any interrupts (such as the
* timer interrupt). Full topology setup happens at smp_init()
* time - but meanwhile we still have a functioning scheduler.
*/
sched_init();
if (WARN(!irqs_disabled(),
"Interrupts were enabled *very* early, fixing it\n"))
local_irq_disable();
radix_tree_init();
/*
* Set up housekeeping before setting up workqueues to allow the unbound
* workqueue to take non-housekeeping into account.
*/
housekeeping_init();
/*
* Allow workqueue creation and work item queueing/cancelling
* early. Work item execution depends on kthreads and starts after
* workqueue_init().
*/
workqueue_init_early();
rcu_init();
/* Trace events are available after this */
trace_init();
if (initcall_debug)
initcall_debug_enable();
context_tracking_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ();
tick_init();
rcu_init_nohz();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
/*
* For best initial stack canary entropy, prepare it after:
* - setup_arch() for any UEFI RNG entropy and boot cmdline access
* - timekeeping_init() for ktime entropy used in random_init()
* - time_init() for making random_get_entropy() work on some platforms
* - random_init() to initialize the RNG from from early entropy sources
*/
random_init(command_line);
boot_init_stack_canary();
perf_event_init();
profile_init();
call_function_init();
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;
local_irq_enable();
kmem_cache_init_late();
/*
* HACK ALERT! This is early. We're enabling the console before
* we've done PCI setups etc, and console_init() must be aware of
* this. But we do want output early, in case something goes wrong.
*/
console_init();
if (panic_later)
panic("Too many boot %s vars at `%s'", panic_later,
panic_param);
lockdep_init();
/*
* Need to run this when irqs are enabled, because it wants
* to self-test [hard/soft]-irqs on/off lock inversion bugs
* too:
*/
locking_selftest();
/*
* This needs to be called before any devices perform DMA
* operations that might use the SWIOTLB bounce buffers. It will
* mark the bounce buffers as decrypted so that their usage will
* not cause "plain-text" data to be decrypted when accessed.
*/
mem_encrypt_init();
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
page_to_pfn(virt_to_page((void *)initrd_start)),
min_low_pfn);
initrd_start = 0;
}
#endif
setup_per_cpu_pageset();
numa_policy_init();
acpi_early_init();
if (late_time_init)
late_time_init();
sched_clock_init();
calibrate_delay();
pid_idr_init();
anon_vma_init();
#ifdef CONFIG_X86
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
#endif
thread_stack_cache_init();
cred_init();
fork_init();
proc_caches_init();
uts_ns_init();
buffer_init();
key_init();
security_init();
dbg_late_init();
vfs_caches_init();
pagecache_init();
signals_init();
seq_file_init();
proc_root_init();
nsfs_init();
cpuset_init();
cgroup_init();
taskstats_init_early();
delayacct_init();
#ifdef CONFIG_RECLAIM_ACCT
reclaimacct_init();
#endif
poking_init();
check_bugs();
acpi_subsystem_init();
arch_post_acpi_subsys_init();
sfi_init_late();
kcsan_init();
/* Do the rest non-__init'ed, we're now alive */
arch_call_rest_init();
prevent_tail_call_optimization();
}
.
.
.
.
.
void __init __weak arch_call_rest_init(void)
{
rest_init();
}
noinline void __ref rest_init(void)
{
struct task_struct *tsk;
int pid;
rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
启动1号进程init
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
/*
* Pin init on the boot CPU. Task migration is not properly working
* until sched_init_smp() has been run. It will set the allowed
* CPUs for init to the non isolated CPUs.
*/
rcu_read_lock();
tsk = find_task_by_pid_ns(pid, &init_pid_ns);
set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));
rcu_read_unlock();
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
/*
* Enable might_sleep() and smp_processor_id() checks.
* They cannot be enabled earlier because with CONFIG_PREEMPTION=y
* kernel_thread() would trigger might_sleep() splats. With
* CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled
* already, but it's stuck on the kthreadd_done completion.
*/
system_state = SYSTEM_SCHEDULING;
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE);
}
.
.
.
.
.
.
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
kprobe_free_init_mem();
ftrace_free_init_mem();
kgdb_free_init_mem();
free_initmem();
mark_readonly();
/*
* Kernel mappings are now finalized - update the userspace page-table
* to finalize PTI.
*/
pti_finalize();
system_state = SYSTEM_RUNNING;
numa_default_policy();
rcu_end_inkernel_boot();
do_sysctl_args();
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)\n",
ramdisk_execute_command, ret);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}
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;
}
//最终启动了/bin/init可执行程序,同liteos-a
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;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
init进程 (标准系统)
通过BUILD.gn可知如下路径代码编译成了可执行程序init
base\startup\init\services\init\standard\BUILD.gn
ohos_executable("init") {
sources = [
"../adapter/init_adapter.c",
"../standard/device.c",
"../standard/fd_holder_service.c",
"../standard/init.c",
"../standard/init_cmdexecutor.c",
"../standard/init_cmds.c",
"../standard/init_control_fd_service.c",
"../standard/init_firststage.c",
"../standard/init_jobs.c",
"../standard/init_mount.c",
"../standard/init_reboot.c",
"../standard/init_service.c",
"../standard/init_signal_handler.c",
"../standard/switch_root.c",
"bootstagehooker.c",
]
......
}
从init进程main函数开始
base\startup\init\services\init\main.c
static const pid_t INIT_PROCESS_PID = 1;
int main(int argc, char * const argv[])
{
const char *uptime = NULL;
long long upTimeInMicroSecs = 0;
int isSecondStage = 0;
//在接收到SIGPIPE信号时,设置成SIG_IGN忽略信号,不会中断程序执行,而是继续执行后续操作
(void)signal(SIGPIPE, SIG_IGN);
// Number of command line parameters is 2
//从kernel启动的init进程不会携带任何参数,从StartInitSecondStage启动的init进程第二阶段会携带参数
if (argc > 1 && (strcmp(argv[1], "--second-stage") == 0)) {
isSecondStage = 1;
if (argc > 2) {
uptime = argv[2];
}
} else {
upTimeInMicroSecs = GetUptimeInMicroSeconds(NULL);
}
//正常启动init进程的pid为1
if (getpid() != INIT_PROCESS_PID) {
INIT_LOGE("Process id error %d!", getpid());
return 0;
}
//使能init阶段log
EnableInitLog(INIT_INFO);
// Updater mode
if (isSecondStage == 0) {
//从kernel启动的init第一阶段走如下:
SystemPrepare(upTimeInMicroSecs);
} else {
//初始化kmsg
LogInit();
}
SystemInit();//执行init进程的初始化,注册socket
SystemExecuteRcs();//执行Linux的初始化(rcs进程)
SystemConfig(uptime);//1. 读取cfg配置文件内容(根据是否重启计重启原因加载不同的cfg配置),扫描各个系统的启动脚本,解析jobs的pre-init,init,post-init合并到一起存储在/etc/init.cfg中(其他自命名的job默认在post-init阶段执行)
2. 解析services配置,获取要初始化服务的path、uid、gid等信息(/foundation,/appspawn等服务)
3. 最后通过trigger依次执行这些操作,执行如创建文件夹,文件授权等cmd操作和start service的操作
SystemRun();//创建一个LoopEvent处理事件,通过epoll实现,运行启动service服务
return 0;
}
base\startup\init\services\init\standard\init_firststage.c
void SystemPrepare(long long upTimeInMicroSecs)
{
(void)signal(SIGPIPE, SIG_IGN);
EnableInitLog(INIT_INFO);
EarlyLogInit();
INIT_LOGI("Start init first stage.");
//挂载一些目录创建一些设备节点,打开/proc/sys/kernel/printk_devkmsg文件
//base\startup\init\services\init\standard\device.c
CreateFsAndDeviceNode();
//钩子函数 插桩
//base\startup\init\interfaces\innerkits\hookmgr\hookmgr.c
HookMgrExecute(GetBootStageHookMgr(), INIT_FIRST_STAGE, NULL, NULL);
// Updater mode no need to mount and switch root
//升级模式不进入第二阶段
if (InUpdaterMode() != 0) {
return;
}
//挂载required分区
MountRequiredPartitions();
//二级启动init
StartSecondStageInit(upTimeInMicroSecs);
}
.
.
.
int InUpdaterMode(void)
{
const char * const updaterExecutabeFile = "/bin/updater";
if (access(updaterExecutabeFile, X_OK) == 0) { //判断/bin/updater文件是否有执行权限,由于文件不存在,所以不可能为0,那么此函数的返回值为0.
return 1;
} else {
return 0;
}
}
.
.
.
static void MountRequiredPartitions(void)
{
int requiredNum = 0;
//获取required分区信息
Fstab *fstab = LoadRequiredFstab();
char **devices = (fstab != NULL) ? GetRequiredDevices(*fstab, &requiredNum) : NULL;
if (devices != NULL && requiredNum > 0) {
//创建socket,触发内核上报uevent事件
int ret = StartUeventd(devices, requiredNum);
if (ret == 0) {
ret = MountRequriedPartitions(fstab);
}
FreeStringVector(devices, requiredNum);
devices = NULL;
ReleaseFstab(fstab);
fstab = NULL;
if (ret < 0) {
// If mount required partitions failure.
// There is no necessary to continue.
// Just abort
INIT_LOGE("Mount required partitions failed; please check fstab file");
// Execute sh for debugging
#ifndef STARTUP_INIT_TEST
execv("/bin/sh", NULL);
abort();
#endif
}
}
if (fstab != NULL) {
ReleaseFstab(fstab);
fstab = NULL;
}
}
static void StartSecondStageInit(long long uptime)
{
INIT_LOGI("Start init second stage.");
// It will panic if close stdio before execv("/bin/sh", NULL)
CloseStdio();
SwitchRoot("/usr");
char buf[64];
snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "%lld", uptime);
// Execute init second stage
char * const args[] = {
"/bin/init",
"--second-stage",
buf,
NULL,
};
if (execv("/bin/init", args) != 0) {
INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
exit(-1);
}
}
-
init挂载required分区 (详情介绍见:
init进程挂载ruquired分区.md
)所谓required分区,就是系统启动引导过程的必要分区,必须在二级启动开始前进行挂载。比如system、vendor等必选镜像,挂载这些镜像前,需要先创建对应的块设备文件。这些块设备文件是通过内核上报UEVENT事件来创建的。init需要知道存储器的主设备目录,需要bootloader通过default_boot_device传递。
目前init支持两种方式获取required分区信息,一是通过保存在
/proc/cmdline
中的bootargs,init会首先尝试从cmdline读取required分区信息;二是通过读取ramdisk中的fstab.required
文件,只有在前一种方式获取失败的情况下才会尝试通过这种方式获取。-
块设备的创建逻辑
-
准备工作
- init从cmdline中读取required fstab,若获取失败,则尝试读
fstab.required
文件,从中获取必须挂载的块设备的PARTNAME,例如system和vendor. - 创建接收内核上报uevent事件广播消息的socket,从
/proc/cmdline
里读取default_boot_device。 - 带着fstab信息和socket句柄遍历
/sys/devices
目录,准备开始触发内核上报uevent事件。
- init从cmdline中读取required fstab,若获取失败,则尝试读
-
触发事件
- 通过ueventd触发内核上报uevent事件
- 匹配uevent事件中的partitionName与required fstab中的device信息。
- 匹配成功后将会进一步处理,格式化设备节点路径,准备开始创建设备节点。
-
创建节点
- 为了便于用户态下对设备节点的访问以及提高设备节点的可读性,会对即将创建的required块设备节点同时创建软链接,这就需要先格式化软链接的路径。
- 以上工作都完成后,将执行最后的创建设备节点的步骤,根据传入的uevent中的主次设备号、前置步骤中构建的设备节点路径和软链接路径等创建设备节点,并创建相应软链接。
至此,块设备节点创建完毕。
-
-
与default_boot_device匹配关系
内核将bootargs信息写入
/proc/cmdline
,其中就包含了default_boot_device,这个值是内核当中约定好的系统启动必要的主设备目录。以ohos.required_mount.
为前缀的内容则是系统启动必要的分区挂载信息,其内容与fstab.required
文件内容应当是一致的。另外,分区挂载信息中的块设备节点就是default_boot_device
目录中by-name下软链接指向的设备节点。例如,default_boot_device
的值为soc/10100000.himci.eMMC
,那么ohos.required_mount.system
的值就包含了/dev/block/platform/soc/10100000.himci.eMMC/by-name/system
这个指向system设备节点的软链接路径。在创建块设备节点的过程中,会有一个将设备路径与default_boot_device的值匹配的操作,匹配成功后,会在
/dev/block/by-name
目录下创建指向真实块设备节点的软链接,以此在访问设备节点的过程中实现芯片平台无关化。
-
通过StartSecondStageInit函数开始init进程启动的第二阶段
base\startup\init\services\init\main.c
static const pid_t INIT_PROCESS_PID = 1;
int main(int argc, char * const argv[])
{
const char *uptime = NULL;
long long upTimeInMicroSecs = 0;
int isSecondStage = 0;
//在接收到SIGPIPE信号时,设置成SIG_IGN忽略信号,不会中断程序执行,而是继续执行后续操作
(void)signal(SIGPIPE, SIG_IGN);
// Number of command line parameters is 2
//从kernel启动的init进程不会携带任何参数,从StartInitSecondStage启动的init进程第二阶段会携带参数
if (argc > 1 && (strcmp(argv[1], "--second-stage") == 0)) {
isSecondStage = 1;
if (argc > 2) {
uptime = argv[2];
}
} else {
upTimeInMicroSecs = GetUptimeInMicroSeconds(NULL);
}
//正常启动init进程的pid为1
if (getpid() != INIT_PROCESS_PID) {
INIT_LOGE("Process id error %d!", getpid());
return 0;
}
//使能init阶段log
EnableInitLog(INIT_INFO);
// Updater mode
if (isSecondStage == 0) {
//从kernel启动的init第一阶段走如下:
SystemPrepare(upTimeInMicroSecs);
} else {
//初始化kmsg
LogInit();
}
SystemInit();//执行init进程的初始化,注册socket
SystemExecuteRcs();//执行Linux的初始化(rcs进程)
SystemConfig(uptime);//1. 读取cfg配置文件内容(根据是否重启计重启原因加载不同的cfg配置),扫描各个系统的启动脚本,解析jobs的pre-init,init,post-init合并到一起存储在/etc/init.cfg中(其他自命名的job默认在post-init阶段执行)
2. 解析services配置,获取要初始化服务的path、uid、gid等信息(/foundation,/appspawn等服务)
3. 最后通过trigger依次执行这些操作,执行如创建文件夹,文件授权等cmd操作和start service的操作
SystemRun();//创建一个LoopEvent处理事件,通过epoll实现,运行启动service服务
return 0;
}
由于第二阶段启动携带参数--second-stage
,所以走到LogInit(),接着串行执行SystemInit();
base\startup\init\services\init\standard\init.c
void LogInit(void)
{
//创建/dev/kmsg节点文件
int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
makedev(MEM_MAJOR, DEV_KMSG_MINOR));
if (ret == 0) {
//打开节点文件/dev/kmsg
OpenLogDevice();
}
}
.
.
.
.
.
.
void SystemInit(void)
{
CloseStdio();
#ifndef STARTUP_INIT_TEST
// Set up a session keyring that all processes will have access to.
//设置一个所有进程都可以访问的会话密钥环???
//具体见foundation\filemanagement\storage_service\
KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);
#endif
// umask call always succeeds and return the previous mask value which is not needed here
//设置文件权限
(void)umask(DEFAULT_UMASK_INIT);
//递归赋予目录权限
MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
int sock = FdHolderSockInit();
if (sock >= 0) {
RegisterFdHoldWatcher(sock);
}
InitControlFd();
// sysclktz 0
//设置系统时间
struct timezone tz = { 0 };
if (settimeofday(NULL, &tz) == -1) {
INIT_LOGE("Set time of day failed, err = %d", errno);
}
}
.
.
.
static int FdHolderSockInit(void)
{
int sock = -1;
int on = 1;
int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB
//创建一个本地通信的socket,sock 是创建成功的套接字
sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (sock < 0) {
INIT_LOGE("Failed to create fd holder socket, err = %d", errno);
return -1;
}
setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize)); //设置接收缓冲区
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));//允许SCM_CREDENTIALS 控制消息的接收
if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) { //#define INIT_HOLDER_SOCKET_PATH "/dev/unix/socket/fd_holder"
INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);
unlink(INIT_HOLDER_SOCKET_PATH);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),
INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {
INIT_LOGE("Faild to copy fd hoder socket path");
close(sock);
return -1;
}
socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);
if (bind(sock, (struct sockaddr *)&addr, len) < 0) {
INIT_LOGE("Failed to binder fd folder socket %d", errno);
close(sock);
return -1;
}
// Owned by root
if (lchown(addr.sun_path, 0, 0)) {
INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);
}
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {
INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);
}
INIT_LOGI("Init fd holder socket done");
return sock;
}
base\startup\init\services\init\standard\init_control_fd_service.c
void InitControlFd(void)
{
//初始化/dev/unix/socket/init_control_fd,对应的处理函数ProcessControlFd
CmdServiceInit(INIT_CONTROL_FD_SOCKET_PATH, ProcessControlFd, LE_GetDefaultLoop());
return;
}
base\startup\init\services\init\adapter\init_adapter.c
由于只有小型系统定义了NEED_EXEC_RCS_LINUX,所以标准系统不会执行
init程序首先会调用/etc/init.d/rcS脚本,rcS脚本执行第一条命令为"/bin/mount -a",该命令会加载fstab文件,在fstab中的命令执行完后rcS将顺序调用Sxxx脚本完成设备节点创建和扫描、文件权限配置等操作。
void SystemExecuteRcs(void)
{
#if (defined __LINUX__) && (defined NEED_EXEC_RCS_LINUX)
pid_t retPid = fork();
if (retPid < 0) {
INIT_LOGE("ExecuteRcs, fork failed! err %d.", errno);
return;
}
// child process
if (retPid == 0) {
INIT_LOGI("ExecuteRcs, child process id %d.", getpid());
if (execle("/bin/sh", "sh", "/etc/init.d/rcS", NULL, NULL) != 0) {
INIT_LOGE("ExecuteRcs, execle failed! err %d.", errno);
}
_exit(0x7f); // 0x7f: user specified
}
// init process
sem_t sem;
if (sem_init(&sem, 0, 0) != 0) {
INIT_LOGE("ExecuteRcs, sem_init failed, err %d.", errno);
return;
}
SignalRegWaitSem(retPid, &sem);
// wait until rcs process exited
if (sem_wait(&sem) != 0) {
INIT_LOGE("ExecuteRcs, sem_wait failed, err %d.", errno);
}
#endif
base\startup\init\services\init\standard\init.c
SystemConfig
void SystemConfig(const char *uptime)
{
INIT_TIMING_STAT timingStat;
//设置/proc/self/oom_score_adj 值为-1000
InitSysAdj();
HOOK_EXEC_OPTIONS options;
options.flags = 0;
options.preHook = InitPreHook;
options.postHook = InitPostHook;
//主要就是给g_initWorkspace结构体赋值
InitServiceSpace();
HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
//记录开机事件init.prepare
RecordInitBootEvent("init.prepare");
HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
if (InitParamService() != 0) {
ExecReboot("panic");
}
//将解析的cfg值放入对应的groupNodes中
InitParseGroupCfg();
//记录开机事件RecordInitBootEvent
//设置开机的时间属性ohos.boot.time.init
RegisterBootStateChange(BootStateChange);
INIT_LOGI("boot stage: init finish.");
// load SELinux context and policy
// Do not move position!
//加载selinux上下文和策略
PluginExecCmdByName("loadSelinuxPolicy", "");
RecordInitBootEvent("init.prepare");
// after selinux loaded
/*init是一个守护进程,为了防止init的子进程成为僵尸进程(zombie process),需要init在子进程在结束时获取子进程的结束码,通过结束码将程序表中的子进程移除,防止成为僵尸进程的子进程占用程序表的空间(程序表的空间达到上限时,系统就不能再启动新的进程了,会引起严重的系统问题)
在linux当中,父进程是通过捕捉SIGCHLD信号来得知子进程运行结束的情况,SIGCHLD信号会在子进程终止的时候发出*/
SignalInit();
RecordInitBootEvent("init.ParseCfg");
//加载系统的一些特殊参数
LoadSpecialParam();
// parse parameters
HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
//加载系统的参数
InitLoadParamFiles();
// Write kernel uptime into system parameter
//设置kernel启动时间
WriteUptimeSysParam("ohos.boot.time.kernel", uptime);
// read config
HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
//读取cfg参数
ReadConfig();
RecordInitBootEvent("init.ParseCfg");
INIT_LOGI("boot stage: parse config file finish.");
HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);
//根据属性const.sandbox判断sandbox是否启用
IsEnableSandbox();
// execute init
//触发执行对应的init*.cfg中job service
PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
TriggerServices(START_MODE_BOOT);
PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
TriggerServices(START_MODE_NORMAL);
clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
}
.
.
.
static void InitLoadParamFiles(void)
{
if (InUpdaterMode() != 0) {
LoadDefaultParams("/etc/param/ohos_const", LOAD_PARAM_NORMAL);
LoadDefaultParams("/etc/param", LOAD_PARAM_ONLY_ADD);
LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_ONLY_ADD);
return;
}
// Load developer mode param
LoadDefaultParams("/proc/dsmm/developer", LOAD_PARAM_NORMAL);
// Load const params, these can't be override!
LoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);
CfgFiles *files = GetCfgFiles("etc/param");
for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
if (files->paths[i]) {
LoadDefaultParams(files->paths[i], LOAD_PARAM_ONLY_ADD);
}
}
FreeCfgFiles(files);
}
cfg文件 (具体见:cfg文件解析.md
)
base\startup\init\services\init\init_group_manager.c
void InitServiceSpace(void)
{
if (g_initWorkspace.initFlags != 0) {
return;
}
HashInfo info = {
GroupNodeNodeCompare,
GroupNodeKeyCompare,
GroupNodeGetNodeHashCode,
GroupNodeGetKeyHashCode,
GroupNodeFree,
GROUP_HASHMAP_BUCKET
};
for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
int ret = OH_HashMapCreate(&g_initWorkspace.hashMap[i], &info);
if (ret != 0) {
INIT_LOGE("%s", "Failed to create hash map");
}
}
for (int i = 0; i < NODE_TYPE_MAX; i++) {
g_initWorkspace.groupNodes[i] = NULL;
}
// get boot mode, set default mode
strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
int ret = GetParameterFromCmdLine(BOOT_GROUP_NAME,
g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr));
if (ret != 0) {
INIT_LOGV("Failed to get boot group");
if (GetBootModeFromMisc() == GROUP_CHARGE) {
strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), "device.charge.group");
}
}
INIT_LOGI("boot start %s", g_initWorkspace.groupModeStr);
//device.boot.group 系统默认配置,触发执行配置文件中的所有的job和服务。
//device.charge.group charge模式,限制只启动改文件中允许的job和服务。
g_initWorkspace.groupMode = GetBootGroupMode();
g_initWorkspace.initFlags = 1;
}
.
.
.
int InitParseGroupCfg(void)
{
char buffer[128] = {0}; // 128 buffer size
// /data/init_ut/system/etc
char *realPath = GetAbsolutePath(GROUP_DEFAULT_PATH,
g_initWorkspace.groupModeStr, buffer, sizeof(buffer));
INIT_ERROR_CHECK(realPath != NULL, return -1,
"Failed to get path for %s", g_initWorkspace.groupModeStr);
InitParseGroupCfg_(realPath);
InitGroupNode *groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
int level = 0;
while ((groupRoot != NULL) && (level < GROUP_IMPORT_MAX_LEVEL)) { // for more import
g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
InitImportGroupCfg_(groupRoot);
groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
level++;
}
InitFreeGroupNodes_(g_initWorkspace.groupNodes[NODE_TYPE_GROUPS]);
g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
return 0;
}
LoadSpecialParam
base\startup\init\services\param\linux\param_service.c
void LoadSpecialParam(void)
{
// read param area size from cfg and save to dac
LoadParamAreaSize();
// read selinux label
LoadSelinuxLabel("init");
// from cmdline
LoadParamFromCmdLine();
// from build
LoadParamFromBuild();
}
base\startup\init\services\param\manager\param_server.c
INIT_LOCAL_API void LoadParamAreaSize(void)
{
LoadDefaultParam_("/sys_prod/etc/param/ohos.para.size", 0, NULL, 0, LoadOneParamAreaSize_);
LoadDefaultParam_(PARAM_AREA_SIZE_CFG, 0, NULL, 0, LoadOneParamAreaSize_);
}
.
.
.
INIT_LOCAL_API void LoadParamFromBuild(void)
{
PARAM_LOGI("load parameters from build ");
#ifdef INCREMENTAL_VERSION
if (strlen(INCREMENTAL_VERSION) > 0) {
WriteParam("const.product.incremental.version", INCREMENTAL_VERSION, NULL, LOAD_PARAM_NORMAL);
}
#endif
#ifdef BUILD_TYPE
if (strlen(BUILD_TYPE) > 0) {
WriteParam("const.product.build.type", BUILD_TYPE, NULL, LOAD_PARAM_NORMAL);
}
#endif
#ifdef BUILD_USER
if (strlen(BUILD_USER) > 0) {
WriteParam("const.product.build.user", BUILD_USER, NULL, LOAD_PARAM_NORMAL);
}
#endif
#ifdef BUILD_TIME
if (strlen(BUILD_TIME) > 0) {
WriteParam("const.product.build.date", BUILD_TIME, NULL, LOAD_PARAM_NORMAL);
}
#endif
#ifdef BUILD_HOST
if (strlen(BUILD_HOST) > 0) {
WriteParam("const.product.build.host", BUILD_HOST, NULL, LOAD_PARAM_NORMAL);
}
#endif
#ifdef BUILD_ROOTHASH
if (strlen(BUILD_ROOTHASH) > 0) {
WriteParam("const.ohos.buildroothash", BUILD_ROOTHASH, NULL, LOAD_PARAM_NORMAL);
}
#endif
}
ReadConfig
base\startup\init\services\init\init_config.c
void ReadConfig(void)
{
// parse cfg
char buffer[32] = {0}; // 32 reason max leb
uint32_t len = sizeof(buffer);
//读取启动模式,根据不同模式解析对应的cfg文件
SystemReadParam("ohos.boot.mode", buffer, &len);
INIT_LOGI("ohos.boot.mode %s", buffer);
if (strcmp(buffer, "charger_mode") == 0) {
ParseInitCfg(INIT_CONFIGURATION_FILE, NULL);
ReadFileInDir(OTHER_CHARGE_PATH, ".cfg", ParseInitCfg, NULL);
ParseInitCfgByPriority();
} else if (strcmp(buffer, "charger") == 0) {
ParseInitCfg(INIT_CONFIGURATION_FILE, NULL);
ReadFileInDir(OTHER_CHARGE_PATH, ".cfg", ParseInitCfg, NULL);
} else if (InUpdaterMode() == 0) {
ParseInitCfg(INIT_CONFIGURATION_FILE, NULL);
ParseInitCfgByPriority();
} else {
ReadFileInDir("/etc", ".cfg", ParseInitCfg, NULL);
}
}
static void ParseInitCfgContents(const char *cfgName, const cJSON *root)
{
INIT_ERROR_CHECK(root != NULL, return, "Root is null");
ConfigContext context = { INIT_CONTEXT_MAIN };
context.type = GetConfigContextType(cfgName);
INIT_LOGV("Parse %s configs in context %d", cfgName, context.type);
// 解析cfg文件中的services
ParseAllServices(root, &context);
// 解析cfg文件中的jobs
ParseAllJobs(root, &context);
// parse imports
//解析所有导入cfg文件
ParseAllImports(root);
}
int ParseInitCfg(const char *configFile, void *context)
{
UNUSED(context);
INIT_LOGV("Parse init configs from %s", configFile);
char *fileBuf = ReadFileToBuf(configFile);
INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Cfg error, %s not found", configFile);
cJSON *fileRoot = cJSON_Parse(fileBuf);
INIT_ERROR_CHECK(fileRoot != NULL, free(fileBuf);
return -1, "Cfg error, failed to parse json %s ", configFile);
ParseInitCfgContents(configFile, fileRoot);
cJSON_Delete(fileRoot);
free(fileBuf);
return 0;
}
SystemRun
base\startup\init\services\init\standard\init.c
void SystemRun(void)
{
StartParamService();
}
base\startup\init\services\param\linux\param_service.c
int StartParamService(void)
{
// read selinux label
LoadSelinuxLabel("permission");
return ParamServiceStart();
}
base\startup\init\services\param\linux\param_msgadp.c
int ParamServiceStart(void)
{
LE_RunLoop(LE_GetDefaultLoop());
return 0;
}
samgr系统服务进程
samgr是各个SystemAbility的服务进程中心,每个SA的启动都需要向samgr注册,然后分配到一个ID,通过ID才能访问到该SA。
samgr由init进程启动,由之前的SystemConfig函数可知,执行post-init的时候会触发early-fs,此时执行samgr的job。samgr服务配置的模式为boot则会在init阶段启动
void SystemConfig(const char *uptime)
{
.....
// execute init
PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
TriggerServices(START_MODE_BOOT);
PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
TriggerServices(START_MODE_NORMAL);
clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
}
base\startup\init\services\etc\init.cfg
{
"name" : "post-init",
"cmds" : [
"trigger early-fs",
"trigger fs",
"trigger post-fs",
"trigger late-fs",
"trigger post-fs-data",
"trigger firmware_mounts_complete",
"trigger early-boot",
"trigger boot"
]
}
samgr的cfg文件如下。(服务介绍详见:服务管理.md
)
foundation\systemabilitymgr\samgr\etc\samgr_standard.cfg
{
"jobs" : [{
"name" : "early-fs",
"cmds" : [
"mkdir /data/samgr 0740 samgr samgr"
]
}
],
"services" : [{
"name" : "samgr",
"path" : ["/system/bin/samgr"],
"critical" : [1, 1, 60],
"uid" : "samgr",
"gid" : ["samgr", "readproc"],
"bootevents":"bootevent.samgr.ready",
"permission": [
"ohos.permission.DISTRIBUTED_DATASYNC",
"ohos.permission.ACCESS_SERVICE_DM",
"ohos.permission.RECEIVER_STARTUP_COMPLETED",
"ohos.permission.MANAGE_LOCAL_ACCOUNTS",
"ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS",
"ohos.permission.LOCATION",
"ohos.permission.GET_WIFI_INFO",
"ohos.permission.USE_BLUETOOTH",
"ohos.permission.DISCOVER_BLUETOOTH",
"ohos.permission.MANAGE_SECURE_SETTINGS",
"ohos.permission.LISTEN_BUNDLE_CHANGE",
"ohos.permission.STORAGE_MANAGER",
"ohos.permission.RECEIVE_SMS",
"ohos.permission.GET_TELEPHONY_STATE",
"ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT"
],
"secon" : "u:r:samgr:s0",
"start-mode" : "boot" //启动模式
}
]
}
foundation进程
ams,wms等服务都在foundation进程中。
foundation是一个特殊的SA服务进程,提供用户程序管理框架及基础服务,该进程负责应用的生命周期管理,ready可进行startAbility/connectAbility。当多个服务都完成对应的启动事件后,由bootevents投票,在init进程中设置bootevent.boot.completed事件为true,表示系统启动完成。
在foundation监控到此事件再以CES事件的方式广播出去,让应用能够检测到。foundation服务进程想应用孵化器appspawn发送应用启动请求。appspawn接收到应用启动请求,直接孵化出应用进程。当foundation启动Openharmony应用Home即我们看到的桌面程序,至此从开机到应用启动所有过程就完成了。
foundation在post-init阶段启动
foundation\systemabilitymgr\safwk\etc\profile\foundation.cfg
"services" : [{
"name" : "foundation",
"path" : ["/system/bin/sa_main", "/system/profile/foundation.json"],
"critical" : [1, 4, 240],
"importance" : -20,
"uid" : "foundation",
"permission" : [
"ohos.permission.INPUT_MONITORING",
"ohos.permission.PERMISSION_USED_STATS",
"ohos.permission.DISTRIBUTED_SOFTBUS_CENTER",
"ohos.permission.DISTRIBUTED_DATASYNC",
"ohos.permission.MANAGE_AUDIO_CONFIG",
"ohos.permission.WRITE_CALL_LOG",
"ohos.permission.READ_CONTACTS",
"ohos.permission.READ_DFX_SYSEVENT",
"ohos.permission.GRANT_SENSITIVE_PERMISSIONS",
"ohos.permission.REVOKE_SENSITIVE_PERMISSIONS",
"ohos.permission.MANAGE_SECURE_SETTINGS",
"ohos.permission.START_ABILITIES_FROM_BACKGROUND",
"ohos.permission.ACCESS_SERVICE_DM",
"ohos.permission.STORAGE_MANAGER",
"ohos.permission.PROXY_AUTHORIZATION_URI",
"ohos.permission.ABILITY_BACKGROUND_COMMUNICATION",
"ohos.permission.USE_USER_IDM",
"ohos.permission.MANAGE_LOCAL_ACCOUNTS",
"ohos.permission.LISTEN_BUNDLE_CHANGE",
"ohos.permission.GET_TELEPHONY_STATE",
"ohos.permission.SEND_MESSAGES",
"ohos.permission.CONNECT_CELLULAR_CALL_SERVICE",
"ohos.permission.SET_TELEPHONY_STATE",
"ohos.permission.VIBRATE",
"ohos.permission.SYSTEM_LIGHT_CONTROL",
"ohos.permission.MANAGE_HAP_TOKENID",
"ohos.permission.WRITE_WHOLE_CALENDAR",
"ohos.permission.UPDATE_CONFIGURATION",
"ohos.permission.REPORT_RESOURCE_SCHEDULE_EVENT",
"ohos.permission.START_INVISIBLE_ABILITY",
"ohos.permission.GET_BUNDLE_INFO",
"ohos.permission.GET_SUSPEND_STATE",
"ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT",
"ohos.permission.GET_BUNDLE_INFO_PRIVILEGED",
"ohos.permission.GET_SENSITIVE_PERMISSIONS",
"ohos.permission.CLEAN_APPLICATION_DATA",
"ohos.permission.REMOVE_CACHE_FILES",
"ohos.permission.INSTALL_SANDBOX_BUNDLE",
"ohos.permission.USE_BLUETOOTH",
"ohos.permission.CONNECTIVITY_INTERNAL",
"ohos.permission.GET_RUNNING_INFO",
"ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS",
"ohos.permission.ACCESS_BLUETOOTH",
"ohos.permission.RUNNING_STATE_OBSERVER"
],
"permission_acls":[
"ohos.permission.MANAGE_HAP_TOKENID",
"ohos.permission.GRANT_SENSITIVE_PERMISSIONS",
"ohos.permission.INPUT_MONITORING",
"ohos.permission.REVOKE_SENSITIVE_PERMISSIONS",
"ohos.permission.START_INVISIBLE_ABILITY",
"ohos.permission.INSTALL_SANDBOX_BUNDLE"
],
"gid" : ["system", "appspawn", "update"],
"caps" : ["SYS_PTRACE", "KILL"],
"bootevents": [
"bootevent.wms.fullscreen.ready",
"bootevent.appfwk.ready",
"bootevent.lockscreen.ready"
],
"jobs" : {
"on-start" : "services:foundation",
"on-restart" : "services:restartfoundation"
},
"secon" : "u:r:foundation:s0"
}
]
系统服务框架组件(SystemAbility)(具体详见: 系统服务框架部件.md
)
SystemAbility实现一般采用XXX.cfg + profile.json + libXXX.z.so的方式由init进程执行对应的XXX.cfg文件拉起相关SystemAbility进程。
AbilityManagerService的启动
由系统服务框架部件.md
可知的服务配置需要对应.json文件和BUILD.gn文件以及cfg文件。
对应的ams的json和BUILD.gn文件如下:
foundation\ability\ability_runtime\services\sa_profile\180.json
foundation\ability\ability_runtime\services\sa_profile\BUILD.gn
{
"process": "foundation",
"systemability": [
{
"name": 180,
"libpath": "libabilityms.z.so",
"run-on-create": true,
"distributed": false,
"dump_level": 1
}
]
}
import("//build/ohos/sa_profile/sa_profile.gni")
ohos_sa_profile("ams_sa_profile") {
sources = [
"180.json",
"182.json",
"183.json",
"184.json",
"501.json",
]
part_name = "ability_runtime"
}
由于ams跑在foundation进程中,所以对应的文件查看foundation.cfg
所以查看对应的/system/bin/sa_main的流程,找到对应的main函数
foundation\systemabilitymgr\safwk\services\safwk\src\main.cpp
int main(int argc, char *argv[])
{
HILOGD(TAG, "[PerformanceTest] SAFWK main entry process starting!");
// find update list
//检测服务cfg文件中是否配置按需启动ondemand
bool checkOnDemand = true;
string updateList;
for (int i = 0; i < argc - 1; ++i) {
if (PARAM_PREFIX_U.compare(argv[i]) == 0) {
if (i == EVENT_INDEX) {
checkOnDemand = false;
}
updateList = argv[i + 1];
break;
}
}
if (!updateList.empty()) {
LocalAbilityManager::GetInstance().SetUpdateList(updateList);
}
// Load ondemand system abilities related shared libraries from specific json-format profile
// when this process starts.
//从.json配置文件加载与ondemand系统功能相关的共享库(如:ams配置的180.json中加载libabilityms.z.so )
int32_t saId = DEFAULT_SAID;
if (checkOnDemand && argc > ONDEMAND_LOAD) {
nlohmann::json eventMap;
saId = ParseArgv(argv, eventMap);
if (!CheckSaId(saId)) {
HILOGE(TAG, "saId is invalid!");
return 0;
}
LocalAbilityManager::GetInstance().SetStartReason(saId, eventMap);
}
//启动服务进程
DoStartSAProcess(argc, argv, saId);
return 0;
}
....
static int DoStartSAProcess(int argc, char *argv[], int32_t saId)
{
auto setProcessName = [argc, argv](const string& name) -> void {
char *endCh = strchr(argv[argc - 1], 0);
if (endCh == nullptr) {
HILOGW(TAG, "argv is invalid");
return;
}
uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
uintptr_t end = reinterpret_cast<uintptr_t>(endCh);
uintptr_t argvSize = end - start;
if (memset_s(argv[0], argvSize, 0, argvSize) != EOK) {
HILOGW(TAG, "failed to clear argv:%{public}s", strerror(errno));
return;
}
if (strcpy_s(argv[0], argvSize, name.c_str()) != EOK) {
HILOGW(TAG, "failed to set process name:%{public}s", strerror(errno));
return;
}
HILOGI(TAG, "Set process name to %{public}s", argv[0]);
};
// Load default system abilities related shared libraries from specific format profile
// when this process starts.
string profilePath(DEFAULT_JSON);
if (argc > DEFAULT_LOAD) {
string filePath(argv[PROFILE_INDEX]);
//寻找对应的json文件
if (filePath.empty() || filePath.find(".json") == string::npos) {
HILOGE(TAG, "profile file path is invalid!");
return 0;
}
SetProcName(filePath, setProcessName);
profilePath = std::move(filePath);
}
LocalAbilityManager::GetInstance().DoStartSAProcess(profilePath, saId);
return 0;
}
foundation\systemabilitymgr\safwk\services\safwk\src\local_ability_manager.cpp
void LocalAbilityManager::DoStartSAProcess(const std::string& profilePath, int32_t saId)
{
startBegin_ = GetTickCount();
HILOGD(TAG, "SA:%{public}d", saId);
string realProfilePath = "";
//检测文件路径是否正确
if (!CheckAndGetProfilePath(profilePath, realProfilePath)) {
HILOGE(TAG, "DoStartSAProcess invalid path");
return;
}
{
std::string traceTag = GetTraceTag(realProfilePath);
HITRACE_METER_NAME(HITRACE_TAG_SAMGR, traceTag);
//初始化sa profiles
bool ret = InitSystemAbilityProfiles(realProfilePath, saId);
if (!ret) {
HILOGE(TAG, "InitSystemAbilityProfiles no right profile, will exit");
return;
}
//等待samg的启动
ret = CheckSystemAbilityManagerReady();
if (!ret) {
HILOGE(TAG, "CheckSystemAbilityManagerReady failed! will exit");
return;
}
//启动SA
ret = Run(saId);
if (!ret) {
HILOGE(TAG, "Run failed! will exit");
return;
}
}
IPCSkeleton::JoinWorkThread();
ClearResource();
HILOGE(TAG, "JoinWorkThread stop, will exit");
}
.....
bool LocalAbilityManager::CheckAndGetProfilePath(const std::string& profilePath, std::string& realProfilePath)
{
if (profilePath.length() > PATH_MAX) {
HILOGE(TAG, "profilePath length too long!");
return false;
}
char realPath[PATH_MAX] = {'\0'};
if (realpath(profilePath.c_str(), realPath) == nullptr) {
HILOGE(TAG, "file path does not exist!");
return false;
}
// realProfilePath must begin with "/system/profile/" or begin with "/system/usr/"
realProfilePath = realPath;
if (realProfilePath.find(PROFILES_DIR) != 0 && realProfilePath.find(DEFAULT_DIR) != 0) {
HILOGE(TAG, "file path is not matched");
return false;
}
return true;
}
.....
bool LocalAbilityManager::InitSystemAbilityProfiles(const std::string& profilePath, int32_t saId)
{
HILOGD(TAG, "[PerformanceTest]parse sa profiles!");
int64_t begin = GetTickCount();
//解析profile
bool ret = profileParser_->ParseSaProfiles(profilePath);
if (!ret) {
HILOGW(TAG, "ParseSaProfiles failed!");
return false;
}
procName_ = profileParser_->GetProcessName();
auto saInfos = profileParser_->GetAllSaProfiles();
std::string process = Str16ToStr8(procName_);
HILOGI(TAG, "[PerformanceTest]parse process:%{public}s profiles finished, spend:%{public}"
PRId64 " ms", process.c_str(), (GetTickCount() - begin));
std::string path = PREFIX + process + SUFFIX;
bool isExist = profileParser_->CheckPathExist(path);
if (isExist) {
CheckTrustSa(path, process, saInfos);
}
return InitializeSaProfiles(saId);
}
bool LocalAbilityManager::InitializeSaProfiles(int32_t saId)
{
if (saId != DEFAULT_SAID) {
return InitializeOnDemandSaProfile(saId);
} else {
return InitializeRunOnCreateSaProfiles(BOOT_START);
}
}
void LocalAbilityManager::CheckTrustSa(const std::string& path, const std::string& process,
const std::list<SaProfile>& saInfos)
{
HILOGD(TAG, "CheckTrustSa start");
std::map<std::u16string, std::set<int32_t>> trustMaps;
//解析trust sa profiles,并移除不受信任的sa
//foundation进程受信任profile配置在如下文件中:
//foundation\systemabilitymgr\safwk\etc\profile\foundation_trust.json
bool ret = profileParser_->ParseTrustConfig(path, trustMaps);
if (ret && !trustMaps.empty()) {
// 1.get allowed sa set in the process
const auto& saSets = trustMaps[Str8ToStr16(process)];
// 2.check to-load sa in the allowed sa set, and if to-load sa not in the allowed, will remove and not load it
for (const auto& saInfo : saInfos) {
if (saSets.find(saInfo.saId) == saSets.end()) {
HILOGW(TAG, "SA:%{public}d not allow to load in %{public}s", saInfo.saId, process.c_str());
profileParser_->RemoveSaProfile(saInfo.saId);
}
}
}
}
.....
bool LocalAbilityManager::CheckSystemAbilityManagerReady()
{
int32_t timeout = RETRY_TIMES_FOR_SAMGR;
constexpr int32_t duration = std::chrono::microseconds(MILLISECONDS_WAITING_SAMGR_ONE_TIME).count();
sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
//循环检测samg是否初始化完成
while (samgrProxy == nullptr) {
HILOGI(TAG, "%{public}s waiting for samgr...", Str16ToStr8(procName_).c_str());
if (timeout > 0) {
usleep(duration);
samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
} else {
HILOGE(TAG, "wait for samgr time out (10s)");
return false;
}
timeout--;
}
return true;
}
.....
bool LocalAbilityManager::InitializeRunOnCreateSaProfiles(uint32_t bootPhase)
{
/*bootphase:可不设置;可以设置的值有三种:BootStartPhase、CoreStartPhase、OtherStartPhase(默认类型),三种优先级依次降低,当同一个进程中,会优先拉起注册配置BootStartPhase的SystemAbility,然后是配置了CoreStartPhase的SystemAbility,最后是OtherStartPhase;当高优先级的SystemAbility全部启动注册完毕才会启动下一级的SystemAbility的注册启动。*/
if (bootPhase > OTHER_START) {
return false;
}
int64_t begin = GetTickCount();
HILOGD(TAG, "[PerformanceTest]load phase %{public}d libraries", bootPhase);
//dlopen各sa所在的so库
profileParser_->OpenSo(bootPhase);
HILOGI(TAG, "[PerformanceTest]load process:%{public}s phase %{public}d finished, spend:%{public}" PRId64 " ms",
Str16ToStr8(procName_).c_str(), bootPhase, (GetTickCount() - begin));
auto& saProfileList = profileParser_->GetAllSaProfiles();
if (saProfileList.empty()) {
HILOGW(TAG, "sa profile is empty");
return false;
}
for (const auto& saProfile : saProfileList) {
if (saProfile.bootPhase != bootPhase) {
continue;
}
//将sa对象注册到abilityPhaseMap_中
if (!InitializeSaProfilesInnerLocked(saProfile)) {
HILOGW(TAG, "SA:%{public}d init fail", saProfile.saId);
continue;
}
}
return true;
}
bool LocalAbilityManager::InitializeSaProfilesInnerLocked(const SaProfile& saProfile)
{
std::unique_lock<std::shared_mutex> readLock(abilityMapLock_);
auto iterProfile = abilityMap_.find(saProfile.saId);
if (iterProfile == abilityMap_.end()) {
HILOGW(TAG, "SA:%{public}d not found", saProfile.saId);
return false;
}
auto systemAbility = iterProfile->second;
if (systemAbility == nullptr) {
HILOGW(TAG, "SA:%{public}d is null", saProfile.saId);
return false;
}
auto& saList = abilityPhaseMap_[saProfile.bootPhase];
saList.emplace_back(systemAbility);
return true;
}
......
bool LocalAbilityManager::Run(int32_t saId)
{
HILOGD(TAG, "local ability manager is running...");
bool addResult = AddLocalAbilityManager();
if (!addResult) {
HILOGE(TAG, "failed to add local abilitymanager");
return false;
}
HILOGD(TAG, "success to add process name:%{public}s", Str16ToStr8(procName_).c_str());
//获取系统支持的并发线程数
uint32_t concurrentThreads = std::thread::hardware_concurrency();
HILOGI(TAG, "concurrentThreads is %{public}d, process:%{public}s, SA:%{public}d",
concurrentThreads, Str16ToStr8(procName_).c_str(), saId);
//通过线程池启动线程,可以通过增加线程数优化sa启动时间
initPool_->Start(concurrentThreads);
initPool_->SetMaxTaskNum(MAX_TASK_NUMBER);
//对应ondemand类型的sa的信息添加到samgr
RegisterOnDemandSystemAbility(saId);
//遍历sa,调用对应sa的start()函数
FindAndStartPhaseTasks(saId);
initPool_->Stop();
return true;
}
bool LocalAbilityManager::AddLocalAbilityManager()
{
auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgrProxy == nullptr) {
HILOGE(TAG, "failed to get samgrProxy");
return false;
}
if (localAbilityManager_ == nullptr) {
localAbilityManager_ = this;
}
//通过 IPC 调用 samgr 服务的 AddSystemProcess()方法将服务进程(本质上是一个绑定了服务相关信息的 lsamgr 实例)注册到 samgr,然后启动服务进程
int32_t ret = samgrProxy->AddSystemProcess(procName_, localAbilityManager_);
return ret == ERR_OK;
}
......
void LocalAbilityManager::RegisterOnDemandSystemAbility(int32_t saId)
{
auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgrProxy == nullptr) {
HILOGI(TAG, "failed to get samgrProxy");
return;
}
auto& saProfileList = profileParser_->GetAllSaProfiles();
for (const auto& saProfile : saProfileList) {
if (NeedRegisterOnDemand(saProfile, saId)) {
HILOGD(TAG, "register ondemand SA:%{public}d to samgr", saProfile.saId);
//SA 对应的系统进程启动之后,便需要加载启动 SA 自身。首先,samgr 调用 AddOnDemandSystemAbilityInfo(),将对应的 SA 实例与服务进程进行绑定,并准备启动对应的 SA
//将对应ondemand类型的sa的信息添加到samgr
int32_t ret = samgrProxy->AddOnDemandSystemAbilityInfo(saProfile.saId, procName_);
if (ret != ERR_OK) {
HILOGI(TAG, "failed to add ability info for on-demand SA:%{public}d", saProfile.saId);
}
}
}
}
.....
void LocalAbilityManager::FindAndStartPhaseTasks(int32_t saId)
{
if (saId == DEFAULT_SAID) {
for (uint32_t bootPhase = BOOT_START; bootPhase <= OTHER_START; ++bootPhase) {
auto iter = abilityPhaseMap_.find(bootPhase);
if (iter != abilityPhaseMap_.end()) {
StartPhaseTasks(iter->second);
InitializeRunOnCreateSaProfiles(bootPhase + 1);
WaitForTasks();
} else {
InitializeRunOnCreateSaProfiles(bootPhase + 1);
}
}
} else {
for (uint32_t bootPhase = BOOT_START; bootPhase <= OTHER_START; ++bootPhase) {
auto iter = abilityPhaseMap_.find(bootPhase);
if (iter != abilityPhaseMap_.end()) {
StartPhaseTasks(iter->second);
WaitForTasks();
}
}
}
}
//启动sa
void LocalAbilityManager::StartPhaseTasks(const std::list<SystemAbility*>& systemAbilityList)
{
if (systemAbilityList.empty()) {
return;
}
for (auto systemAbility : systemAbilityList) {
if (systemAbility != nullptr) {
HILOGD(TAG, "add phase task for SA:%{public}d", systemAbility->GetSystemAbilitId());
std::lock_guard<std::mutex> autoLock(startPhaseLock_);
++startTaskNum_;
auto task = std::bind(&LocalAbilityManager::StartSystemAbilityTask, this, systemAbility);
initPool_->AddTask(task);
}
}
}
void LocalAbilityManager::StartSystemAbilityTask(SystemAbility* ability)
{
if (ability != nullptr) {
HILOGD(TAG, "StartSystemAbility is called for SA:%{public}d", ability->GetSystemAbilitId());
if (ability->GetDependSa().empty()) {
//调用SystemAbility::Start()
ability->Start();
} else {
StartDependSaTask(ability);
}
HILOGI(TAG, "%{public}s SA:%{public}d init finished, %{public}" PRId64 " ms",
Str16ToStr8(procName_).c_str(), ability->GetSystemAbilitId(), (GetTickCount() - startBegin_));
}
std::lock_guard<std::mutex> lock(startPhaseLock_);
if (startTaskNum_ > 0) {
--startTaskNum_;
}
startPhaseCV_.notify_one();
}
foundation\systemabilitymgr\safwk\services\safwk\src\system_ability.cpp
//在 Start()方法中会触发钩子函数 OnStart()的调用,OnStart()通常由 SA 自己实现,用来完成其的初始化工作,并调用 Publish()发布 SA。
最后 Publish()方法会调用 samgr 的 AddSystemAbility()方法,将 SA 注册到 samgr 中
void SystemAbility::Start()
{
// Ensure that the lifecycle is sequentially called by SAMGR
HILOGD(TAG, "starting system ability...");
{
std::lock_guard<std::recursive_mutex> autoLock(abilityLock);
if (abilityState_ != SystemAbilityState::NOT_LOADED) {
return;
}
}
HILOGD(TAG, "[PerformanceTest]OnStart SA:%{public}d", saId_);
int64_t begin = GetTickCount();
HITRACE_METER_NAME(HITRACE_TAG_SAMGR, ToString(saId_) + "_OnStart");
nlohmann::json startReason = LocalAbilityManager::GetInstance().GetStartReason(saId_);
SystemAbilityOnDemandReason onDemandStartReason =
LocalAbilityManager::GetInstance().JsonToOnDemandReason(startReason);
GetOnDemandReasonExtraData(onDemandStartReason);
OnStart(onDemandStartReason);
std::lock_guard<std::recursive_mutex> autoLock(abilityLock);
isRunning_ = true;
HILOGI(TAG, "[PerformanceTest]OnStart SA:%{public}d finished, spend:%{public}" PRId64 " ms",
saId_, (GetTickCount() - begin));
}
// The details should be implemented by subclass
void SystemAbility::OnStart()
{
}
// The details should be implemented by subclass
void SystemAbility::OnStart(const SystemAbilityOnDemandReason& startReason)
{
OnStart();
}
// The details should be implemented by subclass
void SystemAbility::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
{
}
......
bool SystemAbility::Publish(sptr<IRemoteObject> systemAbility)
{
if (systemAbility == nullptr) {
HILOGE(TAG, "systemAbility is nullptr");
return false;
}
HILOGD(TAG, "[PerformanceTest]Publish SA:%{public}d", saId_);
// Avoid automatic destruction of system ability caused by failure of publishing ability
publishObj_ = systemAbility;
int64_t begin = GetTickCount();
sptr<ISystemAbilityManager> samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgrProxy == nullptr) {
HILOGE(TAG, "failed to get samgrProxy");
return false;
}
ISystemAbilityManager::SAExtraProp saExtra(GetDistributed(), GetDumpLevel(), capability_, permission_);
std::lock_guard<std::recursive_mutex> autoLock(abilityLock);
//调用 samgr 的 AddSystemAbility()方法,将 SA 注册到 samgr 中
int32_t result = samgrProxy->AddSystemAbility(saId_, publishObj_, saExtra);
HILOGI(TAG, "[PerformanceTest]Publish SA:%{public}d result:%{public}d, spend:%{public}" PRId64 " ms",
saId_, result, (GetTickCount() - begin));
if (result == ERR_OK) {
abilityState_ = SystemAbilityState::ACTIVE;
return true;
}
return false;
}
foundation\ability\ability_runtime\services\abilitymgr\src\ability_manager_service.cpp
//服务启动完成,可以对外提供服务
void AbilityManagerService::OnStart()
{
if (state_ == ServiceRunningState::STATE_RUNNING) {
HILOG_INFO("AMS has already started.");
return;
}
HILOG_INFO("AMS starting.");
if (!Init()) {
HILOG_ERROR("Failed to init AMS.");
return;
}
state_ = ServiceRunningState::STATE_RUNNING;
/* Publish service maybe failed, so we need call this function at the last,
* so it can't affect the TDD test program */
instance_ = DelayedSingleton<AbilityManagerService>::GetInstance().get();
if (instance_ == nullptr) {
HILOG_ERROR("AMS enter OnStart, but instance_ is nullptr!");
return;
}
bool ret = Publish(instance_);
if (!ret) {
HILOG_ERROR("Publish AMS failed!");
return;
}
//投票
SetParameter(BOOTEVENT_APPFWK_READY.c_str(), "true");
AddSystemAbilityListener(BACKGROUND_TASK_MANAGER_SERVICE_ID);
AddSystemAbilityListener(DISTRIBUTED_SCHED_SA_ID);
AddSystemAbilityListener(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
HILOG_INFO("AMS start success.");
}
account进程
account在post-init阶段启动
base\account\os_account\services\accountmgr\accountmgr.cfg
"services" : [{
"name" : "accountmgr",
"path" : ["/system/bin/sa_main", "/system/profile/accountmgr.json"],
"permission" : [
"ohos.permission.GET_BUNDLE_INFO_PRIVILEGED",
"ohos.permission.GET_RUNNING_INFO",
"ohos.permission.ENFORCE_USER_IDM",
"ohos.permission.USE_USER_IDM",
"ohos.permission.MANAGE_USER_IDM",
"ohos.permission.ACCESS_USER_AUTH_INTERNAL",
"ohos.permission.ACCESS_PIN_AUTH",
"ohos.permission.STORAGE_MANAGER",
"ohos.permission.securityguard.REPORT_SECURITY_INFO",
"ohos.permission.DISTRIBUTED_DATASYNC",
"ohos.permission.RUNNING_STATE_OBSERVER",
"ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT",
"ohos.permission.STORAGE_MANAGER_CRYPT"
],
"permission_acls" : [
"ohos.permission.ENFORCE_USER_IDM",
"ohos.permission.STORAGE_MANAGER_CRYPT"
],
"uid" : "account",
"gid" : ["account", "shell", "access_token"],
"bootevents" : [ "bootevent.account.ready" ],
"writepid" : [
"/dev/cpuset/foreground/tasks",
"/dev/stune/foreground/tasks",
"/dev/blkio/foreground/tasks"
],
"jobs" : {
"on-start" : "services:accountmgr"
},
"secon" : "u:r:accountmgr:s0"
}
]
base\account\os_account\services\accountmgr\src\account_mgr_service.cpp
//服务启动
void AccountMgrService::OnStart()
{
if (state_ == ServiceRunningState::STATE_RUNNING) {
ACCOUNT_LOGI("AccountMgrService has already started.");
return;
}
UpdateTraceLabelAdapter();
StartTraceAdapter("accountmgr service onstart");
CountTraceAdapter("activeid", -1);
PerfStat::GetInstance().SetInstanceStartTime(GetTickCount());
ACCOUNT_LOGI("start is triggered");
if (!Init()) {
ACCOUNT_LOGE("failed to init AccountMgrService");
FinishTraceAdapter();
return;
}
bool isAccountCompleted = false;
std::int32_t defaultActivatedId = Constants::START_USER_ID;
osAccountManagerService_->GetDefaultActivatedOsAccount(defaultActivatedId);
osAccountManagerService_->IsOsAccountCompleted(defaultActivatedId, isAccountCompleted);
if (!isAccountCompleted) {
AddSystemAbilityListener(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
}
AddSystemAbilityListener(STORAGE_MANAGER_MANAGER_ID);
AddSystemAbilityListener(ABILITY_MGR_SERVICE_ID);
ACCOUNT_LOGI("AccountMgrService::OnStart start service finished.");
FinishTraceAdapter();
IPCSkeleton::SetMaxWorkThreadNum(5); // 5: ipc thread num
}
void AccountMgrService::OnStop()
{
PerfStat::GetInstance().SetInstanceStopTime(GetTickCount());
ACCOUNT_LOGI("onstop is called");
IAccountContext::SetInstance(nullptr);
SelfClean();
}
//addSystemAbility回调
void AccountMgrService::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
{
ACCOUNT_LOGI("OnAddSystemAbility systemAbilityId %{public}d", systemAbilityId);
std::lock_guard<std::mutex> lock(statusMutex_);
switch (systemAbilityId) {
case STORAGE_MANAGER_MANAGER_ID: {
isStorageReady_ = true;
break;
}
case ABILITY_MGR_SERVICE_ID: {
isAmsReady_ = true;
break;
}
case BUNDLE_MGR_SERVICE_SYS_ABILITY_ID: {
isBmsReady_ = true;
break;
}
default:
break;
}
if (!isStorageReady_) {
return;
}
bool isAccountCompleted = false;
std::int32_t defaultActivatedId = Constants::START_USER_ID;
osAccountManagerService_->GetDefaultActivatedOsAccount(defaultActivatedId);
osAccountManagerService_->IsOsAccountCompleted(defaultActivatedId, isAccountCompleted);
if (!isAccountCompleted && !isBmsReady_) {
return;
}
if (isAccountCompleted && !isAmsReady_) {
return;
}
//创建基础账户
osAccountManagerService_->CreateBasicAccounts();
}
base\account\os_account\services\accountmgr\src\osaccount\os_account_manager_service.cpp
void OsAccountManagerService::CreateBasicAccounts()
{
ACCOUNT_LOGI("enter!");
//初始化
innerManager_.Init();
ACCOUNT_LOGI("exit!");
}
base\account\os_account\services\accountmgr\src\osaccount\inner_os_account_manager.cpp
void IInnerOsAccountManager::Init()
{
CreateBaseAdminAccount();
CreateBaseStandardAccount();
//启动账户
StartAccount();
#ifdef ENABLE_MULTIPLE_ACTIVE_ACCOUNTS
RestartActiveAccount();
#endif // ENABLE_MULTIPLE_ACTIVE_ACCOUNTS
CleanGarbageAccounts();
}
......
void IInnerOsAccountManager::StartAccount()
{
ACCOUNT_LOGI("start to activate default account");
ResetAccountStatus();
OsAccountInfo osAccountInfo;
ErrCode errCode = osAccountControl_->GetOsAccountInfoById(defaultActivatedId_, osAccountInfo);
if (errCode != ERR_OK) {
ACCOUNT_LOGE("account not found, localId: %{public}d, error: %{public}d", defaultActivatedId_, errCode);
RetryToGetAccount(osAccountInfo);
defaultActivatedId_ = osAccountInfo.GetLocalId();
osAccountControl_->SetDefaultActivatedOsAccount(defaultActivatedId_);
}
auto task = std::bind(&IInnerOsAccountManager::WatchStartUser, this, defaultActivatedId_);
std::thread taskThread(task);
pthread_setname_np(taskThread.native_handle(), WATCH_START_USER);
taskThread.detach();
if (!osAccountInfo.GetIsCreateCompleted() && (SendMsgForAccountCreate(osAccountInfo) != ERR_OK)) {
ACCOUNT_LOGE("account %{public}d not created completely", defaultActivatedId_);
return;
}
// activate
//传输账号信息
SendMsgForAccountActivate(osAccountInfo);
}
.....
ErrCode IInnerOsAccountManager::SendMsgForAccountActivate(OsAccountInfo &osAccountInfo)
{
// activate
int localId = osAccountInfo.GetLocalId();
ErrCode errCode = OsAccountInterface::SendToStorageAccountStart(osAccountInfo);
if (errCode != ERR_OK) {
ACCOUNT_LOGE("account %{public}d call storage active failed, errCode %{public}d.",
localId, errCode);
return ERR_ACCOUNT_COMMON_GET_SYSTEM_ABILITY_MANAGER;
}
//通知ams账号启动
errCode = OsAccountInterface::SendToAMSAccountStart(osAccountInfo);
if (errCode != ERR_OK) {
ACCOUNT_LOGE("account %{public}d call ams active failed, errCode %{public}d.",
localId, errCode);
return errCode;
}
// update info
osAccountInfo.SetIsActived(true);
int64_t time =
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
osAccountInfo.SetLastLoginTime(time);
errCode = osAccountControl_->UpdateOsAccount(osAccountInfo);
if (errCode != ERR_OK) {
ACCOUNT_LOGE("update %{public}d account info failed, errCode %{public}d.",
localId, errCode);
return ERR_OSACCOUNT_SERVICE_INNER_UPDATE_ACCOUNT_ERROR;
}
RefreshActiveList(localId);
//投票
SetParameter(ACCOUNT_READY_EVENT.c_str(), "true");
OsAccountInterface::SendToCESAccountSwitched(osAccountInfo);
subscribeManager_.Publish(localId, OS_ACCOUNT_SUBSCRIBE_TYPE::ACTIVED);
ACCOUNT_LOGI("SendMsgForAccountActivate ok");
return errCode;
}
base\account\os_account\services\accountmgr\src\osaccount\os_account_interface.cpp
ErrCode OsAccountInterface::SendToAMSAccountStart(OsAccountInfo &osAccountInfo)
{
ACCOUNT_LOGI("start");
StartTraceAdapter("AbilityManagerAdapter StartUser");
ErrCode code = AbilityManagerAdapter::GetInstance()->StartUser(osAccountInfo.GetLocalId());
if (code != ERR_OK) {
ACCOUNT_LOGE("AbilityManagerAdapter StartUser failed! errcode is %{public}d", code);
ReportOsAccountOperationFail(osAccountInfo.GetLocalId(), Constants::OPERATION_ACTIVATE, code,
"AbilityManagerAdapter StartUser failed!");
FinishTraceAdapter();
return code;
}
ACCOUNT_LOGI("end, succeed!");
FinishTraceAdapter();
return ERR_OK;
}
base\account\os_account\services\accountmgr\src\ability_manager_adapter\ability_manager_adapter.cpp
ErrCode AbilityManagerAdapter::StartUser(int32_t accountId)
{
auto abms = GetAbilityManager();
if (abms == nullptr) {
ACCOUNT_LOGE("ability manager proxy is nullptr.");
return ERR_ACCOUNT_COMMON_CONNECT_ABILITY_MANAGER_SERVICE_ERROR;
}
int error;
MessageParcel data;
MessageParcel reply;
MessageOption option;
if (!data.WriteInterfaceToken(ABILITY_MGR_DESCRIPTOR)) {
ACCOUNT_LOGE("write interface token failed.");
return INNER_ERR;
}
if (!data.WriteInt32(accountId)) {
ACCOUNT_LOGE("StartUser:WriteInt32 fail.");
return ERR_INVALID_VALUE;
}
//ipc调用startUser
error = abms->SendRequest(static_cast<uint32_t>(AbilityManagerInterfaceCode::START_USER), data, reply, option);
if (error != NO_ERROR) {
ACCOUNT_LOGE("StartUser:SendRequest error: %{public}d", error);
return error;
}
return reply.ReadInt32();
}
foundation\ability\ability_runtime\services\abilitymgr\src\ability_manager_stub.cpp
消息码START_USER对应的函数为StartUserInner();
requestFuncMap_[static_cast<uint32_t>(AbilityManagerInterfaceCode::START_USER)] =
&AbilityManagerStub::StartUserInner;
......
int AbilityManagerStub::StartUserInner(MessageParcel &data, MessageParcel &reply)
{
int32_t userId = data.ReadInt32();
int result = StartUser(userId);
if (!reply.WriteInt32(result)) {
HILOG_ERROR("StartUser failed.");
return ERR_INVALID_VALUE;
}
return NO_ERROR;
}
StartUser对应的实现在AbilityManagerStub的实现类AbilityManagerService中
foundation\ability\ability_runtime\services\abilitymgr\src\ability_manager_service.cpp
int AbilityManagerService::StartUser(int userId)
{
HILOG_DEBUG("%{public}s, userId:%{public}d", __func__, userId);
//权限验证
if (IPCSkeleton::GetCallingUid() != ACCOUNT_MGR_SERVICE_UID) {
HILOG_ERROR("%{public}s: Permission verification failed, not account process", __func__);
return CHECK_PERMISSION_FAILED;
}
if (userController_) {
return userController_->StartUser(userId, true);
}
return 0;
}
foundation\ability\ability_runtime\services\abilitymgr\src\user_controller.cpp
int32_t UserController::StartUser(int32_t userId, bool isForeground)
{
if (userId < 0 || userId == USER_ID_NO_HEAD) {
HILOG_ERROR("StartUser userId is invalid:%{public}d", userId);
return -1;
}
if (IsCurrentUser(userId)) {
HILOG_WARN("StartUser user is already current:%{public}d", userId);
return 0;
}
if (!IsExistOsAccount(userId)) {
HILOG_ERROR("StartUser not exist such account:%{public}d", userId);
return -1;
}
if (isForeground && GetCurrentUserId() != USER_ID_NO_HEAD && !Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) {
// start freezing screen
SetFreezingNewUserId(userId);
DelayedSingleton<AbilityManagerService>::GetInstance()->StartFreezingScreen();
}
auto oldUserId = GetCurrentUserId();
auto userItem = GetOrCreateUserItem(userId);
auto state = userItem->GetState();
if (state == STATE_STOPPING || state == STATE_SHUTDOWN) {
HILOG_ERROR("StartUser user is stop now, userId:%{public}d", userId);
return -1;
}
if (isForeground) {
SetCurrentUserId(userId);
// notify wms switching now
}
bool needStart = false;
if (state == STATE_BOOTING) {
needStart = true;
// send user start msg.
SendSystemUserStart(userId);
}
if (isForeground) {
SendSystemUserCurrent(oldUserId, userId);
SendReportUserSwitch(oldUserId, userId, userItem);
SendUserSwitchTimeout(oldUserId, userId, userItem);
}
if (needStart) {
BroadcastUserStarted(userId);
}
UserBootDone(userItem);
if (isForeground) {
MoveUserToForeground(oldUserId, userId);
}
return 0;
}
......
void UserController::MoveUserToForeground(int32_t oldUserId, int32_t newUserId)
{
auto manager = DelayedSingleton<AbilityManagerService>::GetInstance();
if (!manager) {
return;
}
//切到当前用户
manager->SwitchToUser(oldUserId, newUserId);
BroadcastUserBackground(oldUserId);
BroadcastUserForeground(newUserId);
}
foundation\ability\ability_runtime\services\abilitymgr\src\ability_manager_service.cpp
void AbilityManagerService::SwitchToUser(int32_t oldUserId, int32_t userId)
{
HILOG_INFO("%{public}s, oldUserId:%{public}d, newUserId:%{public}d", __func__, oldUserId, userId);
SwitchManagers(userId);
if (!Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) {
PauseOldUser(oldUserId);
ConnectBmsService();
//启动用户应用
StartUserApps();
}
bool isBoot = oldUserId == U0_USER_ID ? true : false;
//启动luancher或者开机引导
StartHighestPriorityAbility(userId, isBoot);
PauseOldConnectManager(oldUserId);
}
......
void AbilityManagerService::StartUserApps()
{
if (currentMissionListManager_ && currentMissionListManager_->IsStarted()) {
HILOG_INFO("missionListManager ResumeManager");
currentMissionListManager_->ResumeManager();
}
}
......
void AbilityManagerService::StartHighestPriorityAbility(int32_t userId, bool isBoot)
{
HILOG_DEBUG("%{public}s", __func__);
auto bms = GetBundleManager();
CHECK_POINTER(bms);
/* Query the highest priority ability or extension ability, and start it. usually, it is OOBE or launcher */
Want want;
want.AddEntity(HIGHEST_PRIORITY_ABILITY_ENTITY);
AppExecFwk::AbilityInfo abilityInfo;
AppExecFwk::ExtensionAbilityInfo extensionAbilityInfo;
int attemptNums = 0;
//查询优先级最高的ability
while (!IN_PROCESS_CALL(bms->ImplicitQueryInfoByPriority(want,
AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_DEFAULT, userId,
abilityInfo, extensionAbilityInfo))) {
HILOG_INFO("Waiting query highest priority ability info completed.");
++attemptNums;
if (!isBoot && attemptNums > SWITCH_ACCOUNT_TRY) {
HILOG_ERROR("Query highest priority ability failed.");
return;
}
AbilityRequest abilityRequest;
usleep(REPOLL_TIME_MICRO_SECONDS);
}
if (abilityInfo.name.empty() && extensionAbilityInfo.name.empty()) {
HILOG_ERROR("Query highest priority ability failed");
return;
}
Want abilityWant; // donot use 'want' here, because the entity of 'want' is not empty
if (!abilityInfo.name.empty()) {
/* highest priority ability */
HILOG_INFO("Start the highest priority ability. bundleName: %{public}s, ability:%{public}s",
abilityInfo.bundleName.c_str(), abilityInfo.name.c_str());
abilityWant.SetElementName(abilityInfo.bundleName, abilityInfo.name);
} else {
/* highest priority extension ability */
HILOG_INFO("Start the highest priority extension ability. bundleName: %{public}s, ability:%{public}s",
extensionAbilityInfo.bundleName.c_str(), extensionAbilityInfo.name.c_str());
abilityWant.SetElementName(extensionAbilityInfo.bundleName, extensionAbilityInfo.name);
}
#ifdef SUPPORT_GRAPHICS
abilityWant.SetParam(NEED_STARTINGWINDOW, false);
// wait BOOT_ANIMATION_STARTED to start LAUNCHER
//等待开机动画是否准备好才能继续往下走启动launcher
WaitBootAnimationStart();
#endif
/* OOBE APP启动完成之后需要disable自己,否者每次重启都会启动 */
(void)StartAbility(abilityWant, userId, DEFAULT_INVAL_VALUE);
}
......
void AbilityManagerService::WaitBootAnimationStart()
{
//判读属性bootevent.bootanimation.ready是否被置为true.
char value[BOOTEVENT_BOOT_ANIMATION_READY_SIZE] = "";
int32_t ret = GetParameter(BOOTEVENT_BOOT_ANIMATION_READY.c_str(), "", value,
BOOTEVENT_BOOT_ANIMATION_READY_SIZE);
if (ret > 0 && !std::strcmp(value, "false")) {
// Get new param success and new param is not ready, wait the new param.
WaitParameter(BOOTEVENT_BOOT_ANIMATION_READY.c_str(), "true",
AmsConfigurationParameter::GetInstance().GetBootAnimationTimeoutTime());
} else if (ret <= 0 || !std::strcmp(value, "")) {
// Get new param failed or new param is not set, wait the old param.
WaitParameter(BOOTEVENT_BOOT_ANIMATION_STARTED.c_str(), "true",
AmsConfigurationParameter::GetInstance().GetBootAnimationTimeoutTime());
}
// other, the animation is ready, not wait.
}
......
std::shared_ptr<AppExecFwk::BundleMgrHelper> AbilityManagerService::GetBundleManager()
{
if (bundleMgrHelper_ == nullptr) {
bundleMgrHelper_ = AbilityUtil::GetBundleManagerHelper();
}
return bundleMgrHelper_;
}
至此launcher或者开机引导(OOBE)就启动完成。
foundation\ability\ability_runtime\frameworks\native\appkit\ability_bundle_manager_helper\bundle_mgr_helper.cpp
bool BundleMgrHelper::ImplicitQueryInfoByPriority(
const Want &want, int32_t flags, int32_t userId, AbilityInfo &abilityInfo, ExtensionAbilityInfo &extensionInfo)
{
HILOG_DEBUG("Called.");
//绑定服务BundleMgrService
auto bundleMgr = Connect();
if (bundleMgr == nullptr) {
HILOG_ERROR("Failed to connect.");
return false;
}
//调用包管理服务的ImplicitQueryInfoByPriority
return bundleMgr->ImplicitQueryInfoByPriority(want, flags, userId, abilityInfo, extensionInfo);
}
......
sptr<IBundleMgr> BundleMgrHelper::Connect()
{
HILOG_DEBUG("Called.");
std::lock_guard<std::mutex> lock(mutex_);
if (bundleMgr_ == nullptr) {
sptr<ISystemAbilityManager> systemAbilityManager =
SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (systemAbilityManager == nullptr) {
HILOG_ERROR("Failed to get system ability manager.");
return nullptr;
}
sptr<IRemoteObject> remoteObject_ = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (remoteObject_ == nullptr || (bundleMgr_ = iface_cast<IBundleMgr>(remoteObject_)) == nullptr) {
HILOG_ERROR("Failed to get bundle mgr service remote object.");
return nullptr;
}
std::weak_ptr<BundleMgrHelper> weakPtr = shared_from_this();
auto deathCallback = [weakPtr](const wptr<IRemoteObject>& object) {
auto sharedPtr = weakPtr.lock();
if (sharedPtr == nullptr) {
HILOG_ERROR("Bundle helper instance is nullptr.");
return;
}
sharedPtr->OnDeath();
};
deathRecipient_ = new (std::nothrow) BundleMgrServiceDeathRecipient(deathCallback);
if (deathRecipient_ == nullptr) {
HILOG_ERROR("Failed to create death recipient ptr deathRecipient_!");
return nullptr;
}
if (bundleMgr_->AsObject() != nullptr) {
bundleMgr_->AsObject()->AddDeathRecipient(deathRecipient_);
}
}
return bundleMgr_;
}
foundation\bundlemanager\bundle_framework\interfaces\inner_api\appexecfwk_core\src\bundlemgr\bundle_mgr_proxy.cpp
bool BundleMgrProxy::ImplicitQueryInfoByPriority(const Want &want, int32_t flags, int32_t userId,
AbilityInfo &abilityInfo, ExtensionAbilityInfo &extensionInfo)
{
APP_LOGD("begin to ImplicitQueryInfoByPriority");
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
MessageParcel data;
if (!data.WriteInterfaceToken(GetDescriptor())) {
APP_LOGE("fail to implicit query info by priority due to write MessageParcel fail");
return false;
}
if (!data.WriteParcelable(&want)) {
APP_LOGE("fail to implicit query info by priority due to write want fail");
return false;
}
if (!data.WriteInt32(flags)) {
APP_LOGE("fail to implicit query info by priority due to write flags fail");
return false;
}
if (!data.WriteInt32(userId)) {
APP_LOGE("fail to implicit query info by priority due to write userId error");
return false;
}
MessageParcel reply;
//将消息码和对应的数据发给服务端
if (!SendTransactCmd(BundleMgrInterfaceCode::IMPLICIT_QUERY_INFO_BY_PRIORITY, data, reply)) {
return false;
}
if (!reply.ReadBool()) {
APP_LOGE("reply result false");
return false;
}
std::unique_ptr<AbilityInfo> abilityInfoPtr(reply.ReadParcelable<AbilityInfo>());
if (abilityInfoPtr == nullptr) {
APP_LOGE("read AbilityInfo failed");
return false;
}
abilityInfo = *abilityInfoPtr;
std::unique_ptr<ExtensionAbilityInfo> extensionInfoPtr(reply.ReadParcelable<ExtensionAbilityInfo>());
if (extensionInfoPtr == nullptr) {
APP_LOGE("read ExtensionAbilityInfo failed");
return false;
}
extensionInfo = *extensionInfoPtr;
return true;
}
foundation\bundlemanager\bundle_framework\interfaces\inner_api\appexecfwk_core\src\bundlemgr\bundle_mgr_host.cpp
//消息码对应的函数
funcMap_.emplace(static_cast<uint32_t>(BundleMgrInterfaceCode::IMPLICIT_QUERY_INFO_BY_PRIORITY),
&BundleMgrHost::HandleImplicitQueryInfoByPriority);
......
ErrCode BundleMgrHost::HandleImplicitQueryInfoByPriority(MessageParcel &data, MessageParcel &reply)
{
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
std::unique_ptr<Want> want(data.ReadParcelable<Want>());
if (want == nullptr) {
APP_LOGE("ReadParcelable<want> failed");
return ERR_APPEXECFWK_PARCEL_ERROR;
}
int32_t flags = data.ReadInt32();
int32_t userId = data.ReadInt32();
AbilityInfo abilityInfo;
ExtensionAbilityInfo extensionInfo;
bool ret = ImplicitQueryInfoByPriority(*want, flags, userId, abilityInfo, extensionInfo);
if (!reply.WriteBool(ret)) {
APP_LOGE("write failed");
return ERR_APPEXECFWK_PARCEL_ERROR;
}
if (ret) {
if (!reply.WriteParcelable(&abilityInfo)) {
APP_LOGE("write AbilityInfo failed");
return ERR_APPEXECFWK_PARCEL_ERROR;
}
if (!reply.WriteParcelable(&extensionInfo)) {
APP_LOGE("write ExtensionAbilityInfo failed");
return ERR_APPEXECFWK_PARCEL_ERROR;
}
}
return ERR_OK;
}
foundation\bundlemanager\bundle_framework\services\bundlemgr\src\bundle_mgr_host_impl.cpp
//ImplicitQueryInfoByPriority函数对应的服务端实现
bool BundleMgrHostImpl::ImplicitQueryInfoByPriority(const Want &want, int32_t flags, int32_t userId,
AbilityInfo &abilityInfo, ExtensionAbilityInfo &extensionInfo)
{
APP_LOGD("start ImplicitQueryInfoByPriority, flags : %{public}d, userId : %{public}d", flags, userId);
//判断是否是系统应用以及sdk版本号是否为9
if (!BundlePermissionMgr::IsSystemApp() &&
!BundlePermissionMgr::VerifyCallingBundleSdkVersion(Constants::API_VERSION_NINE)) {
APP_LOGD("non-system app calling system api");
return true;
}
//判断是否有对应的权限
if (!BundlePermissionMgr::VerifyCallingPermissionsForAll({Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED,
Constants::PERMISSION_GET_BUNDLE_INFO}) &&
!BundlePermissionMgr::IsBundleSelfCalling(want.GetElement().GetBundleName())) {
APP_LOGE("verify permission failed");
return false;
}
auto dataMgr = GetDataMgrFromService();
if (dataMgr == nullptr) {
APP_LOGE("DataMgr is nullptr");
return false;
}
return dataMgr->ImplicitQueryInfoByPriority(want, flags, userId, abilityInfo, extensionInfo);
}
foundation\bundlemanager\bundle_framework\services\bundlemgr\src\bundle_data_mgr.cpp
bool BundleDataMgr::ImplicitQueryInfoByPriority(const Want &want, int32_t flags, int32_t userId,
AbilityInfo &abilityInfo, ExtensionAbilityInfo &extensionInfo) const
{
int32_t requestUserId = GetUserId(userId);
if (requestUserId == Constants::INVALID_USERID) {
APP_LOGW("invalid userId");
return false;
}
//查询对应的abilityInfos和extensionInfos
std::vector<AbilityInfo> abilityInfos;
bool abilityValid =
ImplicitQueryAbilityInfos(want, flags, requestUserId, abilityInfos) && (abilityInfos.size() > 0);
std::vector<ExtensionAbilityInfo> extensionInfos;
bool extensionValid =
ImplicitQueryExtensionInfos(want, flags, requestUserId, extensionInfos) && (extensionInfos.size() > 0);
if (!abilityValid && !extensionValid) {
// both invalid
APP_LOGW("can't find target AbilityInfo or ExtensionAbilityInfo");
return false;
}
if (abilityValid && extensionValid) {
// both valid
if (abilityInfos[0].priority >= extensionInfos[0].priority) {
APP_LOGD("find target AbilityInfo with higher priority, name : %{public}s", abilityInfos[0].name.c_str());
abilityInfo = abilityInfos[0];
} else {
APP_LOGD("find target ExtensionAbilityInfo with higher priority, name : %{public}s",
extensionInfos[0].name.c_str());
extensionInfo = extensionInfos[0];
}
} else if (abilityValid) {
// only ability valid
APP_LOGD("find target AbilityInfo, name : %{public}s", abilityInfos[0].name.c_str());
abilityInfo = abilityInfos[0];
} else {
// only extension valid
APP_LOGD("find target ExtensionAbilityInfo, name : %{public}s", extensionInfos[0].name.c_str());
extensionInfo = extensionInfos[0];
}
return true;
}
......
bool BundleDataMgr::ImplicitQueryAbilityInfos(
const Want &want, int32_t flags, int32_t userId, std::vector<AbilityInfo> &abilityInfos, int32_t appIndex) const
{
int32_t requestUserId = GetUserId(userId);
if (requestUserId == Constants::INVALID_USERID) {
return false;
}
//开机启动的时候传进来的entity为HIGHEST_PRIORITY_ABILITY_ENTITY
if (want.GetAction().empty() && want.GetEntities().empty()
&& want.GetUriString().empty() && want.GetType().empty()) {
APP_LOGE("param invalid");
return false;
}
APP_LOGD("action:%{public}s, uri:%{private}s, type:%{public}s",
want.GetAction().c_str(), want.GetUriString().c_str(), want.GetType().c_str());
APP_LOGD("flags:%{public}d, userId:%{public}d", flags, userId);
std::shared_lock<std::shared_mutex> lock(bundleInfoMutex_);
if (bundleInfos_.empty()) {
APP_LOGW("bundleInfos_ is empty");
return false;
}
//开机启动的时候没有设置bundleName,所以为empty
std::string bundleName = want.GetElement().GetBundleName();
if (!bundleName.empty()) {
// query in current bundleName
if (!ImplicitQueryCurAbilityInfos(want, flags, requestUserId, abilityInfos, appIndex)) {
APP_LOGD("ImplicitQueryCurAbilityInfos failed, bundleName: %{public}s", bundleName.c_str());
return false;
}
} else {
// query all
ImplicitQueryAllAbilityInfos(want, flags, requestUserId, abilityInfos, appIndex);
}
// sort by priority, descending order.
//根据proority做排序
if (abilityInfos.size() > 1) {
std::stable_sort(abilityInfos.begin(), abilityInfos.end(),
[](AbilityInfo a, AbilityInfo b) { return a.priority > b.priority; });
}
return true;
}
......
void BundleDataMgr::ImplicitQueryAllAbilityInfos(const Want &want, int32_t flags, int32_t userId,
std::vector<AbilityInfo> &abilityInfos, int32_t appIndex) const
{
APP_LOGD("begin to ImplicitQueryAllAbilityInfos.");
int32_t requestUserId = GetUserId(userId);
if (requestUserId == Constants::INVALID_USERID) {
APP_LOGW("invalid userId");
return;
}
// query from bundleInfos_
if (appIndex == 0) {
for (const auto &item : bundleInfos_) {
const InnerBundleInfo &innerBundleInfo = item.second;
int32_t responseUserId = innerBundleInfo.GetResponseUserId(requestUserId);
if (CheckInnerBundleInfoWithFlags(innerBundleInfo, flags, responseUserId) != ERR_OK) {
APP_LOGD("ImplicitQueryAllAbilityInfos failed, bundleName:%{public}s, responseUserId:%{public}d",
innerBundleInfo.GetBundleName().c_str(), responseUserId);
continue;
}
GetMatchAbilityInfos(want, flags, innerBundleInfo, responseUserId, abilityInfos);
}
} else {
// query from sandbox manager for sandbox bundle
if (sandboxAppHelper_ == nullptr) {
APP_LOGW("sandboxAppHelper_ is nullptr");
return;
}
auto sandboxMap = sandboxAppHelper_->GetSandboxAppInfoMap();
for (const auto &item : sandboxMap) {
InnerBundleInfo info;
size_t pos = item.first.rfind(Constants::FILE_UNDERLINE);
if (pos == std::string::npos) {
APP_LOGD("sandbox map contains invalid element");
continue;
}
std::string innerBundleName = item.first.substr(pos + 1);
if (sandboxAppHelper_->GetSandboxAppInfo(innerBundleName, appIndex, userId, info) != ERR_OK) {
APP_LOGD("obtain innerBundleInfo of sandbox app failed");
continue;
}
int32_t responseUserId = info.GetResponseUserId(userId);
GetMatchAbilityInfos(want, flags, info, responseUserId, abilityInfos);
}
}
APP_LOGD("finish to ImplicitQueryAllAbilityInfos.");
}
void BundleDataMgr::GetMatchAbilityInfos(const Want &want, int32_t flags,
const InnerBundleInfo &info, int32_t userId, std::vector<AbilityInfo> &abilityInfos) const
{
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_SYSTEMAPP_ONLY) == GET_ABILITY_INFO_SYSTEMAPP_ONLY &&
!info.IsSystemApp()) {
return;
}
std::map<std::string, std::vector<Skill>> skillInfos = info.GetInnerSkillInfos();
for (const auto &abilityInfoPair : info.GetInnerAbilityInfos()) {
bool isPrivateType = MatchPrivateType(
want, abilityInfoPair.second.supportExtNames, abilityInfoPair.second.supportMimeTypes);
auto skillsPair = skillInfos.find(abilityInfoPair.first);
if (skillsPair == skillInfos.end()) {
continue;
}
for (const Skill &skill : skillsPair->second) {
if (isPrivateType || skill.Match(want)) {
AbilityInfo abilityinfo = abilityInfoPair.second;
AddAbilitySkillUrisInfo(flags, skill, abilityinfo);
if (abilityinfo.name == Constants::APP_DETAIL_ABILITY) {
continue;
}
if (!(static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_DISABLE)) {
if (!info.IsAbilityEnabled(abilityinfo, GetUserId(userId))) {
APP_LOGW("GetMatchAbilityInfos %{public}s is disabled", abilityinfo.name.c_str());
continue;
}
}
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_APPLICATION) ==
GET_ABILITY_INFO_WITH_APPLICATION) {
info.GetApplicationInfo(
ApplicationFlag::GET_APPLICATION_INFO_WITH_CERTIFICATE_FINGERPRINT, userId,
abilityinfo.applicationInfo);
}
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_PERMISSION) !=
GET_ABILITY_INFO_WITH_PERMISSION) {
abilityinfo.permissions.clear();
}
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_METADATA) != GET_ABILITY_INFO_WITH_METADATA) {
abilityinfo.metaData.customizeData.clear();
abilityinfo.metadata.clear();
}
abilityInfos.emplace_back(abilityinfo);
break;
}
}
}
}
void BundleDataMgr::AddAbilitySkillUrisInfo(int32_t flags, const Skill &skill, AbilityInfo &abilityInfo) const
{
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_SKILL_URI) == GET_ABILITY_INFO_WITH_SKILL_URI) {
std::vector<SkillUriForAbilityAndExtension> skillUriTmp;
for (const SkillUri &uri : skill.uris) {
SkillUriForAbilityAndExtension skillinfo;
skillinfo.scheme = uri.scheme;
skillinfo.host = uri.host;
skillinfo.port = uri.port;
skillinfo.path = uri.path;
skillinfo.pathStartWith = uri.pathStartWith;
skillinfo.pathRegex = uri.pathRegex;
skillinfo.type = uri.type;
skillinfo.utd = uri.utd;
skillinfo.maxFileSupported = uri.maxFileSupported;
skillUriTmp.emplace_back(skillinfo);
}
abilityInfo.skillUri = skillUriTmp;
}
}
AbilityInfo> &abilityInfos) const
{
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_SYSTEMAPP_ONLY) == GET_ABILITY_INFO_SYSTEMAPP_ONLY &&
!info.IsSystemApp()) {
return;
}
std::map<std::string, std::vector<Skill>> skillInfos = info.GetInnerSkillInfos();
for (const auto &abilityInfoPair : info.GetInnerAbilityInfos()) {
bool isPrivateType = MatchPrivateType(
want, abilityInfoPair.second.supportExtNames, abilityInfoPair.second.supportMimeTypes);
auto skillsPair = skillInfos.find(abilityInfoPair.first);
if (skillsPair == skillInfos.end()) {
continue;
}
for (const Skill &skill : skillsPair->second) {
if (isPrivateType || skill.Match(want)) {
AbilityInfo abilityinfo = abilityInfoPair.second;
AddAbilitySkillUrisInfo(flags, skill, abilityinfo);
if (abilityinfo.name == Constants::APP_DETAIL_ABILITY) {
continue;
}
if (!(static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_DISABLE)) {
if (!info.IsAbilityEnabled(abilityinfo, GetUserId(userId))) {
APP_LOGW("GetMatchAbilityInfos %{public}s is disabled", abilityinfo.name.c_str());
continue;
}
}
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_APPLICATION) ==
GET_ABILITY_INFO_WITH_APPLICATION) {
info.GetApplicationInfo(
ApplicationFlag::GET_APPLICATION_INFO_WITH_CERTIFICATE_FINGERPRINT, userId,
abilityinfo.applicationInfo);
}
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_PERMISSION) !=
GET_ABILITY_INFO_WITH_PERMISSION) {
abilityinfo.permissions.clear();
}
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_METADATA) != GET_ABILITY_INFO_WITH_METADATA) {
abilityinfo.metaData.customizeData.clear();
abilityinfo.metadata.clear();
}
abilityInfos.emplace_back(abilityinfo);
break;
}
}
}
}
void BundleDataMgr::AddAbilitySkillUrisInfo(int32_t flags, const Skill &skill, AbilityInfo &abilityInfo) const
{
if ((static_cast<uint32_t>(flags) & GET_ABILITY_INFO_WITH_SKILL_URI) == GET_ABILITY_INFO_WITH_SKILL_URI) {
std::vector<SkillUriForAbilityAndExtension> skillUriTmp;
for (const SkillUri &uri : skill.uris) {
SkillUriForAbilityAndExtension skillinfo;
skillinfo.scheme = uri.scheme;
skillinfo.host = uri.host;
skillinfo.port = uri.port;
skillinfo.path = uri.path;
skillinfo.pathStartWith = uri.pathStartWith;
skillinfo.pathRegex = uri.pathRegex;
skillinfo.type = uri.type;
skillinfo.utd = uri.utd;
skillinfo.maxFileSupported = uri.maxFileSupported;
skillUriTmp.emplace_back(skillinfo);
}
abilityInfo.skillUri = skillUriTmp;
}
}