OpenHarmony基于HDF简单驱动开发实例

2024-01-09

背景

  • OpenHarmony-3.0-LTS
  • qemu_small_system_demo
  • liteos_a
  • qemu

添加配置

device/qemu/arm_virt/liteos_a/hdf_config/device_info/device_info.hcs

device_info 新增:

sample_host :: host {
    hostName = "sample_host";
    sample_device :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            preload = 1;
            permission = 0664;
            moduleName = "sample_driver";
            serviceName = "sample_service";
        }
    }
}

添加驱动代码

目录:device/qemu/arm_virt/liteos_a/drivers

新建驱动实现

mkdir sample_driver

vim sample_driver/sample_driver.c

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "hdf_log.h"
#include "hdf_base.h"
#include "hdf_device_desc.h"

#define HDF_LOG_TAG sample_driver

#define SAMPLE_WRITE_READ 123

static int32_t HdfSampleDriverDispatch(  \
    struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    HDF_LOGI("%{public}s: received cmd %{public}d", __func__, id);
    if (id == SAMPLE_WRITE_READ) {
        const char *readData = HdfSbufReadString(data);
        if (readData != NULL) {
            HDF_LOGE("%{public}s: read data is: %{public}s", __func__, readData);
        }
        if (!HdfSbufWriteInt32(reply, INT32_MAX)) {
            HDF_LOGE("%{public}s: reply int32 fail", __func__);
        }
        return HdfDeviceSendEvent(client->device, id, data);
    }
    return HDF_FAILURE;
}

static void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
    // release resources here
    return;
}

static int HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        return HDF_FAILURE;
    }
    static struct IDeviceIoService testService = {
        .Dispatch = HdfSampleDriverDispatch,
    };
    deviceObject->service = &testService;
    return HDF_SUCCESS;
}

static int HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        HDF_LOGE("%{public}s::ptr is null!", __func__);
        return HDF_FAILURE;
    }
    HDF_LOGI("Sample driver Init success");
    return HDF_SUCCESS;
}

static struct HdfDriverEntry g_sampleDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "sample_driver",
    .Bind = HdfSampleDriverBind,
    .Init = HdfSampleDriverInit,
    .Release = HdfSampleDriverRelease,
};

HDF_INIT(g_sampleDriverEntry);

新建Makefile和BUILD.gn

新建Makefile和BUILD.gn,可参考其他平台,例如 device/hisilicon/drivers/rtc/

Makefile:

include $(LITEOSTOPDIR)/config.mk
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk

MODULE_NAME := sample_driver

LOCAL_CFLAGS += $(HDF_INCLUDE)

LOCAL_SRCS += sample_driver.c

LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror -fsigned-char -fno-strict-aliasing -fno-common

include $(HDF_DRIVER)

BUILD.gn:

import("//drivers/adapter/khdf/liteos/hdf.gni")

#module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_RTC)
module_name = "sample_driver"
hdf_driver(module_name) {
  sources = [ "sample_driver.c" ]
}

修改上层BUILD.gn

import("//drivers/adapter/khdf/liteos/hdf.gni")

group("drivers") {
  public_deps = [ "../../../drivers" ]

  #新增
  deps = [
    "sample_driver",
  ]

}

config("public") {
  configs = [ "../../../drivers:public" ]
}

编写驱动交互代码

目录:vendor/ohemu/qemu_small_system_demo/

新建用户代码实现

mkdir hdf_test

vim hdf_test/sample_service.c

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_log.h"
#include "hdf_io_service_if.h"

#define HDF_LOG_TAG sample_test
#define SAMPLE_SERVICE_NAME "sample_service"

#define SAMPLE_WRITE_READ 123

int g_replyFlag = 0;

static int OnDevEventReceived(void *priv,  uint32_t id, struct HdfSBuf *data)
{
    const char *string = HdfSbufReadString(data);
    if (string == NULL) {
        HDF_LOGE("fail to read string in event data");
        g_replyFlag = 1;
        return HDF_FAILURE;
    }
    HDF_LOGI("%{public}s: dev event received: %{public}u %{public}s",  (char *)priv, id, string);
    g_replyFlag = 1;
    return HDF_SUCCESS;
}

