摘要:本文介绍了startup子系统之bootstrap_lite服务启动引导部件的移植适配案例及原理。

本文分享自华为云社区《OpenHarmony移植案例与原理 - startup子系统之bootstrap_lite服务启动引导部件》,作者:zhushy。

bootstrap_lite服务启动引导组件提供了各服务和功能的启动入口标识。在SAMGR(System ability manager,系统服务管理)启动时,会调用bootstrap_lite标识的入口函数,并启动系统服务。本文介绍下移植开发板时如何适配服务启动引导部件bootstrap_lite,并介绍下相关的运行机制原理。bootstrap_lite启动引导部件定义在build\lite\components\startup.json。bootstrap_lite启动引导部件源代码目录如下:

base/startup/bootstrap_lite/    # 启动引导组件
└── services
└── source # 启动引导组件源文件目录

1、bootstrap_lite服务启动引导部件适配示例

1.1 产品解决方案配置启用部件

移植开发板适配startup子系统之bootstrap_lite服务启动引导部件时,需要在产品解决方案的config.json增加下述配置项,可以参考vendor\bestechnic\display_demo\config.json中的配置示例:

 {
"subsystem": "startup",
"components": [
{
"component": "bootstrap_lite"
},
......
]
},

1.2 使用bootstrap服务启动部件提供的初始化宏函数

然后就可以使用bootstrap服务启动部件提供的初始化宏函数SYS_SERVICE_INIT、APP_SERVICE_INIT等来自动初始化服务,示例代码可以参考device\board\fnlink\v200zr\liteos_m\at\at_wifi.c中的用法,片段如下,可以看到调用了宏函数来初始化RegisterCustomATCmd函数实现的服务。device\board\bearpi\bearpi_hm_nano\app\目录下有更多的使用示例。下文分析实现机制原理。

static void RegisterCustomATCmd()
{
cmd_tbl_t cmd_list[] = {
{"AT+IFCFG", 8, at_lwip_ifconfig, "AT+IFCFG - ifconfig\n"},
{"AT+STARTAP", 7, at_start_softap, "AT+STARTAP - start wifi softap\n"},
{"AT+STOPAP", 1, at_stop_softap, "AT+STOPAP - stop wifi softap\n"},
{"AT+STARTSTA", 1, at_start_wifista, "AT+STARTSTA - start wifi sta\n"},
{"AT+STOPSTA", 1, at_stop_wifista, "AT+STOPSTA - stop wifi sta\n"},
{"AT+DHCP", 3, at_setup_dhcp, "AT+DHCP - dhcp\n"},
{"AT+DHCPS", 3, at_setup_dhcps, "AT+DHCPS - dhcps\n"},
};
for (int i = 0; i < sizeof(cmd_list) / sizeof(cmd_tbl_t); i++) {
console_cmd_add(&cmd_list[i]);
}
}
SYS_SERVICE_INIT(RegisterCustomATCmd);

1.3 链接脚本中增加zInit代码段

适配bootstrap_lite部件时,还需要在链接脚本文件中手动新增如下段,链接脚本示例可以参考//device/soc/bestechnic/bes2600/liteos_m/sdk/bsp/out/best2600w_liteos/_best2001.lds,还可以参考device\soc\hisilicon\hi3861v100\sdk_liteos\build\link\link.ld.S。从链接脚本片段中可以看出,有.zinitcall.bsp、.zinitcall.device、.zinitcall.core、.zinitcall.sys.service、.zinitcall.sys.feature、.zinitcall.run、.zinitcall.app.service、.zinitcall.app.feature、.zinitcall.test和.zinitcall.exit等几种类型的段。

