OpenHarmony-4.HDI 框架

  • HDI 框架

1.HDI介绍

  HDI(Hardware Device Interface,硬件设备接口)是HDF驱动框架为开发者提供的硬件规范化描述性接口,位于基础系统服务层和设备驱动层之间,是连通驱动程序和系统服务进行数据流通的桥梁,是提供给硬件系统服务开发者使用的、统一的硬件设备功能抽象接口,其目的是为系统服务屏蔽南向设备差异。

  在OpenHarmony 分层结构中,HDI位于 “基础系统服务层”和“设备抽象层(DAL)”之间。硬件设备通过DAL抽象化,并基于IDL(Interface Description Language)接口描述语言描述后,为上层应用或服务提供了规范的硬件设备接口。
在这里插入图片描述

2.HDI实现

2.1.IDL接口描述语言

  IDL(Interface Description Language)是一类用来描述接口的语言,通过一种中立的方式来定义客户端与服务端均认可的编程接口,可以实现在二者间的跨进程通信(IPC)。跨进程通信意味着可以在一个进程访问另一个进程的数据,或调用另一个进程的方法。通常把应用接口提供方(供调用)称为服务端,调用方称为客户端。

  IDL先把需要传递的对象分解成操作系统能够理解的基本类型,然后根据接口声明编译,生成IPC/RPC代理(Proxy)和桩(Stub)的C/C++代码,从而为调用者提供一致的接口和调用方式。

  使用IDL语法描述HDI接口并保存为.idl文件,.idl文件在编译过程中转换为C/C++语言的函数接口声明、客户端与服务端IPC相关过程代码,开发时只需要基于生成的头文件中函数接口实现具体服务功能即可。代码生成与编译功能已经集成在hdi.gni编译模板,基于该编译模板编写idl文件的BUILD.gn就可以简单的生成客户端、服务端代码并编译为共享库。如下图所示:
在这里插入图片描述

drivers_interface 仓库:

├── README.en.md
├── README.md
├── sensor                          #sensor HDI 接口定义
│   └── v1_0                        #sensor HDI 接口 v1.0版本定义
│       ├── BUILD.gn                #sensor idl文件编译脚本
│       ├── ISensorCallback.idl     #sensor callback 接口定义idl文件
│       ├── ISensorInterface.idl    #sensor interface 接口定义idl文件
│       └── SensorTypes.idl         #sensor 数据类型定义idl文件
├── audio                           #audio HDI 接口定义
│   └── ...
├── camera                          #camera HDI接口定义
├── codec                           #codec HDI接口定义
├── display                         #display HDI接口定义
├── face_auth                       #faceauth HDI接口定义
├── format                          #format HDI接口定义
├── input                           #input HDI接口定义
├── misc                            #misc HDI接口定义
├── pinauth                         #pinauth HDI接口定义
├── usb                             #usb HDI接口定义
├── fingerprint_auth                #fingerprintauth HDI接口定义
└── wlan                            #wlan HDI接口定义

2.2.使用IDL语法编写 .idl 文件

  创建对应模块/版本接口目录,初始版本定义为v1_0,如 drivers/interface/input/v1.0/目录:

-rw-r--r--. 1 iscas iscas 1.1K Dec 17 11:28 BUILD.gn
-rw-r--r--. 1 iscas iscas 2.4K Dec 17 11:28 IInputCallback.idl
-rw-r--r--. 1 iscas iscas  14K Dec 17 11:28 IInputInterfaces.idl
-rw-r--r--. 1 iscas iscas 5.4K Dec 17 11:28 InputTypes.idl
  • 定义接口IInputInterfaces.idl
 46 package ohos.hdi.input.v1_0;
 47
 48 import ohos.hdi.input.v1_0.IInputCallback;
 49 import ohos.hdi.input.v1_0.InputTypes;

 61 interface IInputInterfaces {
 75     ScanInputDevice([out] struct DevDesc[] staArr);
 89     OpenInputDevice([in] unsigned int devIndex);
 103    CloseInputDevice([in] unsigned int devIndex);
 118    GetInputDevice([in] unsigned int devIndex, [out] struct DeviceInfo devInfo);
 119    ...
 120 }
  • 如果接口中用到了自定义数据类型,将自定义类型定义到一个单独的.idl文件,如InputTypes.idl
 53 struct DevDesc {
 54     unsigned int devIndex;        /**< Device index */
 55     unsigned int devType;         /**< Device type */
 56 };
 57
 61 struct DevIdentify {
 62     unsigned short busType;       /**< Bus type */
 63     unsigned short vendor;        /**< Vendor ID */
 64     unsigned short product;       /**< Product ID */
 65     unsigned short version;       /**< Version */
 66 };
  • 如果需要从服务端回调,可以定义callback接口类,如IInputCallback.idl
 45 package ohos.hdi.input.v1_0;
 47 import ohos.hdi.input.v1_0.InputTypes;
 
 58 [callback] interface IInputCallback {
 69     EventPkgCallback([in] struct EventPackage[] pkgs, [in] unsigned int devIndex);
 79     HotPlugCallback([in] struct HotPlugEvent event);
 80 }