static int SendEvent(struct HdfIoService *serv, char *eventData)
{
    int ret = 0;
    struct HdfSBuf *data = HdfSBufObtainDefaultSize();
    if (data == NULL) {
        HDF_LOGE("fail to obtain sbuf data");
        return 1;
    }

    struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
    if (reply == NULL) {
        HDF_LOGE("fail to obtain sbuf reply");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }

    if (!HdfSbufWriteString(data, eventData)) {
        HDF_LOGE("fail to write sbuf");
        ret = HDF_FAILURE;
        goto out;
    }

    ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("fail to send service call");
        goto out;
    }

    int replyData = 0;
    if (!HdfSbufReadInt32(reply, &replyData)) {
        HDF_LOGE("fail to get service call reply");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }
    HDF_LOGI("Get reply is: %{public}d", replyData);
out:
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    return ret;
}

int main()
{
    char *sendData = "default event info";

    HDF_LOGI(SAMPLE_SERVICE_NAME "start");

    struct HdfIoService *serv = HdfIoServiceBind(SAMPLE_SERVICE_NAME);
    if (serv == NULL) {
        HDF_LOGE("fail to get service %s", SAMPLE_SERVICE_NAME);
        return HDF_FAILURE;
    }

    static struct HdfDevEventlistener listener = {
        .callBack = OnDevEventReceived,
        .priv ="Service0"
    };

    if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
        HDF_LOGE("fail to register event listener");
        return HDF_FAILURE;
    }
    if (SendEvent(serv, sendData)) {
        HDF_LOGE("fail to send event");
        return HDF_FAILURE;
    }

    while (g_replyFlag == 0) {
        sleep(1);
    }

    if (HdfDeviceUnregisterEventListener(serv, &listener)) {
        HDF_LOGE("fail to  unregister listener");
        return HDF_FAILURE;
    }

    HdfIoServiceRecycle(serv);
    return HDF_SUCCESS;
}

新建BUILD.gn

vim sample_service/BUILD.gn,可参考huawei/hdf/sample/platform/uart/dispatch/BUILD.gn

import("//build/lite/config/component/lite_component.gni")
HDF_FRAMEWORKS = "//drivers/framework"

lite_component("hdf_test") {
  features = [ ":sample_service" ]
}

executable("sample_service") {
  sources = [ "sample_service.c" ]

  include_dirs = [
    "$HDF_FRAMEWORKS/ability/sbuf/include",
    "$HDF_FRAMEWORKS/core/shared/include",
    "$HDF_FRAMEWORKS/core/host/include",
    "$HDF_FRAMEWORKS/core/master/include",
    "$HDF_FRAMEWORKS/include/core",
    "$HDF_FRAMEWORKS/include/utils",
    "$HDF_FRAMEWORKS/utils/include",
    "$HDF_FRAMEWORKS/include/osal",
    "//drivers/adapter/uhdf/posix/include",
    "//third_party/bounds_checking_function/include",
    "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
  ]

  deps = [
    "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
    "//drivers/adapter/uhdf/manager:hdf_core",
    "//drivers/adapter/uhdf/posix:hdf_posix_osal",
  ]

  public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
  defines = [ "__USER__" ]

  cflags = [
    "-Wall",
    "-Wextra",
    "-Wno-format",
    "-Wno-format-extra-args",
  ]

}

说明: 用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf_core和osal的动态库,在gn编译文件中添加如下依赖项:

deps = [
​ "//drivers/hdf_core/adapter/uhdf/manager:hdf_core",
​ "//drivers/hdf_core/adapter/uhdf/posix:hdf_posix_osal",
]

修改上层BUILD.gn

group("qemu_small_system_demo") {
  deps = [
    "apps",
    "init_configs",
    "hdf_test",  #新增
  ]
}

以上都是趟过了许多坑后再跑通的

编译测试

使用 hb 重新编译镜像,会生成对应带新增驱动的内核和带用户程序的镜像


  
#编译
hb clean
hb build

运行新编译的镜像


#运行qemu
./vendor/ohemu/qemu_small_system_demo/patches/qemu-run

