Android个层次调用流程概述

简介: Android的硬件抽象层:         简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。         也就是说,把对硬件的支持分成了两层,                一层放在用户空间(User...

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");

                  ServiceManageraddService("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);  

       }  

   }  



本文转载于:http://blog.chinaunix.net/uid-25150360-id-3180053.html

相关文章
|
2月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
84 6
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
2月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
28 3
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
25 2
|
2月前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
39 3
|
2月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
18 0
|
3月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
50 4
|
3月前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
53 0
|
4月前
|
Android开发
我的Android进阶修炼:安卓启动流程之init(1)
本文深入分析了Android系统中的init进程,包括其源码结构、主要功能以及启动流程的详细注解,旨在帮助读者理解init作为用户空间的1号进程在Android启动过程中的关键作用。
70 1
|
3月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
153 0