鸿蒙OS启动流程

server/2024/10/18 1:27:11/

启动流程(基于openharmony4.1)

系统上电加载内核后,按照以下流程完成系统各个服务和应用的启动:

  1. 内核加载init进程,一般在bootloader启动内核时通过设置内核的cmdline来指定init的位置。
  2. init进程启动后,会挂载tmpfs,procfs,创建基本的dev设备节点,提供最基本的根文件系统。
  3. init也会启动ueventd监听内核热插拔设备事件,为这些设备创建dev设备节点。包括block设备各个分区设备都是通过此事件创建。
  4. init进程挂载block设备各个分区(system,vendor)后,开始扫描各个系统服务的init启动脚本,并拉起各个SA服务。
  5. samgr是各个SA的服务注册中心,每个SA启动时,都需要向samgr注册,每个SA会分配一个ID,应用可以通过该ID访问SA。
  6. foundation是一个特殊的SA服务进程,提供了用户程序管理框架及基础服务。由该进程负责应用的生命周期管理。
  7. 由于应用都需要加载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&nbsp、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.imgNA内核和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.imgvendor.img的挂载)。
  • 扫描system.imgvendor.imgetc/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传递关键信息给内核,这一部分内容是与平台相关的,主要信息如下:

    名称示例说明
    initrd0x84000000,0x292e00参考内核文档。
    ramfs-rootfs-initramfs.rst
    initrd.rst
    init/init
    blkdevpartsmmcblk0:1M(boot),15M(kernel),200M(system),200M(vendor),
    2M(misc),20M(updater),-(userdata)
    分区表信息,kernel会根据此信息创建物理分区。
    hardwareHi3516DV300、rk3568等(必要信息)硬件平台。
    root/dev/ram0(Hi3516DV00)、root=PARTUUID=614e0000-0000 rw(rk3568)kernel加载的启动设备。
    rootfstypeext4根文件系统类型。
    default_boot_devicesoc/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_STATISTICSUINT64 startNsec, endNsec, durationUsec;
#endifret = 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_STATISTICSstartNsec = 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_SMPOsSmpInit();
#endifOsInitCall(LOS_INIT_LEVEL_KMOD_TASK);#ifdef LOS_INIT_STATISTICSendNsec = LOS_CurrNanosec();durationUsec = (endNsec - startNsec) / OS_SYS_NS_PER_US;PRINTK("The main core takes %lluus to start.\n", durationUsec);
#endifreturn 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);//安全方式重置清0LOS_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_CONTAINEROsInitRootContainer();
#endif
#ifdef LOSCFG_KERNEL_PLIMITSOsProcLimiterSetInit();
#endifSystemProcessEarlyInit(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;//16ksysTask.pcName = "SystemInit";//任务名称sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;//内核默认优先级10sysTask.uwResved = LOS_TASK_STATUS_DETACHED;//任务分离模式
#ifdef LOSCFG_KERNEL_SMPsysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
#endifreturn 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_QUICKSTARTSystemInit1();SystemInit2();SystemInit3();
#endifSystemInit_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_ENTRYparam.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, &param);//用户进程开始初始化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.entryKEEP(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 = 参数3register UINT32 reg1 __asm__("r1") = (UINT32)(parm2);//R1 = 参数2register 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_DYNLOADsys_call3(__NR_execve, (UINTPTR)g_initPath, 0, 0);//发起系统调用,陷入内核态,对应 SysExecve ,加载elf运行
#endifwhile (true) {}
}
#endif

最终启动了/bin/init可执行程序