2.3.编写 idl文件的BUILD.gn

  drivers_interface/input/v1_0目录中添加BUILD.gn文件,内容如下:

 14 import("//build/config/components/hdi/hdi.gni")
 15
 16 if (defined(ohos_lite)) {
 17   group("libinput_proxy_1.0") {
 18     deps = []
 19     public_configs = []
 20   }
 21 } else {
 22   hdi("input") {
 23     module_name = "input_service"
 24
 25     sources = [
 26       "IInputCallback.idl",
 27       "IInputInterfaces.idl",
 28       "InputTypes.idl",
 29     ]
 30     mode = "passthrough"
 31     language = "cpp"
 32     subsystem_name = "hdf"
 33     part_name = "drivers_interface_input"
 34   }
 35 }

2.4.实现 HDI 服务

   .idl文件在编译过程中除了生成C/C++语言的函数接口声明、客户端与服务端IPC相关过程代码,还会生成驱动入口文件和驱动服务实现文件的模板(如图中间部分所示),实际开发中需要做的就是参照这两个模板根据实际业务需求将文件重新实现即可(如图右侧目录结构所示)。参考Battery IDL 接口如下图所示:
在这里插入图片描述

  在上述步骤中idl编译后将在out目录out/rk3568/gen/drivers/interfaces/input/v1_0生成中间代码。基于工具自动生成的input_interface_service.h,实现其中的服务接口。

oh41/out/rk3568/gen/drivers/interface/input/v1_0$ ls -lh
total 56K
-rw-rw-r-- 1 iscas iscas 1.7K 1217 16:16 iinput_callback.h
-rw-rw-r-- 1 iscas iscas 3.4K 1217 16:16 iinput_interfaces.h
-rw-rw-r-- 1 iscas iscas 1.1K 1217 16:16 input_callback_service.cpp
-rw-rw-r-- 1 iscas iscas 1.3K 1217 16:16 input_callback_service.h
-rw-rw-r-- 1 iscas iscas 1.7K 1217 16:16 input_interfaces_proxy.cpp
-rw-rw-r-- 1 iscas iscas 3.2K 1217 16:16 input_interfaces_service.cpp
-rw-rw-r-- 1 iscas iscas 2.7K 1217 16:16 input_interfaces_service.h
-rw-rw-r-- 1 iscas iscas 2.6K 1217 16:16 input_types.h

2.4.1.实现HDI服务接口

  基于工具自动生成的input_interface_service.h,实现其中的服务接口,并将相关源码编译为 libinput_interfaces_service_1.0.z.so。

  • drivers_peripheral\input\hdi_service\input_interfaces_impl.h:
#ifndef OHOS_HDI_INPUT_V1_0_INPUTINTERFACEIMPL_H
#define OHOS_HDI_INPUT_V1_0_INPUTINTERFACEIMPL_H

#include "input_manager.h"
#include "v1_0/iinput_interfaces.h"

