Chinaunix首页 | 论坛 | 博客
  • 博客访问: 201457
  • 博文数量: 37
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 375
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-23 21:00
个人简介

潜心静气。。慢慢出成果

文章分类

全部博文(37)

文章存档

2018年(5)

2017年(6)

2016年(23)

2015年(3)

我的朋友

分类: Android平台

2018-05-25 11:09:56

这里的思路依然是从应用到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的权限问题了

这里的inogpioservicecontext的定义。

./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;

而后进入到JNIC++世界,这里依然简单,

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 有关

这里的ioctlread write的操作都是一个寄存器的操作。

不再啰嗦

进入到设备树看看


        innopro_gpio{

                compatible = "amlogic, innopro_gpio";

                dev_name = "innopro_gpio";

                status = "okay";

                ao6_pins = <&gpio GPIOAO_6 0>;

                ao6_name = "GPIOAO_6";

                ao6_value = <1 1="">;

                ao9_pins = <&gpio GPIOAO_9 0>;

                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,默认,privateprotect 问题

private 只能被类内使用,protect子类访问,default在包内使用,public都可以使用。


阅读(2988) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~