第一部分: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; } } } |
|
来自: dwlinux_gs > 《Android HAL/JNI》