namespace OHOS {
namespace HDI {
namespace Input {
namespace V1_0 {
class InputInterfacesImpl : public IInputInterfaces {
public:
    InputInterfacesImpl(): inputInterface_(NULL) {}
    virtual ~InputInterfacesImpl()
    {
        ReleaseInputInterface(&inputInterface_);
    }
    void Init();
    int32_t ScanInputDevice(std::vector<DevDesc> &staArr) override;
    int32_t OpenInputDevice(uint32_t devIndex) override;
    int32_t CloseInputDevice(uint32_t devIndex) override;
    int32_t GetInputDevice(uint32_t devIndex, DeviceInfo &devInfo) override;
    int32_t GetInputDeviceList(uint32_t &devNum, std::vector<DeviceInfo> &devList, uint32_t size) override;
    int32_t SetPowerStatus(uint32_t devIndex, uint32_t status) override;
    int32_t GetPowerStatus(uint32_t devIndex, uint32_t &status) override;
    int32_t GetDeviceType(uint32_t devIndex, uint32_t &deviceType) override;
    int32_t GetChipInfo(uint32_t devIndex, std::string &chipInfo) override;
    int32_t GetVendorName(uint32_t devIndex, std::string &vendorName) override;
    int32_t GetChipName(uint32_t devIndex, std::string &chipName) override;
    int32_t SetGestureMode(uint32_t devIndex, uint32_t gestureMode) override;
    int32_t RunCapacitanceTest(uint32_t devIndex, uint32_t testType, std::string &result,
        uint32_t length) override;
    int32_t RunExtraCommand(uint32_t devIndex, const ExtraCmd &cmd) override;
    int32_t RegisterReportCallback(uint32_t devIndex, const sptr<IInputCallback> &eventPkgCallback) override;
    int32_t UnregisterReportCallback(uint32_t devIndex) override;
    int32_t RegisterHotPlugCallback(const sptr<IInputCallback> &hotPlugCallback) override;
    int32_t UnregisterHotPlugCallback() override;
private:
    IInputInterface *inputInterface_;
};
} // V1_0
} // Input
} // HDI
} // OHOS

#endif // OHOS_HDI_INPUT_V1_0_INPUTINTERFACEIMPL_H
  • drivers_peripheral\input\hdi_service\input_interfaces_impl.cpp:
int32_t InputInterfacesImpl::ScanInputDevice(std::vector<DevDesc> &staArr)
{
    if (inputInterface_ == nullptr || inputInterface_->iInputManager == nullptr ||
        inputInterface_->iInputManager->ScanInputDevice == nullptr) {
        HDF_LOGE("%{public}s: get input device Module instance failed", __func__);
        return HDF_FAILURE;
    }

    InputDevDesc staArrHdf[MAX_DEVICES];
    int32_t ret = memset_s(staArrHdf, MAX_DEVICES * sizeof(InputDevDesc), 0, MAX_DEVICES * sizeof(InputDevDesc));

    ret = inputInterface_->iInputManager->ScanInputDevice(staArrHdf, MAX_DEVICES);

    for (uint32_t i = 0; i < MAX_DEVICES; i++) {
        DevDesc StaArr;
        StaArr.devIndex = staArrHdf[i].devIndex;
        StaArr.devType = staArrHdf[i].devType;
        staArr.push_back(StaArr);
    }
    return ret;
}

int32_t InputInterfacesImpl::OpenInputDevice(uint32_t devIndex)
{
    if (inputInterface_ == nullptr || inputInterface_->iInputManager == nullptr ||
        inputInterface_->iInputManager->OpenInputDevice == nullptr) {
        HDF_LOGE("%{public}s: get input device Module instance failed", __func__);
        return HDF_FAILURE;
    }

    int32_t ret = inputInterface_->iInputManager->OpenInputDevice(devIndex);
    return ret;
}
...

2.4.2.实现驱动入口

  HDI服务发布是基于用户态HDF驱动框架,所以需要实现一个驱动入口。驱动实现代码参考已经在out目录中生成,可以根据业务需要直接使用该文件或参考该文件按业务需要重新实现, 然后将驱动入口源码编译为libinput_driver.z.so(该名称无强制规定,与hcs配置中配套即可)。

  • drivers_peripheral\input\hdi_service\input_interfaces_driver.cpp:
