Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0)

2023-05-16

Android系统HAL驱动开发经典案例详解(基于Android4.0)

 

目的:通过学习一个LED点灯的简单功能,掌握Linux驱动程序与HAL硬件抽象层之间的调用方法,同时掌握JNI层的编写思想,学会使用Eclipse编写Android应用程序,深入体会Android HAL架构。本章内容主要参考文献:《Android深度探索(卷1) HAL与驱动开发》、《TQ210开发板Android_HAL_LED_V1.2.pdf》

目录:

一、架构分析

1.1 功能介绍

1.2 HAL架构

1.3 接口定义

二、驱动程序

2.1 驱动功能简介

2.2 驱动源码分析

2.3 利用可执行文件测试驱动

2.3.1 源文件

2.3.2 利用交叉编译器编译

2.3.3 使用原生C程序测试驱动

三、HAL硬件抽象层

3.1 HAL简介

3.2 HAL层源码与分析

3.3 HAL源码编译

四、Jni/Service服务层

4.1 直接使用JNI调用驱动程序

4.2 JNI/Service程序代码

五、APP应用程序层

5.1 activity_main.xml

5.2 LedServer.java

5.3 MainActivity.java

 

一、架构分析

1.1 功能介绍

Linux版本:3.0.8

Android版本:4.0

开发板:FriendlyARM smart210

功能介绍:应用程序界面如下图所示,为求方便,截图来自模拟器,实际开发板界面和下图是一样的。CheckBox复选框分别对应开发板上四个LED灯,选中复选框,按动led_hal_jni按键后,相应LED就会亮起来。功能很简单,代码中几乎不会涉及任何逻辑算法,主要是为了方便理清整个程序架构,体会Android系统通过HAL硬件抽象层与实际硬件之间交互的编程思想。

 

 

1.2 HAL架构

想要点亮一个灯当然简单,可以直接烧写ARM裸机程序,也可以在跑Linux系统的板子上通过写/dev/leds这样的设备文件来达到目的。Android系统为了解决一些调用接口和版权方面的问题提出了一个HAL架构。目前最新的HAL架构是下面这个样子的。

 

 

可以看出,Android应用程序直接调用的是JNI或者Service程序库文件(.so),程序库文件是通过一个ID来定位到相应的HAL的库文件(.so),最终和硬件打交道的是HAL模块。需要注意的是,HAL及其以上层均属于应用程序范畴,也就是都运行在了用户空间,只有Linux驱动程序运行在了Linux内核空间。

 

1.3 接口定义

 

从Android HAL架构来看,一套完整的点灯的程序应该包括四个层次。为了方便程序维护,层与层之间应该尽可能的降低耦合程度,每个层对其他层开放的仅仅是一个操作接口即可。每个层的源文件位置和其向其他层提供的关键接口表述如下,这里指的关键接口实际上就是“调用函数”。各个源文件的具体内容会在下文给出。如果你能亲自动手写完整套程序再回过头来看这部分接口定义,应该能体会得更深些。

1、底层驱动。

源文件位置:$(linux_source)/drivers/char/mini210_led.c    

对应开发板上的驱动设备文件为:/dev/leds

关键接口定义:

//发送IO命令

ioctl(file_handler, cmd, arg);

//调用方法如下

./ioctl_test /dev/leds 1 2   //表示点亮第二盏灯

//发送写命令

write(fd,buf,strlen(buf));

//调用方法如下

./write_test /dev/s3c6410_leds "1111" // 点亮所有灯

这里的ioctl_test和write_test是两个可执行文件,它们分别是由ioctl_test.c和write_test.c源文件通过交叉编译器或Android原生代码编译出来的,这两个源文件是为了验证驱动程序专门写的,后文会贴出具体代码。

 

2、HAL层。

源文件位置:

//这个.c文件也可以放到其他目录

$(Android_source)/device/friendly-arm/mini210/libled/led_hal.c 

//这个.h文件最好放到指定位置,以免包含头文件的时候发生错误

$(Android_source)/hardware/libhardware/include/hardware/led_hal.h

生成模块位置:Android_source/out/target/product/mini210/lib/hw/led_hal.default.so

关键接口定义:

int led_on(struct led_control_device_t *dev, int32_t LED_NUMBER)  //表示LED_NUMBER灯亮

{

... ...

ioctl(fd,IOCTL_GPIO_ON,LED_NUMBER);

... ...

}

int led_off(struct led_control_device *dev, int32_t LED_NUMBER)   //表示LED_NUMBER灯灭

{

... ...

ioctl(fd,IOCTL_GPIO_OFF,LED_NUMBER);

... ...

}

 

3、jni/service层

源文件位置:$(Android_source)/packages/apps/led/jni/LedHalService.cpp

生成模块位置:Android_source/out/target/product/mini210/lib/libled_hal_jni.so

关键接口定义:

jboolean Java_com_example_leds_MainActivity_ledSetOn (JNIEnv* env, jobject obj,jint number)

{

... ...

return sLedDevice->set_on(sLedDevice,number);

... ...

}

jboolean Java_com_example_leds_MainActivity_ledSetOff (JNIEnv* env, jobject obj,jint number)

{

... ...

return sLedDevice->set_off(sLedDevice,number);

... ...

}

类名定义:

//注意这里的kClassName决定了调用该JNI模块的应用程序的包名与类名。

int register_android_server_LedService(JNIEnv *env)

{

... ...

static const char* const kClassName = "com/example/leds/LedService";

... ...

}

 

二、驱动程序

2.1 驱动功能简介

mini210_led.c主要提供了mini210_leds_ioctl和mini210_leds_write两个接口。应用程序通过向/dev/leds发送I/O指令或写命令就可以实现控制LED灯的功能了。

2.2 驱动源码分析

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/moduleparam.h>

#include <linux/slab.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/delay.h>

 

#include <mach/gpio.h>

#include <mach/regs-gpio.h>

#include <plat/gpio-cfg.h>

#include <asm/uaccess.h>

 

#define DEVICE_NAME "leds"

static unsigned char mem[4];

