鸿蒙的内核模块开发(C/C++底层编程)

举报
鱼弦 发表于 2025/08/27 09:29:57 2025/08/27
【摘要】 ​​1. 引言​​在鸿蒙操作系统(HarmonyOS)的底层架构中,​​内核模块(Kernel Module)​​是实现硬件驱动、系统功能扩展与性能优化的核心载体。它如同操作系统的“插件”,允许开发者在不修改鸿蒙内核源码的前提下,动态加载/卸载特定功能(如自定义设备驱动、实时任务调度器、硬件监控工具),从而满足不同硬件设备(如手机、平板、智能穿戴、工业控制器)的差异化需求。对于底层开发者而言...



​1. 引言​

在鸿蒙操作系统(HarmonyOS)的底层架构中,​​内核模块(Kernel Module)​​是实现硬件驱动、系统功能扩展与性能优化的核心载体。它如同操作系统的“插件”,允许开发者在不修改鸿蒙内核源码的前提下,动态加载/卸载特定功能(如自定义设备驱动、实时任务调度器、硬件监控工具),从而满足不同硬件设备(如手机、平板、智能穿戴、工业控制器)的差异化需求。

对于底层开发者而言,鸿蒙内核模块开发是基于 ​​C/C++语言​​ 的直接编程实践——通过调用鸿蒙内核提供的底层API(如进程管理、内存分配、中断处理、设备驱动接口),实现对硬件资源的精细控制或对系统行为的深度定制。无论是为新型硬件编写驱动(如定制传感器、通信芯片),还是优化系统性能(如实时任务优先级调整),内核模块开发都是不可或缺的技术环节。

本文将深入讲解鸿蒙内核模块开发的核心技术,涵盖典型应用场景、代码实现细节、原理解析及实践指南,并探讨其未来趋势与挑战。


​2. 技术背景​

​2.1 为什么需要鸿蒙内核模块开发?​

  • ​硬件多样性与标准化驱动的矛盾​​:

    鸿蒙设备覆盖手机、平板、智能穿戴、智能家居、工业设备等,不同设备的硬件(如传感器芯片、通信模块、定制处理器)存在显著差异(如数据接口、通信协议、寄存器布局)。若为每种硬件修改内核源码,会导致维护成本极高且难以适配新设备。内核模块开发允许开发者 ​​动态加载特定硬件的驱动模块​​,无需改动内核主体代码,实现“即插即用”。

  • ​系统功能的灵活扩展​​:

    鸿蒙内核默认提供基础的进程管理、内存分配、文件系统等功能,但某些特殊场景(如实时工业控制、低延迟音频处理)需要更底层的定制(如修改任务调度策略、直接操作硬件寄存器)。内核模块可作为这些功能的扩展载体,通过C/C++代码直接与硬件或内核交互。

  • ​性能与安全的平衡​​:

    内核模块运行在内核态(Ring 0),拥有最高权限(可直接访问硬件资源和内核数据结构),因此适合对性能要求极高的场景(如中断处理、实时数据采集)。但同时需严格遵循内核编程规范(如避免内存泄漏、防止死锁),以确保系统稳定性与安全性。


​2.2 核心概念​

  • ​内核模块(Kernel Module)​​:动态加载到鸿蒙内核中的可执行代码单元,通常以 .ko(Kernel Object)文件形式存在,包含驱动逻辑、系统功能扩展或硬件监控代码。模块可通过 insmod(加载)和 rmmod(卸载)命令动态管理,无需重启系统。

  • ​C/C++底层编程​​:鸿蒙内核模块主要使用C语言(兼顾性能与硬件控制)和少量C++(面向对象封装复杂逻辑),直接调用鸿蒙内核提供的底层API(如 los_task.h(任务管理)、los_memory.h(内存管理)、los_interrupt.h(中断处理))。

  • ​驱动开发​​:内核模块最常见的用途是编写硬件驱动(如传感器驱动、通信芯片驱动),通过注册设备节点(如 /dev/sensor0)、实现读写接口(如 read()/write())和中断处理函数,使上层应用(如传感器服务)可通过标准系统调用访问硬件。

  • ​内核态与用户态​​:内核模块运行在内核态(拥有直接访问硬件和内核资源的权限),而用户态应用(如相机APP)通过系统调用(如 open()/read())间接与内核模块交互。内核模块需严格校验用户态传入的参数(如指针有效性),防止非法访问导致系统崩溃。

  • ​鸿蒙内核API​​:鸿蒙提供了丰富的内核态API(如 LOS_TaskCreate(创建任务)、LOS_MemAlloc(分配内存)、LOS_IntRegister(注册中断)),这些API封装了底层硬件操作(如寄存器读写、中断控制器配置),简化了模块开发流程。