static void HdfInputInterfacesDriverRelease(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("HdfInputInterfacesDriverRelease enter");
    if (deviceObject->service == nullptr) {
        HDF_LOGE("HdfInputInterfacesDriverRelease not initted");
        return;
    }

    auto *hdfInputInterfacesHost = CONTAINER_OF(deviceObject->service, struct HdfInputInterfacesHost, ioService);
    delete hdfInputInterfacesHost;
}

struct HdfDriverEntry g_inputinterfacesDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "input_service",
    .Bind = HdfInputInterfacesDriverBind,
    .Init = HdfInputInterfacesDriverInit,
    .Release = HdfInputInterfacesDriverRelease,
};

vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs

2.4.3.发布服务

  在产品hcs配置中声明HDI服务,以标准系统rk3568为例,HDF设备配置路径为vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs,在其中新增以下配置:

310             input_hdi_device :: device {
311                 device0 :: deviceNode {
312                     policy = 2;
313                     priority = 100;
314                     moduleName = "libinput_driver.z.so";
315                     serviceName = "input_interfaces_service";
316                 }
317             }

2.4.6.HDI使用

  • 在需要使用HDI服务的客户端BUILD.gn中增加依赖: “drivers_interface_input:libinput_proxy_1.0”
 powermgr/battery_manager/charger/BUILD.gn:
 60   external_deps = [
 61     "c_utils:utils",
 62     "config_policy:configpolicy_util",
 63     "drivers_interface_battery:libbattery_proxy_2.0",
 64     "drivers_interface_input:libinput_proxy_1.0",
 65     "init:libbegetutil",
 66     "ipc:ipc_core",
 67   ]
  • 在代码中调用HDI接口
base/powermgr/battery_manager/charger/src/charger_thread.cpp:
339 void ChargerThread::InitInput()
340 {
341     inputInterface = nullptr;
342     inputInterface = HDI::Input::V1_0::IInputInterfaces::Get(true);
347
348     const uint32_t POWERKEY_INPUT_DEVICE = 2;
349     int32_t ret = inputInterface->OpenInputDevice(POWERKEY_INPUT_DEVICE);
355
356     uint32_t devType = INDEV_TYPE_UNKNOWN;
357     ret = inputInterface->GetDeviceType(POWERKEY_INPUT_DEVICE, devType);
363
364     /* first param is powerkey input device, refer to device node '/dev/hdf_input_event2', so pass 2 */
365     if (g_callback == nullptr) {
366         g_callback = new (std::nothrow) HdfInputEventCallback();
367     }
372     ret = inputInterface->RegisterReportCallback(POWERKEY_INPUT_DEVICE, g_callback);
378 }

3.HDI 部署

  在不同量级的 OpenHarmony 系统上,HDI 存在两种部署形态,IPC 模式和直通模式。

在这里插入图片描述

  • 轻量级 OpenHarmony 系统,出于减小系统性能负载考虑,HDI 实现为用户态共享库,由系统服务直接加载 HDI 实现到自己进程中函数调用使用。HDI 实现封装具体的用户态-内核态交互过程,当需要访问驱动程序时使用 IO Service 请求将消息通过 system call 方式调用到内核驱动实现。

  • 标准 OpenHarmony 系统,HDI 以独立服务进程方式部署,系统服务只加载 HDI 客户端实现到自己进程中,实际业务运行在独立进程中,客户端通过 IPC 与服务端交互,便于架构解耦、权限管理。

3.1.HDI接口实现

  直通模式为函数实现方式,无论调用还是实现都不需要其他组件支持即可实现。

  IPC 模式基于 OpenHarmony 系统通信框架的通用模型,但是因为驱动很多时候涉及到底层操作和多系统迁移的场景而使用C语言编写,所以驱动框架还提供了 HDI 服务的 C 语言实现的基础组件,C++实现则主要使用系统通信框架组件。

3.2.IPC模式下的调用原理

  在IPC模式下,当系统服务调用HDI接口时,通过proxy库将函数调用转换为IPC请求,将接口调用的参数进行序列化;IPC请求通过IPC框架发送到服务端,请求将被stub库先处理,然后对接口调用的参数进行反序列化,再转换成对服务实现的函数调用,从而实现接口调用过程。

