Hardware-javaaplication.

eg:hello
一:Hardware
 //作用,向系统申请设备号,设备节点实体化file_operations,cdv
 struct cdev{
                 dev_t dev; 
  };
        
 static struct file_operations hello_ops={
  .owner = THIS_MODULE,
  .ioctl = hello_ioctl,
  .read  = hello_read,
  .write = hello_write,
  .open  = hello_open,
  ......
 };
 
 static __init xxx_init()   模块加载函数
 {
 }
 static __exit xxx_exit() 模块卸载函数
 {
 }
  module_init(hello_init);
  module_exit(hello_exit);
二:HAL
 /*
 Android硬件抽象层规范的要求,
 分别定义模块ID、模块结构体以及硬件接口结构体。
 在硬件接口结构体中,fd表示设备文件描述符,对应我们将要处理的设备文件"/dev/hello",
 set_val和get_val为该HAL对上提供的函数接口。
 __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); 
     int (*get_val)(struct hello_device_t* dev, int* val); 
 };
 /*设备打开和关闭接口*/ 
 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, 
     } 
 }; 
 //这里,实例变量名必须为HAL_MODULE_INFO_SYM,tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的 
 
 //定义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;                                                                                             
 }
 //DEVICE_NAME定义为"/dev/hello"。由于设备文件是在内核驱动里面通过device_create创建的,
 //而device_create创建的设备文件默认只有root用户可读写,而hello_device_open一般是由上层APP来调用的,
 //这些APP一般不具有root权限,这时候就导致打开设备文件失败  
 //解决办法是类似于Linux的udev规则,打开Android源代码工程目录下,进入到system/core/rootdir目录,
 //里面有一个名为ueventd.rc文件,往里面添加一行:                                                                                                         
 /dev/hello 0666 root root   
 //定义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;                                                           
 }  
三:JNI
 /*
 Android的Application Frameworks层提供硬件服务
 Java应用程序通过JNI来调用硬件抽象层接口
 准备好硬件抽象层模块,确保Android系统镜像文件system.img已经包含hello.default模块。
 二. 进入到frameworks/base/services/jni目录,新建com_android_server_HelloService.cpp文件:
 在com_android_server_HelloService.cpp文件中,实现JNI方法。注意文件的命令方法,com_android_server前缀表示的是包名,表示硬件服务HelloService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloService的类。这里,我们暂时略去HelloService类的描述,在下一篇文章中,我们将回到HelloService类来。简单地说,HelloService是一个提供Java接口的硬件访问服务类。
  接着定义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);
  }
         /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器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......");
   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));
  }
 };
       注意,在hello_init函数中,通过Android硬件抽象层提供的hw_get_module方法来加载模块ID为HELLO_HARDWARE_MODULE_ID的硬件抽象层模块,其中,HELLO_HARDWARE_MODULE_ID是在<hardware/hello.h>中定义的。Android硬件抽象层会根据HELLO_HARDWARE_MODULE_ID的值在Android系统的/system/lib/hw目录中找到相应的模块,然后加载起来,并且返回hw_module_t接口给调用者使用。在jniRegisterNativeMethods函数中,第二个参数的值必须对应HelloService所在的包的路径,即com.android.server.HelloService。
 
       三. 修改同目录下的onload.cpp文件,首先在namespace android增加register_android_server_HelloService函数声明:
 
       namespace android {
 
       ..............................................................................................
 
       int register_android_server_HelloService(JNIEnv *env);
 
       };
 
       在JNI_onLoad增加register_android_server_HelloService函数调用:
       extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)
       {
        .................................................................................................
        register_android_server_HelloService(env);
        .................................................................................................
       }
       这样,在Android系统初始化时,就会自动加载该JNI方法调用表。
       四. 修改同目录下的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
       五. 编译和重新找亿system.img:
      
USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base/services/jni
      
USER-NAME@MACHINE-NAME:~/Android$ make snod
       这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI方法了,也就是我们可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件了。前面提到,在这篇文章中,我们暂时忽略了HelloService类的实现,在下一篇文章中,我们将描述如何实现硬件服务HelloService,敬请关注。
四:java Frameworks
 /*
 一:
 我们要先定义好通信接口。进入到frameworks/base/core/java/android/os目录
 新增IHelloService.aidl接口定义文件:
 IHelloService接口主要提供了设备和获取硬件寄存器val的值的功能,分别通过setVal和getVal两个函数来实现。
 eg
 */
 package android.os;
 interface IHelloService {
     void setVal(int val);
     int getVal();
 }
 
 /*
 二
 返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloService.aidl源文件:
 eg
 */
 core/java/android/os/IHelloService.aidl /
 /*
 三
 编译IHelloService.aidl接口:
 
USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base
 这样,就会根据IHelloService.aidl生成相应的IHelloService.Stub接口。
 */
 /*
 四
 .进入到frameworks/base/services/java/com/android/server目录,新增HelloService.java文件:
 HelloService主要是通过调用JNI方法init_native、setVal_native和getVal_native
 (见在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供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();
  }
  
  private static native boolean init_native();
      private static native void setVal_native(int val);
  private static native int getVal_native();
 };
 /*
 五. 修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载HelloService的代码:
 */
  try {
 
                   Slog.i(TAG, "Hello Service");
 
                   ServiceManager.addService("hello", new HelloService());
 
             } catch (Throwable e) {
 
                   Slog.e(TAG, "Failure starting Hello Service", e);
 
             }
 /*
 七. 编译HelloService和重新打包system.img:
 
     
USER-NAME@MACHINE-NAME:~/Android$ mmm frameworks/base/services/java
 
     
USER-NAME@MACHINE-NAME:~/Android$ make snod
 
      这样,重新打包后的system.img系统镜像文件就在Application Frameworks层中包含了我们自定义的硬件服务HelloService了,并且会在系统启动的时候,自动加载HelloService。这时,应用程序就可以通过Java接口来访问Hello硬件服务了。我们将在下一篇文章中描述如何编写一个Java应用程序来调用这个HelloService接口来访问硬件,敬请期待。
 
 
 */

五:Application
 /*
 我们将在Android系统的应用层增加一个内置的应用程序,
 这个内置的应用程序通过ServiceManager接口获取指定的服务,然后通过这个服务来获得硬件服务。
 */
 package shy.luo.hello;
 
 import shy.luo.hello.R;
 import android.app.Activity;
 import android.os.ServiceManager;
 import android.os.Bundle;
 import android.os.IHelloService;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.EditText;
 
 public class Hello extends Activity implements 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);
 
  helloService = IHelloService.Stub.asInterface(
   ServiceManager.getService("hello"));
        
         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, "Remote Exception 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, "Remote Exception while writing value to device.");
   }
      }
      else if(v.equals(clearButton)) {
       String text = "";
       valueText.setText(text);
      }
     }
 }
 /*
 程序通过ServiceManager.getService("hello")来获得HelloService,
 接着通过IHelloService.Stub.asInterface函数转换为IHelloService接口。
 其中,服务名字“hello”是系统启动时加载HelloService时指定的,
 而IHelloService接口定义在android.os.IHelloService中,
 具体可以参考在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务一文。
 这个程序提供了简单的读定自定义硬件有寄存器val的值的功能,
 通过IHelloService.getVal和IHelloService.setVal两个接口实现。
 */
 ServiceManager.addService("hello", new HelloService());
 ServiceManager.getService("hello")
 public class HelloService extends IHelloService.Stub {}
 
 helloService = IHelloService.Stub.asInterface(
   ServiceManager.getService("hello"));
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值