博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android个层次调用流程概述
阅读量:5914 次
发布时间:2019-06-19

本文共 13126 字,大约阅读时间需要 43 分钟。

Android的硬件抽象层:

        简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。

        也就是说,把对硬件的支持分成了两层,

               一层放在用户空间(User Space),(硬件抽象层)

               一层放在内核空间(Kernel Space),(Linux内核驱动程序)

 

下面这个图阐述了硬件抽象层在Android系统中的位置,以及它和其它层的关系:

二,简单的总结

进入到Android源代码工程的external目录,创建hello目录:

cd external

mkdir hello

 

在hello目录中新建Android.mk文件:

      LOCAL_PATH := $(call my-dir)

      include $(CLEAR_VARS)

      LOCAL_MODULE_TAGS := optional

      LOCAL_MODULE := hello

      LOCAL_SRC_FILES := $(call all-subdir-c-files)

      include $(BUILD_EXECUTABLE)

注意,BUILD_EXECUTABLE表示我们要编译的是可执行程序。 

 

使用mmm命令进行编译:

      mmm ./external/hello

      编译成功后,就可以在out/target/product/gerneric/system/bin目录下,看到可执行文件hello了。

 

重新打包Android系统文件system.img:

      make snod

      这样,重新打包后的system.img文件就包含刚才编译好的hello可执行文件了。

 

      七. 运行模拟器,使用/system/bin/hello可执行程序来访问Linux内核驱动程序。

      emulator -kernel ./kernel/common/arch/arm/boot/zImage &

      adb shell

           cd system/bin

          ./hello

 ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------

 三,编写硬件抽象层

       进入到在hardware/libhardware/include/hardware目录,新建hello.h文件:

 

      cd hardware/libhardware/include/hardware

      vi hello.h

      hello.h文件的内容如下:

 

#ifndef ANDROID_HELLO_INTERFACE_H

#define ANDROID_HELLO_INTERFACE_H

#include <hardware/hardware.h>

__BEGIN_DECLS

 

/*定义模块ID*/

#define HELLO_HARDWARE_MODULE_ID  "hello"

 

/*硬件模块结构体*/

struct hello_module_t {

      struct   hw_module_t   common;

};

 

/*硬件接口结构体*/

struct hello_device_t {

      struct hw_device_t   common;

      int fd;         // 设备文件描述符

      int (*set_val)(struct hello_device_t* dev, int val);        // 为该HAL对上提供的函数接口

      int (*get_val)(struct hello_device_t* dev, int* val);

};

__END_DECLS

#endif

 

 

进入到hardware/libhardware/modules目录,新建hello目录,并添加hello.c文件。 hello.c的内容较多,我们分段来看。

      首先是包含相关头文件和定义相关结构:

 

#define LOG_TAG "HelloStub"  

#include <hardware/hardware.h>  

#include <hardware/hello.h>  

#include <fcntl.h>  

#include <errno.h>  

#include <cutils/log.h>  

#include <cutils/atomic.h>  

  

#define DEVICE_NAME            "/dev/hello"  

#define MODULE_NAME          "Hello"  

#define MODULE_AUTHOR     "shyluo@gmail.com"  

  

/*设备打开和关闭接口*/  

static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  

static int hello_device_close(struct hw_device_t* device);  

  

/*设备访问接口*/  

static int hello_set_val(struct hello_device_t* dev, int val);  

static int hello_get_val(struct hello_device_t* dev, int* val);  

  

/*模块方法表*/  

static struct    hw_module_methods_t    hello_module_methods = {  

    open: hello_device_open  

};  

  

/*模块实例变量*/  

struct   hello_module_t    HAL_MODULE_INFO_SYM = {  

    common: {  

        tag: HARDWARE_MODULE_TAG,  

        version_major: 1,  

        version_minor: 0,  

        id: HELLO_HARDWARE_MODULE_ID,  

        name: MODULE_NAME,  

        author: MODULE_AUTHOR,  

        methods: &hello_module_methods,  

    }  

};  

 <Android硬件抽象层规范规定>

      实例变量名必须为HAL_MODULE_INFO_SYM

      tag也必须为HARDWARE_MODULE_TAG

 

 

定义hello_device_open函数:

