OpenHarmony L0 与 L1 的 BMS / AMS 区别详解

本文基于对两套真实源码树的逐文件阅读整理而成:

系统级别 源码路径(WSL) 目标板 内核 产品类型
L0(轻量系统 / mini) /home/gaoxining/openharmony ArtInChip D21X LiteOS-M "type": "mini"
L1(小型系统 / small) /home/gaoxining/openharmony_l1 HiSilicon Hi3516DV300(hispark_taurus_linux) Linux "type": "small"

系统类型的直接证据:vendor/artinchip/artinchip_d21x/config.json"type":"mini""kernel_type":"liteos_m"vendor/hisilicon/hispark_taurus_linux/config.json"type": "small""kernel_type": "linux"


〇、先建立一个最重要的认识

很多人以为 L0 和 L1 是两套不同的 BMS/AMS 代码。其实不是。

两棵树里的 BMS(foundation/bundlemanager/bundle_framework_lite)和 AMS(foundation/ability/ability_lite是同一份源码仓库。我把两边的核心文件逐个对比过,文件清单完全一致,唯一的一处实质差异是 bundle_installer.cpp 里 L1 多了一行 #include <algorithm> —— 可以忽略不计的版本漂移。

那 L0 和 L1 的区别到底在哪?答案是三句话:

  1. 同一份代码,两套编译分支。 所有 BUILD.gn 里都用 if (ohos_kernel_type == "liteos_m") 分岔:L0 编出一小半文件,L1 编出全部文件。
  2. 同一份常量头文件,两套宏定义。 bundle_common.h 里用 #ifdef OHOS_APPEXECFWK_BMS_BUNDLEMANAGER 分岔:L0 用一套路径/格式,L1 用另一套。
  3. 同一套框架接口,两种运行形态。 L0 上所有东西跑在一个进程里(LiteOS-M 没有 MMU、没有真正意义上的"进程");L1 上是真正的多进程系统(Linux,每个应用一个进程,由 appspawn 孵化)。

打个比方:

  • L0 像一间"夫妻老婆店":老板(BMS)、伙计(AMS)、顾客(应用)全在一个屋子里,喊一嗓子(函数调用/消息队列)就把事办了。店小,所以只请得起一个兼职伙计(slite 精简版代码)。
  • L1 像一家正规公司:有前台(Samgr 服务注册)、档案室(BMS 管安装包)、人事部(AMS 管员工上下班)、保安(验签/权限)、还有专门的"招聘官"(appspawn)负责给每个新员工(应用)开独立办公室(进程)。部门之间打电话(Unix Socket IPC)沟通。

下面分别把 BMS 和 AMS 拆开讲。


一、BMS(Bundle Manager Service,包管理服务)

1.1 BMS 是干什么的(通俗版)

BMS 就是系统的"应用档案室 + 收发室"。一个应用包(hap/bin)要装进系统,得经过它:拆包、验货(签名)、登记户口(写 bundle.json)、分配住处(解压到运行目录)、发门牌号(uid/gid)。以后谁想查"系统里装了哪些应用""这个应用叫什么名、图标在哪",也都来问它。

1.2 代码在哪

两棵树位置相同:

foundation/bundlemanager/bundle_framework_lite/
├── services/bundlemgr_lite/        ← BMS 服务端
│   ├── src/                        ← 23 个 .cpp(两棵树完全相同)
│   ├── include/bundle_common.h     ← 关键常量(两套宏分支)
│   ├── bundle_daemon/              ← 解压守护进程(两棵树都有源码,但只有 L1 编译)
│   └── tools/                      ← bm 命令行工具(只有 L1 编译)
└── frameworks/bundle_lite/         ← BMS 客户端(应用侧调用接口)
    └── src/slite/                  ← L0 专用精简客户端

1.3 编译分支:L0 只编一半,L1 全编

证据在 services/bundlemgr_lite/BUILD.gn

L0 分支(ohos_kernel_type == "liteos_m")—— 静态库,只编 10 个文件:

static_library("bundlems") {
  sources = [
    "src/bundle_map.cpp",               # 已安装应用的内存索引
    "src/bundle_mgr_service.cpp",       # 对外服务壳
    "src/bundle_mgr_slite_feature.cpp", # Samgr Feature(slite 版)
    "src/bundle_util.cpp",
    "src/gt_bundle_extractor.cpp",      # 解包
    "src/gt_bundle_installer.cpp",      # 安装流程
    "src/gt_bundle_manager_service.cpp",# 核心管理(GtManagerService)
    "src/gt_bundle_parser.cpp",         # 解析包信息
    "src/gt_extractor_util.cpp",
  ]
  deps = [ ..., jerryscript, ace_lite ]  # 注意:依赖 JS 引擎和 ACE Lite
}

L1 分支(else,即 Linux)—— 动态库,编 15 个文件,另加两个独立组件:

shared_library("bundlems") {
  configs += [ ":bundle_config" ]   # ← 这里注入了 OHOS_APPEXECFWK_BMS_BUNDLEMANAGER 宏
  sources = [
    "src/bundle_daemon_client.cpp",  # 与解压守护进程通信
    "src/bundle_extractor.cpp",
    "src/bundle_info_creator.cpp",
    "src/bundle_inner_feature.cpp",  # 系统应用扫描 Feature
    "src/bundle_installer.cpp",      # 完整安装流程
    "src/bundle_manager_service.cpp",# 完整核心管理(ManagerService)
    "src/bundle_map.cpp",
    "src/bundle_ms_feature.cpp",     # IPC Feature
    "src/bundle_ms_host.cpp",
    "src/bundle_parser.cpp",
    "src/bundle_res_transform.cpp",
    "src/bundle_util.cpp",
    "src/extractor_util.cpp",
    "src/hap_sign_verify.cpp",       # ← 签名验证(L0 没有)
    "src/zip_file.cpp",
  ]
}
lite_component("appexecfwk_services_lite") {
  features = [ ":bundlems", "tools:bm", "bundle_daemon:bundle_daemon" ]
  #                          ↑ bm 命令行工具   ↑ 独立解压守护进程(L0 都没有)
}

对照表:

能力 L0(mini / LiteOS-M) L1(small / Linux)
编译产物 静态库 libbundlems.a 动态库 libbundlems.so
源文件数量 10 个(gt_* 系列为主) 15 个 + bm 工具 + bundle_daemon
安装流程类 GtBundleInstaller BundleInstaller
核心管理类 GtManagerService ManagerService
签名验证 hap_sign_verify.cpp ❌ 不编译 ✅ 编译
bm 命令行工具 ✅(串口里可敲 bm install ...
解压守护进程 bundle_daemon ❌(源码在,不编) ✅(init.cfg 里作为独立服务启动)
依赖 JS 引擎 jerryscript ✅(L0 应用是 JS 写的)

1.4 路径常量:一个宏分出两个世界

services/bundlemgr_lite/include/bundle_common.h 里的 #ifdef OHOS_APPEXECFWK_BMS_BUNDLEMANAGER(这个宏只在 L1 的编译配置里定义):

常量 L1(宏定义时) L0(#else 分支)
系统应用目录 SYSTEM_BUNDLE_PATH /system/internal OHOS_PATH(system/ace/sys)
第三方预置目录 THIRD_SYSTEM_BUNDLE_PATH /system/external OHOS_PATH(system/ace/vendor)
安装运行目录 INSTALL_PATH /storage/app/run OHOS_PATH(user/ace/run)
数据目录 DATA_PATH /storage/app/data OHOS_PATH(user/ace/data)
应用包后缀 INSTALL_FILE_SUFFIX .hap .bin
设备类型 DEFAULT_DEVICE_TYPE smartVision liteWearable
版本名最大长度 127 20
第三方应用数量上限 (无硬上限) MAX_THIRD_BUNDLE_NUMBER = 45
uid/gid 分配 ✅(BASE_APP_UID = 10000 起) ❌(单进程不需要)

这正解释了你在 D21X 板上看到的现象:预置应用全是 .bin 后缀、放在 system/ace/vendor/ 下 —— 那就是 L0 分支的常量。

1.5 安装流程对比

L0:启动时"按名单点名"式预安装

L0 的预安装名单写在厂商适配层 ~/ohos_vendor_adapter/bms/src/pre_install_app.cpp(经符号链接指向 ~/build_lite/ohos_vendor_adapter),全文只有 49 行,逻辑一目了然:

static const char * const app_lists[] = {
    "calc_hisi_signed.bin", "demo.bin", "cals.bin", "fruit.bin",
    "guessNums.bin", "dj.bin", "pushBox.bin", "wangyi.bin",
    "entry-default-unsigned.bin"
};

void PreInstallApp() {
    PreAppList* preAppList = InitPreAppInfo();
    for (每个 .bin) {
        snprintf(hapFilePath, ..., "/data/system/ace/vendor/%s", app_lists[i]);
        InsertPreAppInfo(hapFilePath, preAppList);   // 串成链表
    }
    SetPreAppInfo(preAppList);                       // 交给 BMS
    RegisterInstallerCallback(InstallerCallbackFunction); // 注册完成回调
}
APP_FEATURE_INIT(PreInstallApp);   // ← Samgr 启动阶段自动调用

流程就是:开机 → Samgr 拉起各 Feature → APP_FEATURE_INIT 自动执行 → 把 9 个 .bin 的路径串成链表塞给 BMS → GtBundleInstaller 逐个解包、登记。装完一个回调一次。这些 .bin 实体就躺在 ohos_vendor_adapter/bms/resources/system/ace/vendor/ 里,编译时被打进 rootfs。

注意 .bin 其实就是改了扩展名的 hap(zip),只是 L0 分支按 .bin 后缀识别。

L1:启动时"扫楼"式自动安装

L1 没有谁给它名单,它自己扫目录。bundle_manager_service.cpp

void ManagerService::ScanBundle() {
    ScanAppDir(SYSTEM_BUNDLE_PATH, ...);        // /system/internal —— 系统应用
    ScanAppDir(THIRD_SYSTEM_BUNDLE_PATH, ...);  // /system/external —— 第三方预置
    ScanAppDir(INSTALL_PATH, ...);              // /storage/app/run —— 已安装的普通应用
    ScanAppDir(EXTEANAL_INSTALL_PATH, ...);     // /sdcard/app/run —— SD 卡
}

void ManagerService::InstallSystemBundle(const char *fileDir, const char *fileName) {
    // 对每个 .hap:解压 → 验签(hap_sign_verify) → 解析 config.json
    // → 提取 so 到运行目录 → 写入 /storage/app/etc/bundles/ 登记
}

初始化入口 bundle_inner_feature.cpp 同样是 APP_FEATURE_INIT(Init),由 Linux 的 init 进程按 init.cfg 拉起 foundation 服务后触发。

一句话总结安装差异

  • L0:编译时定死名单,开机"点名安装";包叫 .bin;不验签(签名验证代码压根没编进去);装到 user/ace/run
  • L1:开机自己扫四个目录;包叫 .hap;验签;装到 /storage/app/run;还能用 bm install/uninstall 在串口里动态装卸。

二、AMS(Ability Manager Service,Ability 管理服务)

2.1 AMS 是干什么的(通俗版)

如果说 BMS 管"应用装没装",AMS 就管"应用活没活":启动一个 Ability(页面/服务)、前后台切换、退出、记录谁在最上层。它是应用的"人事部 + 调度室"。

2.2 代码在哪

两棵树位置相同:

foundation/ability/ability_lite/
├── services/abilitymgr_lite/       ← AMS 服务端
│   ├── src/                        ← 完整版:33 个文件(任务、任务栈、进程管理、IPC 客户端…)
│   ├── src/slite/                  ← L0 精简版:11 个文件
│   └── tools/                      ← aa 命令行(只有 L1 编译)
└── frameworks/ability_lite/        ← 应用侧框架(Ability 基类、加载器、主线程)

2.3 编译分支:同样是 ohos_kernel_type 分岔

证据在 services/abilitymgr_lite/BUILD.gn

L0 分支 —— 只编 slite 目录的 11 个文件:

if (ohos_kernel_type == "liteos_m") {
  sources = [
    "src/slite/ability_list.cpp",
    "src/slite/ability_mgr_service_slite.cpp",   # AMS 服务(slite 版)
    "src/slite/ability_record.cpp",              # 一个 Ability 一条记录
    "src/slite/ability_record_manager.cpp",      # 核心调度
    "src/slite/ability_record_observer_manager.cpp",
    "src/slite/ability_thread.cpp",              # Ability 运行线程(基类)
    "src/slite/ability_thread_loader.cpp",       # 按 JS/Native 创建线程
    "src/slite/bms_helper.cpp",                  # 向 BMS 查应用信息
    "src/slite/js_ability_thread.cpp",           # JS 应用的线程
    "src/slite/native_ability_thread.cpp",       # Native 应用的线程
    "src/slite/slite_ability_loader.cpp",
  ]
}

L1 分支 —— 编 33 个文件的完整版:

else {
  target_type = "shared_library"
  sources = [
    "src/ability_mgr_service.cpp",      # AMS 服务本体
    "src/ability_mgr_feature.cpp",      # Samgr IPC 接口
    "src/ability_mgr_handler.cpp",      # 消息分发
    "src/ability_stack_manager.cpp",    # Ability 栈管理
    "src/ability_mission_stack.cpp", "src/ability_mission_record.cpp",  # 任务栈
    "src/page_ability_record.cpp",
    "src/app_manager.cpp",              # ★ 应用进程管理
    "src/app_record.cpp",               # ★ 一个进程一条记录
    "src/ability_worker.cpp",           # Service Ability 连接
    "src/client/app_spawn_client.cpp",  # ★ 找 appspawn 孵化进程
    "src/client/bundlems_client.cpp",   # 找 BMS 查包信息
    "src/client/wms_client.cpp",        # 找窗口服务
    "src/client/ability_thread_client.cpp",
    "src/task/ability_start_task.cpp",  # 生命周期全部做成了"任务"对象
    "src/task/ability_stop_task.cpp", "src/task/ability_background_task.cpp",
    "src/task/ability_activate_task.cpp", "src/task/ability_connect_task.cpp",
    ... 共 19 个 task ...
  ]
  defines = [ "OHOS_APPEXECFWK_BMS_BUNDLEMANAGER" ]
}
lite_component("aafwk_services_lite") {
  features = [ ":abilityms" ]
  if (ohos_kernel_type != "liteos_m") {
    features += [ "tools:aa", "unittest:ability_test" ]   # aa 命令只给 L1
  }
}

对照表:

能力 L0(slite 版) L1(完整版)
服务端文件数 11 33
每个应用 一个线程(LiteOS 任务) 一个进程(appspawn fork 出来)
appspawn(进程孵化器) ❌ 源码树里都没有 base/startup/appspawn
Ability 栈 / Mission 管理 ❌(只有简单记录链表) ✅(stack manager + mission stack)
生命周期任务对象 ❌(直接发状态消息) ✅(19 种 task)
Service Ability 连接(connect/disconnect) ✅(ability_worker + connect task)
aa 命令行 ✅(aa start -p 包名 -n Ability名aa dump
窗口服务联动(wms) ✅(ABILITY_WINDOW_SUPPORT

2.4 启动一个 Ability:两条完全不同的路

L0:同一个进程里开一个线程

slite/ability_mgr_service_slite.cpp 里注册了两个"线程工厂":

void AbilityMgrServiceSlite::InitAbilityThreadLoad() {
    AbilityThreadLoader::GetInstance().SetCreatorFunc(JS_CREATOR, CreateJsAbilityThread);
    AbilityThreadLoader::GetInstance().SetCreatorFunc(NATIVE_CREATOR, CreateNativeAbilityThread);
}

启动链路:

JS 页面路由/launcher 请求启动
  → AbilityMgrServiceSlite::StartAbility(want)
    → AbilityRecordManager::StartAbility(want)        (ability_record_manager.cpp)
      → PreCheckStartAbility()  —— 经 bms_helper 向 BMS 查这个包的信息
      → CreateAppTask(record)                          (同文件, 670 行)
          按应用类型创建 JsAbilityThread 或 NativeAbilityThread
          → InitAbilityThread():在【当前进程】里开一个 LiteOS 任务(线程)
      → SendMsgToAbilityThread(SLITE_STATE_ACTIVE / BACKGROUND, record)
          用消息通知线程切换状态

要点:

  • 没有新进程。D21X 的 config.json 里 "config_ohos_aafwk_ams_task_size = 32768""config_ohos_aafwk_aafwk_lite_task_stack_size = 65536" 就是在给这些线程配栈大小 —— 32KB/64KB 的栈,这是典型的 MCU 级玩法。
  • 生命周期不是函数调用链,而是状态消息SLITE_STATE_ACTIVESLITE_STATE_BACKGROUND 等,丢给 Ability 所在线程的消息队列。
  • 应用在编译期就静态链接进固件(配合 ace_engine_lite 的 JS 应用),不需要运行时 dlopen。

L1:appspawn 孵化一个全新进程

启动链路:

串口敲 aa start -p com.xxx -n MainAbility(或 launcher 点击图标)
  → AbilityMgrFeature::StartAbilityInvoke()        (ability_mgr_feature.cpp, IPC 入口)
    → AbilityMgrHandler 分发
      → AbilityStackManager / PageAbilityRecord 建栈、建记录
      → 生成 AbilityStartTask 排队执行
        → AppManager::StartAppProcess(bundleInfo)   (app_manager.cpp, 26 行)
            已存在该应用的 AppRecord?→ 直接复用
            否则:生成 token → new AppRecord
            → spawnClient_.SpawnProcess(*appRecord)   (client/app_spawn_client.cpp)
                → 通过 IPC 请求 appspawn 服务
                    → appspawn fork() 出一个新进程,带独立 uid/gid
        → 新进程入口 AbilityMain()
          → AbilityThread::ThreadMain()             (frameworks/ability_lite/src/ability_thread.cpp)
            → dlopen(应用的 so, RTLD_NOW | RTLD_GLOBAL)   (182 行,运行时动态加载!)
            → so 里的构造函数执行 REGISTER_AA → 注册 Ability 工厂
            → 工厂 newAbilityInit()OnStart(want) → 生命周期跑起来

要点:

  • 每个应用一个独立 Linux 进程,有独立 uid/gid(BMS 安装时从 BASE_APP_UID = 10000 开始分配),崩溃互不影响。
  • 应用代码是运行时才 dlopen 加载的 so —— 这就是 L1 能支持"装完新应用立刻启动"的原因,也是你做 shim_bin_loader(用一个壳 Ability 去包 bin)能成立的前提。
  • 生命周期走完整任务队列:AbilityStartTask → AbilityActivateTask → ... → AbilityStopTask,AMS 通过 ability_thread_client 与应用进程双向 IPC。
  • 这一切依赖一堆只有 L1 才有的"配角":init.cfg 里启动的 foundation(Samgr 宿主)、appspawnbundle_daemonwms_server(窗口)等服务。

2.5 生命周期模型对比

L0 L1
Ability 活在哪 主进程里的一个 LiteOS 任务 独立进程的主线程
状态切换方式 AMS 往线程消息队列发 SLITE_STATE_* 消息 AMS 生成 Task 对象排队执行,IPC 通知应用进程
典型状态 INITIAL / ACTIVE / BACKGROUND INITIAL / INACTIVE / ACTIVE / BACKGROUND(+连接态)
崩溃影响面 可能拖垮整个固件(同进程) 只崩自己那个进程

三、支撑环境的差异(为什么会有上面这些区别)

BMS/AMS 的形态差异,根子在底层。同样以 ohos_kernel_type 分岔的还有服务管理框架 Samgr(foundation/systemabilitymgr/samgr_lite/samgr/BUILD.gn):

L0(LiteOS-M) L1(Linux)
内核形态 RTOS,无 MMU,单地址空间 完整 Linux,有 MMU,进程隔离
Samgr 产物 静态库,全部服务编进同一个固件进程 动态库 + ipc_single,服务是独立进程,靠 Unix Socket 通信
跨"进程"调用 本质是同进程内的消息队列/函数调用 真正的 IPC(communication/ipc 的 ipc_single)
服务怎么启动 APP_FEATURE_INIT 在固件启动流程里逐个执行 Linux init 解析 init.cfg 拉起 foundation/appspawn/bundle_daemon 等守护进程
进程孵化 无此概念 base/startup/appspawn(L0 树里压根没有这个目录)
应用形态 JS 应用(jerryscript + ace_engine_lite)为主,包为 .bin Native so + .hap,运行时 dlopen
配套子系统 极简:无窗口服务、无分布式 有 wms(窗口)、dmsfwk_lite(分布式调度)、softbus 等

四、一页看懂:L0 vs L1 BMS/AMS 总结

维度 L0(D21X / LiteOS-M / mini) L1(Hi3516 / Linux / small)
BMS/AMS 源码 与 L1 同一份仓库 与 L0 同一份仓库
区别来源 ohos_kernel_type == "liteos_m" 编译分支 + 无 OHOS_APPEXECFWK_BMS_BUNDLEMANAGER else 编译分支 + 定义该宏
BMS 类 GtManagerService / GtBundleInstaller(10 文件静态库) ManagerService / BundleInstaller(15 文件动态库 + bm + bundle_daemon)
预置应用 写死名单 9 个 .binsystem/ace/vendor/SetPreAppInfo 点名安装 /system/internal/system/external 等 4 个目录自动装 .hap
签名验证 有(hap_sign_verify.cpp)
命令行 无 bm / aa(适配层自加了 install/uninstall shell 命令) bm install/uninstall/dumpaa start/dump
AMS 类 AbilityMgrServiceSlite + AbilityRecordManager(11 文件) AbilityMgrService + AbilityStackManager + AppManager + 19 种 Task(33 文件)
应用运行单位 线程(32KB 栈的 LiteOS 任务),全系统一个进程 进程(appspawn fork),独立 uid/gid
代码加载 编译期静态链接 运行时 dlopen + REGISTER_AA 注册
多任务/后台 简单的前后消息切换 完整 Ability 栈、Mission、前后台调度
进程隔离/崩溃隔离

五、关键文件速查

L0(/home/gaoxining/openharmony + ohos_vendor_adapter

文件 作用
foundation/bundlemanager/bundle_framework_lite/services/bundlemgr_lite/BUILD.gn liteos_m 分支:10 文件静态库
.../services/bundlemgr_lite/include/bundle_common.h #else 分支:.binsystem/ace/vendor 等 L0 常量
.../services/bundlemgr_lite/src/gt_bundle_manager_service.cpp L0 BMS 核心(Install / SetPreAppInfo)
.../services/bundlemgr_lite/src/gt_bundle_installer.cpp L0 安装流程
frameworks/bundle_lite/src/slite/(3 个文件) L0 专用精简客户端
foundation/ability/ability_lite/services/abilitymgr_lite/src/slite/ L0 AMS 全部(11 文件)
.../src/slite/ability_record_manager.cpp(670 行 CreateAppTask) L0 在同进程开线程跑 Ability
vendor/artinchip/artinchip_d21x/config.json "type":"mini"、线程栈大小、组件开关
~/ohos_vendor_adapter/bms/src/pre_install_app.cpp 预安装名单 + APP_FEATURE_INIT 入口
~/ohos_vendor_adapter/bms/resources/system/ace/vendor/*.bin 9 个预置应用包

L1(/home/gaoxining/openharmony_l1

文件 作用
.../bundle_framework_lite/services/bundlemgr_lite/BUILD.gn else 分支:15 文件动态库 + bm + bundle_daemon
.../services/bundlemgr_lite/src/bundle_manager_service.cpp L1 BMS 核心(ScanBundle / InstallSystemBundle)
.../services/bundlemgr_lite/src/bundle_installer.cpp / hap_sign_verify.cpp 完整安装 + 验签
.../services/bundlemgr_lite/bundle_daemon/ 解压守护进程
foundation/ability/ability_lite/services/abilitymgr_lite/src/app_manager.cpp StartAppProcess → 找 appspawn 孵进程
.../src/client/app_spawn_client.cpp 与 appspawn 的 IPC 客户端
.../services/abilitymgr_lite/tools/src/main.cpp aa start -p ... -n ... 命令
foundation/ability/ability_lite/frameworks/ability_lite/src/ability_thread.cpp(182 行) dlopen 加载应用 so
base/startup/appspawn/ 进程孵化器(L0 树无此目录)
vendor/hisilicon/hispark_taurus_linux/init_configs/init_linux_3516dv300_openharmony_debug.cfg 开机拉起 foundation / appspawn / bundle_daemon / wms_server 等服务
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