注: 需要修改上述脚本中的 rebuild=yes,让其每次都重新生成qemu镜像

开机log有如下打印,说明驱动已加载成功,并且在/dev/hdf/下面会生成 sample_service的节点:

...

01-01 00:00:00.119 2 4 W 02500/driver_loader: failed to load node, property is null, match attr is: 
01-01 00:00:00.119 2 4 I 02500/sample_driver: Sample driver Init success
01-01 00:00:00.119 2 4 I 02500/osal_cdev: OsalRegisterCdev:register /dev/hdf/sample_service
01-01 00:00:00.119 2 4 D 02500/devmgr_service: DevmgrServiceUpdateStatus host:sample_host 0 device:sample_service 0 status:1

...
OHOS:/$ ls /dev/hdf/                                                           
dev_mgr  event2  hdf_input_event1  input_dev_manager  sample_service 

运行测试应用 sample_service,会有如下打印:

OHOS:/$ sample_service                                                         
01-01 00:00:59.059 10 44 I 02500/sample_test: sample_servicestart
01-01 00:00:59.063 10 44 I 02500/sample_driver: HdfSampleDriverDispatch: received cmd 123
01-01 00:00:59.063 10 44 E 02500/sample_driver: HdfSampleDriverDispatch: read data is: default event info
01-01 00:00:59.064 10 44 I 02500/sample_test: Get reply is: 2147483647
01-01 00:00:59.068 10 45 I 02500/sample_test: Service0: dev event received: 123 default event info
01-01 00:01:00.065 10 44 D 02500/hdf_syscall_adapter: ioctl send poll thread(4) exit event, ret=0
OHOS:/$ 01-01 00:01:00.066 10 45 I 02500/hdf_syscall_adapter: event listener task received exit event
01-01 00:01:00.066 10 45 I 02500/hdf_syscall_adapter: event listener task exit
01-01 00:01:00.067 10 44 I 02500/hdf_syscall_adapter: poll thread exited
^C
OHOS:/$ ^C

总结

以上的内容主要简单介绍了OpenHarmony基于HDF简单驱动开发实例

要想成为一名鸿蒙高级开发,以上知识点是必须要掌握的,除此之外,还需要掌握一些鸿蒙应用开发相关的一些技术,需要我们共同去探索。

为了节省大家一些查找的时间,这边联合几位行业大佬, 为大家准备了一份《Open Harmony4.0&Next》的学习导图 从入门到进阶再到南北向开发实战的一整套完整体系 ,想要学习了解更多鸿蒙开发的相关知识可以借鉴:

除了以上的知识内容,我还为大家整理了一份 《鸿蒙 (Harmony OS)开发学习手册》都是整理成PDF文档方式,分享给大家参考学习:《 鸿蒙开发学习指南

《鸿蒙 (Harmony OS)开发学习手册》

一、入门必看

1. 应用开发导读(ArkTS)

2. 应用开发导读(Java)

3.......

二、HarmonyOS 概念

1. 系统定义

2. 技术架构

3. 技术特性

4. 系统安全

5......

三、如何快速入门?《 鸿蒙基础入门开发宝典!

1. 基本概念

2. 构建第一个ArkTS应用

3. 构建第一个JS应用

4. ……

四、开发基础知识

1. 应用基础知识

2. 配置文件

3. 应用数据管理

4. 应用安全管理

5. 应用隐私保护

6. 三方应用调用管控机制

7. 资源分类与访问

8. 学习ArkTS语言

9. ……

五、基于ArkTS 开发

1. Ability开发

2. UI开发

3. 公共事件与通知

4. 窗口管理

5. 媒体

6. 安全

7. 网络与链接

8. 电话服务

9. 数据管理

10. 后台任务(Background Task)管理

11. 设备管理

12. 设备使用信息统计

13. DFX

14. 国际化开发

15. 折叠屏系列