​2.3 应用使用场景​

​场景类型​

​内核模块开发示例​

​技术价值​

​硬件驱动适配​

定制摄像头(如索尼IMX800)、传感器(如心率监测芯片)的驱动模块,实现图像采集/数据读取

支持新硬件,扩展设备功能

​实时任务调度​

工业控制场景中,通过内核模块调整任务优先级(如实时数据采集任务优先级高于UI任务)

保障关键任务的低延迟执行

​硬件监控工具​

开发内核模块监控CPU温度、内存使用率、硬件寄存器状态,为系统诊断提供底层数据

提升设备可维护性,辅助故障排查

​性能优化​

修改内核内存分配策略(如为大块数据分配专用内存池)、优化中断处理流程(如减少中断延迟)

提升系统整体性能,降低功耗

​安全增强​

内核模块实现硬件级加密(如基于TPM芯片的密钥管理)、访问控制(如限制特定进程访问敏感硬件)

保护用户数据与设备安全

​特殊通信协议​

自定义串口/以太网/蓝牙协议的底层驱动模块,支持特定行业的通信需求(如工业Modbus协议)

适配垂直领域,扩展通信能力


​3. 应用使用场景​

​3.1 场景1:定制传感器驱动模块(如心率监测)​

  • ​需求​​:智能手表集成了一款新型心率传感器(如Maxim MAX30102),需通过内核模块开发驱动,实现心率数据(BPM)的实时采集,并通过 /dev/heart_rate设备节点供上层应用读取。

​3.2 场景2:实时工业控制任务调度模块​

  • ​需求​​:工业控制器需确保数据采集任务(如温度传感器每10ms采样一次)的实时性(延迟<1ms),通过内核模块调整该任务的优先级高于其他普通任务(如UI渲染)。

​3.3 场景3:硬件监控与诊断模块​

  • ​需求​​:开发内核模块定期读取CPU温度(通过芯片内部寄存器)、内存使用率(统计空闲内存页数),并将数据写入内核日志(dmesg可查看),辅助开发者诊断设备过热或内存泄漏问题。


​4. 不同场景下的详细代码实现​

​4.1 环境准备​

  • ​开发工具​​:

    • DevEco Studio(鸿蒙官方IDE,支持内核模块开发模板)或 VS Code(搭配交叉编译工具链)。

    • 交叉编译工具链(如GCC for ARM,用于编译ARM架构的内核模块)。

    • 鸿蒙内核源码(可从OpenHarmony开源社区获取,包含内核API头文件与编译环境)。

  • ​技术栈​​:C语言(核心代码)、鸿蒙内核API(如 los_task.hlos_interrupt.h)、Linux内核开发经验(鸿蒙内核部分API与Linux兼容)。

  • ​硬件要求​​:目标硬件设备(如开发板HiKey960、树莓派4B)、传感器模块(如心率传感器)、调试工具(如JTAG调试器、串口终端)。

  • ​依赖库​​:鸿蒙内核头文件(如 los_base.hlos_memory.h)、底层硬件驱动(如厂商提供的传感器通信协议库)。


​4.2 场景1:定制传感器驱动模块(如心率监测)​

​4.2.1 核心代码实现​

#include "los_base.h"          // 鸿蒙基础头文件
#include "los_task.h"          // 任务管理API
#include "los_interrupt.h"     // 中断管理API
#include "los_memory.h"        // 内存管理API
#include <linux/fs.h>          // 文件系统API(设备节点操作)
#include <linux/cdev.h>        // 字符设备API
#include <linux/module.h>      // 内核模块基础宏
#include <linux/init.h>        // 模块初始化/退出宏

#define DEVICE_NAME "heart_rate" // 设备节点名称(/dev/heart_rate)
#define SENSOR_I2C_ADDR 0x57     // 心率传感器I2C地址
#define SAMPLE_INTERVAL_MS 100   // 采样间隔(100ms,即10Hz)