static int  hello_device_open ( const struct hw_module_t* module,   const char* name,   struct hw_device_t** device ) {  

     struct hello_device_t * dev;

     dev  =  (struct hello_device_t*)malloc(sizeof(struct hello_device_t));  

    if(!dev) {  

        LOGE("Hello Stub: failed to alloc space");  

        return -EFAULT;  

    }  

  

    memset(dev, 0, sizeof(struct hello_device_t));  

    dev->common.tag             = HARDWARE_DEVICE_TAG;  

    dev->common.version      = 0;  

    dev->common.module      = (hw_module_t*)module;  

    dev->common.close         = hello_device_close;  

    dev->set_val                    = hello_set_val;

    dev->get_val                    = hello_get_val;  

  

    if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  

        LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev);  

        return -EFAULT;  

    }  

    *device = &(dev->common);  

    LOGI("Hello Stub: open /dev/hello successfully.");  

    return 0;  

}  

  

 

定义hello_device_close、hello_set_val和hello_get_val这三个函数:

static int   hello_device_close (struct hw_device_t* device) {  

    struct hello_device_t *  hello_device = (struct hello_device_t*)device;  

    if(hello_device) {  

        close(hello_device->fd);  

        free(hello_device);  

    }  

    return 0;  

}  

  

static int  hello_set_val(struct hello_device_t* dev, int val) {  

    LOGI("Hello Stub: set value %d to device.", val);  

    write(dev->fd, &val, sizeof(val));  

    return 0;  

}  

  

static int hello_get_val(struct hello_device_t* dev, int* val) {  

    if(!val) {  

        LOGE("Hello Stub: error val pointer");  

        return -EFAULT;  

    }  

    read(dev->fd, val, sizeof(*val));  

    LOGI("Hello Stub: get value %d from device", *val);  

  

    return 0;  

}  

 

 

继续在hello目录下新建Android.mk文件:

      LOCAL_PATH := $(call my-dir)

      include $(CLEAR_VARS)

      LOCAL_MODULE_TAGS := optional

      LOCAL_PRELINK_MODULE := false

      LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw

      LOCAL_SHARED_LIBRARIES := liblog

      LOCAL_SRC_FILES := hello.c

      LOCAL_MODULE := hello.default

      include $(BUILD_SHARED_LIBRARY)

      注意,LOCAL_MODULE的定义规则,hello后面跟有default,hello.default能够保证我们的模块总能被硬象抽象层加载到。

编译:

      mmm hardware/libhardware/modules/hello

      编译成功后,就可以在out/target/product/generic/system/lib/hw目录下看到hello.default.so文件了。

重新打包Android系统镜像system.img:

      make snod

      重新打包后,system.img就包含我们定义的硬件抽象层模块hello.default了。

      虽然我们在Android系统为我们自己的硬件增加了一个硬件抽象层模块,但是现在Java应用程序还不能访问到我们的硬件。

      我们还必须编写JNI方法和在Android的Application Frameworks层增加API接口,才能让上层Application访问我们的硬件。

  ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------

四:JNI方法

如何为Android硬件抽象层接口编写JNI方法,以便使得上层的Java应用程序能够使用下层提供的硬件服务。

 

      一. 确保Android系统镜像文件system.img已经包含hello.default模块。

      二. 进入到frameworks/base/services/jni目录,新建com_android_server_HelloService.cpp文件:

      cd frameworks/base/services/jni

      vi com_android_server_HelloService.cpp

 

      com_android_server前缀表示的是包名,表示硬件服务HelloService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloService的类。

 

首先是包含相应的头文件:

 #define LOG_TAG "HelloService"  

#include "jni.h"  

#include "JNIHelp.h"  

#include "android_runtime/AndroidRuntime.h"  

#include <utils/misc.h>  

#include <utils/Log.h>  

#include <hardware/hardware.h>  

#include <hardware/hello.h>  

#include <stdio.h>  

/* 接着定义hello_init、hello_getVal和hello_setVal三个JNI方法:*/ 

 namespace android  

{  

    /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/ 

        struct hello_device_t*  hello_device = NULL;  

    /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/  

        static void hello_setVal (JNIEnv* env,   jobject clazz,   jint value) {  

        int val = value;  

        LOGI("Hello JNI: set value %d to device.", val);  

        if(!hello_device) {  

            LOGI("Hello JNI: device is not open.");  

            return;  

        }  

        hello_device->set_val(hello_device, val);          // 在抽象层的open中定义

    }  

       /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/  

    static jint hello_getVal(JNIEnv* env,   jobject clazz) {

   

        int val = 0;  

        if(!hello_device) {  

            LOGI("Hello JNI: device is not open.");  

            return val;  

        }  

        hello_device->get_val(hello_device, &val);  

        LOGI("Hello JNI: get value %d from device.", val);  

        return val;  

    }  

       /*通过硬件抽象层定义的硬件模块打开接口  打开硬件设备*/  