16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《 做鸿蒙应用开发到底学习些啥?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenHarmony基于HDF简单驱动开发实例 的相关文章

  • ArkTS @Observed、@ObjectLink状态装饰器的使用

    作用 Observed ObjectLink装饰器用于在涉及嵌套对象或者数组元素为对象的场景中进行双向数据同步 状态的使用 1 嵌套对象 我们将父类设置为 Observed状态 这个时候 子应该设置 ObjectLink才能完成数据的双向绑
  • 一文揭秘人才成长规律,看到就是赚到

    社会不教 精英不讲 看到就是赚到 为啥你比别人挣得少 职场当中 决定你能拿多少钱 并不在于你的学历 也并不在于你的背景 而在于你处于什么位置 你能做什么 你做了什么 你为谁做什么 能做什么 代表的是能力 你做了什么 代表的是方向和业绩 你为
  • 邮件进入垃圾邮箱的三大原因及避免方法:有效防止邮件被误判

    经常使用邮件的人 特别是用邮件做营销宣传的企业 可能会遇到这样的问题 发出去的邮件总是进垃圾箱 不仅没起到营销作用 还可能会让邮箱造成被封的风险 怎么避免 我们先来了解 为什么邮件会进垃圾箱 Q1 为什么邮件会进垃圾箱 1 邮件内容质量差
  • linux ARM64 处理器内存屏障

    一 内存类型 ARMv8架构将系统中所有的内存 按照它们的特性 划分成两种 即普通内存和设备内存 并且它们是互斥的 也就是说系统中的某段内存要么是普通内存 要么是设备内存 不能都是 1 普通内存 Normal Memory 普通内存的特性是
  • 抓包干什么用?

    抓包是一种网络分析工具 用于捕获和分析网络流量 它可以用于各种测试和调试场景 包括但不限于以下几个方面 1 网络故障排除 当网络出现问题时 抓包可以帮助你捕获和分析数据包 以确定问题的根本原因 你可以检查数据包的源和目标地址 协议 端口等信
  • 为什么要编写测试用例,测试用例写给谁看?

    为什么要编写测试用例 测试用例写给谁看 这个问题看似简单 但却涵盖了一系列复杂的考虑因素 并不太好回答 为了向各位学测试的同学们解释清楚 为什么编写测试用例是至关重要的 我将通过以下5个方面进行展开 1 为什么要写测试用例 2 测试用例写给
  • ArkTS @Observed、@ObjectLink状态装饰器的使用

    作用 Observed ObjectLink装饰器用于在涉及嵌套对象或者数组元素为对象的场景中进行双向数据同步 状态的使用 1 嵌套对象 我们将父类设置为 Observed状态 这个时候 子应该设置 ObjectLink才能完成数据的双向绑
  • 海报制作软件有哪些?看完这篇你就知道了

    在如今快节奏的生活中 许多人都深陷于工作的繁忙中 特别是那些从事创意设计的人 他们时常面对老板一些不可思议的要求 海报设计师更是如此 老板总是在最短的时间内要求完成海报设计 老板的创意常常超乎寻常 让设计师感到摸不着头脑 不知如何下手 使用
  • 二分查找(二)

    点名 点名 某班级 n 位同学的学号为 0 n 1 点名结果记录于升序数组 records 假定仅有一位同学缺席 请返回他的学号 二分法思路 判断数组的值和对应的下标是否相等 将数组分为两个区间 不相等区间的最左端 就是第缺席的同学的学号
  • 二分查找(二)

    点名 点名 某班级 n 位同学的学号为 0 n 1 点名结果记录于升序数组 records 假定仅有一位同学缺席 请返回他的学号 二分法思路 判断数组的值和对应的下标是否相等 将数组分为两个区间 不相等区间的最左端 就是第缺席的同学的学号
  • 技术大拿私房课:掌握Task、Thread、ThreadPool的终极秘籍!

    大家好 我是小米 在这个充满技术和创新的时代 作为一名喜欢分享的技术探索者 我想和大家聊一聊一些在社招面试中常常被提到的热门话题 task thread threadpool 这是一组关于并发编程的核心问题 也是我们在日常工作中不可避免要面
  • 软件测试基础知识与面试理论总结(答案+文档)

    一 什么是软件 软件是计算机系统中的程序和相关文件或文档的总称 二 什么是软件测试 说法一 使用人工或自动的手段来运行或测量软件系统的过程 以检验软件系统是否满足规定的要求 并找出与预期结果之间的差异 说法二 软件测试就是利用一定的方法对软
  • 外包干了2个月,技术退步明显...

    先说一下自己的情况 大专生 18年通过校招进入武汉某软件公司 干了接近4年的功能测试 今年年初 感觉自己不能够在这样下去了 长时间呆在一个舒适的环境会让一个人堕落 而我已经在一个企业干了四年的功能测试 已经让我变得不思进取 谈了2年的女朋友
  • HarmonyOS鸿蒙开发指南:容器组建 stepper开发指导

    目录 创建Stepper组件 设置index属性 设置样式 添加事件 场景示例 创建Stepper组件 在pages index目录下的hml文件中创建一个Stepper组件 div class container div
  • HarmonyOS鸿蒙开发指南:容器组建 tabs开发指导

    目录 创建Tabs 设置Tabs方向 设置样式 显示页签索引 场景示例 创建Tabs 在pages index目录下的hml文件中创建一个Tabs组件 div class container div
  • 外包干了2个月,技术退步明显...

    先说一下自己的情况 大专生 18年通过校招进入武汉某软件公司 干了接近4年的功能测试 今年年初 感觉自己不能够在这样下去了 长时间呆在一个舒适的环境会让一个人堕落 而我已经在一个企业干了四年的功能测试 已经让我变得不思进取 谈了2年的女朋友
  • 新入职一个00后卷王,每天加班到2点,太让人崩溃了····

    在程序员职场上 什么样的人最让人反感呢 是技术不好的人吗 并不是 技术不好的同事 我们可以帮他 是技术太强的人吗 也不是 技术很强的同事 可遇不可求 向他学习还来不及呢 真正让人反感的 是技术平平 却急于表现自己的人 每天加班到12点 在老
  • msyql 异常,别干着急,70%的问题都在这里!

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 3k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • 新手也能看懂的【前端自动化测试入门】

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 3k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • 做好这几件事,30岁的你也能转行鸿蒙(HarmonyOS)?

    当你年过30 不管你愿不愿意承认 你的精力都在走下坡路 25岁熬一个通宵能写出来的代码 30岁有可能需要一整天 当然你也可以选择不拼精力和体力 当自身的一线经验积累到一定程度后 就会选择慢慢过渡到管理者的角色 通过经验分享及任务分配来参与项