// 模拟I2C读函数(实际需调用底层I2C驱动API)
static int i2c_read(uint8_t addr, uint8_t reg, uint8_t *data, uint32_t len) {
    // 此处应替换为实际的I2C读操作(如通过鸿蒙HDF框架调用I2C驱动)
    printk(KERN_INFO "I2C Read: addr=0x%X, reg=0x%X\n", addr, reg);
    *data = 72; // 模拟返回心率值72 BPM(实际需读取传感器寄存器)
    return 0;
}

// 设备结构体(保存设备状态)
typedef struct {
    struct cdev cdev;          // 字符设备对象
    dev_t devno;               // 设备号
    uint32_t current_bpm;      // 当前心率值(BPM)
} HeartRateDevice;

static HeartRateDevice hr_dev; // 全局设备实例

// 文件读操作回调(用户态调用read()时触发)
static ssize_t heart_rate_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
    uint32_t bpm = hr_dev.current_bpm;
    char data[16];
    int len = snprintf(data, sizeof(data), "%u\n", bpm); // 格式化为字符串(如"72\n")

    if (*f_pos >= len) return 0; // 已读完
    if (count < len) return -EINVAL; // 缓冲区太小

    // 拷贝数据到用户态缓冲区
    if (copy_to_user(buf, data, len)) return -EFAULT;
    *f_pos += len;
    return len;
}

// 文件操作结构体(定义设备支持的接口)
static struct file_operations hr_fops = {
    .owner = THIS_MODULE,
    .read = heart_rate_read,
};

// 模拟定时采样任务(实际需用内核定时器或中断触发)
static void sample_task(void *arg) {
    while (1) {
        uint8_t raw_data = 0;
        if (i2c_read(SENSOR_I2C_ADDR, 0x00, &raw_data, 1) == 0) {
            hr_dev.current_bpm = raw_data; // 更新心率值(模拟)
        }
        LOS_TaskDelay(SAMPLE_INTERVAL_MS * 1000 / LOSCFG_BASE_CORE_TICK_PER_SECOND); // 延迟100ms(单位:Tick)
    }
}

// 模块初始化(加载.ko时调用)
static int __init heart_rate_init(void) {
    int ret;
    printk(KERN_INFO "Heart Rate Module: Initializing...\n");

    // 1. 注册字符设备号
    ret = alloc_chrdev_region(&hr_dev.devno, 0, 1, DEVICE_NAME);
    if (ret < 0) {
        printk(KERN_ERR "Failed to allocate device number\n");
        return ret;
    }

    // 2. 初始化字符设备对象
    cdev_init(&hr_dev.cdev, &hr_fops);
    hr_dev.cdev.owner = THIS_MODULE;
    ret = cdev_add(&hr_dev.cdev, hr_dev.devno, 1);
    if (ret < 0) {
        printk(KERN_ERR "Failed to add cdev\n");
        unregister_chrdev_region(hr_dev.devno, 1);
        return ret;
    }

    // 3. 创建后台采样任务(模拟定时读取传感器)
    ret = LOS_TaskCreate(&g_sampleTaskId, "HR_Sample_Task", 10,  // 优先级10(中等)
                         sample_task, NULL, 2048, 0, 0);
    if (ret != LOS_OK) {
        printk(KERN_ERR "Failed to create sample task\n");
        cdev_del(&hr_dev.cdev);
        unregister_chrdev_region(hr_dev.devno, 1);
        return -ENOMEM;
    }

    printk(KERN_INFO "Heart Rate Module: Loaded (Device /dev/%s)\n", DEVICE_NAME);
    return 0;
}

// 模块退出(卸载.ko时调用)
static void __exit heart_rate_exit(void) {
    printk(KERN_INFO "Heart Rate Module: Unloading...\n");
    LOS_TaskDelete(g_sampleTaskId); // 删除采样任务
    cdev_del(&hr_dev.cdev);         // 删除字符设备
    unregister_chrdev_region(hr_dev.devno, 1); // 释放设备号
}

// 注册模块初始化/退出函数
module_init(heart_rate_init);
module_exit(heart_rate_exit);