    static inline int  hello_device_open (const hw_module_t* module, struct hello_device_t** device) {  

        return  module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);  

    }  

        /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/  

    static jboolean  hello_init (JNIEnv* env, jclass clazz) {

  

        hello_module_t* module;  

          

        LOGI("Hello JNI: initializing......");  

            /* 加载模块ID为HELLO_HARDWARE_MODULE_ID的硬件抽象层模块,  Android硬件抽象层会根据HELLO_HARDWARE_MODULE_ID的值

             * 在Android系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回hw_module_t接口给调用者使用。

             */

        if ( hw_get_module HELLO_HARDWARE_MODULE_ID,   (const struct hw_module_t**)&module ) == 0 )  {

  

            LOGI("Hello JNI: hello Stub found.");  

            if(hello_device_open(&(module->common), &hello_device) == 0) {  

                LOGI("Hello JNI: hello device is open.");  

                return 0;  

            }  

            LOGE("Hello JNI: failed to open hello device.");  

            return -1;  

       }  

        LOGE("Hello JNI: failed to get hello stub module.");  

        return -1;        

   } 

       /*JNI方法表*/  

    static const   JNINativeMethod   method_table[ ] = {  

        {"init_native",           "()Z",          (void*)hello_init},  

        {"setVal_native",     "(I)V",         (void*)hello_setVal},  

        {"getVal_native",      "()I",          (void*)hello_getVal},  

    };  

        /*注册JNI方法*/  

    int  register_android_server_HelloService(JNIEnv *env) {  

            return  jniRegisterNativeMethods(env,   "com/android/server/HelloService",   method_table,   NELEM(method_table) );  

                                                                                 // 必须对应HelloService所在的包的路径

    }  

};  

      

在Android系统初始化时,使其自动加载该JNI方法调用表

----------------------------------------------------------------------------

      修改同目录下的onload.cpp文件,

      (1)在namespace android增加 register_android_server_HelloService函数声明:

 

      namespace android {

      ..............................................................................................

      int  register_android_server_HelloService(JNIEnv *env);

      };

 

      (2)在JNI_onLoad 增加 register_android_server_HelloService函数调用:

      extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)

      {

       .................................................................................................

       register_android_server_HelloService(env);

       .................................................................................................

      }

 

      (3)修改同目录下的Android.mk文件,在 LOCAL_SRC_FILES变量 中增加一行:

     LOCAL_SRC_FILES:= \

      com_android_server_AlarmManagerService.cpp \

      com_android_server_BatteryService.cpp \

      com_android_server_InputManager.cpp \

      com_android_server_LightsService.cpp \

      com_android_server_PowerManagerService.cpp \

      com_android_server_SystemServer.cpp \

      com_android_server_UsbService.cpp \

      com_android_server_VibratorService.cpp \

      com_android_server_location_GpsLocationProvider.cpp \

      com_android_server_HelloService.cpp /

      onload.cpp

       最后编译

      mmm frameworks/base/services/jni

      make snod

      这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI方法了,

      我们可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件了。

 五:提供Java访问硬件服务接口

         Linux内核层、硬件抽象层和运行时库层提供的自定义硬件服务接口,这些接口都是通过C或者C++语言来实现的。

         以下,我们将介绍如何在Android系统的Application Frameworks层提供Java接口的硬件服务。

 

(为什么用代理?)

        在Android系统中,硬件服务一般是运行在一个独立的进程中为各种应用程序提供服务。因此,调用这些硬件服务的应用程序与这些硬件服务之间的通信需要通过代理来进行。为此,我们要先定义好通信接口。

(1)进入到frameworks/base/core/java/android/os目录,新增IHelloService.aidl接口定义文件:

      cd   frameworks/base/core/java/android/os

      vi    IHelloService.aidl

 

IHelloService.aidl定义了IHelloService接口:

      package android.os;  

      interface  IHelloService{  

          void setVal (int val);  

          int    getVal ( );  

      }  

该接口主要提供了设备获取硬件寄存器val的值的功能,分别通过setVal和getVal两个函数来实现。

 

(2)返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloService.aidl源文件: 

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

 

(3)编译IHelloService.aidl接口:

    mmm frameworks/base

   这样,就会根据IHelloService.aidl生成相应的IHelloService.Stub接口。

 

(4)进入到frameworks/base/services/java/com/android/server目录,新增HelloService.java文件:

package com.android.server;  

import android.content.Context;  

import android.os.IHelloService;  

import android.util.Slog;  

public class HelloService extends  IHelloService Stub {  

    private static final String TAG = "HelloService";  

