# hica

## 1. 功能简介
hica代码仓：主要用于存放拉起子系统进程需要的配置文件和入口代码

## 2. 关键特性
配置仓，主要用于存放skynet配置文件和systemd配置文件

## 3. 对外接口
NA

## 4. 配置介绍
本节主要对几个目录的关键配置和代码进行说明。由于不同服务的配置相差不大，选取alarm服务的配置文件作为样例介绍。
```
├── build                                               --用于存放一些构建打包的脚本
│   └── customization.py
```
```
https://gitcode.com/openUBMC/manifest
└── build
    └──product
        └──产品名/rootfs
            ├──etc
            |   └── systemd
            |       └── system
            |           ├── alarm.service
            |           └── multi-user.target.wants     --保存上级目录systemd配置的软连接，用于支持自动拉起systemd配置对应的服务
            |              └── alarm.service -> ../alarm.service
            └──opt/bmc/apps/hica/subsys                 --存放子系统程序的skynet配置文件及入口代码
                └── alarm
                    ├── config.cfg
                    ├── secbox.cfg
                    └── service
                        └── main.lua
```


### 4.1 build/customization.py
对于需要合并到子系统拉起的组件，需要对组件自带的systemd配置文件进行裁剪，否则可能出现组件被多次拉起的问题，在subsys_startup_components中添加组件名即可完成对组件自带的systemd配置文件的裁剪\
subsys_startup_components 配置存放在 [manifest](https://gitcode.com/openUBMC/manifest)/build/customization/prototype.py\

```
subsys_startup_components = [
    # bmc_core components
    'firmware_mgmt',
    'bmc_upgrade',
    'bmc_time',
    'fructrl',
    'bmc_network',
    'bmc_health',
    'ipmi_core',
    'bmc_soc',
    # alarm components
    'sensor',
    'host_agent',
    'frudata',
    'event',
    # energy components
    'cooling',
    'power_strategy',
    # framework components
    'libsoc_adapter',
    'hwproxy',
    'hwdiscovery'
]
```

### 4.2 skynet配置
skynet配置文件及入口代码存放在 [manifest](https://gitcode.com/openUBMC/manifest)/build/product/对应产品/rootfs/opt/bmc/apps/hica/subsys/子系统名/ 目录下

#### 4.2.1 config.cfg
skynet程序的配置文件，用于初始化Skynet的运行环境，包括设置工作线程数、日志输出、服务地址等关键参数

##### 4.2.1.1 include_app
子系统新增组件时的必须配置，配置后才能对组件对应目录的代码进行访问
```
config:set_root("/")
config:set_start("hica/subsys/bmc_core/service/main")
config:include_app("firmware_mgmt")
config:include_app("bmc_upgrade")
config:include_app("bmc_time")
config:include_app("fructrl")
config:include_app("bmc_network")
config:include_app("frudata")
config:include_app("event")
config:include_app("manufacture")
config:done()
```

#### 4.2.2 secbox.cfg
沙箱配置文件，目前主要用于与最小子系统做隔离，进行一些权限相关的配置

##### 4.2.2.1 目录相关配置
配置格式：dir*** = /系统目录,/映射目录,权限（read\write）
组件运行的最小公共配置如下：
```
dir_com = /opt,/opt,read   # 程序区，需要有读权限
dir_com = /etc,/etc,read   # 时区，主机名的配置文件在该目录下，某些系统调用（例如getpwuid）涉及该目录
dir_com = /lib64,/lib64,read
dir_com = /usr/lib64,/usr/lib64,read
dir_com = /lib,/lib,read   # 组件运行lib库，read权限
dir_com = /data,/data,write # 低可信分区
dir_com = /dev,/dev,read   # 最低需要有read权限，记录日志涉及/dev/log设备文件
dir_com = /data/trust,/data/trust,read # 高可信组件则配置write权限，低可信组件则read权限
```
非必选公共配置：
```
dir_com = /dev/shm,/dev/shm,write        # 共享内存区，本地临时持久化涉及该目录
dir_com = /tmp,/tmp,write             # 涉及tmp目录读写则需配置write，比如一键收集等
dir_com = /opt/bmc/pram,/opt/bmc/pram,write #复位分区（AC则清除数据）， 涉及本地复位持久化则需配置
dir_com = /bin,/bin,read              # 若涉及/bin目录则需配置read权限，比如执行/bin/sh
dir_com = /usr/sbin,/usr/sbin,read       # 若涉及/usr/sbin目录则需配置read权限，比如执行/usr/sbin/sqlite3
dir_com = /run,/run,read       # systemctl命令需要有对/run目录的访问，该目录有相关信息
```
有业务特殊配置则按照格式dir_*** = /系统目录,/映射目录,权限（read\write）配置：
```
例如soctrl组件usb功能需要使用到/sys/kernel/debug/usb目录，则可配置
dir_soctrl = /sys/kernel/debug/usb,/sys/kernel/debug/usb,write
```

##### 4.2.2.2 能力集配置
进程运行时需要一些capability，而通过沙箱启动进程会剥离其所有的capability，进而导致进程无法正常工作，此时需要配置沙箱给进程继承的能力集
沙箱则通过设置子进程的Inheritable以及Ambient来完成能力集的设置继承；最终达到的效果是通过沙箱启动的子进程以及子进程拉起的其它进程都可拥有设置的能力集；
该功能由2个配置选项控制：
```
cap_enable：表示是否要对沙箱内进程设置权限（1：是， 0：否），默认或不配置该项时视为配置0，仅允许配置0或1；
capabilities：表示要设置的权限，后可列出权限列表，内容间以逗号分隔，当cap_enable=1时生效。
```

##### 4.2.2.3 日志路径配置
不同的用户启动沙箱需要配置不同的日志路径
建议以 /var/log/用户名 方式配置
```
# Log file
log_path = /var/log/secbox      # 第三级目录使用用户名
```

#### 4.2.3 service/main.lua
skynet服务的入口点，负责启动和初始化服务，需要在此处做一些必要的操作

##### 4.2.3.1 设置记录日志时的模块名
```lua
local module_name = skynet.getenv('MODULE_NAME')
if type(module_name) == 'string' and module_name ~= '' then
    log:set_log_module_name(module_name)
end
```

##### 4.2.3.2 使用malloc_trim定期清理堆上无用内存
```lua
-- 内存持续增长的glibc内存管理配置项设置
-- M_ARENA_MAX: 最大ARENA数量,可以理解成进程拥有的堆内存池最大数量
utils_core.mallopt(M_ARENA_MAX, 1)
-- M_TRIM_THRESHOLD: 自动回收堆顶空闲内存空间给内核的阈值,单元:byte
utils_core.mallopt(M_TRIM_THRESHOLD, 4 * 1024)

skynet.fork(function()
    while true do
        utils_core.malloc_trim(0)
        skynet.sleep(5 * 60 * 100) -- 5分钟trim一次
    end
end)
```

##### 4.2.3.3 沙箱进程需要设置dbus环境变量
```lua
utils_core.setenv('DBUS_SESSION_BUS_ADDRESS', utils_core.getenv('DBUS_SESSION_BUS_ADDRESS'):gsub("%$", ","), true)
```

##### 4.2.3.4 拉起dbus用于创建dbus io线程
```lua
skynet.uniqueservice('sd_bus')
```

##### 4.2.3.5 根据manifest中的launch_control.json配置拉起子系统中的业务服务
```lua
launch_control.launch_components('bmc_core')
```

### 4.3 systemd配置
systemd配置文件用于定义和管理系统服务，是子系统进程拉起的入口配置，存放在 [manifest](https://gitcode.com/openUBMC/manifest)/build/product/对应产品/rootfs/etc/systemd/system/ 目录下。\
此处重点介绍一些需要特别关注的配置，更多systemd配置的说明可参考https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html

##### 4.3.1 Requires
表示一种强的依赖关系，被依赖的服务停止/重启时，本服务也需要停止/重启，目前所有进程默认都需要配置对dbus和framework服务的依赖，保证框架主程序重启时，能够清理共享内存，保证共享内存数据的一致性
```
Requires=dbus.service framework.service
```

##### 4.3.2 ExecStartPre
为了控制进程的启动时序，使用shell命令延迟部分进程的启动，比如以下操作表示在uptime小于100s时，睡眠30s再拉起进程
```
ExecStartPre=/bin/bash -c "uptime=`/bin/cat /proc/uptime |awk -F '.' '{print $1}'`; if [ $uptime -lt 100 ]; then /bin/sleep 30; fi"
```

##### 4.3.3 ExecStart
用于拉起主程序，目前通常是根据配置文件拉起一个skynet进程，并按子系统为进程起一个别名，样例：
```
ExecStart=bash -c 'exec -a bmc_core /opt/bmc/skynet/skynet /opt/bmc/apps/hica/subsys/bmc_core/config.cfg'
```
