Android HAL技术详解

第一部分:HAL层
hardware\led\include\Led.h
定义常见数据结构
struct led_module_t {
   struct hw_module_t common;
};

struct led_control_device_t { 
   struct hw_device_t common;  /*表示硬件设备*/
   /* 属性 */
   int fd;
   /* 提供出来的方法 */
   int (*set_on)(struct led_control_device_t *dev, int32_t led);
   int (*set_off)(struct led_control_device_t *dev, int32_t led);
};

nstruct led_control_context_t {
 struct led_control_device_t device;
};


hardware\led\led\Led.cpp 分析

static int led_device_open(const struct hw_module_t* module, const char* name,
        struct hw_device_t** device)
{
 struct led_control_device_t *dev;
 /* 分配设备 */
 dev = (struct led_control_device_t *)malloc(sizeof(*dev));
 memset(dev, 0, sizeof(*dev));

 dev->common.tag =  HARDWARE_DEVICE_TAG;
 dev->common.version = 0;
 dev->common.module = (struct hw_module_t*)module;  /*设置是属于哪个模块 */
 dev->common.close = led_device_close;
 
 dev->set_on = led_on{ 
  /*自定义方法*/
  int led_off(struct led_control_device_t *dev, int32_t led)
  {
   ioctl(g_fd, 0, led); //led on
  }
 }
 dev->set_off = led_off; /*自定义方法*/

 *device = &dev->common;
 /*
 /dev/leds0 内核驱动的device_create创建的
 假如打开设备时候发生:Hello Stub: failed to open /dev/leds0 -- Permission denied.
 进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:
     /dev/hello 0666 root leds0
 */
     g_fd = open("/dev/leds0", 0);
 return 0;
}

/*模块方法表*/ 
static struct hw_module_methods_t led_module_methods = {
    open: led_device_open
};
/* 
 模块信息
 实例变量名必须为HAL_MODULE_INFO_SYM,
 tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的。
*/
extern "C" ① const struct led_module_t HAL_MODULE_INFO_SYM = {
    common: {
        tag: HARDWARE_MODULE_TAG, 
        version_major: 1,
        version_minor: 0,
        id: LED_HARDWARE_MODULE_ID,
        name: "Sample LED Stub",
        author: "The Forlinx Open Source Project",
        methods: &led_module_methods,  /*设置方法  */
    }
    /* supporting APIs go here */
};

① extern "C" :C++编写的代码片段可能被使用在其它语言编写的代码中。不同语言编写的代码互相调用是困难的。
为了使它们遵守统一规则,可以使用extern指定一个编译和连接规约。extern "C"指令中的C,表示的一种编译和连接规约,
而不是一种语言。C表示符合C语言的编译和连接规约的任何语言。


第二层: JNI  层次编写
frameworks\base\services\forlinx_led_jni\LedService.cpp
struct led_control_device_t *sLedDevice = NULL;//硬件设备的公告属性和方法
//方法描述
gMethods[] = {
    { "_init",    "()Z", (void *)forlinx_init {
  jboolean forlinx_init(JNIEnv *env, jclass clazz)
  {
   led_module_t* module;
   hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
   {
    问:怎么获得模块信息的?
    答:hardware\libhardware\Hardware.c
    hw_get_module(const char *id, const struct hw_module_t **module)
    {
     char prop[PATH_MAX];
     char path[PATH_MAX];
     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++)
     {
      property_get(variant_keys[i], prop, NULL)
      {
       问: variant_keys的数据是什么?
       答: static const char *variant_keys[] = {
        "ro.hardware", 
        "ro.product.board",
        "ro.board.platform",
        "ro.arch"
       };
       问:ro.hardware代表的值是什么?
       答: system\core\init\init.c
       set_init_properties_action(int nargs, char **args)
        property_set("ro.hardware", hardware)
       get_hardware_name(char *hardware, unsigned int *revision)
       {
        //该函数在int main(int argc, char **argv)中被调用
        fd = open("/proc/cpuinfo", O_RDONLY);
        hw = strstr(data, "\nHardware");
        while (*x && !isspace(*x)) {
         hardware[n++] = tolower(*x);
         x++;
         if (n == 31) break;
        }
       }
      }
      snprintf(path, sizeof(path), "%s/%s.%s.so",HAL_LIBRARY_PATH1, id, prop);
      {
       #define HAL_LIBRARY_PATH1 "/system/lib/hw"
      }
     }
     status = load(id, path, module); /* 调用load函数打开动态链接库 */
    }
    led_control_open(&module->common, &sLedDevice)
    {
     led_control_open(const struct hw_module_t* module,struct led_control_device_t** device) {
      return module->methods->open(module,LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
     }
    }
   }
  }
 }},
    { "_set_on",        "(I)Z", (void *)forlinx_setOn
  {
    sLedDevice->set_on(sLedDevice, led);//sLedDevice:硬件设备的公告属性和方法
  }
 },
    { "_set_off",       "(I)Z", (void *)forlinx_setOff
  {
   sLedDevice->set_off(sLedDevice, led);
  }
 },
}