随机推荐

  • 搜索二叉树(BSTree)

    一 搜索二叉树的概念 二叉搜索树又称为做二叉排序树 二叉查找树 其要么是一棵空树 要么是一个满足以下性质的二叉树 若它的左子树不空 则左子树上所有结点的关键字均小于根结点关键字 若它的右子树不空 则右子树上所有结点的关键字均大于根结点关键字
  • 9个最受欢迎的开源自动化测试框架盘点

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 自动化测试框架可以帮助测试人员评估多个Web和移动应用程序的功能 安全性 可用性和可访问性 尽管团队可以自己构建复杂的自动化测试框架 但是当他们可以使用
  • 深入了解鸿鹄电子招投标系统:Java版企业电子招标采购系统的核心功能

    随着市场竞争的加剧和企业规模的扩大 招采管理逐渐成为企业核心竞争力的重要组成部分 为了提高招采工作的效率和质量 我们提出了一种基于电子化平台的解决方案 该方案旨在通过电子化招投标 使得招标采购的质量更高 速度更快 同时节约招标成本 提升企业
  • 游戏被攻击了要怎么办

    有客户反馈刚上线新款游戏 没两天就被攻击了 导致用户无法登录 来咨询到我们这边能不能帮他解决 今天就来分享下 怎么预防游戏攻击和已经被攻击的游戏服务器该怎么处理 服务器不管是个人还是企业 被攻击的都有 在所难免 特别是新上线时候要承受住外来
  • 985毕业,我依然过不好这一生?(大厂java开发2年被裁)

    前言 看到标题 可能很多读者朋友恐怕又要骂我了 985这个特殊的字眼也确实异常晃眼 实际上现在985 211也越来越多 它能代表你能够进入到更高的平台 拿到 高级工厂 的入场券 但并不意味着你会成为赢家 或者说也不代表着你会站在金字塔的顶端
  • 前端如何处理大量数据。

    理论就是分割后台数据 然后通过定时器将数据加载到虚拟dom上 加载完成后渲染一部分 在项目中经常会碰到大量数据需要在前端页面渲染 很多时候会使用分页的功能 但是数据量过大的时候比如10万条这种的 一直滑动列表后面会出现卡顿 滑不动的现象 这
  • HarmonyOS鸿蒙开发指南:容器组建 dialog开发指导

    目录 创建Dialog组件 设置弹窗响应 场景示例 创建Dialog组件 在pages index目录下的hml文件中创建一个Dialog组件 并添加Button组件来触发Dialog Dialog组件仅支持width height mar
  • 工作五年,一年内我靠这系列java面试宝典从13K到大厂30K

    我认为对于面试以及进阶最佳的学习方法莫过于 刷题 博客 书籍 总结 前三者我将淋漓尽致地挥毫于这篇文章中 至于总结要靠个人 实际上越到后面你越会发现面试并不难 其次就是在刷题的过程中有没有去思考 刷题只是次之 这又是一个层次了 这里暂时不提
  • 如何处理不稳定的自动化测试?

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 abluecolor 在解决这个问题之前 请停止编写更多测试 因为这将花费你较高的测试维护成本 你需要尽快行动起来对不稳定的原因进行深入研究 找到不稳定
  • HarmonyOS鸿蒙开发指南:容器组建 tabs开发指导

    目录 创建Tabs 设置Tabs方向 设置样式 显示页签索引 场景示例 创建Tabs 在pages index目录下的hml文件中创建一个Tabs组件 div class container div
  • 阿里巴巴大神发布的Java零基础笔记,实战教程多到手软,跪了

    前言 现值金九银十之际 是面试高峰季 很多学校开始校招 也是跳槽转行的最佳时机 根据数据显示 程序员是金九银十里最热门的行业 也是需求量最大的行业 但是程序员是个门槛低 但金字塔顶峰比较高的行业 意味着你的付出要比别人多才能拔尖 我们都知道
  • 987页的Java面试宝典,看完才发现,应届生求职也没那么难

    前言 现在已经九月底 金九银十也已经过去了一大半 很明显今年的面试季明显不如往年火热 对于求职者来说 也更难了一些 马上迎来国庆节 假期一过 十月份又过去了三分之一 综合来看今年确实不是面试的最佳时期 不过趁今年所剩的时间来好好准备 明年的
  • 基于Java ssm美容院管理系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • 鸿蒙Ability开发-Stage模型下Ability的创建和使用

    创建Ability和Page页面 创建两个Ability EntryAbility DetailsAbility 其中EntryAbility是由工程默认创建的 这里我们只讲如何创建DetailsAbility 使用DevEco Studi
  • 基于Java ssm教资考前指导系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • Airtest常用API介绍

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 今天就继续给大家介绍一下Airtest框架常用的核心API用法 这也是熟悉使用Airtest框架的必备手册之一 一 官方文档 官方文档 https ai
  • 各大厂急招鸿蒙开发员,争抢鸿蒙工程师

    去年9月 余承东宣布鸿蒙原生应用全面启动 华为开始了全面抛弃安卓的进程 多家互联网公司也发布了鸿蒙OS的App开发工程师的岗位 开启了抢人大战 有的企业开出了近百万的年薪招聘鸿蒙OS工程师 而华为甚至为鸿蒙OS资深架构师开出了100万 16
  • 2024年一套超详细Java面试精华资料,让进大厂少走弯路

    在座的诸位有没有是自学Java的 有的话评论区给我扣个1看看 但凡自学过的同学都知道有多难 虽说现在互联网非常发达 不明白的上网一搜就有很多资料 不过大多质量不高 而且非常碎片化 实在很难梳理成一个可持续成长的体系 所以有了这篇文章 我结合
  • 基于Java ssm考研助手系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • OpenHarmony基于HDF简单驱动开发实例

    背景 OpenHarmony 3 0 LTS qemu small system demo liteos a qemu 添加配置 device qemu arm virt liteos a hdf config device info de