一、增加驱动
1. 文件目录:
modified: lichee/linux-3.10/.config
modified: lichee/linux-3.10/drivers/Kconfig
modified: lichee/linux-3.10/drivers/Makefile
new file: lichee/linux-3.10/drivers/demo/Kconfig
new file: lichee/linux-3.10/drivers/demo/Makefile
new file: lichee/linux-3.10/drivers/demo/demo.c
new file: lichee/linux-3.10/drivers/demo/demo.h
2. 代码
lichee/linux-3.10/.config
增加:
CONFIG_DEMO=y
lichee/linux-3.10/drivers/Kconfig
增加:
source "drivers/demo/Kconfig"
lichee/linux-3.10/drivers/Makefile
增加:
obj-$(CONFIG_DEMO) += demo/
新增文件:lichee/linux-3.10/drivers/demo/Kconfig
config DEMO
tristate "Demo Register Driver"
default y
help
This is the deomo driver for android system.
新增文件:lichee/linux-3.10/drivers/demo/Makefile
obj-$(CONFIG_DEMO) += demo.o
新增文件:lichee/linux-3.10/drivers/demo/demo.h
#ifndef _DEMO_H_
#define _DEMO_H_
#include <linux/cdev.h>
#include <linux/semaphore.h>
#define DEMO_DEVICE_NODE_NAME "demo"
#define DEMO_DEVICE_FILE_NAME "demo"
#define DEMO_DEVICE_PROC_NAME "demo"
#define DEMO_DEVICE_CLASS_NAME "demo"
struct demo_reg_dev
{
int val;
struct semaphore sem; // 信号量
struct cdev dev;
};
#endif
增加文件:lichee/linux-3.10/drivers/demo/demo.c
#include <linux/init.h>
#include <linux/module.h>
//#include <linux/type.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include "demo.h"
static int demo_major = 0;
static int demo_minor = 0;
static struct class* demo_class = NULL;
static struct demo_reg_dev* demo_dev = NULL;
static int demo_open(struct inode* inode, struct file* filp);
static int demo_release(struct inode* inode, struct file* filp);
static ssize_t demo_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
static ssize_t demo_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
static struct file_operations demo_fops =
{
.owner = THIS_MODULE,
.open = demo_open,
.release = demo_release,
.read = demo_read,
.write = demo_write,
};
#define SEQ_printf(m, x...) \
do { \
if (m) \
seq_printf(m, x); \
else \
pr_err(x); \
} while(0);
static int demo_proc_show(struct seq_file* m, void* v)
{
SEQ_printf(m, "%d\n", demo_dev->val);
return 0;
}
static int demo_proc_open(struct inode* inode, struct file* filp)
{
return single_open(filp, demo_proc_show, inode->i_private);
}
static ssize_t __demo_set_val(struct demo_reg_dev* dev, const char* buf, size_t count)
{
int val = 0;
val = simple_strtol(buf, NULL, 10);
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
dev->val = val;
up(&(dev->sem));
return count;
}
static ssize_t demo_proc_write(struct file* filp, const char* ubuf, size_t cnt, loff_t* data)
{
int err = 0;
char* page = NULL;
if (cnt > PAGE_SIZE)
{
printk(KERN_ALERT"The buff is too large: %lu.\n", cnt);
return -EFAULT;
}
page = (char*)__get_free_page(GFP_KERNEL);
if (!page)
{
printk(KERN_ALERT"Failed to alloc page.\n");
return -ENOMEM;
}
if (copy_from_user(page, ubuf, cnt))
{
printk(KERN_ALERT"Failed to copy buff from user.\n");
err = -EFAULT;
goto out;
}
err = __demo_set_val(demo_dev, page, cnt);
out:
free_page((unsigned long)page);
return err;
}
static const struct file_operations demo_proc_fops =
{
.open = demo_proc_open,
.write = demo_proc_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static ssize_t demo_val_show(struct device* dev, struct device_attribute* attr, char* buf);
static ssize_t demo_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, demo_val_show, demo_val_store);
// static struct device_attribute dev_attr_val = {
// .attr = {
// .name = "demo_val",
// .mode = 0666,
// },
// // .show = switch_usb_show,
// };
static int demo_open(struct inode* inode, struct file* filp)
{
struct demo_reg_dev* dev;
dev = container_of(inode->i_cdev, struct demo_reg_dev, dev);
filp->private_data = dev;
return 0;
}
static int demo_release(struct inode* inode, struct file* filp)
{
return 0;
}
static ssize_t demo_read(struct file* filp, char __user* buf, size_t count, loff_t* f_pos)
{
ssize_t err = 0;
struct demo_reg_dev* dev = filp->private_data;
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
if (count < sizeof(dev->val))
{
goto out;
}
if (copy_to_user(buf, &(dev->val), sizeof(dev->val)))
{
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
static ssize_t demo_write(struct file* filp, const char __user* buf, size_t count, loff_t* f_pos)
{
struct demo_reg_dev* dev = filp->private_data;
ssize_t err = 0;
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
if (count != sizeof(dev->val))
{
err = -EFAULT;
goto out;
}
if (copy_from_user(&(dev->val), buf, count))
{
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
static ssize_t __demo_get_val(struct demo_reg_dev* dev, char* buf)
{
int val = 0;
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
val = dev->val;
up(&(dev->sem));
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t demo_val_show(struct device* dev, struct device_attribute* attr, char* buf)
{
struct demo_reg_dev* hdev = (struct demo_reg_dev*)dev_get_drvdata(dev);
return __demo_get_val(hdev, buf);
}
static ssize_t demo_val_store(struct device*dev, struct device_attribute* attr, const char* buf, size_t count){
struct demo_reg_dev* hdev = (struct demo_reg_dev*)dev_get_drvdata(dev);
return __demo_set_val(hdev, buf, count);
}
static void demo_create_proc(void)
{
proc_create(DEMO_DEVICE_PROC_NAME, 0644, 0, &demo_proc_fops);
}
static void demo_remove_proc(void)
{
remove_proc_entry(DEMO_DEVICE_PROC_NAME, NULL);
}
static int __demo_setup_dev(struct demo_reg_dev* dev)
{
int err;
dev_t devno = MKDEV(demo_major, demo_minor);
memset(dev, 0, sizeof(struct demo_reg_dev));
cdev_init(&(dev->dev), &demo_fops); // 初始化dev, 绑定对应的fops
dev->dev.owner = THIS_MODULE;
dev->dev.ops = &demo_fops;
err = cdev_add(&(dev->dev), devno, 1); // 注册设备
if (err)
{
return err;
}
sema_init(&(dev->sem), 1); // 初始化信号量为互斥量
dev->val = 0;
return 0;
}
static int __init demo_init(void)
{
int err = -1;
dev_t dev = 0;
struct device* temp = NULL;
printk(KERN_ALERT"Initializing demo device.\n");
err = alloc_chrdev_region(&dev, 0, 1, DEMO_DEVICE_NODE_NAME); // 动态申请设备号,放入dev中
if (err < 0)
{
printk(KERN_ALERT"Failed to alloc char dev region.\n");
goto fail;
}
demo_major = MAJOR(dev); // 得到主设备号
demo_minor = MINOR(dev); // 得到次设备号
demo_dev = kmalloc(sizeof(struct demo_reg_dev), GFP_KERNEL); // 为结构体demo_reg_dev分配内核空间
if (!demo_dev)
{
err = -ENOMEM;
printk(KERN_ALERT"Failed to alloc demo device.\n");
goto unregister;
}
err = __demo_setup_dev(demo_dev); // cdev_init cdev_add
if (err)
{
printk(KERN_ALERT"Failed to setup demo device: %d.\n", err);
goto cleanup;
}
demo_class = class_create(THIS_MODULE, DEMO_DEVICE_CLASS_NAME); // 创建class注册到内核中
if (IS_ERR(demo_class))
{
err = PTR_ERR(demo_class);
printk(KERN_ALERT"Failed to create demo device class.\n");
goto destroy_cdev;
}
temp = device_create(demo_class, NULL, dev, NULL, "%s", DEMO_DEVICE_FILE_NAME);// //在/dev目录下生成demo的设备文件
if(IS_ERR(temp))
{
err = PTR_ERR(temp);
printk(KERN_ALERT"Failed to create demo device.\n");
goto destroy_class;
}
err = device_create_file(temp, &dev_attr_val); // 在/sys/class/xxx/xxx目录下创建属性文件val
if (err < 0)
{
printk(KERN_ALERT"Failed to create attribute val of demo device.\n");
goto destroy_device;
}
dev_set_drvdata(temp, demo_dev);
demo_create_proc();
printk(KERN_ALERT"Succedded to initialize demo device.\n");
return 0;
destroy_device:
device_destroy(demo_class, dev);
destroy_class:
class_destroy(demo_class);
destroy_cdev:
cdev_del(&(demo_dev->dev));
cleanup:
kfree(demo_dev);
unregister:
unregister_chrdev_region(MKDEV(demo_major, demo_minor), 1);
fail:
return err;
}
static void __exit demo_exit(void)
{
dev_t devno = MKDEV(demo_major, demo_minor);
printk(KERN_ALERT"Destroy demo device.\n");
demo_remove_proc(); // 1. remove proc
if (demo_class)
{
device_destroy(demo_class, MKDEV(demo_major, demo_minor)); // 2. device destroy
class_destroy(demo_class); // 3. class destroy
}
if (demo_dev)
{
cdev_del(&(demo_dev->dev)); // 4. delete cdev
kfree(demo_dev);
}
unregister_chrdev_region(devno, 1);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Demo Register Driver");
module_init(demo_init);
module_exit(demo_exit);
二、增加HAL层
1. 代码目录:
android/hardware/libhardware/include/hardware/demo.h
android/hardware/libhardware/modules/Android.mk
android/hardware/libhardware/modules/demo/Android.mk
android/hardware/libhardware/modules/demo/demo.cpp
android/system/core/rootdir/ueventd.rc
2. 代码
android/hardware/libhardware/include/hardware/demo.h
#ifndef ANDROID_INCLUDE_DEMO_H
#define ANDROID_INCLUDE_DEMO_H
#include <hardware/hardware.h>
__BEGIN_DECLS
/**
* The id of this module
*/
#define DEMO_HARDWARE_MODULE_ID "demo"
/**
* The id of this device
*/
#define DEMO_HARDWARE_DEVICE_ID "demo"
struct demo_module_t
{
hw_module_t common;
};
struct demo_device_t
{
struct hw_device_t common;
int fd;
int (*set_val)(struct demo_device_t* dev, int val);
int (*get_val)(struct demo_device_t* dev, int* val);
};
__END_DECLS
#endif
android/hardware/libhardware/modules/demo/demo.cpp
#define LOG_TAG "demoHALStub"
#include <hardware/hardware.h>
#include <hardware/demo.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <malloc.h>
#include <stdint.h>
#include <sys/time.h>
#include <system/audio.h>
#include <hardware/audio.h>
#define DEVICE_NAME "/dev/demo"
#define MODULE_NAME "HardwareDemo"
#define MODULE_AUTHOR "likai@qq.com"
static int demo_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
static int demo_device_close(struct hw_device_t* device);
static int demo_set_val(struct demo_device_t* dev, int val);
static int demo_get_val(struct demo_device_t* dev, int* val);
static struct hw_module_methods_t demo_module_methods =
{
.open = demo_device_open
};
struct demo_module_t HAL_MODULE_INFO_SYM =
{
.common =
{
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = DEMO_HARDWARE_MODULE_ID,
.name = MODULE_NAME,
.author = MODULE_AUTHOR,
.methods = &demo_module_methods,
}
};
static int demo_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device)
{
if (!strcmp(id, DEMO_HARDWARE_DEVICE_ID))
{
struct demo_device_t* dev;
dev = (struct demo_device_t*)malloc(sizeof(struct demo_device_t));
if (!dev)
{
ALOGE("Failed to alloc space for demo_device_t.");
return -EFAULT;
}
memset(dev, 0, sizeof(struct demo_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = demo_device_close;
dev->set_val = demo_set_val;
dev->get_val = demo_get_val;
if ((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1)
{
ALOGE("Failed to open device file /dev/demo --%s", strerror(errno));
free(dev);
return -EFAULT;
}
*device = &(dev->common);
ALOGI("Open device file /dev/demo successfully.");
return 0;
}
return -EFAULT;
}
static int demo_device_close(struct hw_device_t* device)
{
struct demo_device_t* demo_device = (struct demo_device_t*)device;
if (demo_device)
{
close(demo_device->fd);
free(demo_device);
}
return 0;
}
static int demo_set_val(struct demo_device_t* dev, int val)
{
if (!dev)
{
ALOGE("Null dev pointer. demo_set_val");
return -EFAULT;
}
ALOGI("Set val %d to device file /dev/demo.", val);
write(dev->fd, &val, sizeof(val));
return 0;
}
static int demo_get_val(struct demo_device_t* dev, int* val)
{
if (!dev)
{
ALOGE("Null dev pointer. demo_get_val");
return -EFAULT;
}
if (!val)
{
ALOGE("Null val pointer. demo_get_val");
return -EFAULT;
}
read(dev->fd, val, sizeof(*val));
ALOGI("Get value %d from device file.", *val);
return 0;
}
android/hardware/libhardware/modules/demo/Android.mk
LOCAL_PATH := $(call my-dir)
# HAL module implemenation stored in
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_MODULE := demo.$(TARGET_BOARD_PLATFORM)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
#LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_TAGS := debug
LOCAL_CFLAGS += -DQEMU_HARDWARE
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := demo.cpp
include $(BUILD_SHARED_LIBRARY)
android/hardware/libhardware/modules/Android.mk 中增加demo模块,非常重要。
三、增加JNI对HAL的访问
1. 文件目录
android/frameworks/base/services/core/jni/onload.cpp
android/frameworks/base/services/core/jni/Android.mk
android/frameworks/base/services/core/jni/com_android_server_DemoService.cpp
2. 代码
android/frameworks/base/services/core/jni/onload.cpp
int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
int register_dp_android_server_ActivityManagerService(JNIEnv* env);
int register_android_server_DemoService(JNIEnv* env); //增加这一行
};
@@ -92,6 +93,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_HardwarePropertiesManagerService(env);
register_dp_android_server_ActivityManagerService(env);
register_android_server_mcu(env);
register_android_server_DemoService(env); //增加这一行
return JNI_VERSION_1_4;
android/frameworks/base/services/core/jni/Android.mk
# 增加下面一行
LOCAL_SRC_FILES += \
...
$(LOCAL_REL_DIR)/com_android_server_DemoService.cpp \
...
android/frameworks/base/services/core/jni/com_android_server_DemoService.cpp
#define LOG_TAG "DemoService"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/demo.h>
#include <stdio.h>
namespace android
{
static void demo_setVal(JNIEnv* env, jobject jclazz, jint ptr, jint value)
{
demo_device_t* device = (demo_device_t*)ptr;
if (!device)
{
ALOGE("Device demo is not open. demo_setVal");
return;
}
int val = value;
ALOGI("Set value %d to device demo.", val);
device->set_val(device, val);
}
static jint demo_getVal(JNIEnv* env, jobject clazz, jint ptr)
{
demo_device_t* device = (demo_device_t*)ptr;
if (!device)
{
ALOGE("Device demo is not open. demo_getVal");
return 0;
}
int val = 0;
device->get_val(device, &val);
ALOGI("Get value %d from device demo.", val);
return val;
}
static inline int demo_device_open(const hw_module_t* module, struct demo_device_t** device)
{
return module->methods->open(module, DEMO_HARDWARE_DEVICE_ID, (struct hw_device_t**)device);
}
static jint demo_init(JNIEnv* env, jclass clazz)
{
demo_module_t* module;
demo_device_t* device;
ALOGI("Initializing HAL stub demo......");
if (hw_get_module(DEMO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0)
{
ALOGI("Device demo found.");
if (demo_device_open(&(module->common), &device) == 0)
{
ALOGI("Device demo is open.");
return (jint)device;
}
ALOGE("Failed to open device demo.");
return 0;
}
ALOGE("Failed to get HAL stub demo.");
return 0;
}
static const JNINativeMethod method_table[] =
{
{"init_native", "()I", (void*)demo_init},
{"setVal_native", "(II)V", (void*)demo_setVal},
{"getVal_native", "(I)I", (void*)demo_getVal},
};
int register_android_server_DemoService(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/server/DemoService", method_table, NELEM(method_table));
}
};
四、增加系统服务
1. 文件目录
android/frameworks/base/core/java/android/os/IDemoService.aidl
android/frameworks/base/services/core/java/com/android/server/DemoService.java
android/frameworks/base/services/java/com/android/server/SystemServer.java
android/frameworks/base/Android.mk
2. 代码
android/frameworks/base/core/java/android/os/IDemoService.aidl
package android.os;
interface IDemoService {
void setVal(int val);
int getVal();
}
android/frameworks/base/services/core/java/com/android/server/DemoService.java
package com.android.server;
import android.content.Context;
import android.os.IDemoService;
import android.util.Slog;
public final class DemoService extends IDemoService.Stub {
private static final String TAG = DemoService.class.getSimpleName();
private int mPtr = 0;
DemoService() {
mPtr = init_native();
if (mPtr == 0) {
Slog.e(TAG, "Fail to init IDemoService.");
}
}
public void setVal(int val) {
if (mPtr == 0) {
Slog.e(TAG, "IDemoService is not inited.");
}
setVal_native(mPtr, val);
}
public int getVal() {
if (mPtr == 0) {
Slog.e(TAG, "IDemoService is not inited.");
}
return getVal_native(mPtr);
}
private static native int init_native();
private static native void setVal_native(int ptr, int val);
private static native int getVal_native(int ptr);
}
android/frameworks/base/services/java/com/android/server/SystemServer.java
// 在启动其他服务增加启动DemoService代码
public final class SystemServer {
} catch (Throwable e) {
reportWtf("Notifying NetworkScoreService running", e);
}
+
+ try {
+ Slog.i(TAG, "Demo service");
+ ServiceManager.addService("demo", new DemoService());
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Demo service", e);
+ }
+
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
});
android/frameworks/base/Android.mk
# 增加aidl的编译
LOCAL_SRC_FILES += \
core/java/android/os/IUpdateLock.aidl \
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
+ core/java/android/os/IDemoService.aidl \
最后,需要进行api更新:make update-api
五、增加SELinux权限
修改文件:
modified: android/device/softwinner/common/sepolicy/device.te
modified: android/device/softwinner/common/sepolicy/domain.te
modified: android/device/softwinner/common/sepolicy/file_contexts
modified: android/device/softwinner/common/sepolicy/service.te
modified: android/device/softwinner/common/sepolicy/service_contexts
modified: android/device/softwinner/common/sepolicy/system_app.te
modified: android/device/softwinner/common/sepolicy/system_server.te
modified: android/device/softwinner/common/sepolicy/untrusted_app.te
android/device/softwinner/common/sepolicy/device.te
type demo_device, dev_type;
android/device/softwinner/common/sepolicy/domain.te
allow domain demo_device:chr_file rw_file_perms;
android/device/softwinner/common/sepolicy/file_contexts
/dev/demo u:object_r:demo_device:s0
android/device/softwinner/common/sepolicy/service.te
type demo_service, system_api_service, system_server_service, service_manager_type;
android/device/softwinner/common/sepolicy/service_contexts
demo u:object_r:demo_service:s0
android/device/softwinner/common/sepolicy/system_app.te
allow system_app demo_service:service_manager find;
android/device/softwinner/common/sepolicy/system_server.te
allow system_server demo_device:chr_file rw_file_perms;
android/device/softwinner/common/sepolicy/untrusted_app.te
allow untrusted_app demo_service:service_manager find;
六、增加应用访问
在应用中增加服务的访问测试代码:
IDemoService demoService = IDemoService.Stub.asInterface(ServiceManager.getService("demo"));
try {
int val = demoService.getVal();
Log.d(TAG, "val = " + val);
demoService.setVal(100);
val = demoService.getVal();
Log.d(TAG, "val = " + val);
} catch (Exception e) {
e.printStackTrace();
}
参考:业精于勤毁于嬉_行者常至,为者常成_优快云博客-Android,camera专题--MTK,MTK驱动总结领域博主