/* zInit code and data - will be freed after init */
.zInit (.) :
{
__zinitcall_bsp_start = .;
KEEP (*(.zinitcall.bsp0.init))
KEEP (*(.zinitcall.bsp1.init))
KEEP (*(.zinitcall.bsp2.init))
KEEP (*(.zinitcall.bsp3.init))
KEEP (*(.zinitcall.bsp4.init))
__zinitcall_bsp_end = .;
. = ALIGN(4);
__zinitcall_device_start = .;
KEEP (*(.zinitcall.device0.init))
KEEP (*(.zinitcall.device1.init))
KEEP (*(.zinitcall.device2.init))
KEEP (*(.zinitcall.device3.init))
KEEP (*(.zinitcall.device4.init))
__zinitcall_device_end = .;
. = ALIGN(4);
__zinitcall_core_start = .;
KEEP (*(.zinitcall.core0.init))
KEEP (*(.zinitcall.core1.init))
KEEP (*(.zinitcall.core2.init))
KEEP (*(.zinitcall.core3.init))
KEEP (*(.zinitcall.core4.init))
__zinitcall_core_end = .;
. = ALIGN(4);
__zinitcall_sys_service_start = .;
KEEP (*(.zinitcall.sys.service0.init))
KEEP (*(.zinitcall.sys.service1.init))
KEEP (*(.zinitcall.sys.service2.init))
KEEP (*(.zinitcall.sys.service3.init))
KEEP (*(.zinitcall.sys.service4.init))
__zinitcall_sys_service_end = .;
. = ALIGN(4);
__zinitcall_sys_feature_start = .;
KEEP (*(.zinitcall.sys.feature0.init))
KEEP (*(.zinitcall.sys.feature1.init))
KEEP (*(.zinitcall.sys.feature2.init))
KEEP (*(.zinitcall.sys.feature3.init))
KEEP (*(.zinitcall.sys.feature4.init))
__zinitcall_sys_feature_end = .;
. = ALIGN(4);
__zinitcall_run_start = .;
KEEP (*(.zinitcall.run0.init))
KEEP (*(.zinitcall.run1.init))
KEEP (*(.zinitcall.run2.init))
KEEP (*(.zinitcall.run3.init))
KEEP (*(.zinitcall.run4.init))
__zinitcall_run_end = .;
. = ALIGN(4);
__zinitcall_app_service_start = .;
KEEP (*(.zinitcall.app.service0.init))
KEEP (*(.zinitcall.app.service1.init))
KEEP (*(.zinitcall.app.service2.init))
KEEP (*(.zinitcall.app.service3.init))
KEEP (*(.zinitcall.app.service4.init))
__zinitcall_app_service_end = .;
. = ALIGN(4);
__zinitcall_app_feature_start = .;
KEEP (*(.zinitcall.app.feature0.init))
KEEP (*(.zinitcall.app.feature1.init))
KEEP (*(.zinitcall.app.feature2.init))
KEEP (*(.zinitcall.app.feature3.init))
KEEP (*(.zinitcall.app.feature4.init))
__zinitcall_app_feature_end = .;
. = ALIGN(4);
__zinitcall_test_start = .;
KEEP (*(.zinitcall.test0.init))
KEEP (*(.zinitcall.test1.init))
KEEP (*(.zinitcall.test2.init))
KEEP (*(.zinitcall.test3.init))
KEEP (*(.zinitcall.test4.init))
__zinitcall_test_end = .;
. = ALIGN(4);
__zinitcall_exit_start = .;
KEEP (*(.zinitcall.exit0.init))
KEEP (*(.zinitcall.exit1.init))
KEEP (*(.zinitcall.exit2.init))
KEEP (*(.zinitcall.exit3.init))
KEEP (*(.zinitcall.exit4.init))
__zinitcall_exit_end = .;
. = ALIGN(4);
} > FLASH

1.4 配置编译时链接bootstrap库

另外,bootstrap_lite部件会编译//base/startup/bootstrap_lite/services/source/bootstrap_service.c,该文件中,通过SYS_SERVICE_INIT将Init函数符号指定到__zinitcall_sys_service_start和__zinitcall_sys_service_end段中,由于没有显式调用Init函数,所以需要将它强制链接到最终的镜像。可以参考device\board\goodix\gr5515_sk\liteos_m\config.gni文件中的链接选项。恒玄的开发板适配时,是配置到vendor\bestechnic\display_demo\config.json文件中的自己定义的配置项force_link_libs里,该配置项在device\soc\bestechnic\bes2600\BUILD.gn中被解析、链接。

board_ld_flags = [
....
"-lbootstrap",

1.5 调用OHOS_SystemInit接口

函数void OHOS_SystemInit(void)定义在文件base\startup\bootstrap_lite\services\source\system_init.c中,在移植适配时,需要调用该接口。可以参考文件device\soc\bestechnic\bes2600\liteos_m\sdk\bsp\rtos\liteos\liteos_m\board.c中的使用示例。

int main(void);
extern void OHOS_SystemInit(void);
......
OHOS_SystemInit();
......
while (1) {
osDelay(1000);
TRACE(0, "main idle");
}
}