static int led_gpios[] = {

S5PV210_GPJ2(0),

S5PV210_GPJ2(1),

S5PV210_GPJ2(2),

S5PV210_GPJ2(3),

};

 

#define LED_NUM ARRAY_SIZE(led_gpios)

 

//mini210_leds_ioctl函数实现了发送IO控制命令

static long mini210_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

switch(cmd) {

case 0:

case 1:

if (arg > LED_NUM) {

return -EINVAL;

}

 

gpio_set_value(led_gpios[arg], !cmd);

//printk(DEVICE_NAME": %d %d\n", arg, cmd);

break;

 

default:

return -EINVAL;

}

 

return 0;

}

//mini210_leds_write函数实现了写文件命令

ssize_t mini210_leds_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)

{

int i=0;

int tmp=count;

memset(mem,0,4);

if(count>4)

{

tmp=4;

}

if(copy_from_user(mem,buf,tmp))

{

return -EFAULT;

}

 

for(i=0;i<4;i++)

{

if(mem[i]=='1')

{

gpio_set_value(led_gpios[i], 0);

}

else if(mem[i]=='0')

{

gpio_set_value(led_gpios[i], 1);

}

}

return count;

}

static struct file_operations mini210_led_dev_fops = {

.owner = THIS_MODULE,

.unlocked_ioctl = mini210_leds_ioctl,

.write                    = mini210_leds_write,

};

 

static struct miscdevice mini210_led_dev = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &mini210_led_dev_fops,

};

 

static int __init mini210_led_dev_init(void) {

int ret;

int i;

 

for (i = 0; i < LED_NUM; i++) {

ret = gpio_request(led_gpios[i], "LED");

if (ret) {

printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,

led_gpios[i], ret);

return ret;

}

 

s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);

gpio_set_value(led_gpios[i], 1);

}

 

ret = misc_register(&mini210_led_dev);

 

printk(DEVICE_NAME"\tinitialized\n");

 

return ret;

}

 

static void __exit mini210_led_dev_exit(void) {

int i;

 

for (i = 0; i < LED_NUM; i++) {

gpio_free(led_gpios[i]);

}

 

misc_deregister(&mini210_led_dev);

}

 

module_init(mini210_led_dev_init);

module_exit(mini210_led_dev_exit);

 

MODULE_LICENSE("GPL");</span>


 

2.3 利用可执行文件测试驱动

 

2.3.1 源文件

首先给出两个可执行文件的源文件

//ioctl_test.c

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/ioctl.h>  

/*

* ./ioctl_test /dev/leds 1 2  //表示将第二个灯点亮 

*/

int main(int argc, char **argv)

{

int file_handler = 0;

int cmd = 0;

int arg = 0;

if(argc < 4)

{

printf("Usage: ioctl <dev_file> <cmd> <arg>\n");

return 0;

}

cmd = atoi(argv[2]);

arg = atoi(argv[3]);

printf("dev:%s\n", argv[1]);

printf("cmd:%d\n", cmd);

printf("arg:%d\n", arg);

file_handler = open(argv[1], 0);

 

ioctl(file_handler, cmd, arg);

close(file_handler);

return 0;

}</span>


 

 

//write_test.c

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <string.h>

/*

* ./write_test /dev/s3c6410_leds "1111" 表示四个灯全亮

*/

void main(int argc, char *argv[])

{

int fd;

char *buf;

buf=argv[2];

fd=open(argv[1],O_WRONLY);

if(fd<0)

{

printf("file_open failed!\n");

return;

} 

write(fd,buf,strlen(buf));

close(fd);

}</span>


源文件的内容比较简单,不再深入讨论。Android系统有两种编译可执行程序的方法,下面分别介绍。

2.3.2 利用交叉编译器编译

这种方法比较容易实现。直接在命令行模式下编译即可。需要注意的是最好加上静态编译选项“-static”。

Pc:#arm-linux-gcc -static ioctl_test.c -o ioctl_test

Pc:#arm-linux-gcc -static write_test.c -o write_test

然后利用adb命令将可执行文件上传到开发板

Pc:# adb push ioctl_test write_test /data/local

 

进入开发板的命令行终端

Pc:# adb shell

然后就可以执行可执行文件了

Phone#: cd /data/local

Phone:# ./ioctl_test /dev/leds 1 2

Phone:#./write_test /dev/leds “1111”

 

2.3.3 使用原生C程序测试驱动

这种方式更加地道,其编译方式是通过Android源代码直接编译的。所使用的工具就是Android系统自带的编译器以及一些Android系统的头文件,所以编译之前一定确保自己的电脑上已经成功编译了一套Android系统。至于如何编译Android系统,网上有很多教程,难点就是编译的过程中会出现一些莫名其妙的错误,往往是少安装了某些库造成的,耐着性子上网查查一般就能解决。

接下来以ioctl_test为例讲解如何使用原生C程序测试驱动。首先一定要在Android系统源代码目录或子目录下为ioctl_test应用程序单独建立一个文件夹,作为其主目录。然后在ioctrl_test.c的主目录下新建一个Android.mk文件,内容如下:

