HNP(Harmony Native Package)技术讲解
基于
service/hnp/与interfaces/innerkits/hnp/源码整理。
1 概述
HNP 是 OpenHarmony 的 Native 软件包 管理体系,用于在设备上安装、卸载、运行原生二进制(如 Python、Node、Java 等 Native 程序)。Native 软件以 .hnp(zip 格式)为载体,随 HAP 应用分发,安装后在设备上生成软链接供命令行或应用 execv 调用。
整个体系由三个构建产物构成:
| 产物 | 源码入口 | 定义宏 | 运行位置 | 职责 |
|---|---|---|---|---|
hnpcli |
service/hnp/hnpcli_main.c |
HNP_CLI |
开发机(Linux/Win/Mac/OHOS) | 将 Native 软件目录打包成 .hnp 文件 |
hnp |
service/hnp/hnp_main.c |
(默认) | 设备端(/system/bin/hnp) |
安装/卸载 .hnp,生成软链接,管理版本 |
libhnpapi.z.so |
interfaces/innerkits/hnp/src/hnp_api.c |
— | 设备端 | 供 BMS 等系统服务调用的 C API,内部 fork+execve 拉起 hnp 进程 |
2 源码结构
service/hnp/
├── base/ # 打包与安装共用的基础库
│ ├── hnp_base.h # 核心数据结构、错误码、日志宏、路径常量
│ ├── hnp_json.c # hnp.json 解析/生成;hnp_info.json 安装信息管理
│ ├── hnp_zip.c # zip 压缩/解压;ELF 文件识别(判断可执行文件)
│ ├── hnp_sal.c # 软链接生成、进程运行检查(lsof)、相对路径计算
│ ├── hnp_file.c # 文件读写、目录创建/删除
│ └── hnp_log.c # hnpcli 日志输出(非 HiLog 路径)
├── pack/ # 打包功能(hnpcli 专用)
│ ├── include/hnp_pack.h # 打包参数与信息结构体
│ └── src/hnp_pack.c # 打包主逻辑:遍历目录→zip 压缩→注入 hnp.json
├── installer/ # 安装/卸载功能(hnp 专用)
│ ├── include/hnp_installer.h
│ └── src/hnp_installer.c # 安装/卸载主逻辑:解压→软链接→签名→版本管理
├── hnp_main.c # hnp 可执行文件 main():命令分发 install/uninstall
├── hnpcli_main.c # hnpcli 可执行文件 main():命令分发 pack
└── BUILD.gn # 构建定义:hnp 链接 installer+base,hnpcli 链接 pack+base
interfaces/innerkits/hnp/
├── include/hnp_api.h # 对外 API:NativeInstallHnp / NativeUnInstallHnp
├── src/hnp_api.c # API 实现:组装 argv → fork → execve("/system/bin/hnp")
└── BUILD.gn # 构建 libhnpapi.z.so
构建要点(service/hnp/BUILD.gn):
hnp链接base/*.c+installer/hnp_installer.c+hnp_main.c,依赖hilog、selinux_adapter、zlib、code_signature。hnpcli链接base/*.c(去掉hnp_sal.c)+pack/hnp_pack.c+hnpcli_main.c,定义HNP_CLI(禁用 HiLog,改用HnpLogPrintf;禁用 ELF 检查等设备端逻辑)。libhnpapi.z.so仅含hnp_api.c,依赖libappspawn_util、libbegetutil、libhilog。
3 核心概念
3.1 hnp.json —— 软件包配置文件
每个 .hnp 内必须含 hnp.json,描述软件名、版本、软链接关系:
{
"type": "hnp-config",
"name": "hnpsample",
"version": "1.1",
"install": {
"links": [
{ "source": "/bin/hnpsample", "target": "hnpsample" }
]
}
}
type固定为"hnp-config"(hnp_json.c:83校验)。links.source为软件包内二进制相对路径,links.target为生成的软链接名(为空时默认取 source 文件名)。- 若
links缺失,安装时默认将bin/目录下所有常规文件做软链接(hnp_installer.c:113HnpGenerateSoftLinkAll)。
3.2 公有(public)与私有(private)
HAP 内 hnp 包按目录名区分公私有:
hnp安装包路径
├── public/ # 公有 hnp
│ └── xxx.hnp
└── private/ # 私有 hnp
└── yyy.hnp
安装后落盘路径(hnp_installer.c:693):
| 类型 | 物理路径 | 沙箱软链接路径 | 环境变量 |
|---|---|---|---|
| 公有 | /data/app/el1/bundle/<uid>/hnppublic/<name>.org/<name>_<ver> |
/data/service/hnp/bin |
HNP_PUBLIC_HOME=/data/service/hnp |
| 私有 | /data/app/el1/bundle/<uid>/hnp/<hapPkg>/<name>.org/<name>_<ver> |
/data/app/<bundleName>/... |
HNP_PRIVATE_HOME=/data/app |
HNP_PRIVATE_HOME排在HNP_PUBLIC_HOME之前,同名二进制优先执行私有路径下的。- 公有 hnp 可被所有应用访问;私有 hnp 仅安装它的 HAP 可访问。
- 公有 hnp 安装信息记录在
hnp_info_<uid>.json(旧路径hnp_info.json),私有 hnp 不记入此文件。
3.3 软链接机制
安装时在 <hnpBasePath>/bin/ 下为目标二进制生成相对路径软链接(hnp_sal.c:164 HnpSymlink):
软链接文件: .../hnppublic/bin/hnpsample → ../../hnpsample.org/hnpsample_1.1/bin/hnpsample(相对路径)
使用相对路径而非绝对路径,保证路径迁移后链接不断。公有 hnp 软链接覆盖前会做 CheckSymlink 校验(hnp_sal.c:56),防止覆盖其他 hnp 的链接。
3.4 版本管理
hnp_info_<uid>.json 中每个 hnp 条目记录两个版本(hnp_base.h:148 HnpPackageInfo):
| 字段 | 含义 |
|---|---|
current_version |
当前生效版本 |
install_version |
本 HAP 实际安装的版本(未安装该版本时为 "none") |
核心约束:每个公有 hnp 名称仅属于一个 HAP。
CanRecovery(hnp_json.c:459)在生成公有 hnp 软链接前校验:遍历 hnp_info 中所有 HAP 条目,若发现已有其他 HAP 安装了同名的 hnp,则返回 false → 安装失败(HNP_ERRNO_SYMLINK_CHECK_FAILED)。仅当无 HAP 安装过此名称、或安装者就是当前 HAP 时才允许覆盖。README 规格第 5 条也明确:"Hap 应用 A 和 B 先后安装同名公有 hnp 包,后安装的应用 B 会无法安装"。
注:
hnp_base.h:122有一段注释描述了多 HAP (A→v1, B→v2, C→v3) 共享同一 hnp 不同版本的场景,但该模型被CanRecovery限制,在当前代码下不可达,属遗留/理论性描述。
同一 HAP 的版本升级流程:
1. 首次安装 v1: current_version=v1, install_version=v1 → 仅 v1 目录在磁盘
2. 同 HAP 升级 v2:
HnpPublicDealAfterInstall (hnp_installer.c:525)
├── HnpCurrentVersionUninstallCheck: 检查是否有 HAP 的 current==install
│ 当前 {current=v1, install=v1} 匹配 → 返回 "v1" → 跳过卸载旧目录
│ (v1 目录保留在磁盘,不立即清理)
└── HnpInstallInfoJsonWrite: 仅更新 current_version=v2, install_version 保持 v1
结果: current=v2, install=v1 → v1 和 v2 两个目录都在磁盘
3. 卸载该 HAP:
HnpNativeUnInstall (hnp_installer.c:347)
├── hnpExist=false(无其他 HAP 引用)→ 删除 current_version(v2) 目录
└── install_version(v1) != "none" 且 != current → 删除 install_version(v1) 目录
结果: v1、v2 目录均清理
install_version = "none" 的场景在当前正常流程中不产生(isInstall 在 HnpInstallInfoJsonWrite 前必被置 true),仅可能来自旧格式迁移(DoRebuildHnpInfoCfg)。
4 打包流程(hnpcli)
hnpcli pack 命令入口 hnp_pack.c:202 HnpCmdPack:
参数: -i <源目录> -o <输出目录> -n <软件名> -v <版本号>
- 解析参数(
ParsePackArgs):对源目录做realpath校验;检查源目录下是否存在hnp.json。- 存在 → 解析其中的 name/version,校验 links.source 文件是否存在。
- 不存在 → 要求用户传
-n和-v,打包时自动生成hnp.json。
- 压缩(
PackHnp):调用HnpZip(hnp_zip.c:258)递归遍历源目录,将所有文件以相对路径写入<name>.hnp(zip 格式)。- zip 内保存文件 UGO 权限到
external_fa字段(hnp_zip.c:115),安装时恢复。 - Windows 打包时自动为 others 赋可执行权限;Linux/Mac/OHOS 继承源文件权限。
- zip 内保存文件 UGO 权限到
- 注入 hnp.json:若源目录无
hnp.json,调用AddHnpCfgFileToZip用 cJSON 生成并写入压缩包。
跨平台支持:hnp_zip.c 对 Windows 路径做 \ → / 转换、用 wchar_t 支持长路径(>260 字符)。
5 安装流程(hnp install)
hnp install 命令入口 hnp_installer.c:1110 HnpCmdInstall:
hnp install -u <uid> -p <hapPkg> -i <hnp根目录> -s <hap路径> -a <abi> [-f] [-I <appIdentifier>] [-S <独立签名hnp路径>]
5.1 整体流程
ParseInstallArgs 解析 -u/-p/-i/-s/-a/-f/-I/-S 参数
│
▼
RebuildHnpInfoCfg 若 hnp_info 旧格式文件存在则重建为新格式(按 uid 分文件)
│
▼
HnpInstallPre 安装前置
├── CheckInstallPath 拼装路径 + restorecon(SELinux 标签)
├── HnpInstallHapFileCountGet 统计 hnp 文件数(预分配签名信息数组)
└── HapReadAndInstall 遍历 public/ 和 private/ 目录
└── HnpPackageGetAndInstall 递归遍历子目录
└── HnpReadAndInstall 对每个 .hnp 文件
├── HnpCfgGetFromZip 从 zip 中读取 hnp.json
├── HnpInstallPathGet 拼装安装路径 <base>/<name>.org/<name>_<ver>
├── HnpInstallForceCheck 路径已存在则判断 -f 强制/报错
├── HnpInstall 解压 + 生成软链接
│ ├── HnpUnZip 解压到目标目录 + 收集签名信息
│ └── HnpGenerateSoftLink 按 hnp.json links 或默认 bin/ 生成软链接
└── HnpPublicDealAfterInstall 公有 hnp:版本清理 + 写 hnp_info.json
│
▼
CodeSign + BssInstall (若 CODE_SIGNATURE_ENABLE)对可执行 ELF 做验签
│
▼
GetRespFd → write(result) 通过管道回写结果给调用方(API 场景)
5.2 关键细节
- 路径拼装(
hnp_installer.c:498):<hnpBasePath>/<name>.org/<name>_<version>,对..做路径穿越防护。 - 强制安装
-f:路径已存在时先删后装;非强制则返回HNP_ERRNO_INSTALLER_PATH_IS_EXIST。 - 同名版本跳过:若目标版本目录已存在且为公有 hnp,跳过解压,仅刷新软链(
hnp_installer.c:565)。 - 批量安装失败:中途出错直接退出,已安装的保留;出错时对当前 hnp 做回滚卸载(
hnp_installer.c:592)。 - SELinux:安装前对
hnppublic/和hnp/目录做RestoreconRecurse(hnp_installer.c:831)。
6 卸载流程(hnp uninstall)
hnp uninstall 命令入口 hnp_installer.c:1140 HnpCmdUnInstall:
hnp uninstall -u <uid> -p <hapPkg>
流程(HnpUnInstall):
RebuildHnpInfoCfg:配置格式迁移。HnpPackageInfoGet:从hnp_info_<uid>.json读取该 HAP 安装的所有 hnp 条目。- 对每个条目调
HnpNativeUnInstall:- 若
hnpExist=false(无其他 HAP 引用此版本,因CanRecovery限制实际恒为 false)→ 删除current_version目录。 - 若
install_version != "none"且 !=current_version→ 删除install_version目录。 - 删除前调
HnpProcessRunCheck(hnp_sal.c:30):用lsof检查是否有进程正在使用该路径,有则卸载失败。
- 若
HnpPackageInfoDelete:从hnp_info_<uid>.json删除该 HAP 条目。- 删除私有 hnp 目录
.../hnp/<hapPkg>。 ClearSoftLink:清理hnppublic/bin/下失效的软链接(源文件已不存在的链接)。BssUninstall:调用二进制安全 SDK 注销 BSS 信息。
代码中
hnpExist(HnpOtherPackageInstallCheck)仍保留了对"其他 HAP 是否引用此版本"的检查,但由于CanRecovery已限制每个公有 hnp 名称仅属于一个 HAP,该字段在正常流程下恒为false,属兼容性遗留逻辑。
7 API 接口(libhnpapi.z.so)
hnp_api.h 对外暴露两个 C 函数,供 BMS 等系统服务在 HAP 安装/卸载时调用:
7.1 NativeInstallHnp
int NativeInstallHnp(const char *userId, const char *hnpRootPath, const HapInfo *hapInfo, int installOptions);
实现机制(hnp_api.c:149):
IsHnpInstallEnable:读系统参数const.startup.hnp.install.enable,必须为"true"(对应开发者模式开关)。- 组装
hnp install命令行 argv(含-u、-i、-p、-s、-a、-I、-S、-f)。 StartHnpProcess(hnp_api.c:94):pipe(fd)创建管道。fork()子进程调ChildProcessHandler:将pipe[1]写端设入环境变量HNP_INFO_RET_FD_ENV,再execve("/system/bin/hnp", argv, env)。- 父进程
waitpid等待子进程退出,从pipe[0]读回HnpResult{int result}。
返回值通过管道传递,而非进程退出码——这是 API 层与 hnp 进程的通信协议。
7.2 NativeUnInstallHnp
int NativeUnInstallHnp(const char *userId, const char *packageName);
同样 fork+execve 拉起 hnp uninstall -u <uid> -p <pkg>,通过管道回传结果。
7.3 HapInfo 结构体
typedef struct HapInfo {
char packageName[256]; // HAP 包名
char hapPath[512]; // hap 文件路径(用于签名校验)
char abi[128]; // 系统 ABI(如 arm64-v8a)
char appIdentifier[64]; // 应用唯一标识
int count; // 独立签名 hnp 数量
char **independentSignHnpPaths; // 独立签名 hnp 相对路径
} HapInfo;
installOptions 为位掩码,OPTION_INDEX_FORCE = 0(第 0 位为 1 表示强制安装)。
8 签名与安全
8.1 代码签名(Code Signature)
当 CODE_SIGNATURE_ENABLE 定义时(hnp_installer.c:891):
- 安装解压时
HnpUnZip收集所有 ELF 文件的路径与签名 key(格式hnp/<abi>/<subdir>/<file>.hnp!/<internal_path>,hnp_zip.c:415)。 HnpELFFileCheck(hnp_zip.c:362):读文件头判断是否 ELF,进一步判断e_type:ET_EXEC→ 可执行文件ET_DYN且e_entry != 0→ PIE 可执行文件ET_DYN且e_entry == 0→ 动态库(不可执行)
EnforceCodeSignForApp:对 hap 包做文件级强制验签。- 验签失败 → 回滚卸载已安装内容。
8.2 BSS(Binary Security SDK)
安装后若存在 libsps_binary_security_sdk.z.so(hnp_installer.c:34),通过 dlopen+dlsym 动态调用:
ProcessHnpInstall(bundleName, appIdentifier, userId, hnpFiles):注册可执行文件信息。ProcessHnpUninstall(bundleName, userId):注销信息。
独立签名(independentSign)的 hnp 通过 -S 参数指定,与普通 hnp 区分处理。
8.3 路径穿越防护
多处对 .. 做检查:hnp_installer.c:76(links 配置)、hnp_installer.c:517(版本路径)、hnp_zip.c:489(解压文件名)、hnp_installer.c:1004(-S 参数)。
9 错误码体系
错误码按位打包(hnp_base.h:186):
高16位: HNP_ERRNO_HNP_MID (0x80) << 16 = 0x800000
中8位: module id << 8
低8位: 具体错误号
模块 ID(hnp_base.h:194):
| 模块 | ID | 范围 |
|---|---|---|
HNP_MID_MAIN |
0x10 | 0x8010xx |
HNP_MID_BASE |
0x11 | 0x8011xx |
HNP_MID_PACK |
0x12 | 0x8012xx |
HNP_MID_INSTALLER |
0x13 | 0x8013xx |
API 层错误码独立(hnp_api.h:39):基值 0x2000,如 HNP_API_ERRNO_HNP_INSTALL_DISABLED = 0x2009。
10 日志体系
两套日志路径(hnp_base.h:377):
| 宏 | hnp(设备端) | hnpcli(开发机) |
|---|---|---|
HNP_LOGI |
HILOG_INFO + HnpLogPrintf |
仅 HnpLogPrintf |
HNP_LOGE |
HILOG_ERROR + HnpLogPrintf |
仅 HnpLogPrintf |
HiLog 格式串使用 %{public}s 等隐私标记。hnp_log.c 提供 HnpLogPrintf 的 printf 风格实现,供 hnpcli 在无 HiLog 环境下使用。
11 HNP 如何挂载到应用沙箱(appspawn 集成)
HNP 安装后写入的是设备物理路径(/data/app/el1/bundle/...),应用进程无法直接访问。appspawn 在 fork 应用进程后、通过沙箱 bind mount 将 HNP 目录挂载进应用沙箱,再配合环境变量让应用能直接 execv 执行 Native 二进制。
11.1 触发条件:开发者模式 + HNP 执行开关
应用孵化时,appspawn_service.c:1481 ProcessSpawnReqMsg 做两重校验:
if (IsDeveloperModeOpen()) { // 系统开发者模式开关
if (IsSupportRunHnp()) { // 读系统参数 const.startup.hnp.execute.enable == "true"
SetAppSpawnMsgFlag(message, TLV_MSG_FLAGS, APP_FLAGS_DEVELOPER_MODE);
}
}
两个条件均满足时,孵化消息被打上 APP_FLAGS_DEVELOPER_MODE(appspawn.h:196,bit 17)标记。此标记是后续沙箱挂载 HNP 目录的开关。
11.2 沙箱挂载配置
挂载点定义在沙箱 JSON 配置中(appdata-sandbox.json + appdata-sandbox-app.json),归入 DEVELOPER_MODE 标志组:
{
"flags": "DEVELOPER_MODE",
"mount-paths": [
{
"src-path": "/data/app/el1/bundle/<currentUserId>/hnppublic",
"sandbox-path": "/data/service/hnp",
"sandbox-flags": [ "bind", "rec" ],
"check-action-status": "false"
},
{
"src-path": "/data/app/el1/bundle/<currentUserId>/hnp/<PackageName>",
"sandbox-path": "/data/app",
"sandbox-flags": [ "bind", "rec" ],
"check-action-status": "false"
}
]
}
| 挂载源(物理路径) | 挂载目标(沙箱内路径) | 类型 | 对应 HNP |
|---|---|---|---|
/data/app/el1/bundle/<uid>/hnppublic |
/data/service/hnp |
bind + rec | 公有 hnp |
/data/app/el1/bundle/<uid>/hnp/<PackageName> |
/data/app |
bind + rec | 私有 hnp |
<currentUserId>、<PackageName>由沙箱变量替换系统解析(sandbox_core.cpp中的ConvertDebugRealPath等函数)。bind+rec表示递归 bind mount,将整个 hnp 目录树(含bin/软链接)映射进沙箱。- HNP 挂载点仅存在于
appdata-sandbox.json(标准应用)和appdata-sandbox-app.json(app 类沙箱)中,isolated/render/gpu/debug 等沙箱配置不含 HNP 挂载。
11.3 挂载执行流程
沙箱模块(modules/sandbox/normal/sandbox_core.cpp)在 STAGE_CHILD_POST_RELY 阶段执行挂载:
HandleFlagsPoint (sandbox_core.cpp:923)
│ 遍历沙箱 JSON 中的 flags-points 数组
▼
对每条配置:
ConvertFlagStr("DEVELOPER_MODE") → APP_FLAGS_DEVELOPER_MODE
CheckAppMsgFlagsSet(property, APP_FLAGS_DEVELOPER_MODE)?
│ 是 → DoAllMntPointsMount → mount(src, dst, MS_BIND|MS_REC)
│ 否 → 跳过
▼
DoAllSymlinkPointslink → 处理沙箱内软链接
只有 APP_FLAGS_DEVELOPER_MODE 被设置的应用才会触发 HNP 挂载;非开发者模式下应用沙箱中看不到 HNP 目录。
11.4 环境变量
appspawn 为每个应用进程注入环境变量(util/src/appspawn_utils.c:40 COMMON_ENV):
{"HNP_PRIVATE_HOME", "/data/app", false},
{"HNP_PUBLIC_HOME", "/data/service/hnp", false},
{"PATH", "${HNP_PRIVATE_HOME}/bin:${HNP_PUBLIC_HOME}/bin:${PATH}", false},
HNP_PRIVATE_HOME和HNP_PUBLIC_HOME指向沙箱内挂载点(与 11.2 的 sandbox-path 对应)。PATH中HNP_PRIVATE_HOME/bin排在HNP_PUBLIC_HOME/bin前面,同名二进制优先执行私有路径下的。- 环境变量中的
${HNP_PRIVATE_HOME}等占位符在注入前由ConvertEnvValue(appspawn_utils.c:50)展开。
11.5 运行时视角
安装后,应用沙箱内看到的路径结构:
应用沙箱内(fork 后的子进程视角)
├── /data/service/hnp/ ← 公有 hnp 挂载点 (HNP_PUBLIC_HOME)
│ └── bin/
│ ├── python → ../../python.org/python_3.11/bin/python (相对软链接)
│ └── node → ../../node.org/node_20/bin/node
└── /data/app/ ← 私有 hnp 挂载点 (HNP_PRIVATE_HOME)
└── bin/
└── mytool → ../../mytool.org/mytool_1.0/bin/mytool
应用通过 execv("/data/service/hnp/bin/python") 或直接 execvp("python")(依赖 PATH)即可执行 Native 二进制。README_zh.md 示例:
int ret = execv("/data/app/test.org/test_1.1/bin/testBin", NULL); // 私有 hnp 实际路径
12 端到端流程图
开发者侧 设备侧
───────── ──────────
Native 软件目录
bin/ cfg/ lib/ hnp.json
│
▼ hnpcli pack -i ... -o ...
.hnp 文件
│
▼ 打入 HAP 包(module.json5 配置 hnpPackages)
签名后的 HAP
│
▼ 应用市场分发 → 设备安装 HAP
│
▼ BMS 调用 NativeInstallHnp()
libhnpapi.z.so
│ fork + execve
▼
/system/bin/hnp install ...
│
┌──────────────┼──────────────┐
▼ ▼ ▼
解压 .hnp 生成软链接 验签(ELF)
│ │ │
▼ ▼ ▼
hnppublic/ bin/xxx → EnforceCodeSign
<name>.org/ 原二进制 + BssInstall
<name>_<ver>/
│
▼ 管道回写 result
NativeInstallHnp 返回
│
▼ 应用孵化时 appspawn 收到 spawn 请求
ProcessSpawnReqMsg
│ IsDeveloperModeOpen() && IsSupportRunHnp()
▼ 设置 APP_FLAGS_DEVELOPER_MODE
沙箱模块 HandleFlagsPoint
│ bind mount 公有/私有 hnp 目录进沙箱
▼ 注入 HNP_PUBLIC_HOME / HNP_PRIVATE_HOME / PATH 环境变量
fork 子进程 → 应用沙箱就绪
│
▼ execv("/data/service/hnp/bin/xxx") 或 execvp("xxx")
运行 Native 二进制
13 关键文件速查
| 关注点 | 文件 | 关键函数 |
|---|---|---|
| 命令分发 | hnp_main.c |
main → HnpCmdCheck → HnpCmdInstall/HnpCmdUnInstall |
| 命令分发 | hnpcli_main.c |
main → HnpCmdCheck → HnpCmdPack |
| 安装主逻辑 | installer/hnp_installer.c |
HnpInstallPre → HapReadAndInstall → HnpReadAndInstall |
| 卸载主逻辑 | installer/hnp_installer.c |
HnpUnInstall → HnpNativeUnInstall |
| hnp.json 解析 | base/hnp_json.c |
ParseHnpCfgFile → ParseJsonStreamToHnpCfgInfo |
| 安装信息管理 | base/hnp_json.c |
HnpInstallInfoJsonWrite / HnpPackageInfoGet / CanRecovery |
| 压缩/解压 | base/hnp_zip.c |
HnpZip / HnpUnZip / HnpCfgGetFromZip |
| ELF 识别 | base/hnp_zip.c |
HnpELFFileCheck |
| 软链接 | base/hnp_sal.c |
HnpSymlink / CheckSymlink / HnpProcessRunCheck |
| API 接口 | interfaces/.../hnp_api.c |
NativeInstallHnp / NativeUnInstallHnp / StartHnpProcess |
| 核心定义 | base/hnp_base.h |
数据结构、错误码、路径常量、日志宏 |
| 沙箱挂载触发 | standard/appspawn_service.c |
ProcessSpawnReqMsg → IsSupportRunHnp → 设置 APP_FLAGS_DEVELOPER_MODE |
| 沙箱挂载执行 | modules/sandbox/normal/sandbox_core.cpp |
HandleFlagsPoint → DoAllMntPointsMount(bind mount HNP 目录) |
| 标志映射 | modules/sandbox/normal/sandbox_common.cpp |
ConvertFlagStr("DEVELOPER_MODE" → APP_FLAGS_DEVELOPER_MODE) |
| 挂载点配置 | appdata-sandbox.json / appdata-sandbox-app.json |
DEVELOPER_MODE 组定义公有/私有 hnp 的 src/sandbox 路径 |
| 环境变量注入 | util/src/appspawn_utils.c |
COMMON_ENV:HNP_PUBLIC_HOME / HNP_PRIVATE_HOME / PATH |