refer to

  • https://gitee.com/openharmony/drivers_interface
  • https://laval.csdn.net/67341a85cd8b2677c3df7942.html
  • https://baijiahao.baidu.com/s?id=1731328576146856524&wfr=spider&for=pc
  • https://developer.huawei.com/consumer/cn/forum/topic/0204858485287900172
  • https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/IDL/idl-guidelines.md#%E5%88%9B%E5%BB%BAidl%E6%96%87%E4%BB%B6

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/940169.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI Agent与MEME:技术与文化融合驱动Web3创新

AI Agent如何引领Web3新时代&#xff1f; 随着Web3与区块链技术的迅速发展&#xff0c;AI Agent作为人工智能与区块链的交汇点&#xff0c;正在逐步成为推动去中心化生态的重要力量。同时&#xff0c;MEME文化凭借其强大的社区驱动力和文化渗透力&#xff0c;在链上生态中扮演着…

接口测试-Fidder及jmeter使用

一、接口测试的基础 1.接口的含义 也叫做API&#xff0c;是一组定义、程序及协议的集合&#xff0c;提供访问一组例程的能力&#xff0c;无需访问源码获理解内部工作细节 2.接口的分类 代码内部的接口&#xff0c;程序模块间的接口&#xff0c;对于程序接口测试&#xff0c;需…

【数据集】医学常见9种皮肤疾病检测数据集11294张YOLO+VOC格式(已增强)

数据集格式&#xff1a;VOC格式YOLO格式 压缩包内含&#xff1a;3个文件夹&#xff0c;分别存储图片、xml、txt文件 JPEGImages文件夹中jpg图片总计&#xff1a;11294 Annotations文件夹中xml文件总计&#xff1a;11294 labels文件夹中txt文件总计&#xff1a;11294 标签种类数…

JavaSE——绘图入门

一、Java绘图坐标体系 下图说明了Java坐标系&#xff0c;坐标原地位于左上角&#xff0c;以像素为单位。在Java坐标系中&#xff0c;第一个是x坐标&#xff0c;表示当前位置为水平方向&#xff0c;距离坐标原点x个像素&#xff1b;第二个是y坐标&#xff0c;表示当前位置为垂直…

探索 Seaborn Palette 的奥秘:为数据可视化增色添彩

一、引言 在数据科学的世界里&#xff0c;视觉传达是不可或缺的一环。一个好的数据可视化不仅能传递信息&#xff0c;还能引发共鸣。Seaborn 是 Python 中一款广受欢迎的可视化库&#xff0c;而它的调色板&#xff08;palette&#xff09;功能&#xff0c;则为我们提供了调配绚…

Sigrity System Explorer Snip Via Pattern From Layout模式从其它设计中截取过孔模型和仿真分析操作指导

Sigrity System Explorer Snip Via Pattern From Layout模式从其它设计中截取过孔模型和仿真分析操作指导 Sigrity System Explorer Snip Via Pattern From Layout模式支持从其它设计中截取过孔模型用于仿真分析,同样以差分模板为例 具体操作如下 双击打开System Explorer软件…

数据分析实战—玻璃类别分类

1.实战内容 (1) 加载玻璃类别数据集&#xff0c;划分训练集、测试集 import pandas as pd import numpy as np pd.set_option(display.max_columns, None) pd.set_option(display.max_rows, None) # 读取数据集 glass pd.read_csv(glass.csv, encodinggbk, headerNone) glas…

Hive是什么,Hive介绍

官方网站&#xff1a;Apache Hive Hive是一个基于Hadoop的数据仓库工具&#xff0c;主要用于处理和查询存储在HDSF上的大规模数据‌。Hive通过将结构化的数据文件映射为数据库表&#xff0c;并提供类SQL的查询功能&#xff0c;使得用户可以使用SQL语句来执行复杂的​MapReduce任…

GIN

gin是什么 Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架。 它具有类似 Martini 的 API&#xff0c;但性能比 Martini 快 40 倍。如果你需要极好的性能&#xff0c;使用 Gin 吧。 特点&#xff1a;gin是golang的net/http库封装的web框架&#xff0c;api友好&#xff0c;注…

