openharmony之启动恢复子系统详解

OpenHarmony的启动恢复子系统负责整个系统的启动流程,其中init进程是整个系统启动的第一个用户态进程(PID=1),承担着系统初始化的核心职责

🎯 目录结构

  • [📋 理论基础](#📋 理论基础)
  • [🔍 源码结构分析](#🔍 源码结构分析)
  • [⚙️ 配置体系详解](#⚙️ 配置体系详解)
  • [🚀 启动流程深度解析](#🚀 启动流程深度解析)
  • [🐛 调试与故障排除](#🐛 调试与故障排除)
  • [📊 性能优化实践](#📊 性能优化实践)
  • [🎯 实战配置案例](#🎯 实战配置案例)

系统启动大致流程:

上电 -> Bootloader -> Kernel -> init进程 -> (解析init.cfg) -> 启动appspawn、foundation -> foundation启动AMS、BMS等核心服务 -> 启动Launcher桌面 ->
系统就绪

📋 理论基础

🔄 init进程核心概念

1️⃣ 进程模型与职责

OpenHarmony的init进程是系统的第一个用户态进程(PID=1),采用多阶段启动模型,职责包括:

🎯 核心职责 📝 具体任务 🔗 相关源码
系统初始化 挂载文件系统、创建设备节点、设置系统参数 init/main.c
服务管理 解析配置、启动服务、监控状态、重启策略 init/service_manager.c
事件处理 处理uevent、属性变化、信号处理 init/event_handler.c
安全管理 SELinux策略加载、权限检查、沙盒管理 init/security.c
2️⃣ 三阶段启动架构

基本概念:

1.jobs是init组件下init.cfg文件中的一组命令构成的集合, 最多添加4096个job。 jobs可以在 cfg 文件中配置,通常在init启动过程中执行,服务于service的正常启动或特定基础功能的初始化。init解析程序会把相同名字job的命令合并到一个job中。同一名字的job只能保证init.cfg中的命令优先执行,其他cfg间的命令执行顺序不保证。

1.1.init进程的三个阶段: pre-init:init前置阶段,其他服务所依赖的,类似于ueventd、watchdog、hilogd等的关键服务会在这一阶段启动,data分区的挂载也在这一阶段进行。 init:init进程的主要阶段,这一阶段除了大量命令的执行,同时也是init分组并行启动boot组(第一组)服务的启动阶段,一些关乎系统功能的重要服务会在这一阶段被拉起。 post-init:这一阶段主要是通过trigger命令触发其他阶段执行,可以把所有被触发的阶段看作一个个的小阶段,也可以把它们统一看作post-init阶段,这一阶段会执行大量命令,并且它还是init分组并行启动normal组(第二组)服务的启动阶段,cfg中配置的大部分服务都是在这一阶段被拉起的。

2.服务管理: 服务管理主要通过init解析服务进程配置文件来实现,服务进程配置文件(xxx.cfg)可以根据业务场景按需配置服务,当前支持的增值服务包括启动控制、按需启动、命令执行、定时启动、fd代持、沙盒。

2.1服务进程配置文件: 一般命名为:serviceName.cfg(serviceName 为服务进程名,例如:appspawn.cfg)

3.系统参数配置: OHOS系统参数为各系统服务提供简单易用的键值对访问接口,使得各个系统服务可以通过各自的系统参数来进行业务功能的配置。

bash 复制代码
读参数:
param get paramName
GetParameter(const char* key, const char* def, char* value, unsigned int len) 
写参数:
param set paramName paramValue
SetParameter(const char* key, const char* value) 
监听参数:
hdc shell进入终端,执行param shell,进入Parameter shell后执行 watcher parameter param.key.xxx(系统参数名),
当系统参数值发生变化时,会收到类似"Receive parameter commit 691 change aaa.aaa 11111"的消息
3.1注意事项: 默认DAC规则只允许三方应用对参数具有get, watch 的权限,因此三方应用若需要set权限需要重新设置DAC规则。 此外, 三方应用的selinux权限默认是未设置的,因此需要参照mac访问控制权限设置进行设置

4.沙箱管理: 在init里面创建系统组件沙盒和芯片组件沙盒,native服务根据功能进入system沙盒或者chipset沙盒。在system-sandbox.json、chipset-sandbox.json等配置文件中设置沙盒组件中mount

bind 的目录或文件,实现沙盒组件通过mount属性进行隔离

沙箱相关配置文件:base/startup/init/interfaces/innerkits/sandbox


🔍 源码结构分析

📁 源码目录结构

复制代码
base/startup/init/
├── 📋 核心模块
│   ├── main.c              # 主入口
│   ├── init.c              # 初始化逻辑
│   ├── service_manager.c   # 服务管理
│   ├── job_parser.c        # 作业解析
│   └── param_manager.c     # 参数管理
├── 🔧 配置解析
│   ├── cfg_parser.c        # 配置解析器
│   ├── json_parser.c       # JSON解析
│   └── import_handler.c    # 导入处理
├── 🛡️ 安全模块
│   ├── security.c          # 安全检查
│   ├── selinux.c          # SELinux集成
│   └── sandbox.c          # 沙盒管理
├── 🐛 调试工具
│   ├── debug.c            # 调试接口
│   ├── log.c              # 日志系统
│   └── begetctl.c         # 调试命令
└── 📊 工具函数
    ├── utils.c            # 通用工具
    ├── file_utils.c       # 文件操作
    └── string_utils.c     # 字符串处理

🔍 关键数据结构

1️⃣ 服务结构体(service结构)
c 复制代码
// 源码位置: base/startup/init/interfaces/innerkits/service_define.h
typedef struct {
    char *name;                    // 服务名称
    char **path;                   // 可执行文件路径数组
    int pathArgs;                 // 路径参数数量
    uid_t uid;                    // 用户ID
    gid_t gid;                    // 组ID
    gid_t *gidCount;              // 附加组ID数组
    int gidCount;                 // 附加组数量
    char *secon;                  // SELinux上下文
    char *permission;             // 权限声明
    int critical;                 // 是否为关键服务
    int once;                     // 是否只启动一次
    int restartDelay;             // 重启延迟(秒)
    int restartTimes;             // 最大重启次数
    int restartPeriod;            // 重启周期(秒)
    struct socket_info *sockets;  // socket信息
    struct sandbox_info *sandbox; // 沙盒配置
} service_t;
2️⃣ job结构体
c 复制代码
typedef struct {
    char *name;                   // 名称
    char **cmds;                  // 命令数组
    int cmdCount;                 // 命令数量
    int priority;                 // 执行优先级
    struct job *next;             // 下一个作业
} job_t;

⚙️ 配置体系详解

📂 配置文件架构

init进程启动时,首先完成系统初始化工作,然后开始解析配置文件。系统在解析配置文件时,会将配置文件分成三类:

  1. init.cfg默认配置文件,由init系统定义,优先解析。

  2. /system/etc/init/*.cfg各子系统定义的配置文件。

  3. /vendor/etc/init/*.cfg厂商定义的配置文件。

    /system/etc/init/
    ├── init.cfg # 主配置
    ├── ueventd.cfg # 设备节点管理
    ├── servicemgr.cfg # 服务管理器
    ├── appspawn.cfg # 应用孵化器
    └── *.cfg # 各子系统配置

    /vendor/etc/init/ # 厂商定制配置
    /chipset/etc/init/ # 芯片相关配置
    /sys_prod/etc/init/ # 产品配置
    /chip_prod/etc/init/ # 单板配置

1️⃣ 分层配置模型
2️⃣ 配置优先级规则
🏆 优先级 📂 配置路径 🎯 覆盖范围 💡 使用场景
1️⃣ 最高 /chip_prod/etc/init/*.cfg 单板特定配置 硬件适配
2️⃣ 高 /sys_prod/etc/init/*.cfg 产品级配置 产品定制
3️⃣ 中 /chipset/etc/init/*.cfg 芯片级配置 芯片适配
4️⃣ 低 /system/etc/init/*.cfg 系统通用配置 基础服务

📝 配置文件详解

1️⃣ init.cfg 主配置文件

文件路径 : /system/etc/init/init.cfg

完整结构:

json 复制代码
{
  "import": [
    "/system/etc/init/servicemgr.cfg",
    "/system/etc/init/appspawn.cfg",
    "/system/etc/init/hiview.cfg"
  ],
  "jobs": [
    {
      "name": "pre-init",
      "priority": 0,
      "cmds": [
        "mkdir /dev/pts 0755 root root",
        "mount devpts /dev/pts devpts 0 0",
        "start ueventd",
        "load_persist_params",
        "mount_required_partitions",
        "chmod 0666 /dev/__properties__",
        "setparam sys.boot.phase pre-init"
      ]
    },
    {
      "name": "init",
      "priority": 1,
      "cmds": [
        "start servicemgr",
        "start hiview",
        "start appspawn",
        "setparam sys.boot.phase init"
      ]
    },
    {
      "name": "post-init",
      "priority": 2,
      "cmds": [
        "trigger late-init",
        "trigger boot-complete",
        "setparam sys.boot.phase post-init"
      ]
    },
    {
      "name": "boot-complete",
      "priority": 3,
      "cmds": [
        "setparam sys.boot.completed 1",
        "setparam sys.boot.phase completed"
      ]
    }
  ],
  "services": [
    {
      "name": "ueventd",
      "path": ["/system/bin/ueventd"],
      "uid": "root",
      "gid": ["root"],
      "secon": "u:r:ueventd:s0",
      "critical": true,
      "once": 1,
      "capabilities": ["CAP_MKNOD", "CAP_SYS_ADMIN"],
      "priority": -20
    }
  ]
}
2️⃣ 服务配置文件示例

servicemgr.cfg:

json 复制代码
{
  "services": [
    {
      "name": "servicemgr",
      "path": ["/system/bin/sa_main", "/system/profile/servicemgr.xml"],
      "uid": "system",
      "gid": ["system"],
      "secon": "u:r:servicemgr:s0",
      "permission": ["ohos.permission.SYSTEM_STARTUP"],
      "critical": true,
      "restart_delay": 5,
      "restart_times": 3,
      "restart_period": 300,
      "socket": [
        {
          "name": "servicemgr",
          "family": "unix",
          "type": "stream",
          "perm": "0666",
          "uid": "system",
          "gid": "system"
        }
      ]
    }
  ]
}
appspawn.cfg(应用孵化器)
json 复制代码
{
  "services" : [{
    "name" : "appspawn",
    "path" : ["/system/bin/appspawn"],
    "uid" : "root",
    "gid" : ["system"],
    "secon" : "u:r:appspawn:s0",
    "permission" : ["ohos.permission.APP_SPAWN"],
    "socket" : [{
      "name" : "appspawn",
      "family" : "unix",
      "type" : "stream",
      "perm" : "0666",
      "uid" : "root",
      "gid" : "system"
    }],
    "critical" : true
  }]
}

注意事项:

  1. cfg文件是严格按照JSON格式编写的,当添加服务或命令未生效时,可以优先排查添加内容的格式是否正确。
  2. 对于import解析,在解析完成一个import中的cfg文件路径时,会立即解析该cfg文件。
  3. example1.cfg 需要导入的cfg文件。
  4. serviceName:service名称, 用户自定义。
  5. /system/bin/serviceName: 当前服务的可执行文件全路径和参数, 数组形式。
  6. jobName1:job名称, 用户自定义。
3️⃣ 系统参数配置

参数文件结构:

bash 复制代码
# 📂 参数文件层次结构
/system/etc/param/
├── ohos_const/              # 系统常量参数
│   ├── ohos.para           # 基础系统参数
│   └── build.para          # 构建相关参数
├── *.para                  # 子系统参数
└── ohos.para.dac          # 参数权限配置

参数示例:

bash 复制代码
# 📋 /system/etc/param/ohos.para
# 系统基础参数
const.product.name=OpenHarmony
const.product.model=Dayu200
const.os.version.api=9
const.os.version.release=OpenHarmony 4.0
const.arkui.engine.enable=true

# 启动参数
startup.bootanim.enable=true
startup.appspawn.delay=0
startup.servicemgr.timeout=30

# 调试参数
debug.init.log.level=INFO
debug.init.log.tags=init,service,job

🚀 启动流程深度解析

🔍 详细启动时序

🔄 内核 📋 init进程 🔌 ueventd 🎯 servicemgr 🥚 appspawn 启动/init进程 解析init.cfg 执行pre-init作业 启动ueventd服务 监听设备事件 挂载required分区 启动servicemgr 加载服务配置 启动appspawn 初始化应用孵化器 触发boot-complete 🔄 内核 📋 init进程 🔌 ueventd 🎯 servicemgr 🥚 appspawn

📊 关键阶段分析

1️⃣ pre-init阶段(0-2秒)

核心任务:

  • ✅ 创建基础目录结构
  • ✅ 挂载必要的文件系统
  • ✅ 启动ueventd服务
  • ✅ 加载系统参数

实际执行命令:

bash 复制代码
# 📂 目录创建
mkdir /dev/pts 0755 root root
mkdir /dev/socket 0755 root root
mkdir /data/misc 0771 system misc

# 🔗 文件系统挂载
mount tmpfs /dev tmpfs rw,seclabel,nosuid,relatime,size=1024k,mode=755 0 0
mount devpts /dev/pts devpts rw,seclabel,relatime,mode=600,ptmxmode=000 0 0

# ⚙️ 系统参数加载
load_persist_params /system/etc/param/*.para
2️⃣ init阶段(2-5秒)

核心任务:

  • ✅ 启动boot组服务
  • ✅ 建立服务间通信
  • ✅ 初始化核心组件

服务启动顺序:

🔄 顺序 🎯 服务 📂 配置文件 🔗 依赖关系
1 ueventd init.cfg 无依赖
2 servicemgr servicemgr.cfg 依赖ueventd
3 hiview hiview.cfg 依赖servicemgr
4 appspawn appspawn.cfg 依赖servicemgr

服务启动顺序表

阶段 服务 配置路径 依赖检查
pre-init ueventd /system/etc/init/init.cfg
init servicemgr /system/etc/init/servicemgr.cfg ueventd
init hiview /system/etc/init/hiview.cfg servicemgr
post-init appspawn /system/etc/init/appspawn.cfg servicemgr
3️⃣ post-init阶段(5-10秒)

核心任务:

  • ✅ 启动normal组服务
  • ✅ 触发boot-complete事件
  • ✅ 进入用户态

🐛 调试与故障排除

🔧 调试工具集

1️⃣ begetctl命令详解

基础调试命令:

bash 复制代码
# 📋 查看服务状态
begetctl dump_service [service_name]

# 📊 查看配置加载
begetctl dump_cfg_files

# 🔍 查看作业队列
begetctl dump_jobs

# ⚙️ 查看系统参数
begetctl param get [param_name]
begetctl param set [param_name] [value]

# 🐛 调试日志
begetctl loglevel [level]      # 设置日志级别
begetctl logtags [tags]        # 设置日志标签

高级调试:

bash 复制代码
# 🔄 手动启动服务
begetctl start [service_name]

# ⏹️ 停止服务
begetctl stop [service_name]

# 🔄 重启服务
begetctl restart [service_name]

# 📊 查看服务依赖
begetctl check_dependency [service_name]
2️⃣ 日志系统配置

日志级别设置:

json 复制代码
{
  "services": [
    {
      "name": "init",
      "loglevel": "DEBUG",
      "logtags": ["init", "service", "job", "param"]
    }
  ]
}

日志文件位置:

bash 复制代码
# 📂 日志文件
/var/log/init.log          # init主日志
/var/log/servicemgr.log    # 服务管理器日志
/var/log/appspawn.log      # 应用孵化器日志

# 📊 查看日志
tail -f /var/log/init.log | grep -E "(ERROR|WARN)"

🚨 常见故障诊断

1️⃣ 启动卡Logo问题

🔍 故障现象: 设备启动后卡在启动动画界面

📊 诊断步骤:

bash 复制代码
# 1. 检查关键服务状态
begetctl dump_service | grep -E "(servicemgr|appspawn|hiview)"

# 2. 查看系统参数
param get sys.boot.phase
param get sys.boot.completed

# 3. 检查文件系统挂载
mount | grep -E "(system|vendor|data)"

# 4. 查看SELinux状态
getenforce
ausearch -m avc -ts recent

🛠️ 解决方案:

json 复制代码
{
  "jobs": [
    {
      "name": "boot-repair",
      "cmds": [
        "chmod 0666 /dev/__properties__",
        "setenforce 0",
        "start servicemgr --force"
      ]
    }
  ]
}
2️⃣ 服务重启循环

🔍 故障现象: 某个服务不断重启,查看日志显示启动失败

📊 诊断步骤:

bash 复制代码
# 1. 查看服务重启计数
begetctl dump_service [service_name] | grep restart

# 2. 检查服务配置
begetctl dump_service [service_name] | grep -E "(path|uid|gid|secon)"

# 3. 手动执行服务
/system/bin/[service_binary] --debug

# 4. 检查依赖服务
begetctl check_dependency [service_name]

🛠️ 解决方案:

json 复制代码
{
  "services": [
    {
      "name": "problem_service",
      "restart_delay": 30,
      "restart_times": 5,
      "restart_period": 600,
      "critical": false,
      "loglevel": "DEBUG"
    }
  ]
}
3️⃣ 权限拒绝问题

🔍 故障现象: 服务启动报Permission denied

📊 诊断步骤:

bash 复制代码
# 1. 检查文件权限
ls -l /system/bin/[service_binary]

# 2. 检查SELinux上下文
ls -Z /system/bin/[service_binary]

# 3. 检查capabilities
getcap /system/bin/[service_binary]

# 4. 查看audit日志
ausearch -m avc -ts recent | grep [service_name]

🛠️ 解决方案:

json 复制代码
{
  "services": [
    {
      "name": "permission_service",
      "secon": "u:r:correct_context:s0",
      "capabilities": ["CAP_NET_ADMIN", "CAP_SYS_TIME"],
      "permission": ["ohos.permission.SYSTEM_STARTUP"]
    }
  ]
}

📊 性能优化实践

⚡ 启动时间优化

1️⃣ 服务并行启动

优化策略:

json 复制代码
{
  "jobs": [
    {
      "name": "parallel-init",
      "cmds": [
        "start servicemgr &",
        "start hiview &",
        "start appspawn &",
        "wait"
      ]
    }
  ]
}
2️⃣ 延迟启动策略

非关键服务延迟启动:

json 复制代码
{
  "services": [
    {
      "name": "delayed_service",
      "path": ["/system/bin/delayed_service"],
      "start_mode": "ondemand",
      "trigger": "sys.boot.completed=1"
    }
  ]
}
3️⃣ 启动时间分析

测量工具:

bash 复制代码
# 📊 启动时间统计
begetctl bootchart start      # 开始记录
begetctl bootchart stop       # 停止记录
begetctl bootchart dump       # 导出报告

# 📈 性能分析
time begetctl start [service_name]

🎯 内存优化

1️⃣ 服务内存限制

内存配置:

json 复制代码
{
  "services": [
    {
      "name": "memory_limited_service",
      "memory_limit": "64M",
      "memory_swappiness": 0,
      "oom_score_adj": -1000
    }
  ]
}
2️⃣ 资源监控

监控配置:

bash 复制代码
# 📊 内存监控脚本
#!/system/bin/sh
while true; do
    echo "=== $(date) ===" >> /var/log/memory.log
    cat /proc/meminfo >> /var/log/memory.log
    begetctl dump_service | grep memory >> /var/log/memory.log
    sleep 60
done

🎯 实战配置案例

📋 案例1:添加自定义服务

需求 : 添加一个名为my_service的自定义服务

步骤1: 创建服务配置

json 复制代码
// 📁 /system/etc/init/my_service.cfg
{
  "services": [
    {
      "name": "my_service",
      "path": ["/system/bin/my_service", "--config", "/etc/my_service.conf"],
      "uid": "system",
      "gid": ["system", "inet"],
      "secon": "u:r:my_service:s0",
      "permission": [
        "ohos.permission.INTERNET",
        "ohos.permission.WRITE_SETTINGS"
      ],
      "critical": false,
      "restart_delay": 10,
      "restart_times": 3,
      "socket": [
        {
          "name": "my_service",
          "family": "unix",
          "type": "stream",
          "perm": "0666",
          "uid": "system",
          "gid": "system"
        }
      ],
      "env": [
        "MY_SERVICE_HOME=/data/my_service",
        "MY_SERVICE_LOG=/var/log/my_service.log"
      ]
    }
  ]
}

步骤2: 添加到主配置

json 复制代码
// 📁 /system/etc/init/init.cfg
{
  "import": [
    "/system/etc/init/my_service.cfg"
  ],
  "jobs": [
    {
      "name": "post-init",
      "cmds": [
        "start my_service"
      ]
    }
  ]
}

步骤3: 验证配置

bash 复制代码
# ✅ 检查配置格式
jq . /system/etc/init/my_service.cfg

# 🔄 重新加载配置
begetctl reload

# 📊 验证服务状态
begetctl dump_service my_service

📋 案例2:创建系统启动钩子

需求: 在系统启动完成后执行自定义脚本

配置:

json 复制代码
// 📁 /system/etc/init/startup_hook.cfg
{
  "jobs": [
    {
      "name": "custom-startup",
      "priority": 100,
      "cmds": [
        "chmod 0755 /system/etc/init.d/*",
        "exec /system/etc/init.d/startup_hook.sh",
        "log info \"Custom startup hook executed\""
      ]
    }
  ]
}

钩子脚本:

bash 复制代码
#!/system/bin/sh
# 📁 /system/etc/init.d/startup_hook.sh

# 等待系统完全启动
while [ "$(param get sys.boot.completed)" != "1" ]; do
    sleep 1
done

# 执行自定义操作
/system/bin/custom_init
/system/bin/setup_network
/system/bin/start_monitoring

echo "Custom startup hook completed at $(date)" >> /var/log/startup.log

📋 案例3:调试配置问题

问题: 服务启动失败,需要详细调试信息

调试配置:

json 复制代码
// 📁 /system/etc/init/debug.cfg
{
  "services": [
    {
      "name": "debug_service",
      "path": ["/system/bin/debug_service"],
      "uid": "root",
      "gid": ["root"],
      "secon": "u:r:debug_service:s0",
      "loglevel": "DEBUG",
      "logtags": ["service", "debug", "init"],
      "stdout": "/var/log/debug_service.out",
      "stderr": "/var/log/debug_service.err",
      "environment": {
        "DEBUG": "1",
        "VERBOSE": "1"
      }
    }
  ]
}

调试脚本:

bash 复制代码
#!/system/bin/sh
# 📁 /system/bin/debug_init.sh

echo "=== Debug Service Analysis ==="
echo "Service: debug_service"
echo "Binary: /system/bin/debug_service"
echo "Config: /system/etc/init/debug.cfg"
echo ""

echo "1. 检查文件权限:"
ls -la /system/bin/debug_service

echo "2. 检查SELinux上下文:"
ls -Z /system/bin/debug_service

echo "3. 检查依赖:"
ldd /system/bin/debug_service

echo "4. 检查配置:"
begetctl dump_service debug_service

echo "5. 手动测试:"
/system/bin/debug_service --test-mode

📚 附录

📋 参考资源

1️⃣ 源码位置
复制代码
base/startup/init/                    # init主目录
├── services/                        # 服务配置
├── docs/                           # 官方文档
├── tests/                          # 测试用例
└── tools/                          # 调试工具
2️⃣ 调试工具
  • begetctl - init调试命令
  • param - 系统参数管理
  • `hilog - 日志查看
  • hitrace - 系统调用跟踪
3️⃣ 配置文件模板
  • /system/etc/init/*.cfg - 服务配置
  • /system/etc/param/*.para - 参数配置
  • /system/etc/selinux/* - 安全策略

🎯 总结

OpenHarmony init进程的完整生命周期。

  1. 🔄 三阶段启动模型 - pre-init、init、post-init
  2. ⚙️ 配置体系 - 分层配置、优先级规则
  3. 🐛 调试工具 - begetctl、日志系统、故障诊断
  4. 📊 性能优化 - 并行启动、延迟加载、内存管理
  5. 🎯 实战案例 - 自定义服务、启动钩子、调试配置
相关推荐
爱笑的眼睛113 小时前
HarmonyOS TextArea 组件:文本输入区域的简单使用指南
华为·harmonyos
前端世界3 小时前
鸿蒙异步处理从入门到实战:Promise、async/await、并发池、超时重试全套攻略
华为·harmonyos
祥睿夫子4 小时前
鸿蒙ArkTS开发:Number、Boolean、String三种核心基本数据类型详解(附实战案例)
harmonyos·arkts
小喷友4 小时前
第5章 高级UI与动画
前端·app·harmonyos
whysqwhw4 小时前
鸿蒙ArkTS 与 Native 交互场景分类总结与关键实现
harmonyos
爱笑的眼睛115 小时前
HarmonyOS 递归实战:文件夹文件统计案例解析
华为·harmonyos
GeniuswongAir9 小时前
交叉编译.so到鸿蒙使用
华为·harmonyos
keepDXRcuriosity10 小时前
ArkTS 语言全方位解析:鸿蒙生态开发新选择
华为·harmonyos·arkts·鸿蒙
whysqwhw10 小时前
鸿蒙图标快捷菜单
harmonyos