Android硬件访问服务 (硬核最终篇)
zhilu.zhang
zhilu.zhang
发布于 2020-02-08 / 76 阅读 / 0 评论 / 0 点赞

Android硬件访问服务 (硬核最终篇)

一、调用关系及流程简要

SystemService.java:(调库、启动服务)

1.System.loadLibbrary("android_servers");

  • libandroid_servers.so依赖jni文件夹下所有的com_android_server_xxx Service.cpp文件和onload.cpp文件。

  • System.loadLibbrary()函数会调用JNI_OnLoad()函数。JNI_OnLoad()函数在onload.cpp.

2.Slog.i(TAG,"xxx Service")。

3.xxx = new xxxService(context)。

4.ServiceManager.addService(“xxx”,xxx)。

onload.cpp:(实现native方法、获得env、找类)

1.JNI_OnLoad(Java* vm, void* /* reserver */)

  • 获得env,vm->GetEnv((void**) &env, JNI_VERSION_1_4) 。

  • 找类, JNI_OnLoad()函数调用一系列register_android_server_XXXService(env)函数,进行找类。

Com_android_server_XXXService.cpp:(为onload.cpp提供register_android_server_XXXService()

1.register_android_server_XXXService(env)函数进行找类。

  • jniRegisterNativeMethods(env, "com/android/server/xxxService",method_table, NELEM(method_table))

2.JNINativeMethod methods[],自定义native修饰的 java_ioctl函数对应的 c_ioctl方法。

com/android/server/xxxService.java:

1.实现xxxService类。

  • native static int java_ioctl(int which,int status)。声明native方法。

  • 实现IHelloService.aidl生成IHelloService.java的生成binder机制的接口led_ioctl。

hal.c:(硬件抽象层)

1.自定义一个led_device_t结构体。

  • 第一个成员为struct hw_device_t comm结构体实例。

2.定义一个struct led_device_t led_device实例。

  • 填充.hal_ioctl = led_hal_ioctl。

3.int led_open(const struct hw_module_t* module,const char* id,struct hw_device_t device)。**

4.struct hw_module_methods_t method。

5.struct hw_module_t HMI。

led_driver.c:(内核层驱动)

1.static struct file_operations fops。

2.static void __init。

3.static void __exit。

IHelloService.aidl:

1.package android.os。

2.interface xxxService。

  • int led_ioctl(int which,int status)。

3.在androidM/frameworks/base/Android.mk加一行

  • core/java/android/os/IHelloService.aidl \

IHelloService.java:

1.由aidl生成IHelloService.java

2.生成binder机制的接口。

  • public int led_ioctl(int which ,int status) throws android.os.RemoteException。

APP:

1.ServiceManager.getservice()。

2.IHelloService IHelloService.Stub.asInterface(Ibinder obj)。

二、编程示例

1.IHelloService.aidl:

package android.os;

/** {@hide} */
interface IHelloService
{
        int led_ioctrl(int which, int status);
}

修改IHelloService.aidl文件对应的Android.mk文件**添加一行:

core/java/android/os/IHelloService.aidl \

执行mm命令,由IHelloService.aidl文件自动生成IHelloService.java文件。

2.IHelloService.java:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: frameworks/base/./core/java/android/os/ILedService.aidl
 */
package android.os;
/** {@hide} */
public interface IHelloServiceextends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
// Stub供服务端实现
public static abstract class Stub extends android.os.Binder implements android.os.ILedService
{
// binder的唯一标识
private static final java.lang.String DESCRIPTOR = "android.os.ILedService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an android.os.IHelloServiceinterface,
 * generating a proxy if needed.
 */
 // 提供给客户端:将IBinder转化成IPlusService接口
public static android.os.IHelloServiceasInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
// 如果是客户端跟服务端同一个进程,直接返回server端的binder对象
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.os.ILedService))) {
return ((android.os.ILedService)iin);
}
// 若不同进程,则生成一个binder的代理
return new android.os.ILedService.Stub.Proxy(obj);
}
// 底层对应BBinder
@Override public android.os.IBinder asBinder()
{
return this;
}
// 运行在服务端:客户端调用transact(),会引发服务端onTransact()
// code 表示客户端请求方法标志
// data 表示参数
// reply 表示写入返回值
// 返回值:客户端请求结果,可以做权限控制
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_led_ioctrl:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
// 从Parcel读取客户端传过来的数据
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
// 调用服务端的led_ioctrl()
int _result = this.led_ioctrl(_arg0, _arg1);
reply.writeNoException();
// 写入返回给客户端的数据
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
// 客户端:服务的代理类
private static class Proxy implements android.os.ILedService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
// 底层对应 BinderProxy
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
// 客户端:打包数据,调用代理binder的transact(),会引发服务端transact()
@Override public int led_ioctrl(int which, int status) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(which);
_data.writeInt(status);
// 代理类,调用transact()
mRemote.transact(Stub.TRANSACTION_led_ioctrl, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_led_ioctrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
// 真正实现服务的地方
public int led_ioctrl(int which, int status) throws android.os.RemoteException;
}