初始Python篇(13)—— 模块以及Python中常用的内置模块

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 模块的概念 模块的导入 包的概念以及使用 主程序运行 Python中常用的内置模块 random模块 time模块 datetime模块 …

时间序列异常值检测方法

文章目录 一、基于统计的方法1.1、标准差1.2、箱线图1.3、Z-Score法 二、基于机器学习算法的方法2.1、K-NN2.2、孤立森林 三、基于密度的方法3.1、LOF3.2、DBSCAN密度聚类 时间序列相关参考文章&#xff1a; 时间序列预测算法—ARIMA 时间序列预测算法—Prophet 时间序列分类任…

8K+Red+Raw+ProRes422分享5个影视级视频素材网站

Hello&#xff0c;大家好&#xff0c;我是后期圈&#xff01; 在视频创作中&#xff0c;电影级的视频素材能够为作品增添专业质感&#xff0c;让画面更具冲击力。无论是广告、电影短片&#xff0c;还是品牌宣传&#xff0c;高质量的视频素材都是不可或缺的资源。然而&#xff…

顺序表的操作

注意位序和数组下标的关系 插入&#xff1a; 插入的时间复杂度&#xff1a; 最深层语句&#xff1a; 最好情况 最坏情况 平均情况 删除&#xff1a; 查找&#xff1a;

五、windows上vscode构建c/c++环境

1、安装vscode 官网下载界面&#xff1a;https://code.visualstudio.com/Download 请根据电脑系统安装所需版本点击下载链接&#xff08;一般情况下点击windows按钮即可&#xff09;鼠标左键双击&#xff0c;即可运行安装程序&#xff0c;点击【确认】&#xff1b;选择安装路径…

Spring实例化的基本流程和Bean处理器

目录 Spring实例化的基本流程 Bean的处理器 Bean工厂后处理器&#xff08;BeanFactoryPostProcessor&#xff09; 动态注册beanDefinition Bean后处理器&#xff08;BeanPostProcessor&#xff09; Spring实例化的基本流程 在了解处理器之前&#xff0c;要清除spring实例化…

【SH】Ubuntu Server 24搭建Web服务器访问Python程序研发笔记

文章目录 说个问题写个方案一、安装Ubuntu Server二、安装Web服务器采用Nginx服务器 三、安装Python及依赖创建项目虚拟环境 四、安装Python Web框架采用Flask框架创建和运行Flask应用&#xff08;以后的重点&#xff09; 五、安装WSGI服务器采用Gunicorn 六、配置Nginx七、验证…

109.【C语言】数据结构之求二叉树的高度

目录 1.知识回顾&#xff1a;高度&#xff08;也称深度&#xff09; 2.分析 设计代码框架 返回左右子树高度较大的那个的写法一:if语句 返回左右子树高度较大的那个的写法二:三目操作符 3.代码 4.反思 问题 出问题的代码 改进后的代码 执行结果 1.知识回顾&#xf…

瑞吉外卖项目学习笔记(二)Swagger、logback、表单校验和参数打印功能的实现

瑞吉外卖项目学习笔记(一)准备工作、员工登录功能实现 文章目录 3 项目组件优化3.1 实现Swagger文档输出3.2 实现logback日志打印3.3 实现表单校验功能3.4 实现请求参数和响应参数的打印 3 项目组件优化 3.1 实现Swagger文档输出 1&#xff09;在application.yml中增加knife4…

OpenEuler 22.03 安装 flink-1.17.2 集群

零&#xff1a;规划 本次计划安装三台OpenEuler 22.03 版本操作系统的服务器&#xff0c;用于搭建 flink 集群。这里使用flink1.17.2 的原因&#xff0c;是便于后续与springboot的整合 服务器名IP地址作用其他应用flink01192.168.159.133主jdk11、flink-1.17.2flink02192.168.…

[数据结构] 链表

目录 1.链表的基本概念 2.链表的实现 -- 节点的构造和链接 节点如何构造? 如何将链表关联起来? 3.链表的方法(功能) 1).display() -- 链表的遍历 2).size() -- 求链表的长度 3).addFirst(int val) -- 头插法 4).addLast(int val) -- 尾插法 5).addIndex -- 在任意位置…