linux_626">标准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_INITRDif (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;}
#endifsetup_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_X86if (efi_enabled(EFI_RUNTIME_SERVICES))efi_enter_virtual_mode();
#endifthread_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_ACCTreclaimacct_init();
#endifpoking_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号进程initpid = 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);elsereturn 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为1if (getpid() != INIT_PROCESS_PID) {INIT_LOGE("Process id error %d!", getpid());return 0;}//使能init阶段logEnableInitLog(INIT_INFO);// Updater modeif (isSecondStage == 0) {//从kernel启动的init第一阶段走如下:SystemPrepare(upTimeInMicroSecs);} else {//初始化kmsgLogInit();}SystemInit();//执行init进程的初始化,注册socketSystemExecuteRcs();//执行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.cCreateFsAndDeviceNode();//钩子函数 插桩//base\startup\init\interfaces\innerkits\hookmgr\hookmgr.cHookMgrExecute(GetBootStageHookMgr(), INIT_FIRST_STAGE, NULL, NULL);// Updater mode no need to mount and switch root//升级模式不进入第二阶段if (InUpdaterMode() != 0) {return;}//挂载required分区MountRequiredPartitions();//二级启动initStartSecondStageInit(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 abortINIT_LOGE("Mount required partitions failed; please check fstab file");// Execute sh for debugging
#ifndef STARTUP_INIT_TESTexecv("/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 stagechar * 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文件,只有在前一种方式获取失败的情况下才会尝试通过这种方式获取。

    • 块设备的创建逻辑

      • 准备工作

        1. init从cmdline中读取required fstab,若获取失败,则尝试读fstab.required文件,从中获取必须挂载的块设备的PARTNAME,例如system和vendor.
        2. 创建接收内核上报uevent事件广播消息的socket,从/proc/cmdline里读取default_boot_device。
        3. 带着fstab信息和socket句柄遍历/sys/devices目录,准备开始触发内核上报uevent事件。
      • 触发事件

        1. 通过ueventd触发内核上报uevent事件
        2. 匹配uevent事件中的partitionName与required fstab中的device信息。
        3. 匹配成功后将会进一步处理,格式化设备节点路径,准备开始创建设备节点。
      • 创建节点

        1. 为了便于用户态下对设备节点的访问以及提高设备节点的可读性,会对即将创建的required块设备节点同时创建软链接,这就需要先格式化软链接的路径。
        2. 以上工作都完成后,将执行最后的创建设备节点的步骤,根据传入的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为1if (getpid() != INIT_PROCESS_PID) {INIT_LOGE("Process id error %d!", getpid());return 0;}//使能init阶段logEnableInitLog(INIT_INFO);// Updater modeif (isSecondStage == 0) {//从kernel启动的init第一阶段走如下:SystemPrepare(upTimeInMicroSecs);} else {//初始化kmsgLogInit();}SystemInit();//执行init进程的初始化,注册socketSystemExecuteRcs();//执行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/kmsgOpenLogDevice();}
}
.
.
.
.
.
.
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 rootif (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,对应的处理函数ProcessControlFdCmdServiceInit(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 processif (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 processsem_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 exitedif (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 值为-1000InitSysAdj();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.prepareRecordInitBootEvent("init.prepare");HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);if (InitParamService() != 0) {ExecReboot("panic");}//将解析的cfg值放入对应的groupNodes中InitParseGroupCfg();//记录开机事件RecordInitBootEvent//设置开机的时间属性ohos.boot.time.initRegisterBootStateChange(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 parametersHookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);//加载系统的参数InitLoadParamFiles();// Write kernel uptime into system parameter//设置kernel启动时间WriteUptimeSysParam("ohos.boot.time.kernel", uptime);// read configHookMgrExecute(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 servicePostTrigger(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 paramLoadDefaultParams("/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 modestrcpy_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/etcchar *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 importg_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 dacLoadParamAreaSize();// read selinux labelLoadSelinuxLabel("init");// from cmdlineLoadParamFromCmdLine();// from buildLoadParamFromBuild();
}

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_VERSIONif (strlen(INCREMENTAL_VERSION) > 0) {WriteParam("const.product.incremental.version", INCREMENTAL_VERSION, NULL, LOAD_PARAM_NORMAL);}
#endif
#ifdef BUILD_TYPEif (strlen(BUILD_TYPE) > 0) {WriteParam("const.product.build.type", BUILD_TYPE, NULL, LOAD_PARAM_NORMAL);}
#endif
#ifdef BUILD_USERif (strlen(BUILD_USER) > 0) {WriteParam("const.product.build.user", BUILD_USER, NULL, LOAD_PARAM_NORMAL);}
#endif
#ifdef BUILD_TIMEif (strlen(BUILD_TIME) > 0) {WriteParam("const.product.build.date", BUILD_TIME, NULL, LOAD_PARAM_NORMAL);}
#endif
#ifdef BUILD_HOSTif (strlen(BUILD_HOST) > 0) {WriteParam("const.product.build.host", BUILD_HOST, NULL, LOAD_PARAM_NORMAL);}
#endif
#ifdef BUILD_ROOTHASHif (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 cfgchar buffer[32] = {0}; // 32 reason max lebuint32_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文件中的servicesParseAllServices(root, &context);// 解析cfg文件中的jobsParseAllJobs(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 labelLoadSelinuxLabel("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 initPostTrigger(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文件中是否配置按需启动ondemandbool 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 profilesbool 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;}//启动SAret = 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();//解析profilebool 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.jsonbool ret = profileParser_->ParseTrustConfig(path, trustMaps);if (ret && !trustMaps.empty()) {// 1.get allowed sa set in the processconst 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 itfor (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的信息添加到samgrRegisterOnDemandSystemAbility(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的信息添加到samgrint32_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 SAMGRHILOGD(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 abilitypublishObj_ = 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_ACCOUNTSRestartActiveAccount();
#endif // ENABLE_MULTIPLE_ACTIVE_ACCOUNTSCleanGarbageAccounts();
}......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)
{// activateint 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 infoosAccountInfo.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调用startUsererror = 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 screenSetFreezingNewUserId(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;//查询优先级最高的abilitywhile (!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 emptyif (!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_GRAPHICSabilityWant.SetParam(NEED_STARTINGWINDOW, false);// wait BOOT_ANIMATION_STARTED to start LAUNCHER//等待开机动画是否准备好才能继续往下走启动launcherWaitBootAnimationStart();
#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.");//绑定服务BundleMgrServiceauto bundleMgr = Connect();if (bundleMgr == nullptr) {HILOG_ERROR("Failed to connect.");return false;}//调用包管理服务的ImplicitQueryInfoByPriorityreturn 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版本号是否为9if (!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和extensionInfosstd::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 invalidAPP_LOGW("can't find target AbilityInfo or ExtensionAbilityInfo");return false;}if (abilityValid && extensionValid) {// both validif (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 validAPP_LOGD("find target AbilityInfo, name : %{public}s", abilityInfos[0].name.c_str());abilityInfo = abilityInfos[0];} else {// only extension validAPP_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_ENTITYif (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,所以为emptystd::string bundleName = want.GetElement().GetBundleName();if (!bundleName.empty()) {// query in current bundleNameif (!ImplicitQueryCurAbilityInfos(want, flags, requestUserId, abilityInfos, appIndex)) {APP_LOGD("ImplicitQueryCurAbilityInfos failed, bundleName: %{public}s", bundleName.c_str());return false;}} else {// query allImplicitQueryAllAbilityInfos(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 bundleif (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;}
}

