以下实现一个简单的 LED 控制系统,包括驱动程序、HAL 层和 Framework 层的代码示例。
我们将使用 AIDL 来定义应用程序与 Framework 层之间的接口,并使用 Binder 机制在 Framework 层与 HAL 层之间进行通信。(仅简单示例,便于理解代码开发流程,不保证能运行)
1. LED 驱动程序
创建一个名为 led_driver.c 的文件,内容如下:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "led"
#define CLASS_NAME "led_class"
static int major;
static struct class *led_class;
static struct cdev led_cdev;
static bool led_on = false;
static int led_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "led: Device opened\n");
return 0;
}
static int led_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "led: Device closed\n");
return 0;
}
static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
char status = led_on ? '1' : '0';
if (copy_to_user(buf, &status, 1)) {
return -EFAULT;
}
printk(KERN_INFO "led: Read %c\n", status);
return 1;
}
static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
char command;
if (copy_from_user(&command, buf, 1)) {
return -EFAULT;
}
if (command == '1') {
led_on = true;
printk(KERN_INFO "led: LED turned on\n");
} else if (command == '0') {
led_on = false;
printk(KERN_INFO "led: LED turned off\n");
} else {
return -EINVAL;
}
return count;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.read = led_read,
.write = led_write,
};
static int __init led_init(void) {
dev_t dev;
int result;
result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
if (result < 0) {
printk(KERN_WARNING "led: Can't get major number\n");
return result;
}
major = MAJOR(dev);
cdev_init(&led_cdev, &fops);
led_cdev.owner = THIS_MODULE;
result = cdev_add(&led_cdev, dev, 1);
if (result) {
printk(KERN_NOTICE "led: Error %d adding led", result);
unregister_chrdev_region(dev, 1);
return result;
}
led_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(led_class)) {
cdev_del(&led_cdev);
unregister_chrdev_region(dev, 1);
return PTR_ERR(led_class);
}
device_create(led_class, NULL, dev, NULL, DEVICE_NAME);
printk(KERN_INFO "led: Registered with major number %d\n", major);
return 0;
}
static void __exit led_exit(void) {
dev_t dev = MKDEV(major, 0);
device_destroy(led_class, dev);
class_destroy(led_class);
cdev_del(&led_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "led: Unregistered\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple LED driver");
MODULE_VERSION("1.0");
2. HAL 层代码
HAL 层代码需要实现一个标准的 HAL 接口,并通过 hw_device_t
结构体与驱动进行交互。
PS:关于HAL层的知识,老罗的《Android系统源代码情景分析》第二章有详细介绍:
这篇写得很详细:
第二章 硬件抽象层
2.1. 定义 HAL 接口
首先,我们定义一个 HAL 接口文件,用于描述 HAL 层提供的服务。创建一个名为 led_hal.h
的文件,内容如下:
#ifndef ANDROID_LED_HAL_H
#define ANDROID_LED_HAL_H
#include <hardware/hardware.h>
__BEGIN_DECLS
#define LED_HARDWARE_MODULE_ID "led"
struct led_device_t {
struct hw_device_t common;
int (*set_on)(struct led_device_t* dev);
int (*set_off)(struct led_device_t* dev);
int (*get_state)(struct led_device_t* dev, int* state);
};
__END_DECLS
#endif // ANDROID_LED_HAL_H
2.2. 实现 HAL 模块
接下来,我们实现 HAL 模块。创建一个名为 led_hal.cpp
的文件,内容如下:
#include <hardware/hardware.h>
#include <hardware/led_hal.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#define LED_DEVICE "/dev/led"
static int led_set_on(struct led_device_t* dev) {
int fd = open(LED_DEVICE, O_WRONLY);
if (fd < 0) {
return -errno;
}
write(fd, "1", 1);
close(fd);
return 0;
}
static int led_set_off(struct led_device_t* dev) {
int fd = open(LED_DEVICE, O_WRONLY);
if (fd < 0) {
return -errno;
}
write(fd, "0", 1);
close(fd);
return 0;
}
static int led_get_state(struct led_device_t* dev, int* state) {
int fd = open(LED_DEVICE, O_RDONLY);
if (fd < 0) {
return -errno;
}
char status;
read(fd, &status, 1);
close(fd);
*state = (status == '1') ? 1 : 0;
return 0;
}
static int led_close(hw_device_t* device) {
free(device);
return 0;
}
static int led_open(const hw_module_t* module, const char* id, hw_device_t** device) {
if (strcmp(id, LED_HARDWARE_MODULE_ID) != 0) {
return -EINVAL;
}
led_device_t* dev = (led_device_t*)malloc(sizeof(led_device_t));
if (!dev) {
return -ENOMEM;
}
memset(dev, 0, sizeof(led_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = led_close;
dev->set_on = led_set_on;
dev->set_off = led_set_off;
dev->get_state = led_get_state;
*device = (hw_device_t*)dev;
return 0;
}
static struct hw_module_methods_t led_module_methods = {
.open = led_open,
};
extern "C" {
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 = "LED HAL",
.author = "Your Name",
.methods = &led_module_methods,
},
};
}
3. Framework 层代码
接下来,我们实现 Framework 层代码。假设我们使用 Java 实现 Framework 层,并使用 Binder 机制进行通信。
3.1. 定义 AIDL 接口
创建一个名为 ILedService.aidl
的文件,内容如下:
package com.example.ledservice;
interface ILedService {
void turnOn();
void turnOff();
boolean isOn();
}
3.2. 实现 Framework 层代码
创建一个名为 LedService.java
的文件,内容如下:
package com.example.ledservice;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
public class LedService extends ILedService.Stub {
private static final String TAG = "LedService";
private ILedService mLedHal;
public LedService() {
mLedHal = ILedService.Stub.asInterface(ServiceManager.getService("ledhal"));
}
@Override
public void turnOn() throws RemoteException {
if (mLedHal != null) {
mLedHal.turnOn();
} else {
Log.e(TAG, "LED HAL service not available");
}
}
@Override
public void turnOff() throws RemoteException {
if (mLedHal != null) {
mLedHal.turnOff();
} else {
Log.e(TAG, "LED HAL service not available");
}
}
@Override
public boolean isOn() throws RemoteException {
if (mLedHal != null) {
return mLedHal.isOn();
} else {
Log.e(TAG, "LED HAL service not available");
return false;
}
}
}
4. 测试应用程序
最后,我们编写一个简单的 Android 应用程序,通过 AIDL 接口与 Framework 层进行通信,测试 LED 控制功能。
4.1. 创建 MainActivity.java
package com.example.ledapp;
import android.app.Activity;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.example.ledservice.ILedService;
public class MainActivity extends Activity {
private ILedService mLedService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IBinder binder = ServiceManager.getService("ledservice");
mLedService = ILedService.Stub.asInterface(binder);
Button turnOnButton = findViewById(R.id.turn_on_button);
Button turnOffButton = findViewById(R.id.turn_off_button);
Button checkStatusButton = findViewById(R.id.check_status_button);
turnOnButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mLedService.turnOn();
Toast.makeText(MainActivity.this, "LED turned on", Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
turnOffButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mLedService.turnOff();
Toast.makeText(MainActivity.this, "LED turned off", Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
checkStatusButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
boolean isOn = mLedService.isOn();
Toast.makeText(MainActivity.this, "LED is " + (isOn ? "on" : "off"), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
}
4.2. 创建 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/turn_on_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Turn On LED" />
<Button
android:id="@+id/turn_off_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Turn Off LED" />
<Button
android:id="@+id/check_status_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Check LED Status" />
</LinearLayout>
总结
通过以上步骤,我们实现了一个完整的 LED 控制系统,包括驱动程序、HAL 层和 Framework 层的代码示例。应用程序通过 AIDL 接口与 Framework 层进行通信,Framework 层通过 Binder 机制与 HAL 层进行通信,HAL 层通过 hw_device_t
结构体与内核驱动程序进行通信,从而实现对 LED 的控制。