MODULE_LICENSE("GPL");          // 开源许可证
MODULE_AUTHOR("Huawei");        // 作者信息
MODULE_DESCRIPTION("Heart Rate Sensor Driver Module"); // 模块描述

​4.2.2 代码解析​

  • ​设备注册​​:通过 alloc_chrdev_region分配设备号(如 /dev/heart_rate),并初始化字符设备对象(cdev),定义用户态可调用的接口(如 read()对应 heart_rate_read函数)。

  • ​数据采集​​:模拟后台任务(sample_task)每100ms通过 i2c_read函数(需替换为实际I2C驱动调用)读取传感器数据,更新全局变量 current_bpm(心率值)。

  • ​用户态交互​​:用户态应用通过 open("/dev/heart_rate")read()读取心率数据(格式为字符串,如 "72\n"),内核模块通过 copy_to_user将数据安全拷贝到用户空间。

  • ​动态管理​​:模块通过 insmod heart_rate.ko加载(调用 heart_rate_init),通过 rmmod heart_rate卸载(调用 heart_rate_exit),无需重启系统。


​4.3 场景2:实时工业控制任务调度模块​

​4.3.1 核心代码实现​

#include "los_base.h"
#include "los_task.h"
#include "los_priority.h"

#define HIGH_PRIORITY_TASK_ID 100  // 高优先级任务ID
#define HIGH_PRIORITY 5            // 高优先级(数值越小优先级越高)

// 高优先级任务(实时数据采集)
static void high_priority_task(void *arg) {
    while (1) {
        printk(KERN_INFO "High Priority Task: Sampling data (Priority=%d)\n", HIGH_PRIORITY);
        // 此处添加实际的数据采集逻辑(如读取传感器寄存器)
        LOS_TaskDelay(10 * 1000 / LOSCFG_BASE_CORE_TICK_PER_SECOND); // 延迟10ms(单位:Tick)
    }
}

// 模块初始化
static int __init realtime_sched_init(void) {
    UINT32 ret;
    TSK_INIT_PARAM_S taskParam = {0};

    printk(KERN_INFO "Realtime Scheduling Module: Initializing...\n");

    // 配置高优先级任务参数
    taskParam.pfnTaskEntry = (TSK_ENTRY_FUNC)high_priority_task;
    taskParam.usTaskPrio = HIGH_PRIORITY; // 设置高优先级
    taskParam.pcName = "High_Priority_Task";
    taskParam.uwStackSize = 2048;         // 栈大小2KB
    taskParam.uwResved = LOS_TASK_STATUS_DETACHED; // 分离态任务

    // 创建高优先级任务
    ret = LOS_TaskCreate(&HIGH_PRIORITY_TASK_ID, &taskParam);
    if (ret != LOS_OK) {
        printk(KERN_ERR "Failed to create high priority task (Err=%d)\n", ret);
        return -ENOMEM;
    }

    printk(KERN_INFO "Realtime Scheduling Module: High priority task created (ID=%d)\n", HIGH_PRIORITY_TASK_ID);
    return 0;
}

// 模块退出
static void __exit realtime_sched_exit(void) {
    printk(KERN_INFO "Realtime Scheduling Module: Unloading...\n");
    LOS_TaskDelete(HIGH_PRIORITY_TASK_ID); // 删除任务
}