http://www.ppmy.cn/server/131280.html

相关文章

51单片机-第十四节-AD/DA(XPT2046触摸屏)

一、AD/DA介绍&#xff1a; AD&#xff1a;模拟-数字转换&#xff0c;将模拟信号转换为计算机可操作的数字信号。 DA&#xff1a;数字-模拟转换&#xff0c;将计算机输出的数字信号转换为模拟信号。 二、运算放大器&#xff1a; 1.介绍&#xff1a; &#xff08;1&#xf…

笔试算法总结

文章目录 题目1题目2题目3题目4 题目1 使用 StringBuilder 模拟栈的行为&#xff0c;通过判断相邻2个字符是否相同&#xff0c;如果相同就进行删除 public class Main {public static String fun(String s) {if (s null || s.length() < 1) return s;StringBuilder builde…

python发邮件附件:配置SMTP服务器与认证?

python发邮件附件技巧&#xff1f;Python发送多附件邮件的方法&#xff1f; Python作为一种强大的编程语言&#xff0c;提供了丰富的库和工具来实现这一功能。AokSend将深入探讨如何使用Python发邮件附件&#xff0c;并详细介绍配置SMTP服务器与认证的关键步骤。 python发邮件…

自然语言处理问答系统:技术进展、应用与挑战

自然语言处理&#xff08;NLP&#xff09;问答系统是人工智能领域的一个重要分支&#xff0c;它通过理解和分析用户的提问&#xff0c;从大量的文本数据中提取相关信息&#xff0c;并以自然语言的形式回答用户的问题。随着深度学习技术的发展&#xff0c;尤其是预训练语言模型&…

JavaScript设计案例

JavaScript设计案例详解 JavaScript&#xff08;JS&#xff09;作为Web开发的核心技术之一&#xff0c;不仅在前端交互中扮演着至关重要的角色&#xff0c;还在数据处理、动画效果、游戏开发等多个领域展现出强大的功能。本文将通过几个实际的JavaScript设计案例&#xff0c;深…

YoloV8改进策略:BackBone改进|CAFormer在YoloV8中的创新应用,显著提升目标检测性能

摘要 在目标检测领域,模型性能的提升一直是研究者和开发者们关注的重点。近期,我们尝试将CAFormer模块引入YoloV8模型中,以替换其原有的主干网络,这一创新性的改进带来了显著的性能提升。 CAFormer,作为MetaFormer框架下的一个变体,结合了深度可分离卷积和普通自注意力…

Apache DolphinScheduler社区9月进展记录

各位热爱 Apache DolphinScheduler 的小伙伴们&#xff0c;社区 9 月月报更新啦&#xff01;这里将记录 Apache DolphinScheduler 社区每月的重要更新&#xff0c;欢迎关注&#xff01; 月度 Merge Star 感谢以下小伙伴上个月为 Apache DolphinScheduler 做的精彩贡献&#x…

仿IOS桌面悬浮球(支持拖拽、自动吸附、自动改变透明度与点击、兼容PC端与移动端)

使用 pointerdown/pointermove/pointerup 实现仿IOS桌面悬浮球效果&#xff0c;支持拖拽、指定拖拽选对容器&#xff0c;指定拖拽安全区、自动吸附、自动改变透明度与点击&#xff0c;兼容PC端与移动端。 效果展示 https://code.juejin.cn/pen/7423757568268304421 代码实现 …