int register_forlinx_server_LedService(JNIEnv* env)
{
 char* const kClassName ="forlinx_led_server/server/LedService";
    /* look up the class */
    jclass clazz = env->FindClass(kClassName);
 /* 注册方法
 java类: forlinx_led_server/server/LedService
 方法描述: gMethods
 */
 env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); //gMethods 方法描述数组
}


简单的Jni 例子都是映射模式,及对应的Jni 的c/c++ 实现需要,
被java的函数命名规则限制死,为了解决这类毛病,引入的JNI_OnLoad这类方法。
jint JNI_OnLoad(JavaVM* vm, void* reserved)
该方法在Jni so 被加载时调用。
当VM释放该组件时会呼叫JNI_OnUnload()函数
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("GetEnv failed!");
        return result;
    }
    register_forlinx_server_LedService(env);
 {
  char* const kClassName ="forlinx_led_server/server/LedService";
 }
    return JNI_VERSION_1_4;
}

第三层: Application Frameworks层增加硬件访问服务
1 接口文件指定
frameworks\base\Android.mk 指定接口文件
{
 LOCAL_SRC_FILES += \
 core/java/android/forlinx/ILedService.aidl \
}
2 接口定义 frameworks\base\core\java\android\forlinx\ILedService.aidl
package android.forlinx;
interface ILedService
{
    boolean setOn(int led);
    boolean setOff(int led);
}
3 实现类 
第一种方法:直接调用service方法的实现过程
import android.forlinx.ILedService;
public final class LedService  extends ILedService.Stub {
 //先与构造函数执行
    static
    {
        System.load("/system/lib/libforlinx_runtime.so"); //路径是怎么确定的?
    }  
    public LedService() {
      _init();
    }
    public boolean setOn(int led)
    {
  return _set_on(led);
    }

    public boolean setOff(int led) {
  return _set_off(led);
    }

    private static native boolean _init();
    private static native boolean _set_on(int led);
    private static native boolean _set_off(int led);
}
第二种方法:经过Manager调用service 
为什么要这样做?
LedManager代理者模式,LedSystemServer单例模式
(1):添加服务 packages\apps\forlinxled\src\com\led\LedSystemServer.java
import forlinx_led_server.server.LedService;
public class LedSystemServer extends Service {
    @Override
    public IBinder onBind(Intent intent) { return null;}
    public void onStart(Intent intent, int startId) {
        if(ServiceManager.getService("led") == null) //单例模式
        {
     LedService ls = new LedService();
           ServiceManager.addService("led", ls);
        }
    }
}
由Manager充当代理  代理模式
frameworks\base\core\java\android\forlinx\LedManager.java
public class LedManager
{
    private static final String TAG = "LedManager";
    private ILedService mLedService;

    public LedManager() {
        mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
    }

    public boolean LedOn(int n) {
        boolean result = false;
        if (mLedService == null) //try
        {
           mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
        }
        if(mLedService != null)
        {
          result = mLedService.setOn(n);
        }
        return result;
    }

    public boolean LedOff(int n) {
        boolean result = false;
        try {
              if (mLedService == null) //try
              {
                mLedService = ILedService.Stub.asInterface(
                ServiceManager.getService("led"));
              }
             if(mLedService != null)
             {
               Log.i(TAG, "The LedManager object will set off");
               result = mLedService.setOff(n);
             }

        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
        }
        return result;
    }
}

 

4 测试程序 第一种方法:直接调用service方法的实现过程
import android.widget.TextView;

public class LedClient extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Call an API on the library.
  LedService ls = new LedService();
  ls.setOn(0);
  ls.setOn(1);
  ls.setOn(2);
  ls.setOn(3);
        TextView tv = new TextView(this);
        tv.setText("All Leds On");
        setContentView(tv);
    }
}
第二种方法:经过Manager调用service。HAL、JNI两层和第一种方法一样。

public class LedTest extends Activity implements OnClickListener {
 
 private LedManager mLedManager = null;
 private Button btnLED1On;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        // Start LedService in a seperated process.
        startService(new Intent("com.led.systemserver"));
       
  // Get LedManager.
        if (mLedManager == null)
        {
        mLedManager = new LedManager();
        }
     btnLED1On = (Button)findViewById(R.id.btnLED1On);
     btnLED1On.setOnClickListener(this);
    }
   
 public void onClick(View v) {
  switch (v.getId()) {
   case R.id.btnLED1On:
    if (mLedManager != null)
    {
     mLedManager.LedOn(0);
    }
    break;
   default:
    break;
  }
 }
}

原创分析, 转载请著名出处:http://dayhappyhappy.blog.163.com/
作者email: dayhppyhappy@163.com

posted @ 2012-04-17 19:31  朗笑江湖  阅读(243)  评论(0编辑  收藏  举报