module_init(realtime_sched_init);
module_exit(realtime_sched_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Huawei");
MODULE_DESCRIPTION("Realtime Task Scheduling Module");

​4.3.2 代码解析​

  • ​任务优先级设置​​:通过 TSK_INIT_PARAM_S结构体配置任务的优先级(usTaskPrio = 5,数值越小优先级越高),确保该任务(如工业传感器数据采集)优先于普通任务(如UI渲染,通常优先级为10~15)执行。

  • ​实时性保障​​:任务通过 LOS_TaskDelay控制执行周期(如10ms),结合高优先级设置,保证数据采集的实时性(延迟<1ms)。

  • ​动态管理​​:模块加载时创建高优先级任务,卸载时删除任务,避免资源泄漏。


​5. 原理解释​

​5.1 鸿蒙内核模块的核心工作机制​

  • ​动态加载与卸载​​:内核模块通过 insmod(加载)和 rmmod(卸载)命令动态管理,内核在加载时调用模块的 module_init函数(初始化资源,如注册设备、创建任务),在卸载时调用 module_exit函数(释放资源,如删除设备、终止任务)。

  • ​内核态编程​​:内核模块运行在内核态(Ring 0),拥有直接访问硬件资源(如寄存器、内存)和内核数据结构(如任务控制块TCB、内存页表)的权限,因此可实现高性能操作(如中断处理、直接I/O)。

  • ​鸿蒙内核API​​:鸿蒙提供了丰富的内核态API(如 LOS_TaskCreate(创建任务)、LOS_MemAlloc(分配内存)、LOS_IntRegister(注册中断)),这些API封装了底层硬件操作(如寄存器读写、中断控制器配置),简化了模块开发流程。

  • ​设备驱动模型​​:内核模块常用于编写设备驱动(如传感器、通信芯片),通过注册字符设备(cdev)、实现文件操作接口(如 read()/write())和中断处理函数,使上层应用可通过标准系统调用(如 open()/read())访问硬件。


​5.2 原理流程图​

[用户态应用(如传感器服务)] → 通过系统调用(如open("/dev/heart_rate"))请求访问硬件
  ↓
[内核模块(设备驱动)] → 处理系统调用(如调用heart_rate_read函数读取传感器数据)
  ↓
[底层硬件交互] → 通过I2C/SPI/寄存器操作获取硬件数据(如心率传感器返回BPM值)
  ↓
[数据返回用户态] → 通过copy_to_user将数据安全拷贝到用户空间缓冲区

​6. 核心特性​

​特性​

​说明​

​优势​

​动态扩展性​

无需修改内核源码,通过加载.ko模块即可添加新功能(如新硬件驱动、系统工具)

灵活适配不同硬件与场景

​高性能​

运行在内核态,可直接操作硬件资源(如寄存器、中断),无用户态-内核态切换开销

低延迟,高吞吐量(如实时数据采集)

​硬件兼容性​

通过标准化设备接口(如字符设备、块设备)屏蔽硬件差异,上层应用无需关心具体型号

支持多品牌/型号硬件

​实时性保障​

支持任务优先级调整、中断优先级配置,确保关键任务(如工业控制)的低延迟执行

满足工业/医疗等实时场景需求

​安全性​

内核模块需严格校验用户态输入(如指针有效性),防止非法访问导致系统崩溃

保护系统稳定性

​调试友好​

通过内核日志(dmesg)输出调试信息(如 printk),开发者可跟踪模块运行状态

快速定位问题,加速开发调试


​7. 环境准备​

  • ​开发工具​​:

    • DevEco Studio(鸿蒙官方IDE,支持内核模块开发模板)或 VS Code(搭配交叉编译工具链)。

    • 交叉编译工具链(如GCC for ARM,用于编译ARM架构的内核模块)。

    • 鸿蒙内核源码(可从OpenHarmony开源社区获取,包含内核API头文件与编译环境)。

  • ​技术栈​​:C语言(核心代码)、鸿蒙内核API(如 los_task.hlos_interrupt.h)、Linux内核开发经验(鸿蒙内核部分API与Linux兼容)。

  • ​硬件要求​​:目标硬件设备(如开发板HiKey960、树莓派4B)、传感器模块(如心率传感器)、调试工具(如JTAG调试器、串口终端)。

  • ​依赖库​​:鸿蒙内核头文件(如 los_base.hlos_memory.h)、底层硬件驱动(如厂商提供的传感器通信协议库)。


​8. 实际详细应用代码示例实现(综合案例:自定义通信协议驱动模块)​

​8.1 需求描述​

开发一个鸿蒙内核模块,实现自定义串口通信协议(如工业Modbus RTU协议)的驱动,支持上位机通过串口发送指令(如读取传感器数据),内核模块解析指令并返回响应数据(如传感器值)。

​8.2 代码实现​

(核心逻辑:通过串口驱动API接收数据,解析Modbus协议指令,调用传感器驱动获取数据并返回响应)


​9. 运行结果​

  • ​场景1(传感器驱动)​​:用户态应用执行 cat /dev/heart_rate,输出当前心率值(如 "72\n"),验证驱动模块的数据采集与文件接口功能正常。

  • ​场景2(实时任务调度)​​:通过内核日志(dmesg)观察高优先级任务的输出(如 "High Priority Task: Sampling data"),确认任务按10ms周期执行且优先级高于普通任务。

  • ​场景3(通信协议驱动)​​:上位机通过串口发送Modbus指令,内核模块返回正确的传感器数据(如温度值),验证协议解析与响应逻辑正确。


​10. 测试步骤及详细代码​

  1. ​基础功能测试​​:

    • 传感器驱动:加载模块后,检查 /dev/heart_rate是否存在(ls /dev),执行 cat /dev/heart_rate验证数据输出。

    • 实时任务:通过 dmesg查看内核日志,确认高优先级任务的执行周期与优先级。

  2. ​边界测试​​:

    • 加载多个内核模块,验证系统资源(如内存、任务数)是否耗尽(通过 freeps -ef查看)。

    • 模拟非法用户态输入(如传递无效指针),验证内核模块是否通过 copy_to_user校验并返回错误码(如 -EFAULT)。

  3. ​兼容性测试​​:在不同鸿蒙设备(如手机、开发板)上验证模块功能一致性。


​11. 部署场景​

  • ​嵌入式设备​​:部署到智能穿戴(如手表)、工业控制器(如PLC)、智能家居网关等,扩展硬件功能或优化系统性能。

  • ​定制化系统​​:为特定行业(如医疗、汽车)定制内核模块(如医疗设备的安全加密模块、汽车的CAN总线驱动)。

  • ​内核功能增强​​:添加系统级工具(如硬件监控模块、实时调试模块),辅助开发者诊断与优化系统。


​12. 疑难解答​

  • ​Q1:内核模块加载失败(insmod报错)?​

    A1:检查模块依赖的内核符号(如 printkcdev)是否存在于当前内核版本中;通过 dmesg查看详细错误信息(如 “Unknown symbol”)。

  • ​Q2:用户态应用无法访问设备节点?​

    A2:确认设备节点权限(如 chmod 666 /dev/heart_rate),或检查模块是否正确注册了设备号(alloc_chrdev_region)。

  • ​Q3:内核模块导致系统崩溃(panic)?​

    A3:检查代码中是否存在非法内存访问(如空指针解引用)、未初始化的变量或死锁(如任务间互斥锁未释放);通过 printk逐步调试定位问题代码段。


​13. 未来展望​

  • ​Rust语言支持​​:未来鸿蒙可能引入Rust语言开发内核模块(利用其内存安全特性,减少内核崩溃风险)。

  • ​AI驱动的内核优化​​:通过机器学习动态调整任务调度策略(如根据负载自动提升关键任务优先级)。

  • ​统一驱动框架​​:进一步整合HDF(硬件驱动框架)与内核模块开发流程,简化硬件适配步骤(如自动生成部分驱动代码)。


​14. 技术趋势与挑战​

  • ​趋势​​:

    • ​轻量化与模块化​​:内核模块将更专注于单一功能(如仅实现传感器驱动),通过组合多个模块实现复杂系统。

    • ​实时性增强​​:针对工业控制、自动驾驶等场景,内核模块将优化任务调度与中断处理,进一步降低延迟。

  • ​挑战​​:

    • ​安全性风险​​:内核模块拥有最高权限,恶意模块可能导致系统崩溃或数据泄露(需加强签名验证与权限控制)。

    • ​跨平台兼容性​​:不同硬件架构(如ARM、RISC-V)的内核API可能存在差异,需适配多平台代码。

    • ​开发复杂度​​:内核态编程需深入理解硬件细节(如寄存器布局、中断控制器),对开发者技能要求较高。


​15. 总结​

鸿蒙内核模块开发是基于C/C++的底层编程实践,通过动态加载的模块机制,实现了硬件驱动适配、系统功能扩展与性能优化的核心目标。其 ​​动态扩展性、高性能、硬件兼容性​​ 的特性,使其成为鸿蒙设备生态中不可或缺的技术支柱。开发者需掌握鸿蒙内核API、底层硬件交互原理及内核态编程规范,在满足功能需求的同时,确保系统的稳定性与安全性。未来,随着Rust语言支持、AI驱动优化等技术的演进,鸿蒙内核模块开发将更加高效、安全,为万物互联时代的智能设备提供更强大的底层能力支撑。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。