這里的思路依然是從應用到drivers編寫,只是貼出來重點部分。
import android.app.InoGpioManager;
((InoGpioManager) context.getSystemService(Context.INOGPIO_SERVICE)).ioctl(cmd,val);
InoGpioManager.java的編寫:
public class InoGpioManager
{
private final IInoGpioManager mService;
InoGpioManager(IInoGpioManager service, Context ctx)
{
mService = sevice;
}
......
然后這里定義常用的API即可,
}
IInoGpioManager.aidl
package android.app;
interface IInoGpioManager{
int write_val(in int[] val,int size);
int[] read_val(int size);
int ioctl_val(int cmd,int val);
}
在這里需要把文件添加到Framework/base/Android.mk
LOCAL_SRC_FILES +=
core/java/android/app/IInoGpioManager.aidl \
一定要一次添加正確,防止出問題,后期找文件刪除
這里啰嗦一句,
aidl_files := \
這里添加的都是類似這種文件
parcelable AlarmManager.AlarmClockInfo;
這種的aidl文件
SystemServiceRegistry.java里如下注冊
registerService(Context.INOGPIO_SERVICE, InoGpioManager.class,
new CachedServiceFetcher() {
@Override
public InoGpioManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.INOGPIO_SERVICE);
IInoGpioManager service = IInoGpioManager.Stub.asInterface(b);
return new InoGpioManager(service, ctx);
}});
此時此刻進入到
InoGpioService.java
這里多說一句,如果按照老羅的寫法,此時此刻應該是
public class InoGpioService extends IInoGpioManager.stub
但是呢他的aidl文件實在Android.os下,我們這里的寫的是Android.app下,最后應用也不一樣
public class InoGpioService extends SystemService
{
這里的寫法更簡單,一個構造函數用來初始化init
再加幾個API,不在啰嗦
}
這里需要在systemserver.java中進行注冊
traceBeginAndSlog("StartInoGpioService");
mSystemServiceManager.startService(InoGpioService.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
使用這種時,可以在onStart里加入
publishBinderService(Context.ALARM_SERVICE, mService);
public void onStart()
{
final IBinder mService = new IInoGpioManager.Stub();
publishBinderService(Context.INOGPIO_SERVICE,mService);
}
這次就栽在這里。
/*try {
Slog.i(TAG,"InoGpioService +1");
ServiceManager.addService(Context.INOGPIO_SERVICE,new InoGpioService());
Slog.i(TAG,"InoGpioService +2 ");
} catch (Throwable e) {
Slog.e(TAG,"InoGpioService new error",e);
}*/
這里的兩種方式都是可以的,
兩種方式的差異如下:
public class InoGpioService extends SystemService {
這里采用的是匿名內部類,函數接口都是定義在匿名內部類的內部,
private final IBinder mb = new IInoGpioManager.Stub() {
這里只能是函數,不能是單個句子。
//public class InoGpioService extends IInoGpioManager.Stub {
這種方式的API都是直接定義,不需要定義在匿名匿名內部類的。
然而INOGPIO_SERVICE這個的定義在Context.java中
此時此刻要修改SELinux的權限問題了
這里的inogpio是service的context的定義。
./app.te:allow untrusted_app inogpio_service:service_manager find;
./service_contexts:inogpio ?????????????????????????????u:object_r:inogpio_service:s0
./service.te:type inogpio_service, ???service_manager_type;
./system_app.te:allow system_app inogpio_service:service_manager find;
./system_server.te:allow system_server inogpio_service:service_manager find;
./system_server.te:allow system_server inogpio_service:service_manager add;
而后進入到JNI的C++世界,這里依然簡單,
register_android_server_InoGpioService
這個再onload.cpp里添加
在當前目錄的Android.mk也要添加
static const JNINativeMethod method_table[] = {
{ "init_native" , "()Z" , (void*)init_native},
{ "writeval_native" , "([II)I" , (void*)writeval_native},
{ "readval_native" , "(I)[I" , (void*)readval_native},
{ "ioctlval_native" , "(II)I" ,(void*)ioctlval_native},
};
static jboolean init_native(JNIEnv *env,jobject clazz)
struct innopro_gpio_module_t *module;
if((hw_get_module(INOGPIO_HARDWARE_MODULE_ID,(const struct hw_module_t **)&module) == 0)){
if(device_open(&(module->common),&gpio_device) == 0){
ALOGI("open the device success");
return 0;
}
這里只是寫了一個init的接口,其他的接口類似
還有就是進入到hardware層,但是hardware層可以不寫,直接在JNI里實現open read write ioctl
還是寫一下的吧,權當練手
#define INOGPIO_HARDWARE_MODULE_ID "inogpio"
struct inogpio_module_t{
struct hw_module_t common;
};
struct inogpio_device_t{
struct hw_device_t common;
int fd;
int (*read_val)(struct inogpio_device_t *dev, int *val,int size);
int (*write_val)(struct inogpio_device_t *dev, int *val,int size);
int (*ioctl_val)(struct inogpio_device_t *dev,int cmd, int val);
};
struct inogpio_module_t HAL_MODULE_INFO_SYM={
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = INOGPIO_HARDWARE_MODULE_ID,
.name = "innopro gpio Module",
.author = "zwh",
.methods = &inogpio_module_methods,
},
};
static struct hw_module_methods_t inogpio_module_methods = {
.open = open_inogpio,
};
static int open_inogpio(const struct hw_module_t *module, char const *name, struct hw_device_t **device)
{
struct inogpio_device_t *dev = malloc(sizeof(struct inogpio_device_t));
ALOGI("name ++ ++ ?= %s",name);
if(dev == NULL){
ALOGE("fail to malloc the device space");
return -1;
}
memset(dev,0,sizeof(struct innogpio_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct hw_module_t *)module;
dev->common.close = close_inogpio;
dev->read_val = read_val;
dev->write_val = write_val;
dev->ioctl_val = ioctl_val;
dev->fd = open(DEV_NAME,O_RDWR);
if(dev->fd == -1){
ALOGE("open the /dev/innopro_gpio fail");
free(dev);
return -1;
}
*device = &(dev->common);
ALOGI("innopro_device open successfuly");
return 0;
}
類似這種風格,其他的按照ioctl 等操作即可
進入到kernel的世界
static const struct of_device_id gpio_dt_match[] = {
{ .compatible = "amlogic, innopro_gpio"},
{},
};
設備樹在dts里的定義
tatic struct platform_driver gpio_driver = {
.driver = {
.name = "innopro_gpio",
.owner = THIS_MODULE,
.of_match_table = gpio_dt_match,
},
.probe = gpio_probe,
#ifdef CONFIG_PM
.suspend = gpio_suspend,
.resume = gpio_resume,
#endif
.shutdown = gpio_shutdown,
};
static __init ?int innopro_init(void)
ret = platform_driver_register(&gpio_driver);
static int gpio_probe(struct platform_device *pdev)
{
int ret = -1;
pr_info("probe\n");
aml_gpio_dt_parse(pdev);
gpio_dev.cdev_.owner = THIS_MODULE;
cdev_init(&(gpio_dev.cdev_), &gpio_ops);
alloc_chrdev_region(&(gpio_dev.devno), 0, 1,
gpio_dev.dev_name);
ret = cdev_add(&(gpio_dev.cdev_), gpio_dev.devno, 1);
if (ret) {
pr_info("cdev_add fail\n");
return ?-EINVAL;
}
if (IS_ERR(gpio_dev.class_)) {
pr_info("Create class error\n");
return -1;
}
device_create(gpio_dev.class_, NULL, gpio_dev.devno,
NULL, gpio_dev.dev_name);
return 0;
}
設備樹的產生還與那句fuck the ARM Linux 有關
這里的ioctl和read write的操作都是一個寄存器的操作。
不再啰嗦
進入到設備樹看看
innopro_gpio{
compatible = "amlogic, innopro_gpio";
dev_name = "innopro_gpio";
status = "okay";
ao6_pins = ;
ao6_name = "GPIOAO_6";
ao6_value = <1 1="">;
ao9_pins = ;
ao9_name = "GPIOAO_9";
ao9_value = <0 1="">;
};
如此而已,這里只是啰嗦大致的寫的流程,代碼細節不做啰嗦。細節都跑通了,其他也就容易的多了。
這里嘟囔幾句曾經遇到而且反復犯的錯誤,
問題一:uboot的編程,
編譯方式:在uboot的目錄下,./mk gxl_p212_v1
生成目錄:/uboot/fip
那么問題來了,為什么打包成aml*.img時,不能自動更新呢?那就是出在不能自動拷貝了,所以需要自動拷貝下,如下目錄out/target/product/p212/upgrade
問題二:修改完或者加入hardware時,并不能自動編譯,需要先mmm hardware時才能繼續打包
問題三:aidl問題,
aidl開始放錯問題,需要把生成的out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app
類似目錄的文件刪掉,然后繼續打包,否則也會打包進去,我覺得這里非常不智能,沒辦法做到刪除不相干文件。
問題四:函數的public,默認,private,protect問題
private 只能被類內使用,protect子類訪問,default在包內使用,public都可以使用。