Android8.0 之从驱动层到应用层的通信

前段时间公司要做一个用旋钮调节音量的手机,简单粗暴的做法是应用层用一个死循环读驱动文件,然后驱动一个死循环读硬件ADC并写文件。但是这样太low了。相信很多小伙伴都知道UEvent机制,我们Android系统电池上报相关的信息就是用的这个机制。好了废话不多说了,直接上代码。

首先是驱动层加节点并读取硬件信息。

我加的文件路径:
kernel-3.18\drivers\input\keyboard\kpd.c

首先在kpd.c文件里面

#define     VOLUME_MAJOR 156
unsigned int g_volume_val=0;
static struct class *volume_class = NULL;
static struct device *volume_dev = NULL;
static struct work_struct vol_work;
//当上层读取file时会调用show_volume_level函数来更新及显示文件内容
static ssize_t show_volume_level(struct device *dev,struct device_attribute *attr, char *buf)
{
     return sprintf(buf, "%u\n", g_volume_val);;
}
//当上层写入file时会调用 store_volume_level函数来更新及写入文件内容
static ssize_t store_volume_level(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
{   
    char *pvalue = NULL;
    unsigned int test_item = 1;
    if(buf != NULL)
    {
        test_item = simple_strtoul(buf,&pvalue,10); 
        g_volume_val = test_item;
        printk("store_volume_level test_item=%d .\n",test_item);        
    }
    return size;;
}

void vol_work_func(struct work_struct *work)
{   
    g_volume_val++;
    kobject_uevent(&volume_dev->kobj, KOBJ_CHANGE); 
    mdelay(2000);
    schedule_work(&vol_work);   
}
static DEVICE_ATTR(volume_level, 0664, show_volume_level, store_volume_level); 
static int __init kpd_mod_init(void)
{   
    //在sys文件系统下建立一个类
    volume_class = class_create(THIS_MODULE, "volume");
    //在类里建立一个设备 
    volume_dev = device_create(volume_class, NULL, 
                                          VOLUME_MAJOR, 
                                           NULL, 
                                           "volume_device");    
    //在设备目录下建立一个属性文件                                                                           
    ret_device_file = device_create_file(volume_dev, &dev_attr_volume_level);
    //注意思在使用kobject_uevent函数发送uevent事件时需要建立一个工作队列来发送,否则会在发送过程中内核死掉。
    INIT_WORK(&vol_work,vol_work_func);
    schedule_work(&vol_work);
    return 0;
}
 static void __exit kpd_mod_exit(void)
{
    class_destroy(volume_class);
}
 module_init(kpd_mod_init);
 module_exit(kpd_mod_exit);

上面代码只是大概流程,不是具体实现细节,小伙伴可根据自己的业务具体实现。
DEVICE_ATTR(volume_level, 0664, show_volume_level, store_volume_level) ,还有上面
store_volume_level ,show_volume_level 这2个方法是里面包含的volume_level 和黑体字标注是固定写法,可根据自己的业务重新命名。最大权限只能给0664 否则编译会出错。

kernel-3.18\drivers\input\keyboard\Makefile这个文件
obj-$(CONFIG_KEYBOARD_MTK) := kpd.o

具体Makefile根据自己需求去写。

其次是JNI层根据驱动uevent事件通知服务主动去读取节点。

com_android_server_vm_VolumeControlService.cpp

static jint readFromFile(JNIEnv* env, jobject obj) {
const char *path = "/sys/class/volume/volume_device/volume_level";
const int SIZE = 128;
char buf[SIZE];
ssize_t count = 0;
int g_vol_val = -1;

if (access(path, R_OK) == 0){
int fd = open(path, O_RDONLY, 0);
if (fd == -1) {
    LOGI("Could not open '%s'\n",path);
    return -1;
}
count = TEMP_FAILURE_RETRY(read(fd, buf, SIZE));
LOGI("g_vol_val '%s'\n",buf);
g_vol_val = atoi(buf);
LOGI("g_vol_val '%d'\n",g_vol_val);
close(fd);
}else{
    LOGI("Could not access '%s'\n",path);
}
return g_vol_val;
}

jni 函数注册就不写了,自己不会百度一下。

然后framework 服务层接到驱动通知主动调用native函数读取。

public class VolumeControlService  extends IVolumeControlService.Stub { 

    private String TAG = "VolumeControlService"; 

    public VolumeControlService(Context context) {
        mUEventObserver.startObserving("SUBSYSTEM=volume");
      }

    @Override  
    public int readState() throws RemoteException {         
        return 0;
    } 

   private UEventObserver mUEventObserver = new UEventObserver() {

         @Override
         public void onUEvent(UEventObserver.UEvent event) { 
             int volumeLevel = readFromFile();
             //TODO 发送广播到应用层,应用层监听
         }

    };

    private static native int readFromFile();   

}      

需要用到的权限。

device.te里面定义
type volume_device, dev_type;
system_server.te里面添加
allow system_server volume_device:chr_file rw_file_perms;
allow system_server volume_device:dir r_dir_perms;
service.te里面添加
type volumecontrol_service, system_api_service, system_server_service, service_manager_type;
service_contexts里面添加
volumecontrol u:object_r:volumecontrol_service:s0

至此驱动到应用层通讯已经完成,如有疑问,请在下方留言。

你可能感兴趣的:(【Linux,】)