Android驱动程序编写过程记录

本文仅仅记录开发Android驱动程序的一个过程,以供以后编写驱动进行参考

第一步:当然就是编写LINUX内核层的驱动程序了,这个很通用的一层,编写后不管是集成在内核中还是单独的ko文件,到最后

系统启动后都需要在dev目录下生成设备节点。

第二步:就是所谓的HAL层,这层代码一般放在hardware/xxx/目录中,这层跟内核中的代码类似,都是C代码,但是该层操作dev

目录下生成的设备节点,同时也为Android层操作做准备,把可以提供给Android层的功能写一遍

该文件需要定义一个结构

struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = KEYLED_HARDWARE_MODULE_ID,
    .name = "Keypad LED Stub",
    .author = "INST Wgj",
    .methods = &led_module_methods,
};
名字必须是HAL_MODULE_INFO_SYM

HARDWARE_MODULE_TAG也是固定的

KEYLED_HARDWARE_MODULE_ID是自定义的,之后JNI层查找就是根据该ID查找的,这里要注意一点

KEYLED_HARDWARE_MODULE_ID的定义为一个字符串,此字符串定义要与Android.mk中的LOCAL_MODULE定义一致,否则在JNI层

初始化调用hw_get_module函数时会失败,现在做的驱动LOCAL_MODULE := keypadleds.$(TARGET_BOARD_PLATFORM)

那么KEYLED_HARDWARE_MODULE_ID就得定义为“keypadleds”,不能为其他,因为系统查找是根据文件名查找的竟然。。。。

led_module_methods定义,里面包含的是公共方法

static struct hw_module_methods_t led_module_methods = {
    open: led_device_open
};
然后呢在open方法中对设备控制结果进行初始化,驱动方法都在此函数中进行赋值
static int led_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device)
{
    struct led_control_device_t *tmp_dev;

    tmp_dev = (struct led_control_device_t *)malloc(sizeof(*tmp_dev));
    if (!tmp_dev){
        return -EINVAL;
    }
    memset(tmp_dev, 0, sizeof(*tmp_dev));

    tmp_dev->common.tag =  HARDWARE_DEVICE_TAG;
    tmp_dev->common.version = 0;
    tmp_dev->common.module = module;
    tmp_dev->common.close = led_device_close;

    tmp_dev->set_on = led_on;
    tmp_dev->set_off = led_off;
    tmp_dev->get_count = get_count;

    *device = &tmp_dev->common;
    if ((led_fd = open(LED_DEVICE, O_RDWR)) == -1){
        LOGE("LED open error");
        return -EINVAL;
    }
    // 打开设备后先读取下LED灯的总数量
    ioctl(led_fd, CMD_COUNT, &led_count);

    return 0;
}
led_control_device_t结构定义

// 定义一个继承自hw_device_t的结构, 记录本stub操作设备时需要包括的接口

struct led_control_device_t {
    struct hw_device_t common;

    // 操作句柄
    int fd;

    // 打开指定序号LED灯
    int (*set_on)(struct led_control_device_t *dev, int32_t led);
    // 关闭指定序号LED灯
    int (*set_off)(struct led_control_device_t *dev, int32_t led);
    // 获取LED灯的数量
    int (*get_count)(struct led_control_device_t *dev);
};
结构以及宏定义都需要定义在一个头文件中,因为JNI层也需要该头文件。。。

到这里HAL层基本就OK了,编译完成后会在system/lib/hw中生成对应的so动态库,JNI层就会操作这个动态库

第三步:编写JNI层

这时候就需要到frameworks目录下了,我为了管理方便在该目录下直接建立了一个专门目录,虽然不符合要求。。。

进入到我的目录,建立个java目录跟jni目录。进入jni目录

将刚才HAL层的头文件建立个超链接引过来

建立个cpp文档,这个文档就是JNI层的具体实现文档,该文档命名也有要求com_xxx_xxx_类名.cpp

在该文档中入口函数为JNI_OnLoad

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env = NULL;
	jint result = -1;

//	ALOGI("JNI_OnLoad LED");
   	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
		ALOGE("ERROR: GetEnv failed\n");
		goto fail;
	}
	
    assert(env != NULL);
	if (registerMethods(env) != 0) {
		ALOGE("ERROR: PlatformLibrary native registration failed\n");
		goto fail;
	}
	
	// success -- return valid version number
	result = JNI_VERSION_1_4;
fail:
	return result;
}

registerMethods函数自己写用来实现方法的注册

该文档中对下操作led_control_device_t定义的设备,对led_control_device_t中实现的方法进行包装

然后声明到方法中以供JAVA层调用,如下定义:

static const JNINativeMethod gMethods[] = {
	{ "_init",	  	"()Z",	(void *)instisu_init },
	{ "_set_on",        "(I)Z", (void *)instisu_setOn },
	{ "_set_off",       "(I)Z", (void *)instisu_setOff },
	{ "_get_count",   "()I", (void *)instisu_getCount },
};
在init函数中有使用hw_get_module(KEYLED_HARDWARE_MODULE_ID, (hw_module_t const**)&module)获取设备

就在这里系统会根据KEYLED_HARDWARE_MODULE_ID去查找HAL层生成的so动态库文件

然后对设备对象进行各种操作

这部分代码需要生成一个运行库以供JAVA层调用,真麻烦。。。

JAVA层不能调用HAL层生成的库而只能用JNI层的库?太深奥。。。

到这里该层就可以进行编译,会在system/lib目录下生成一个so库

第四步:framework中的Sever实现,就是JAVA层了