<span style="font-family:KaiTi_GB2312;font-size:18px;">LOCAL_PATH:=$(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=ioctl_test.c

LOCAL_MODULE:=ioctl_test

LOCAL_MODULE_TAGS:=optional

include $(BUILD_EXECUTABLE)</span>


Android.mk其实就相当与Android系统中的Makefile文档,就是给出了一些编译选项,需要执行mm命令或mmm命令进行编译。关于Android.mk的书写规则,网上有很多,看看就知道了。

在使用mm命令之前,一定确保首先在Android系统源代码下执行:

Pc:# source ./build/envsetup.sh  执行后会出现类似下面的信息。

including device/friendly-arm/mini210/vendorsetup.sh

including device/moto/stingray/vendorsetup.sh

including device/moto/wingray/vendorsetup.sh

including device/samsung/crespo4g/vendorsetup.sh

including device/samsung/crespo/vendorsetup.sh

including device/samsung/maguro/vendorsetup.sh

including device/samsung/toro/vendorsetup.sh

including device/samsung/tuna/vendorsetup.sh

including device/ti/panda/vendorsetup.sh

including sdk/bash_completion/adb.bash

 

这个envsetup.sh就是包含自定义的vendorsetup.sh和初始化mm等命令用的(插一句题外话,如果你想从官方的Android源码定制适合自己开发板的Android系统的话,通常需要自己写一个新的vendorsetup.sh文件)。注意的是,每次启动一个新的Linux命令终端,好像都要重新运行source ./build/envsetup.sh,否则mm命令不能用。

然后执行lunch

Pc:# lunch  

You're building on Linux

 

Lunch menu... pick a combo:

     1. full-eng

     2. full_x86-eng

     3. vbox_x86-eng

     4. full_mini210-userdebug

     5. full_stingray-userdebug

     6. full_wingray-userdebug

     7. full_crespo4g-userdebug

     8. full_crespo-userdebug

     9. full_maguro-userdebug

     10. full_toro-userdebug

     11. full_tuna-userdebug

     12. full_panda-eng

 

Which would you like? [full-eng] 4

在这里选择4。同样的,每次运行完source ./build/envsetup.sh之后也要重新运行lunch命令,否则系统仍会默认以full-eng的方式进行编译。当你编译ioctl_test.c这样的Android应用程序的时候就会出现类似下面的错误。

make: Entering directory `/home/zbl/Android/MySystem/3_Android_resource/android-4.0.3_r1'

make: *** No rule to make target `out/target/product/generic/obj/lib/crtbegin_dynamic.o', needed by `out/target/product/generic/obj/EXECUTABLES/ioctl_test_intermediates/LINKED/ioctl_test'.  Stop.

make: Leaving directory `/home/zbl/Android/MySystem/3_Android_resource/android-4.0.3_r1'

一定要选择full_mini210-userdebug。然后会出现下面的信息。

============================================

PLATFORM_VERSION_CODENAME=REL

PLATFORM_VERSION=4.0.3

TARGET_PRODUCT=full_mini210

TARGET_BUILD_VARIANT=userdebug

TARGET_BUILD_TYPE=release

TARGET_BUILD_APPS=

TARGET_ARCH=arm

TARGET_ARCH_VARIANT=armv7-a-neon

HOST_ARCH=x86

HOST_OS=linux

HOST_BUILD_TYPE=release

BUILD_ID=IML74K

============================================

 

好了,最后然后进入到ioctl_test.c的主目录中执行:

Pc:#mm

============================================

PLATFORM_VERSION_CODENAME=REL

PLATFORM_VERSION=4.0.3

TARGET_PRODUCT=full_mini210

TARGET_BUILD_VARIANT=userdebug

TARGET_BUILD_TYPE=release

TARGET_BUILD_APPS=

TARGET_ARCH=arm

TARGET_ARCH_VARIANT=armv7-a-neon

HOST_ARCH=x86

HOST_OS=linux

HOST_BUILD_TYPE=release

BUILD_ID=IML74K

============================================

make: Entering directory `/home/zbl/Android/MySystem/3_Android_resource/android-4.0.3_r1'

target thumb C: ioctl_test <= /work/MySystem/3_Android_resource/android-4.0.3_r1/ioctl_test/ioctl_test.c

target Executable: ioctl_test (out/target/product/mini210/obj/EXECUTABLES/ioctl_test_intermediates/LINKED/ioctl_test)

target Symbolic: ioctl_test (out/target/product/mini210/symbols/system/bin/ioctl_test)

target Strip: ioctl_test (out/target/product/mini210/obj/EXECUTABLES/ioctl_test_intermediates/ioctl_test)

Install: out/target/product/mini210/system/bin/ioctl_test

make: Leaving directory `/home/zbl/Android/MySystem/3_Android_resource/android-4.0.3_r1'

从编译结果可以看出,编译出的可执行文件ioctl_test被放在了out/target/product/mini210/system/bin/文件下。按照2.3.2的方法将其上传到开发板后即可使用。

 

三、HAL硬件抽象层

3.1 HAL简介

Google为Android加入HAL主要有如下目的。

Ø 统一硬件的调用接口。由于HAL有标准的调用接口,可以利用HAL屏蔽Linux驱动复杂、不统一的接口。

Ø 解决了GPL版权问题。Android系统基于Apache Licence2.0协议。可以让那些不想开源的驱动作者屏蔽源代码。这是基于GPL开源协议的Linux系统所不允许的。所以Linux毫不客气的将Android系统开除族籍了。

Ø 访问用户空间资源。对于有些硬件,可能需要访问一些用户空间的资源,或在内核空间不方便完成的工作以及特殊需要。在这种情况下,可以利用位于用户空间的HAL代码来辅助Linux驱动完成一些工作。

在编写HAL层程序的时候要时刻注意HAL是运行在用户空间的,这有助于理解HAL层的设计思想。HAL(硬件抽象层)的诞生意味着Android系统被Linux大家族给剔除了。原因其实就是HAL层可以不开源。

3.2 HAL层源码与分析

撰写HAL程序关键之处在于3个重要的结构体。分别是描述HAL模块的hw_module_t结构体;描述HAL设备的hw_device_t结构体;描述模块入口函数的hw_module_methods_t结构体。

首先给出头文件led_hal.h

//led_hal.h

<span style="font-family:KaiTi_GB2312;font-size:18px;">#ifndef ANDROID_LED_INTERFACE_H

#define ANDROID_LED_INTERFACE_H

#include <stdint.h>

#include <sys/cdefs.h>

#include <sys/types.h>

#include <hardware/hardware.h>

#include <fcntl.h>

#include <errno.h>

#include <math.h>

#include <poll.h>

#include <unistd.h>

#include <dirent.h>

#include <sys/select.h>

#include <cutils/log.h>

 

__BEGIN_DECLS

/*下面这个ID重要的很,Jni/Service层主要通过它来寻找相应的HAL库文件(.so),所以HAL源文件的名字是可以随便改的,只要保证其中的ID值不变即可*/

#define LED_HARDWARE_MODULE_ID "led_hal"  

 

/*HAL规定不能直接使用hw_module_t结构体,需要在hw_modult_t外再套一层结构体。hw_module_t结构体表示HAL模块的相关信息,成员变量可以随便起,但是hw_module_t结构体必须是led_module_t结构体的第1个成员变量的数据类型。这个东西是整个HAL的核心,后续的工作其实就是不断的完善这个module。*/

struct led_module_t

{

struct hw_module_t common;

};

 

#define IOCTL_GPIO_ON 1

#define IOCTL_GPIO_OFF 0

 

/*led_control_device_t是自定义的hw_device_t类型的结构体,但是hw_device_t必须是该结构体的第一个成员变量,另外还定义了两个控制LED的成员函数*/

struct led_control_device_t

{

struct hw_device_t common;

int (*set_on)(struct led_control_device_t* dev, int32_t LED_NUMBER);

int (*set_off)(struct led_control_device_t* dev, int32_t LED_NUMBER);

};

__END_DECLS

#endif         //ANDROID_LED_INTERFACE_H</span>


/

Led_hal.c文件是HAL层的源文件,我在每个函数前都做了注解,其编号是按照代码书写顺序标注的。也就是说,HAL代码的编写顺序并不是自上而下一行一行写出来的,而是类似于驱动程序的形式,先从接口程序开始写,然后一层一层的把用到的函数补充出来。

 

//Led_hal.c

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <hardware/led_hal.h>

char const * const LED_DEVICE = "/dev/leds";

static int fd = -1;

/*4、打开设备文件,这里的open函数就是运行在了用户空间*/

static int open_led()

{

if((fd = open(LED_DEVICE,O_RDWR))==-1)

{

LOGV("LED stub: open %s failed\n",LED_DEVICE);

return -1;

}

else

{LOGV("LED stub: open %s successed\n",LED_DEVICE);}

return 1;

}

/*5、关闭设备,没什么说的*/

static int close_led(struct hw_device_t *dev)

{

LOGV("close_light is called");

if(fd!=-1)

{

close(fd);

if(dev)

free(dev);

}

return 0;

}

/*6、ioctl(fd,IOCTL_GPIO_ON,LED_NUMBER)运行在了用户空间*/

int led_on(struct led_control_device_t *dev, int32_t LED_NUMBER)

{

if(fd == -1)

return -1;

return ioctl(fd,IOCTL_GPIO_ON,LED_NUMBER);

}

/*7、ioctl(fd,IOCTL_GPIO_OFF,LED_NUMBER)运行在了用户空间*/

int led_off(struct led_control_device *dev, int32_t LED_NUMBER)

{

if(fd == -1)

return -1;

return ioctl(fd,IOCTL_GPIO_OFF,LED_NUMBER);

}

/*3、初始化设备文件*/

static int led_init(const struct hw_module_t* module, const char* name, struct hw_device_t** device)

{

struct led_control_device_t *dev;

/*为led_control_device结构体分配内存空间*/

dev = (struct led_control_device_t *)malloc(sizeof(*dev));

if(dev==NULL)

return 0;

memset(dev,0,sizeof(*dev));

dev->common.tag = HARDWARE_DEVICE_TAG;

dev->common.version = 0;

dev->common.module = (struct hw_module_t*)module;

//dev->common.close = (int (*)(struct hw_device_t *))close_led;

dev->common.close = close_led;

//设置打开LED的函数指针

dev->set_on = led_on;

//设置关闭LED的函数指针

dev->set_off = led_off; 

 

*device = (struct hw_device_t *)&dev->common;

if(open_led() == -1)

{

free(dev);

dev = NULL;

return -1;

}

return 0;

}

/*2、hw_module_methods_t中定义了打开设备的open函数的指针。也就是在这个函数中进行了一些列的初始化工作*/

static struct hw_module_methods_t led_module_methods={

open: led_init

};

/*1、HAL_MODULE_INFO_SYM才是HAL真正的入口,这里面最重要的两个参数是id: LED_HARDWARE_MODULE_ID和methods: &led_module_methods*/

struct led_module_t HAL_MODULE_INFO_SYM={

common:

{

tag: HARDWARE_MODULE_TAG,

version_major: 1,

version_minor: 0,

id: LED_HARDWARE_MODULE_ID,

name: "sample led hal stub",

author: "xxx",

methods: &led_module_methods,

}

};</span>


 

 

3.3 HAL源码编译

//Android.mk

<span style="font-family:KaiTi_GB2312;font-size:18px;">LOCAL_PATH:= $(call my-dir)

# HAL module implemenation stored in

# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so

include $(CLEAR_VARS)

LOCAL_PRELINK_MODULE := false

LOCAL_SRC_FILES := led_hal.c

LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw

#LOCAL_SHARED_LIBRARIES := liblog

LOCAL_MODULE := led_hal.default

#LOCAL_MODULE := led_hal.$(TARGET_BOARD_PLATFORM)

LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)</span>

编译出来的led_hal.default.so模块保存在了$(Android_source)/out/target/produce/mini210/system/lib/hw中。将之上传到开发板中相应的/system/lib/hw文件夹中即可。

 

四、Jni/Service服务层

 

这一层的主要任务就是调用HAL层的程序库,并为上层应用程序层提供调用接口。

4.1 直接使用JNI调用驱动程序

在Java中是可以写C/C++代码的,虽然并不是100%的C/C++语言,但只需要改动一下数据类型的标志并注意一些新定义的用法即可。我们常把C/C++代码称之为原生代码,如果不是特别讲究叫法的话,在Java体系中还可以勉为其难的称之为JNI或NDK,其实JNI和NDK意义并不同,首先介绍一下JNI和NDK的区别。

JNI是java语言提供的Java和C/C++相互沟通的机制,Java可以通过JNI调用本地的C/C++代码,本地的C/C++的代码也可以调用java代码。JNI 是本地编程接口,Java和C/C++互相通过的接口。Java通过C/C++使用本地的代码的一个关键性原因在于C/C++代码的高效性。

 

NDK是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。它集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。它可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

所以可以简单的理解为JNI是接口,NDK是工具。

在涉及到操作硬件的思路上,我们其实可以直接通过Java程序去调用驱动程序,Java程序提供了File.write(str)这样的写函数操作类,所以可以直接向/dev/leds设备驱动文件中写数据。不过Java并没有提供ioctl这样的发送IO控制命令的函数。如果就想发送IO控制命令该怎么办?可以通过JNI层来调用C/C++语言实现。

先给出完成后的操作界面。

 

然后直接贴出各个源文件。

//activity_main.xml

<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

    <LinearLayout

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal" >

 

        <CheckBox

            android:id="@+id/checkbox_str_led1"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED1" />

 

        <CheckBox

            android:id="@+id/checkbox_str_led2"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED2" />

 

        <CheckBox

            android:id="@+id/checkbox_str_led3"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED3" />

 

        <CheckBox

            android:id="@+id/checkbox_str_led4"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED4" />

    </LinearLayout>

 

    <Button

        

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:onClick="onClick_write"

        android:text="write_test" />

    <LinearLayout

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal" >

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led1"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED1" />

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led2"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED2" />

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led3"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED3" />

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led4"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED4" />

    </LinearLayout>

 

    <Button

        

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:onClick="onClick_ioctl"

        android:text="ioctl_test" />

 

    <TextView

        android:id="@+id/textView"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="TextView" />

 

</LinearLayout></span>


 

// jni/leds.c

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <string.h>

#include <stdio.h>

#include <jni.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <stdlib.h>

jstring Java_com_example_leds1_MainActivity_getText (JNIEnv* env, jobject obj)

{

    return (*env)->NewStringUTF(env, "Test Android NDK!Test My NDK!");

}

 

char* jstring_to_pchar(JNIEnv* env, jstring str)

{

char* pstr = NULL;

jclass clsstring = (*env)->FindClass(env, "java/lang/String");

jstring strencode = (*env)->NewStringUTF(env, "utf-8");

jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes",

        "(Ljava/lang/String;)[B");

jbyteArray byteArray = (jbyteArray)(

        (*env)->CallObjectMethod(env, str, mid, strencode));

jsize size = (*env)->GetArrayLength(env, byteArray);

jbyte* pbyte = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);

if (size > 0)

{

pstr = (char*) malloc(size);

memcpy(pstr, pbyte, size);

}

return pstr;

}

 

void Java_com_example_leds1_MainActivity_writeLeds(JNIEnv* env, jobject thiz, jstring str)

{

int fd;

fd = open("/dev/leds",O_RDWR);

char* pstr = jstring_to_pchar(env,str);

write(fd,pstr,strlen(pstr));

close(fd);

}

void Java_com_example_leds1_MainActivity_ioctlLeds(JNIEnv* env, jobject thiz, jint cmd, jint arg)

{

int fd;

fd = open("/dev/leds",O_RDWR);

ioctl(fd,cmd,arg);

close(fd);

}</span>

 

//jni/Android.mk

<span style="font-family:KaiTi_GB2312;font-size:18px;">LOCAL_PATH := $(call my-dir)  

      

include $(CLEAR_VARS)  

     

LOCAL_MODULE := leds  

LOCAL_SRC_FILES := leds.c  

      

include $(BUILD_SHARED_LIBRARY)  </span>


 

//MainActivity.java

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.leds1;

 

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.view.View;

import android.view.MenuItem;

import android.widget.TextView;

import android.widget.CheckBox;

 

public class MainActivity extends Activity {

private CheckBox[] cbStrLeds = new CheckBox[4];

private CheckBox[] cbCmdLeds = new CheckBox[4];

TextView textView;  

    public native String getText();//声明native 方法  

    public native void writeLeds(String str);

    public native void ioctlLeds(int cmd, int arg);

    @Override  

    public void onCreate(Bundle savedInstanceState) {  

        super.onCreate(savedInstanceState);  

        setContentView(R.layout.activity_main);  

        cbStrLeds[0] = (CheckBox)findViewById(R.id.checkbox_str_led1);

     cbStrLeds[1] = (CheckBox)findViewById(R.id.checkbox_str_led2);

     cbStrLeds[2] = (CheckBox)findViewById(R.id.checkbox_str_led3);

     cbStrLeds[3] = (CheckBox)findViewById(R.id.checkbox_str_led4);

    

     cbCmdLeds[0] = (CheckBox)findViewById(R.id.checkbox_cmd_led1);

     cbCmdLeds[1] = (CheckBox)findViewById(R.id.checkbox_cmd_led2);

     cbCmdLeds[2] = (CheckBox)findViewById(R.id.checkbox_cmd_led3);

     cbCmdLeds[3] = (CheckBox)findViewById(R.id.checkbox_cmd_led4);

        

       

        String myString = getText();//调用native方法

     //   long z = add(2, 3);

     //   String zstr=Long.toString(z);

        textView = (TextView)findViewById(R.id.textView); 

        textView.setText(myString);  

    }

public void onClick_write(View view)

{

 

String str="";

for(int i=0;i<4;i++)

{

if(cbStrLeds[i].isChecked())

str +='1';

else

str +='0';

}

TextView textview = (TextView)findViewById(R.id.textView);

textview.setText(str);

writeLeds(str);

}

public void onClick_ioctl(View view)

{

TextView textview = (TextView)findViewById(R.id.textView);

textview.setText("ioctl_test!");

for(int i=0;i<4;i++)

{

if(cbCmdLeds[i].isChecked())

ioctlLeds(1,i);

else

ioctlLeds(0,i);

}

}   

    

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

return true;

}

 

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// Handle action bar item clicks here. The action bar will

// automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();

if (id == R.id.action_settings) {

return true;

}

return super.onOptionsItemSelected(item);

}

    static {  

        System.loadLibrary("leds"); //导入链接库   

    }  

}</span>


需要注意的是,想要编译jni中的文件,必须在电脑上提前装好ndk,这也是一个非常客观的工程量。然后重点是,需要在命令行或者界面形式下编译jni,具体方法上网查查吧。

 

 

4.2 JNI/Service程序代码

//LedHalService.cpp

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <stdlib.h>

#include <string.h>

 

#include <assert.h>

#include <jni.h>

#include <hardware/led_hal.h>   //用到了和HAL层同一个LED_HARDWARE_MODULE_ID = led_hal

 

#ifdef __cplusplus

extern "C" {

#endif

 

struct led_control_device_t *sLedDevice = NULL;

 

//open the led device  by hal

 

static inline int led_control_open(struct hw_module_t *module,struct led_control_device_t **device)

{

return module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)device);

}

 

//close the led device  by hal

jboolean Java_com_example_leds_MainActivity_ledClose (JNIEnv* env, jobject obj)

{

if(sLedDevice)

{

sLedDevice->common.close(&(sLedDevice->common));

}

return 0;

}

//turn on the led

jboolean Java_com_example_leds_MainActivity_ledSetOn (JNIEnv* env, jobject obj,jint number)

{

if(sLedDevice)

{

return sLedDevice->set_on(sLedDevice,number);

}

return false;

}

//turn off the led

jboolean Java_com_example_leds_MainActivity_ledSetOff (JNIEnv* env, jobject obj,jint number)

{

if(sLedDevice)

{

return sLedDevice->set_off(sLedDevice,number);

}

return false;

}

 

//led init

 

jboolean Java_com_example_leds_MainActivity_ledInit (JNIEnv* env, jobject obj)

{

led_module_t *module;

/*看到了吗,hw_get_module是调用HAL模块的核心函数,其中的LED_HARDWARE_MODULE_ID就是前文一直在提的ID号,JNI模块就是通过这个ID号找到的/system/lib/hw文件中相应的HAL共享库模块*/

int err = hw_get_module(LED_HARDWARE_MODULE_ID,(hw_module_t const**)&module);

if(err == 0)

{

if(led_control_open(&(module->common),&sLedDevice) == 0)

return true;

}

sLedDevice = NULL;

return false;

}

 

static led_control_device_t * get_device(hw_module_t* module, char const* name)

{

int err;

hw_device_t* device;

err = module->methods->open(module,name,&device);

if(err == 0)

{

return (led_control_device_t*)device;

}

else

{

return NULL;

}

}

/*通过JNINativeMethod数组定义了函数映射表,注册给Java虚拟机,这样JVM就可以用函数映射表来调用相应的函数,该方式属于动态调用共享库*/

static JNINativeMethod method_table[]={

{"led_init","()Z",(void*)Java_com_example_leds_MainActivity_ledInit},

{"led_setOn","(I)Z",(void*)Java_com_example_leds_MainActivity_ledSetOn},

{"led_setOff","(I)Z",(void*)Java_com_example_leds_MainActivity_ledSetOff},

{"led_close","()Z",(void*)Java_com_example_leds_MainActivity_ledClose},

};

int register_android_server_LedService(JNIEnv *env)

{

//This sentence is very important because we will use this class to call the service

static const char* const kClassName = "com/example/leds/LedService";

//static const char* const kClassName = "com/example/leds";

jclass clazz;

/*Look up the class*/

clazz = env->FindClass(kClassName);

if(clazz == NULL)

{

return -1;

}

/*Register all the methods*/

if(env->RegisterNatives(clazz,method_table,sizeof(method_table)/sizeof(method_table[0]))!=JNI_OK)

{

return -1;

}

/*Fill out the rest of the ID cache*/

return 0;

}

/*系统在成功装在JNI共享库后会自动调用JNI_OnLoad函数,该函数一般用与初始化JNI模块*/

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

JNIEnv* env = NULL;

jint result = -1;

if(vm->GetEnv((void**) &env,JNI_VERSION_1_4)!=JNI_OK)

{

return result;

}

/*使用下面的函数绑定JNI程序库与Java程序库。若想使用静态调用libled_hal_jni.so,则需要将下面的代码屏蔽掉*/

register_android_server_LedService(env);

/*返回JNI_VERSION_1_4,表明只有运行在JDK1.4及以上版本的Java程序才能调用当前的JNI模块*/

return JNI_VERSION_1_4;

}

#ifdef __cplusplus

}

#endif</span>
 

//Android.mk

<span style="font-family:KaiTi_GB2312;font-size:18px;">LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_PRELINK_MODULE :=false

LOCAL_MODULE_TAGS:=optional

LOCAL_SRC_FILES:=LedHalService.cpp

LOCAL_MODULE:=libled_hal_jni

 

LOCAL_SHARED_LIBRARIES := \

libandroid_runtime \

libcutils \

libhardware \

libhardware_legacy \

libnativehelper \

libsystem_server \

libutils \

libui \

libsurfaceflinger_client

 

include $(BUILD_SHARED_LIBRARY)

 </span>


 

五、APP应用程序层

关于如何在APP中调用JNI库文件,上文中4.1节有提到,不过那是在工程中建立了一个jni文件夹,生成的JNI的库文件直接保存到了当前工程的lib文件夹下。当然也可以不用在当前工程下建立jni文件夹,像4.2那样通过Android原生代码进行编译,然后直接通过绝对路径加载模块也能产生相同功能。

 

5.1 activity_main.xml

<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

 

    <LinearLayout

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:orientation="horizontal" >

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led1"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED1" />

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led2"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED2" />

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led3"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED3" />

 

        <CheckBox

            android:id="@+id/checkbox_cmd_led4"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="LED4" />

    </LinearLayout>

 

    <Button

        

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:onClick="onClick_led"

        android:text="led_hal_jni" />

 

</LinearLayout></span>


5.2 LedServer.java

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.leds;

 

 

public class LedService {

private static LedService LedService;

 

public static LedService getInstance()

{

if (LedService == null)

    LedService = new LedService();

return LedService;

}

    

private LedService()  

{  

init(); 

}

    

public boolean init()

{

return led_init();

} 

public boolean setOn(int led)

{

return led_setOn(led);

}  

public boolean setOff(int led)

{ 

return led_setOff(led);

} 

  

//  native method 

private native boolean led_init();

 

private native boolean led_setOn(int led);

 

private native boolean led_setOff(int led);

 

static

{

System.load("/system/lib/libled_hal_jni.so");

}

}</span>


 

5.3 MainActivity.java

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.leds;

 

import com.example.leds.LedService;

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

import android.view.MenuItem;

import android.view.View;

import android.widget.CheckBox;

 

public class MainActivity extends Activity {

 

private CheckBox[] cbCmdLeds = new CheckBox[4];

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

    cbCmdLeds[0] = (CheckBox)findViewById(R.id.checkbox_cmd_led1);

     cbCmdLeds[1] = (CheckBox)findViewById(R.id.checkbox_cmd_led2);

     cbCmdLeds[2] = (CheckBox)findViewById(R.id.checkbox_cmd_led3);

     cbCmdLeds[3] = (CheckBox)findViewById(R.id.checkbox_cmd_led4);

/*

LedService ledService = LedService.getInstance();

ledService.setOn(0);

ledService.setOff(1);

ledService.setOn(2);  

ledService.setOff(3);

*/

}

public void onClick_led(View view)

{

LedService ledService = LedService.getInstance();

for(int i=0;i<4;i++)

{

if(cbCmdLeds[i].isChecked())

ledService.setOn(i);

else

ledService.setOff(i);

}

}   

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

return true;

}

 

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// Handle action bar item clicks here. The action bar will

// automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();

if (id == R.id.action_settings) {

return true;

}

return super.onOptionsItemSelected(item);

}

}</span>


 

好了,关于整套程序都已经写完了。


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

Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0) 的相关文章

  • 如何从android ble扫描结果中获取CRC?

    我每次都从 ble 设备收到 62 字节的扫描结果 使用下面的回调代码获取扫描结果 我可以获取 RSSI 但无法获取 CRC 或者 获取一帧的CRC的逻辑是什么 来自 ble 设备的数据格式 如数据包标头 广告数据 CRC RSSI 如何从
  • 使用DBFlow,如何加密已经存在的数据库?

    我正在使用 DBFlow 来处理项目中的数据库 并且我想对现有数据库进行加密 我知道我可能必须删除现有的未加密数据库并创建另一个加密数据库 我也知道我可以将 SQLCipher 与 DBFlow 一起使用 如上所述文档 https gith
  • Android TelecomManager 中的 addIncomingCall 没有执行任何操作

    我正在尝试使用本机 Android 来电 UI 我有一个连接服务 并且我已经成功注册了一个电话帐户 但在我调用方法 addNewIncomingCall 后什么也没有发生 对我所缺少的有什么想法吗 显现
  • Cordova - 启动后出现白屏,控制台中没有例外

    我已经离开我的 Cordova 应用程序一段时间了 但昨天刚刚进行了一次新的克隆 发现它出现了 死机白屏 症状 启动画面显示 程序加载 然后我就得到一个空白屏幕 更多细节 CLI 科尔多瓦 6 1 1 安卓 5 1 1 ios 4 1 1
  • 嵌套 XML 布局文件

    android 有没有办法从另一个布局文件引用 xml 布局文件 为了更好地解释 我有一个名为layout1 xml 和layout2 xml 的布局文件 我可以从layout1 xml引用layout2 xml吗 用这个
  • 蓝牙 BLE Android 以最大吞吐量写入外设

    我们公司开发了一个具有蓝牙 BLE 的硬件单元 并且我们在 Nexus 7 2013 中有一个服务应用程序 我们希望使用它向该单元发送固件文件 文件最大可达 500kb BT芯片是德州仪器CC2540 我浏览了大量的页面 并扫描了 Stac
  • VOIP通话录音

    我正在开发一个在 android 中录制 VOIP 通话的项目 我没有找到任何解决方案 有很多应用程序支持手机上的 VOIP 录音 我找不到任何教程和帮助 立方体通话记录器 https play google com store apps
  • 更改语言 Flutter 的按钮

    我正在 Flutter 中构建一个应用程序 到目前为止 我正在使用 JSON 国际化 其中应用程序的语言基于用户手机中默认的语言 它工作得很好 但我想给用户有机会在不更改手机系统语言设置的情况下更改语言 只需单击按钮 然后应用程序即可更改语
  • Android L,使用 joda.time 库的异常

    该应用程序适用于所有设备 包括 nexus 5 和 nexus 7 在 Android L 预览版上运行相同的应用程序时 应用程序崩溃了 我一直在调试 并且调用 DateTime 构造函数发现了异常 public static String
  • 什么是 Android 测试协调器?

    谷歌最近发布了Android测试支持库1 0 读完后overview https android developers googleblog com 2017 07 android testing support library 10 is
  • 在 Android 中加密/解密字符串的简单方法

    我的问题是如何加密String String AndroidId Override public void onCreate Bundle savedInstanceState super onCreate savedInstanceSta
  • 模拟器无法加载

    我正在使用 hello android 教程并通过 eclipse 创建 avd 启动模拟器时不使用图像 它只是显示一个黑色的后屏 中间有 ANDROID 字样 并且在 ANDROID 字样的末尾有一个闪烁的光标 我已按照 T 的步骤安装
  • Android 操作项上的通知徽章

    我想在操作栏中放置的购物车图像上添加一个通知徽章 并以编程方式操作它 有帮助吗 您可以显示自定义MenuItem on ActionBar通过创建一个custom layout for MenuItem 要设置自定义布局 您必须使用菜单项属
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • 使 Recyclerview 固定高度并可滚动

    已解决以下检查答案 所以我试图为我的 Android 应用程序创建评论功能 我想在 recyclerview 中显示评论 然后在 recyclerview 下方有一个按钮和文本视图来添加评论 我想让 recyclerview 具有一定的高度
  • 用于请求带有临时缓存的远程 Observable 的 RxJava 模式

    用例是这样的 我想暂时缓存最新发出的昂贵的Observable响应 但在它过期后 返回到昂贵的源Observable并再次缓存它 等等 一个非常基本的网络缓存场景 但我真的很难让它工作 private Observable
  • Android ScrollView,检查当前是否滚动

    有没有办法检查标准 ScrollView 当前是否正在滚动 方向是向上还是向下并不重要 我只需要检查它当前是否正在滚动 ScrollView当前形式不提供用于检测滚动事件的回调 有两种解决方法可用 1 Use a ListView并实施On
  • 调试android数据绑定?

    谁能告诉我如何调试或找到数据绑定生成的代码 从this https www youtube com watch v NBbeQMOcnZ0链接我发现它生成了所需的代码 我猜您正在寻找自动生成的绑定 java 文件 我也在寻找他们 最后我在这
  • 动态更改按钮上的图像视图

    在我的应用程序中 我有按钮和ImageView 当我按下按钮时我想改变ImageView 我的可绘制文件夹中有 5 张图像 按下按钮时 ImageView 根据按钮单击一张一张地更改图像 我想要它的解决方案 感谢任何可以提供帮助的人 维护一
  • 在数组列表中过滤 Filterable 不取消之前的过滤

    我看过过滤器方法文档 其中显示调用过滤器会取消所有先前未执行的过滤请求 并发布一个稍后将执行的新过滤请求 但我收到的实际回调有些不同 在我的实现中 它不会取消先前的过滤器请求并调用publishResults 最近一次搜索条件后的上一次搜索

随机推荐

  • python调用谷歌翻译

    from GoogleFreeTrans import Translator if name 61 61 39 main 39 translator 61 Translator translator src 61 39 en 39 dest
  • C++(4) 运算符重载

    C 43 43 学习心得 xff08 1 xff09 运算符重载 from 谭浩强 C 43 43 面向对象程序设计 第一版 2014 10 6 4 1什么是运算符重载 用户根据C 43 43 提供的运算符进行重载 xff0c 赋予它们新的
  • C++学习心得(3)多态性与虚函数

    C 43 43 学习心得 xff08 3 xff09 多态性与虚函数 from 谭浩强 C 43 43 面向对象程序设计 第一版 2014 10 13 6 1 多态性的概念 在C 43 43 中 xff0c 多态性是指具有不同功能的函数可以
  • C发送http请求

    C语言发送http请求和普通的socket通讯 原理是一样的 无非就三步connect 连上服务器 send 发送数据 recv 接收数据 只不过发送的数据有特定的格式 下面的是简单发送一个http请求的例子 span class hljs
  • tensorflow(四十七):tensorflow模型持久化

    模型保存 span class token keyword from span tensorflow span class token keyword import span graph util graph def span class
  • git subtree使用

    在一个git项目下引用另一个项目的时 xff0c 我们可以使用 git subtree 使用 git subtree 时 xff0c 主项目下包含子项目的所有代码 使用 git subtree 主要关注以下几个功能 一个项目下如何引入另一个
  • tensorflow(四十八): 使用tensorboard可视化训练出的文本embedding

    对应 tensorflow 1 15版本 log dir span class token operator 61 span span class token string 34 logdir 34 span metadata path s
  • java中数组之间的相互赋值

    前言 本文考虑的研究对象是数组 xff0c 需要明确的是在java中 xff0c 数组是一种对象 xff0c java的所有对象的定义都是放在堆当中的 xff0c 对象变量之间的直接赋值会导致引用地址的一致 在java中声明一个数组 spa
  • tensorflow学习笔记(十):sess.run()

    session run fetch1 fetch2 关于 session run fetch1 fetch2 xff0c 请看http stackoverflow com questions 42407611 how tensorflow
  • tensorflow学习笔记(二十三):variable与get_variable

    Variable tensorflow中有两个关于variable的op xff0c tf Variable 与tf get variable 下面介绍这两个的区别 tf Variable与tf get variable tf Variab
  • pytorch 学习笔记(一)

    pytorch是一个动态的建图的工具 不像Tensorflow那样 xff0c 先建图 xff0c 然后通过feed和run重复执行建好的图 相对来说 xff0c pytorch具有更好的灵活性 编写一个深度网络需要关注的地方是 xff1a
  • pytorch学习笔记(五):保存和加载模型

    span class hljs comment 保存和加载整个模型 span torch save model object span class hljs string 39 model pkl 39 span model 61 torc
  • tensorflow:自定义op简单介绍

    本文只是简单的翻译了 https www tensorflow org extend adding an op 的简单部分 xff0c 高级部分请移步官网 可能需要新定义 c 43 43 operation 的几种情况 xff1a 现有的
  • pytorch学习笔记(十二):详解 Module 类

    Module 是 pytorch 提供的一个基类 xff0c 每次我们要 搭建 自己的神经网络的时候都要继承这个类 xff0c 继承这个类会使得我们 搭建网络的过程变得异常简单 本文主要关注 Module 类的内部是怎么样的 初始化方法中做
  • tensorflow学习笔记(四十五):sess.run(tf.global_variables_initializer()) 做了什么?

    当我们训练自己的神经网络的时候 xff0c 无一例外的就是都会加上一句 sess run tf global variables initializer xff0c 这行代码的官方解释是 初始化模型的参数 那么 xff0c 它到底做了些什么
  • 使用 spacy 进行自然语言处理(一)

    介绍 自然语言处理 NLP 是人工智能方向一个非常重要的研究领域 自然语言处理在很多智能应用中扮演着非常重要的角色 xff0c 例如 xff1a automated chat bots article summarizers multi l
  • 威联通ContainerStation部署Oracle11g

    文章目录 前言部署过程详解使用docker compose文件创建容器临时开启NAS的SSH远程访问通过SSH客户端远程连接NAS进入容器创建用户拷贝容器中的数据库相关文件至宿主机在ContainerStation中修改docker com
  • 十六进制数据与字符串的相互转换

    span class hljs keyword public span span class hljs keyword static span String span class hljs title bytesToHexString sp
  • 贪心算法详解

    前言 贪心算法是动态规划的一种特殊情况 xff0c 需要满足更为苛刻的条件 xff1a 贪心选择 算法种类时间复杂度暴力算法指数级别动态规划多项式级别贪心算法线性级别 什么是贪心选择性质呢 xff0c 简单说就是 xff1a 每一步都做出一
  • Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0)

    Android系统HAL驱动开发经典案例详解 xff08 基于Android4 0 xff09 目的 xff1a 通过学习一个LED点灯的简单功能 xff0c 掌握Linux驱动程序与HAL硬件抽象层之间的调用方法 xff0c 同时掌握JN