4.HelloService.java:

package com.android.server;
/* 导入IHelloService.java的IHelloService */
import android.os.IHelloService;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Binder;
import android.os.ServiceManager;
import android.util.Slog;

/* 继承IHelloservice.aidl生成的IHelloservice.java中的类IHelloService */
public class HelloService extends IHelloService.Stub
{
    private static final String TAG = "HelloService";
        /* 构造函数中调用open函数 */
        HelloService(){
                Slog.d(TAG,"this is java_open HelloService");
                java_open();
        }
        /* 将IHelloService.aidl生成的IHelloService.java中的此函数实现 */
    public int led_ioctl(int which, int status) throws android.os.RemoteException;{
                Slog.d(TAG,"this is java_ioctl HelloService");
                java_ioctl(which,status);
                return 0;
        } 
        /* 声明native本地方法 */
        public native int java_open();
        public native java_ioctl(int which,int status);
}

5.SystemService.java:

在SystemService.java添加内容,修改。

/*
 * 1.System.loadLibrary
 * 2.启动服务new HelloSercice
 * 3.添加服务addservice
 */
 public final class SystemServer {
            /* Initialize native services. 
                 * 加载libandroid_servers.so文件。
                 * 此文件由众多com_android_server_xxx Service.cpp文件和一个onload.cpp文件编译得到
                 */
        System.loadLibrary("android_servers");
 }
 
/* 在startOtherServices方法中添加如下内容 */
private void startOtherServices() {
        final Context context = mSystemContext;
                /* 添加一行,定义HelloSercice的变量 */
        HelloSercice Hellop = null;
        
                traceBeginAndSlog("StartHelloService");
                /* 添加一行,new出来HelloSercice的对象,此时HelloSercice的构造函数会执行java_open函数 */
        Hellop = new VibratorService(context);
                /* 添加一行,添加服务,第一个参数服务名,第二个参数服务类的对象 */
        ServiceManager.addService("HelloSercice", Hellop);
        traceEnd();
}

6.com_android_server_HelloService.cpp:

#define LOG_TAG "HelloService"

#include <android/hardware/vibrator/1.0/types.h>
#include <android/hardware/vibrator/1.1/types.h>
#include <android/hardware/vibrator/1.2/IVibrator.h>
#include <android/hardware/vibrator/1.2/types.h>
#include <hardware/hardware.h>

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/vibrator.h>

#include <inttypes.h>
#include <stdio.h>

using android::hardware::Return;
using android::hardware::vibrator::V1_0::EffectStrength;
using android::hardware::vibrator::V1_0::Status;
using android::hardware::vibrator::V1_1::Effect_1_1;

namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_1 = android::hardware::vibrator::V1_1;
namespace V1_2 = android::hardware::vibrator::V1_2;

namespace android {
/* hal层自定义的结构体,第一个成员为hw_device_t */
struct led_device_t{
        struct hw_device_t comm;
        int (*hal_open)();
        int (*hal_ioctl)(int which,int status);
}
/* led_device结构体是hal层自己定义的,此结构体的第一个成员就是结构体就是hw_device_t 结构体 */
struct led_device *led;
jint c_open(JNIEnv *env, jobject self)
{
        /* 只有涉及native方法的jni转换设计的方法返回值和参数列表转换为jint,jchar等,其余的变量还应遵守c规则 */
        int ret;
        
        /* ********  hw_modile_t 结构体定义  ***********
                typedef struct hw_module_t {
                const char *id;   //id是stub的身份证号
                struct hw_module_methods_t* methods; //操作方法
        } hw_module_t;
         ********  hw_module_methods_t结构体定义  ***********
                 typedef struct hw_module_methods_t {

                int (*open)(const struct hw_module_t* module, const char* id,
                                struct hw_device_t** device);

        } hw_module_methods_t;
         *********  hw_device_t 结构体定义  ***********
                 typedef struct hw_device_t {

                struct hw_module_t* module;
                int (*close)(struct hw_device_t* device);
        } hw_device_t;
        */u
        struct hw_module_t * module;
        struct hw_device_t * device;
    ALOGI("this is c_open\n");uu
    /* 通过调用hw_get_module,传入id值“myled” 得到hw_module_t 结构体 module*/
        ret = hw_get_module("myled",(const struct hw_module_t **)&module);
        if(ret == 0)
        {
                /* hw_module_t 结构体的成员结构体methods的open函数返回一个hw_device_t结构体 */
                ret = module->methods->open(module,"myled",&device);
                if(ret == 0)
                {
                        /* 通过上面函数返回的hw_device_t结构体得到第一个成员hw_device_t 的指针。
                        *将hw_device_t 强转为led_device就得到自定义的led_device结构体的指针了,
                        *从而调用其自定义的hal_open()函数了。
                        */
                        led = (struct led_device *)device;
                        led->hal_open();
                }
        }
        return 0;
}
    
/*在jni.h头文件中定义的
typedef struct {
        char *name;       //java中的方法名
        char *signature;  //java中方法所对应的签名
        void *fnPtr;      //c函数的名字
} JNINativeMethod;
*/
static const JNINativeMethod method_table[] = {
    /* 准备为HelloService.java中native声明的java_open(),java_ioctl()
     * 与本文件com_android_server_HelloService.cpp的c_open(),c_ioctl()
     * 进行实现,并绑定,为注册做准备
     */
    { "java_open", "()I", (void*)c_open },
    { "java_ioctl", "(II)I", (void*)c_ioctl },

};
/* 在onload.cpp文件中调用此方法 */
int register_android_server_HelloService(JNIEnv *env)
{
        /* 注册方法函数,com/android/server/HelloService.java */
    return jniRegisterNativeMethods(env, "com/android/server/HelloService",
            method_table, NELEM(method_table));
}

};