2、bootstrap_lite服务启动引导部件实现原理之system_init

bootstrap_lite服务启动部件实现了服务的自动初始化,即服务的初始化函数无需显式调用,它是使用宏定义的方式申明,在系统启动时自动被执行。实现原理是将服务启动的函数通过宏申明之后,放在预定义好的zInit代码段中,系统启动的时候调用OHOS_SystemInit接口,遍历该代码段并调用其中的函数。因此在适配移植时,需要在device/soc/下面具体的芯片的链接脚本中添加zInit段,并且在main函数里调用OHOS_SystemInit接口。

2.1 bootstrap_lite服务启动引导部件的初始化宏

bootstrap_lite服务启动引导部件的初始化宏定义在文件utils\native\lite\include\ohos_init.h,片段如下。初始化函数宏SYS_SERVICE_INIT(func)用于标识核心系统服务的初始化入口,该宏识别的函数在启动过程中核心系统服务优先级2阶段被调用;初始化宏SYS_SERVICE_INIT_PRI(func, priority)可以指定优先级数值,优先级的取值范围为[0,5),调用顺序为0, 1, 2, 3, 4。

  /**
* @brief Identifies the entry for initializing and starting a core system service by the
* priority 2.
*
* This macro is used to identify the entry called at the priority 2 in the core system
* service phase of the startup process. \n
*
* @param func Indicates the entry function for initializing and starting a core system service.
* The type is void (*)(void).
*/
#define SYS_SERVICE_INIT(func) LAYER_INITCALL_DEF(func, sys_service, "sys.service")
/**
* @brief Identifies the entry for initializing and starting a core system service by the
* specified priority.
*
* This macro is used to identify the entry called at the specified priority in the core system
* service phase of the startup process. \n
*
* @param func Indicates the entry function for initializing and starting a core system service.
* The type is void (*)(void).
* @param priority Indicates the calling priority when starting the core system service in the
* startup phase. The value range is [0,5), and the calling sequence is 0, 1, 2, 3, and 4.
*/
#define SYS_SERVICE_INIT_PRI(func, priority) LAYER_INITCALL(func, sys_service, "sys.service", priority)

更多的初始化宏见下文的列表,处理这些初始化宏,还有可以指定优先级的版本XXX_PRI。

2.2 LAYER_INITCALL宏定义

从上文已知,bootstrap_lite服务启动引导部件的初始化宏会调用LAYER_INITCALL_DEF和LAYER_INITCALL宏。这些宏的定义在文件utils\native\lite\include\ohos_init.h,代码片段如下。⑴处声明函数类型,无参无返回值。⑵处处理定义分层初始化共享库宏LAYER_INIT_SHARED_LIB的情况,如果没有定义该宏,则执行⑹。在文件foundation/distributedschedule/samgr_lite/samgr/BUILD.gn中定义了该宏,在移植适配芯片开发板时,没有定义这个宏。⑶处定义5个分层初始化级别,⑷处定义7个构建值(constructor value,简称CTOR Value)。⑸处是宏LAYER_INITCALL的定义,该宏需要4个参数,分别是初始化服务或功能函数func;layer是分层名称,支持的取值为device、core、sys_service、sys_feature、app_service、app_feature和run,拼装为CTOR_VALUE_XXX;clayer参数在定义宏LAYER_INIT_SHARED_LIB时未使用;priority是优先级参数。attribute((constructor))表示这段代码将在main函数前调用。当传入参数为(myFunc, sys_feature, “sys.feature”, 2)时,函数宏替换为:static __attribute__((constructor(130 + 2))) void BOOT_sys_featurer2myFunc {myFunc();}。等于定义个一个新的启动引导函数BOOT_sys_featurer2myFunc()。

当没有定义LAYER_INIT_SHARED_LIB宏时,执行⑹,当传入参数为(myFunc, sys_feature, “sys.feature”, 2)时,函数宏替换为:static const InitCall __attribute__((used)) __zinitcall_sys_feature_myFunc __attribute__((section(".zinitcall.sys.feature2.init"))) = myFunc,除了__attribute__部分,等于声明一个函数类型InitCall的变量__zinitcall_sys_feature_myFunc。该函数变量放入section段".zinitcall.sys.feature2.init"内,所以移植适配时,需要在芯片开发板的链接脚本里添加zInit代码段。