到第三步新建的目录中,进入java目录,然后新建com....等目录,进入hardware目录中新建IXXXService.aidl文档,在其中

声明接口

interface IXXXService
{
    boolean setOn(int led);
    boolean setOff(int led);
    int getCount();
}

在同级的server目录中,新建XXXServer.java文件

继承IXXXService.Stub

在该类中加载JNI层生成的so库

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

在该类中将JNI层提供的方法包装为JAVA方法。

然后呢既然是系统驱动了,让其他应用可以调用,得需要在/system/etc/permission目录下有相应的xml文档声明才行

如:com.instisu.server.xml

内容

<?xml version="1.0" encoding="utf-8"?>
<permissions>
    <library name="com.instisu.server"
            file="/system/framework/instisu.jar"/>
</permissions>

该文档可以放到自定义目录的根目录下,然后编写Android.mk

在编写Android.mk时需要注意不能添加LOCAL_SDK_VERSION := current项,否则会出现

cannot find symbol
symbol  : class ServiceManager
location: package android.os
import android.os.ServiceManager
之类错误

LOCAL_MODULE 要与xml文档中的file设置一致,否则让人家系统怎么找

至此Android的驱动部分就基本完成了


然而,你编译成功后却会发现你生成的jar文档使用现有的编程工具无法使用,因为已经默认为dex化了,不管Eclipse或者Android studio都无法解析,

其实只要进入target/common/obj/JAVA_LIBRARIES目录中找你相应的xxx_intermediates就可以了,里面的classes.jar即可使用


再然后,在使用Eclipse时你可以直接添加自定义系统库,让刚才的jar文件引入工程,而不需要将改jar文件放到工程目录中。。。。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Android应用程序中实现登录注册连接MySQL,需要以下步骤: 1.创建一个MySQL数据库,包含用户表和登录表。 2.在Android应用程序中创建一个用户界面,包括登录和注册表单。 3.使用Java编写代码来连接MySQL数据库,执行查询和插入操作。 4.在用户界面中添加适当的代码,以便在用户提交表单时将数据发送到MySQL数据库。 5.在应用程序中实现适当的验证和错误处理,以确保用户输入的数据正确。 6.在应用程序中实现适当的安全措施,例如加密密码和使用SSL连接。 7.测试应用程序,确保它可以正确地连接和操作MySQL数据库。 总之,要在Android应用程序中实现登录注册连接MySQL,需要一些编程知识和技能。但是,一旦你掌握了这些技能,你就可以创建出一个功能强大的应用程序,可以让用户轻松地注册和登录,并将数据存储在MySQL数据库中。 ### 回答2: Android登录注册连接MySQL是一种常见的开发需求,可以通过以下步骤实现。 首先,需要在MySQL数据库中创建相应的用户表,包括用户名、密码等必要的字段。可以使用phpMyAdmin等工具进行创建。 然后,在Android项目中导入MySQL的JDBC驱动库。这样才能在Android项目中使用MySQL的相关功能。 接下来,在Android应用中创建一个包含登录和注册功能的界面,可以使用EditText控件来获取用户输入的用户名和密码。 在登录功能中,当用户点击登录按钮后,首先需要进行输入验证,确保用户名和密码不为空。然后,Android应用通过JDBC连接MySQL数据库,并执行SQL语句查询用户表中是否有匹配的记录。如果有匹配的记录,说明用户名和密码正确,则登录成功,可以跳转到应用的主界面;否则,登录失败,需要提示用户重新输入。 在注册功能中,当用户点击注册按钮后,同样需要进行输入验证,确保用户名和密码不为空。然后,Android应用通过JDBC连接MySQL数据库,并执行SQL语句将新用户的信息插入到用户表中。插入成功后,提示用户注册成功;否则,提示用户注册失败。 需要注意的是,在连接MySQL数据库时,需要提供数据库的IP地址、端口号、数据库名、用户名和密码等信息。 综上所述,通过以上步骤,可以实现Android应用与MySQL数据库的登录注册功能的连接。最后,可以通过添加一些其他的功能来完善应用,比如修改密码、忘记密码等。 ### 回答3: 要在Android应用中实现登录注册功能并连接MySQL数据库,需要完成以下步骤: 1. 创建一个包含登录和注册界面的Android应用。可以使用Android Studio进行开发,设计合适的布局和界面。 2. 在MySQL数据库中创建一个表格,用于存储用户的用户名和密码等信息。可以使用phpMyAdmin等工具进行数据库表的创建和管理。 3. 在Android应用中添加相关的Java类和方法,以实现与MySQL数据库的连接和操作。可以使用第三方库如Volley库来进行网络请求。 4. 在注册界面中,用户输入用户名和密码等信息后,通过发送HTTP POST请求将信息发送到服务器端的php文件。 5. 服务器端的php文件接收到用户的注册信息后,通过SQL INSERT语句将数据插入到MySQL数据库中的表格中。 6. 在登录界面中,用户输入用户名和密码后,同样通过发送HTTP POST请求将登录信息发送到服务器端的php文件。 7. 服务器端的php文件接收到用户的登录信息后,通过SQL SELECT语句查询数据库,判断用户输入的用户名和密码是否与数据库中的信息匹配。 8. 服务器端将查询结果返回给Android应用,如果匹配成功,则用户登录成功;否则,登录失败。 9. 在登录成功后,可以将用户的相关信息保存在SharedPreferences中,方便应用的其他模块使用。 10. 在Android应用中,根据用户的登录状态,可以控制界面的跳转,如跳转到登录成功后的主界面。 以上是实现Android登录注册连接MySQL的基本步骤,可以根据实际需求进行适当的调整和改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值