7.onload.cpp:

在onload.cpp文件中添加函数声明和函数调用。

namespace android {
    /* 添加一行函数声明 */
    int register_android_server_HelloService(JNIEnv *env);
}
using namespace android;
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    /* 添加一行函数调用 */
    register_android_server_HelloService(env);
}

8.HelloService_HAL.c:

#define LOG_TAG "HelloService"
#include <cutils/log.h>
#include <hardware/hardware.h>
#include <sys/ioctl>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
/* com_android_server_HelloService.cpp复制定义该结构体 */
struct led_device_t{
        struct hw_device_t comm;
        int (*hal_open)();
        int (*hal_ioctl)(int which,int status);
        int (*hal_close)();
}
int fd;
int led_hal_open()
{
        ALOGI("this is led_hal_open");
    fd = open("dev/myled0",O_RDWR);
    if(fd == -1)
    {
        ALOGI("open /dev/led0 is failed");
    }
        return 0;
}
int led_hal_ioctl(int which,int status)
{
        ALOGI("this is led_hal_ioctl");
    ioctl(fd,which,status);
        return 0;
}
        
struct led_device_t led_device = {
        .hal_open = led_hal_open,
        .hal_ioctl = led_hal_ioctl,
}

int led_open(const struct hw_module_t* module,const char* id,struct hw_device_t** device)
{
        /* 在native函数中通过调用hw_get_module函数,根据传进去的id。
        *找到结构体 hw_module_t ,通过 hw_module_t 找到 hw_module_methods_t  。
        *调用 hw_module_methods_t 结构体中的 open 函数 。
        *open 函数得到hw_device_t 结构体。
        *led_device_t 结构体中第一个成员就是 hw_device_t 结构体。
        *所以将 led_device 强转 led_device_t 得到 led_device_t 结构体指针。
        *从而通过led_device_t结构体访问我们自己定义的led_hal_open,led_hal_ioctl,led_hal_close。
        */
        *device = (struct led_device_t *)&led_device;
        return 0;
}

struct hw_module_methods_t method = {
        .open = led_open,
}

/* 1.必须命名为HMI */
struct hw_module_t HMI = {
        .id = "myled",
        .methods = &method,
        
}

Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
#2.生成格式为:id.default.so
LOCAL_MODULE:=myled.default
#指定生成的.so文件存放的路径androidM/out/target/product/astar-fs733/system/lib/hw
LOCAL_MODULE_RELATIVE:= hw
LOCAL_SRC_FILES:=HelloService_HAL.c
#LOCAL_MODULE_PATH:=$(LOCAL_PATH)
#添加eng
LOCAL_SHARED_LIBRARIES:=liblog eng
include $(BUILD_SHARED_LIBARY)
#注意让上层Android.mk包含此文件

在ueventd.sun8i.rc文件中添加:

/dev/myled0            0777           system            system

解决权限问题。

9.应用程序MainActivity.java

package com.company.led_service_app;

import android.os.Bundle;
import android.widget.ImageButton;
import android.app.Activity;

public class MainActivity extends Activity {
        private ImageButton button;
        private boolean status = false;
        
        /* 我们的IHelloService类由IHelloService.aidl文件生成IHelloService.java中
        * 在androidM/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classe.jar
        * 的库中存在我们的IHelloService类
           */
        IHelloService Service;
        
        @override
        protected void onCreate (Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                
                /* ServiceManager.getservice("HelloSercice")获取服务
                 * 但是其返回值为IBinder类型
                 * 在IHelloService.aidl文件生成IHelloService.java中有一个方法用于转换
                 * IHelloService IHelloService.Stub.asInterface(Ibinder obj)
                    */                        
                Service = IHelloService.Stub.asInterface(ServiceManager.getservice("HelloSercice"));
                
                ImageButton button = (ImageButton) findViewByID(R.id.imagebutton);
                button.setOnClickListener(new OnclickListener()){
                        @override
                        public void onClick(View v) {
                                status =! status;
                                if(status){
                                        /* 这里就可以调用IHelloService.aidl文件生成
                                         * Ibinder机制的IHelloService.java中声明
                                         * 在HelloService.java实现中的函数led_ioctl()
                                         */
                                        service.led_ioctl(1,1);
                                }else{
                                        service.led_ioctl(1,0);
                                }
                        }
                        
                }
        }
}