    HelloService() {  

        init_native();  

    }  

    public void  setVal(int val) {  

        setVal_native(val);  

    }     

    public int  getVal() {  

        return getVal_native();  

    }  

     /* HelloService主要是通过调用JNI方法init_native、setVal_native和getVal_native来提供硬件服务 */

    private static native boolean   init_native();  

    private static native void         setVal_native(int val);  

    private static native int            getVal_native();  

};  

 (5)  修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载HelloService的代码:

 

     @Override

     public void run() {

     ....................................................................................

            try {

                  Slog.i(TAG, "Hello Service");

                  ServiceManager. addService("hello", new HelloService());

            } catch (Throwable e) {

                  Slog.e(TAG, "Failure starting Hello Service", e);

            }

     ......................................................................................

     }      

 

(6)编译HelloService和重新打包system.img:

 

     mmm frameworks/base/services/java

     make snod

 

     这样,重新打包后的system.img系统镜像文件就在Application Frameworks层中包含了我们自定义的硬件服务HelloService了,并且会在系统启动的时候,自动加载HelloService。

     这时,应用程序就可以通过Java接口来访问Hello硬件服务了。

  ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------

六:Java调用实例

public class Hello extends Activityimplements OnClickListener {  

   private final static String LOG_TAG ="shy.luo.renju.Hello";  

     

   private IHelloService helloService = null;  

 

   private EditText valueText = null; 

   private Button readButton = null; 

   private Button writeButton = null; 

   private Button clearButton = null; 

     

   /** Called when the activity is first created. */  

   @Override  

   public void onCreate(Bundle savedInstanceState) {  

       super.onCreate(savedInstanceState); 

       setContentView(R.layout.main);  

                 // IHelloService接口定义在android.os.IHelloService中,

   helloService= IHelloService.Stub.asInterface(    // 转换为IHelloService接口

       ServiceManager.getService("hello"));  // 获得HelloService

                               // 服务名字“hello”是系统启动时加载HelloService时指定

       valueText = (EditText)findViewById(R.id.edit_value);  

       readButton = (Button)findViewById(R.id.button_read);  

       writeButton = (Button)findViewById(R.id.button_write);  

       clearButton = (Button)findViewById(R.id.button_clear);  

 

   readButton.setOnClickListener(this); 

   writeButton.setOnClickListener(this); 

   clearButton.setOnClickListener(this); 

         

       Log.i(LOG_TAG, "Hello Activity Created");  

   }  

     

   @Override  

   public void onClick(View v) {  

       if(v.equals(readButton)) {  

       try {  

                int val =helloService.getVal();  

                String text = String.valueOf(val);  

                valueText.setText(text);  

       } catch (RemoteException e) {  

            Log.e(LOG_TAG, "RemoteException while reading value from device.");  

       }         

       }  

       else if(v.equals(writeButton)) {  

       try {  

                String text =valueText.getText().toString();  

                int val =Integer.parseInt(text);  

           helloService.setVal(val);  

       } catch (RemoteException e) {  

            Log.e(LOG_TAG, "RemoteException while writing value to device.");  

       }  

       }  

       else if(v.equals(clearButton)) {  

            String text = "";  

            valueText.setText(text);  

       }  

   }  

本文转载于:

转载于:https://www.cnblogs.com/ouyangpeng/archive/2013/03/26/8538473.html

你可能感兴趣的文章
linux中grep命令
查看>>
H3C模拟器 DHCP Snooping 、中继 实例配置
查看>>
以太坊构建DApps系列教程(二):构建TNS代币
查看>>
sed工具的使用
查看>>
数据仓库工程师、大数据开发工程师、BI工程师、ETL工程师之间有什么区别?...
查看>>
JVM初识-java类加载器
查看>>
对比各类分布式锁缺陷,抓住Redis分布式锁实现命门
查看>>
设置typeid后织梦currentstyle 不起作用的修复方法
查看>>
AndroidManifest.xml解析
查看>>
linux下磁盘分区详解
查看>>
利用iptables屏蔽IP段
查看>>
Oracle动态采样详解
查看>>
APUE读书笔记-03文件输入输出(4)
查看>>
linux系统中top命令输出详解
查看>>
cURL: Learning..
查看>>
540. Single Element in a Sorted Array(有序数组的 Single Element)(leetcode)
查看>>
Python输入输出练习,运算练习,turtle初步练习
查看>>
Codeforces Round #219 (Div. 1) A. Counting Kangaroos is Fun 【二分】
查看>>
Html基础
查看>>
wiki----为用户设置管理员权限
查看>>