本人喜欢用代码+伪代码的方式写笔记。文中的花括号可能是方便记录而已。
如:
hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
{
问:怎么获得模块信息的?
答:hardware\libhardware\Hardware.c
...........
}
作者email:
dayhappyhappy@163.com第一部分: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_on(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方法的实现过程
frameworks\base\services\forlinx_led_server\server\LedService.java
复制代码- 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;
- }
- }
- }
|
[ 此帖被alan加油在2012-04-22 15:55重新编辑 ]