⑴  typedef void (*InitCall)(void);

    #define USED_ATTR __attribute__((used))

⑵  #ifdef LAYER_INIT_SHARED_LIB
⑶ #define LAYER_INIT_LEVEL_0 0
#define LAYER_INIT_LEVEL_1 1
#define LAYER_INIT_LEVEL_2 2
#define LAYER_INIT_LEVEL_3 3
#define LAYER_INIT_LEVEL_4 4
⑷ #define CTOR_VALUE_device 100
#define CTOR_VALUE_core 110
#define CTOR_VALUE_sys_service 120
#define CTOR_VALUE_sys_feature 130
#define CTOR_VALUE_app_service 140
#define CTOR_VALUE_app_feature 150
#define CTOR_VALUE_run 700
⑸ #define LAYER_INITCALL(func, layer, clayer, priority) \
static __attribute__((constructor(CTOR_VALUE_##layer + LAYER_INIT_LEVEL_##priority))) \
void BOOT_##layer##priority##func() {func();}
#else
⑹ #define LAYER_INITCALL(func, layer, clayer, priority) \
static const InitCall USED_ATTR __zinitcall_##layer##_##func \
__attribute__((section(".zinitcall." clayer #priority ".init"))) = func
#endif
// Default priority is 2, priority range is [0, 4]
#define LAYER_INITCALL_DEF(func, layer, clayer) \
LAYER_INITCALL(func, layer, clayer, 2)

2.3 OHOS_SystemInit函数

函数OHOS_SystemInit()定义在文件base\startup\bootstrap_lite\services\source\system_init.c,代码如下。调用宏函数MODULE_INIT、SYS_INIT和函数SAMGR_Bootstrap()进行初始化启动。

void OHOS_SystemInit(void)
{
MODULE_INIT(bsp);
MODULE_INIT(device);
MODULE_INIT(core);
SYS_INIT(service);
SYS_INIT(feature);
MODULE_INIT(run);
SAMGR_Bootstrap();
}

我们详细分析下宏函数MODULE_INIT和SYS_INIT的源代码,这2个宏函数在文件base\startup\bootstrap_lite\services\source\core_main.h中定义,代码如下。这些宏函数的参数大都为name和step,name取值为bsp、device、core、service、feature、run,step取值为0。从⑺和⑻处可以看出,分别调用SYS_CALL、MODULE_CALL两个宏,第二个参数设置为0。⑸处定义的MODULE_BEGIN函数,用于返回链接脚本中定义的代码段的开始地址,当传入参数为bsp时,返回&__zinitcall_bsp_start,MODULE_BEGIN函数被展开为如下片段:

{        extern InitCall __zinitcall_sys_start;      \
InitCall *initCall = &__zinitcall_bsp_start; \
(initCall); \
}

⑹处定义的MODULE_END函数,用于返回链接脚本中定义的代码段的结束地址,当传入参数为bsp时,返回&__zinitcall_bsp_end,MODULE_END函数被展开为如下片段:

{        extern InitCall __zinitcall_bsp_end;      \
InitCall *initCall = &__zinitcall_bsp_end; \
(initCall); \
}

⑶和⑷处定义的SYS_BEGIN、SYS_END代码类似,分于返回链接脚本中定义的标记系统服务或特性的代码段的开始、结束地址,即&__zinitcall_sys_service_start、&__zinitcall_sys_service_end、&__zinitcall_sys_feature_start、&__zinitcall_sys_feature_end。⑴处定义的SYS_CALL函数,分别获取链接脚本中zInit代码段的开始initcall和结束地址initend,这些地址存放的是初始化函数的地址,语句 (*initcall)()会循环调用执行这些初始化函数。⑵处MODULE_CALL宏类似。

⑴  #define SYS_CALL(name, step)                                      \
do { \
InitCall *initcall = (InitCall *)(SYS_BEGIN(name, step)); \
InitCall *initend = (InitCall *)(SYS_END(name, step)); \
for (; initcall < initend; initcall++) { \
(*initcall)(); \
} \
} while (0) ⑵ #define MODULE_CALL(name, step) \
do { \
InitCall *initcall = (InitCall *)(MODULE_BEGIN(name, step)); \
InitCall *initend = (InitCall *)(MODULE_END(name, step)); \
for (; initcall < initend; initcall++) { \
(*initcall)(); \
} \
} while (0) ......
⑶ #define SYS_BEGIN(name, step) \
({ extern InitCall __zinitcall_sys_##name##_start; \
InitCall *initCall = &__zinitcall_sys_##name##_start; \
(initCall); \
}) ⑷ #define SYS_END(name, step) \
({ extern InitCall __zinitcall_sys_##name##_end; \
InitCall *initCall = &__zinitcall_sys_##name##_end; \
(initCall); \
}) ⑸ #define MODULE_BEGIN(name, step) \
({ extern InitCall __zinitcall_##name##_start; \
InitCall *initCall = &__zinitcall_##name##_start; \
(initCall); \
})
⑹ #define MODULE_END(name, step) \
({ extern InitCall __zinitcall_##name##_end; \
InitCall *initCall = &__zinitcall_##name##_end; \
(initCall); \
}) ⑺ #define SYS_INIT(name) \
do { \
SYS_CALL(name, 0); \
} while (0) ⑻ #define MODULE_INIT(name) \
do { \
MODULE_CALL(name, 0); \
} while (0)

3、 bootstrap_lite服务启动引导部件实现原理之bootstrap_service

在文件base\startup\bootstrap_lite\services\source\bootstrap_service.h中定义了2个宏函数INIT_APP_CALL和INIT_TEST_CALL,分别用来调用代码段&__zinitcall_app_XXX_start、&__zinitcall_app_XXX_end和&__zinitcall_test_start、&__zinitcall_test_end之间的初始化启动函数。bootstrap_service.h文件中的宏和base\startup\bootstrap_lite\services\source\core_main.h文件中的宏类似,不再一一分析。

3.1 结构体struct Bootstrap

在文件base\startup\bootstrap_lite\services\source\bootstrap_service.c中定义了结构体struct Bootstrap,如下代码⑵处。其中结构体中的INHERIT_SERVICE定义在文件foundation/distributedschedule/samgr_lite/interfaces/kits/samgr/service.h,见代码片段⑴处。

⑴   #define INHERIT_SERVICE                                          \
const char *(*GetName)(Service * service); \
BOOL (*Initialize)(Service * service, Identity identity); \
BOOL (*MessageHandle)(Service * service, Request * request); \
TaskConfig (*GetTaskConfig)(Service * service) ......
⑵ typedef struct Bootstrap {
INHERIT_SERVICE;
Identity identity;
uint8 flag;
} Bootstrap;

结构体Identity定义在文件foundation\distributedschedule\samgr_lite\interfaces\kits\samgr\message.h中,用于标识一个服务或特性。

/**
* @brief Identifies a service and feature.
*
* You can use this structure to identity a {@link IUnknown} feature to which messages will be
* sent through the asynchronous function of {@link IUnknown}. \n
*
*/
struct Identity {
/** Service ID */
int16 serviceId;
/** Feature ID */
int16 featureId;
/** Message queue ID */
MQueueId queueId;
};

3.2 Init(void)函数

讲解移植适配示例时,我们已经知道,bootstrap_lite部件会编译//base/startup/bootstrap_lite/services/source/bootstrap_service.c,该文件通过函数宏SYS_SERVICE_INIT将Init()函数符号灌段到__zinitcall_sys_service_start和__zinitcall_sys_service_end代码段中,代码片段如下。下文再详细分析GetName、Initialize、MessageHandle和GetTaskConfig函数。

  static const char *GetName(Service *service);
static BOOL Initialize(Service *service, Identity identity);
static TaskConfig GetTaskConfig(Service *service);
static BOOL MessageHandle(Service *service, Request *request); static void Init(void)
{
static Bootstrap bootstrap;
bootstrap.GetName = GetName;
bootstrap.Initialize = Initialize;
bootstrap.MessageHandle = MessageHandle;
bootstrap.GetTaskConfig = GetTaskConfig;
bootstrap.flag = FALSE;
SAMGR_GetInstance()->RegisterService((Service *)&bootstrap);
}
SYS_SERVICE_INIT(Init);

3.3 GetName和Initialize函数

GetName函数代码如下,其中BOOTSTRAP_SERVICE定义在文件foundation\distributedschedule\samgr_lite\interfaces\kits\samgr\samgr_lite.h中,取值为"Bootstrap",表示启动引导服务。

static const char *GetName(Service *service)
{
(void)service;
return BOOTSTRAP_SERVICE;
}

Initialize函数定义如下,用于设置启动引导服务的标识信息。

static BOOL Initialize(Service *service, Identity identity)
{
Bootstrap *bootstrap = (Bootstrap *)service;
bootstrap->identity = identity;
return TRUE;
}

3.4 MessageHandle函数和GetTaskConfig函数

MessageHandle函数和GetTaskConfig函数代码如下,MessageHandle函数用于处理各种请求,请求消息编号定义request->msgId定义在文件foundation\distributedschedule\samgr_lite\interfaces\kits\samgr\samgr_lite.h中的枚举enum BootMessage,如下⑴处所示。在MessageHandle函数中,当请求的消息编号为BOOT_SYS_COMPLETED系统服务初始化完成时,检查应用服务是否加载。当应用没有加载时,执行INIT_APP_CALL宏函数调用zInit代码段上的应用服务和应用特性初始化函数。然后执行⑶,调用函数SAMGR_SendResponseByIdentity进行响应。GetTaskConfig函数用于获取任务配置。

⑴  typedef enum BootMessage {
/** Message indicating that the core system service is initialized */
/** 标识核心系统服务初始化完成 */
BOOT_SYS_COMPLETED,
/** Message indicating that the system and application-layer services are initialized */
/** 标识应用层服务初始化完成 */
BOOT_APP_COMPLETED,
/** Message indicating service registration during running */
/** 标识运行时的服务注册 */
BOOT_REG_SERVICE,
/** Maximum number of message IDs */
/** 标识消息最大值,butt是烟蒂;屁股;枪托的意思,表示尾部吧 */
BOOTSTRAP_BUTT
} BootMessage;
......
static BOOL MessageHandle(Service *service, Request *request)
{
Bootstrap *bootstrap = (Bootstrap *)service;
switch (request->msgId) {
case BOOT_SYS_COMPLETED:
⑵ if ((bootstrap->flag & LOAD_FLAG) != LOAD_FLAG) {
INIT_APP_CALL(service);
INIT_APP_CALL(feature);
bootstrap->flag |= LOAD_FLAG;
}
⑶ (void)SAMGR_SendResponseByIdentity(&bootstrap->identity, request, NULL);
break; case BOOT_APP_COMPLETED:
(void)SAMGR_SendResponseByIdentity(&bootstrap->identity, request, NULL);
break; case BOOT_REG_SERVICE:
(void)SAMGR_SendResponseByIdentity(&bootstrap->identity, request, NULL);
break; default:
break;
}
return TRUE;
} static TaskConfig GetTaskConfig(Service *service)
{
(void)service;
// The bootstrap service uses a stack of 2 KB (0x800) in size and a queue of 20 elements.
// You can adjust it according to the actual situation.
TaskConfig config = {LEVEL_HIGH, PRI_NORMAL, 0x800, 20, SHARED_TASK};
return config;
}

参考站点

点击关注,第一时间了解华为云新鲜技术~

OpenHarmony移植案例:如何适配服务启动引导部件bootstrap_lite的更多相关文章

  1. OpenHarmony移植案例与原理:startup子系统之syspara_lite系统属性部件

    摘要:本文介绍下移植开发板时如何适配系统属性部件syspara_lite,并介绍下相关的运行机制原理. 本文分享自华为云社区<openharmony移植案例与原理 - startup子系统之sy ...

  2. OpenHarmony移植:如何适配utils子系统之KV存储部件

    摘要:本文介绍移植开发板时如何适配utils子系统之KV存储部件,并介绍相关的运行机制原理. 本文分享自华为云社区<OpenHarmony移植案例与原理 - utils子系统之KV存储部件> ...

  3. 【OpenHarmony移植案例与原理】XTS子系统之应用兼容性测试用例开发

    摘要:本文主要介绍ACTS应用兼容性测试用例开发编译. 本文分享自华为云社区<移植案例与原理 - XTS子系统之应用兼容性测试用例开发>,作者: zhushy . XTS(X Test S ...

  4. OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py

    摘要:本文介绍了build lite 轻量级编译构建系统hb命令的源码,主要分析了_\entry__.py文件. 本文分享自华为云社区<移植案例与原理 - build lite源码分析 之 hb ...

  5. 案例十:shell编写nginx服务启动程序

    使用源码包安装的Nginx没办法使用"service nginx start"或"/etc/init.d/nginx start"进行操作和控制,所以写了以下的 ...

  6. 玩转Windows服务系列——Windows服务启动超时时间

    最近有客户反映,机房出现断电情况,服务器的系统重新启动后,数据库服务自启动失败.第一次遇到这种情况,为了查看是不是断电情况导致数据库文件损坏,从客户的服务器拿到数据库的日志,进行分析. 数据库工作机制 ...

  7. Mysql服务启动的时候 如何加载配置文件

    Mysql服务启动的时候 如何引导配置文件 (启动加载顺序)

  8. AngularJS的启动引导过程

    原文:http://www.angularjs.cn/A137?utm_source=ourjs.com 目录: 引导之前 自动引导启动框架 手工引导启动框架 引导第1步:创建注入器 引导第2步:创建 ...

  9. centos6服务启动脚本及开机启动过程

    centos6服务启动脚本 centos6的服务启动脚本都放在/etc/rc.d/init.d/下,/etc/init.d/是/etc/rc.d/init.d/的软链接: centos6的服务启动脚本 ...

  10. 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码

    Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...

随机推荐

  1. Web Woeker和Shared Worker的使用以及案例

    目录 1.前言 2.介绍 Web Worker 3.使用须知及兼容性 3.1.使用须知 3.2.兼容性 4.使用 Web Worker 4.1.创建 Web Worker 4.2.与主线程通信 4.3 ...

  2. AirSim 自动驾驶仿真 (6) 设置采集参数和属性

    https://cloud.tencent.com/developer/article/2011384 1.配置文件在哪 默认情况下,文件位于用户目录下的AirSim文件夹,比如在Windows下,文 ...

  3. Weight Balanced Leafy Tree 学习笔记

    前言: 在这里十分十分感谢 \(\text{lxl}\) 和王思齐发明和总结了 \(\text{WBLT}\). 因为网上关于 \(\text{WBLT}\) 的正确讲解(已除去那篇国家集训队论文,不 ...

  4. 数据结构与算法 | 动态规划算法(Dynamic Programming)

    上一篇文末已经提到了记忆化搜索是动态规划(Dynamic Programming)的一种形式,是一种自顶向下(Top-Down)的思考方式,通常采用递归的编码形式:既然动态规划有自顶向下(Top-Do ...

  5. 使用 TortoiseGit 在两个项目之间共享代码(cherry-pick)

    需求:项目 A 需要新增项目 B 的部分代码,要求不变更 commit message 信息 做法 项目 A 新增上游 Remote,Remote URL 为 项目 B 的 URL 新增方式:依次点击 ...

  6. Java——设计模式

    一.概述 设计模式是历代程序员总结出的经验 二.分类 创建型模式:简单工厂模式 工厂方法模式 单例模式:饿汉式(开发) 懒汉式(面试) 行为型模式 结构型模式 三.简单工厂模式 一个工厂中可以创建很多 ...

  7. ERP到底是什么?

    ERP,全称企业资源计划,ERP系统主要是优化企业内部的业务流程,用信息化管控的方式进行一系列板块的管理,它可以看作是进销存系统的进阶版,主要针对供应链中下游. ERP的业务覆盖范围广,实际上它更加侧 ...

  8. 【封装】二维BIT

    struct BIT{ #define maxn 1000 int n, m; int d1[maxn][maxn], d2[maxn][maxn], d3[maxn][maxn], d4[maxn] ...

  9. [USACO2007NOVS] Cow Hurdles S

    题目描述 Farmer John wants the cows to prepare for the county jumping competition, so Bessie and the gan ...

  10. Chrome扩展的核心:manifest 文件(上)

    大家好,我是dom哥.我正在写关于 Chrome 扩展开发的系列文章,感兴趣的可以点个小星星. Chrome 在全球浏览器市场份额独占 6 成,无论是对普通用户还是开发者,都是电脑里的必备利器.Chr ...