• Android HAL技术详解


    本人喜欢用代码+伪代码的方式写笔记。文中的花括号可能是方便记录而已。

    如:

    hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
    {
        问:怎么获得模块信息的?
        答:hardware\libhardware\Hardware.c

        ...........

    }

    原创分析, 转载请注明出处:http://www.cnblogs.com/langlang/

    作者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, 0sizeof(*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 == 31break;
                                    }
                                }
                            }
                            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) 
    {
        charconst 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);
        {
            charconst 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;
            }
        }
    }

  • 相关阅读:
    Eclipse修改背景颜色(豆沙绿)
    项目导入时报错:The import javax.servlet.http.HttpServletRequest cannot be resolved
    jdk1.7 环境变量配置
    Maven的安装、配置及使用入门
    tomcat端口作用
    《Maven实战》
    Maven 详解
    遍历Map的四种方法
    遍历properties文件
    题库终结
  • 原文地址:https://www.cnblogs.com/langlang/p/2454217.html
Copyright © 2020-2023  润新知