android系统按键从linux到java流程.doc_第1页
android系统按键从linux到java流程.doc_第2页
android系统按键从linux到java流程.doc_第3页
android系统按键从linux到java流程.doc_第4页
android系统按键从linux到java流程.doc_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

android系统按键从linux到java流程概述: android系统的键值转换,从linux到java共经历3个层次,分别是: 1 linux系统层,原始ir键值读取,转变为linux层键值 2 framework层,linux层键值转换为android键值 3 framework层,android键值上报java层 关系图:linux层:原始ir键值读取,转变为linux层键值framework层:linux层键值转换为android键值framework层:android键值上报java层最终输出:framework层:phonewindowmanger.javainterceptKeyBeforeQueueing()interceptKeyBeforeDispatch ing()dev/vinputInputManagerInputReaderThreadInputDispatcherThreadgetevents()mapkey()dev/input剩余疑问:dev/vinput和dev/input之间到底怎么关联的 目前没查到这二者是怎么关联的,但是从用户组可以看出,vinput应该是input的输入。 猜测:这二者之间类似一个软连接处理,避免键值读写都在同一个文件,在不同进程之间造成数据异常;二者由系统负责同步。 后续查到相关资料再补充.1 原始ir键值读取,转变为linux层键值 核心输入: 系统启动android_ir_user后台进程 核心输出: 虚拟设备dev/vinput,写入linux键值1.1 流程图系统启动android_ir_user后台进程,执行ir_user.cpp的main入口 keyarry键值全局数组 原始键读取线程ir_sample_threadkey_pars.c:提供 get_keycode接口,解析key.xml,结合linux_key.h,建立原始码值和linux层键值的映射数组调用get_keycodekeyarry:桥梁输出dev/vinput:读取原始码值,根据keyarry转换为linux层键值,通过ReportKeyEvent写入虚拟设备dev/vinput设备,其他进程再从这读取linux键值key.xml:定义原始硬件码值和对应linux层通用键名: linux_key.h:定义linux层通用键名和linux层键值的对应关系KEY_MUTE,113KEY_MUTE:桥梁1.2转换流程详细说明:1.2.1/device/hisilicon/bigfish/system/ir_user/key_pars/key.xml:该文件编译后输出到/etc目录下。定义原始硬件码值和对应linux层通用键名: 1.2.2/device/hisilicon/bigfish/system/ir_user/key_pars/linux_key.h:定义linux层通用键名和linux层键值的对应关系: KEY_MUTE,113 ,结构linux_keycode_ary类型的数组Linux_KeyCode_Ary512.1.2.3/device/hisilicon/bigfish/system/ir_user/key_pars/ key_pars.c:提供接口get_keycode解析xml建立原始码值和linux层键值的映射数组get_keycode(_key_arry *keyarry, int keyarry_num)解析:a:调用readXml读取/etc/ key.xml,返回xml根节点: key.xml中和分别各一个节点,我们的遥控器原始键值配置在中。b:调用Pars_Key解析每个节点下的所有按键: 解析节点下的所有children节点,通过value属性获取xml定义的原始键值,通过name属性获取xml定义的键名字符串,再调用find_linux_key_code查询这个字符串对应的linux层键值。 把这个映射关系存储到: keyarry-hi_keycodekeynum.ir_keycode = ir_keycode; keyarry-hi_keycodekeynum.linux_keycode = linux_keycode;c: find_linux_key_code函数遍历在linux_key.h定义的Linux_KeyCode_Ary数组,找到参数str(即键名字符串)对应的linux层键值。1.2.4/device/hisilicon/bigfish/system/ir_user/ir_user.cpp:1)编译为后台进程android_ir_user独立运行;2)进程启动,执行main入口函数,调用get_keycode完成key.xml存储原始码值和linux层键值的映射关系到数组keyarry;3)建立ir_sample_thread线程读取原始码值,根据keyarry转换为linux层键值,通过ReportKeyEvent写入dev/vinput设备,其他进程可以读取键值1.3总结 出差拷机,如果不想其他厂家操作我们的盒子,只需要离开的时候删除/system/bin下面的android_ir_user这个bin文件即可。2 linux层键值转换为android键值 核心输入: /dev/input, 输入linux键值 核心输出: 1)getEvents(),输出RawEvent* buffer,存储linux层键值; 2)mapKey(),将linux层键值转换为android键值 2.1流程图EventHub.cpp:1 getEvents() 2 mapKey()1)建立linux层键值到android键值 2)读取/dev/input设备上的的映射集合map 键值到RawEvent* buffer Keyboard.cpp:定位linux到android键第一转换映射文件为Vendor_0001_Product_0001.klKeyLayoutMap.cpp:1)解析Vendor_0001_Product_0001.kl,并结合KeycodeLabels.h最终建立里建立linux层键值到android键值 的映射集合map2)提供mapKeyVendor_0001_Product_0001.kl:定义linux键值和对应的键名字符串key 113 MUTEKeycodeLabels.h:定义键名字符串和android的java层键值对应关系结构数组KEYCODES: MUTE, 91 getEvents():,输出RawEvent* buffermapKey(): 将linux层键值转换为android键值 2.2详细说明2.2.1 /device/hisilicon/bigfish/prebuilts/Vendor_0001_Product_0001.kl: 定义linux键值和对应的键名字符串 key 113 MUTE2.2.2 /frameworks/native/include/input/KeycodeLabels.h 定义键名字符串和android的java层键值对应关系结构数组KEYCODES: MUTE, 91 2.2.3frameworksnativelibsinput Keyboard.cpp 提供函数loadKeyLayout和getPath,定位linux到android键第一转换映射文件为Vendor_0001_Product_0001.kl: 提供函数getKeyCodeByLabel,从KeycodeLabels.h的KEYCODES数组中,查询返回android的java键值。2.2.4frameworksnativelibsinput KeyLayoutMap.cpp 提供函数load和parse等解析Vendor_0001_Product_0001.kl,并调用Keyboard.cpp的getKeyCodeByLabel,通过“linux键值-键名字符串-android的java层键值”的直接建立“linux键值- android的java层键值”map集合; 提供函数mapKey基于此集合供上层转换linux键值为android的java键值2.2.5 frameworksbaseservicesinputEventHub.cpp 1 提供getEvents,完成两个事: 1):建立linux键值- android的java层键值”map集合。 2):扫描linux键值,存储到参数RawEvent* buffer。 2 提供mapKey,调用KeyLayoutMap.cpp的mapKey函数,完成转换linux键值为android的java键值。2.2.6关于建立linux键值- android的java层键值”map集合,代码流程: 1)frameworksbaseservicesinputEventHub.cpp a)getEvents()- scanDevicesLocked(): b)scanDevicesLocked- scanDirLocked(): static const char *DEVICE_PATH = /dev/input; c)scanDirLocked()-openDeviceLocked() d) openDeviceLocked()-loadKeyMapLocked() e) loadKeyMapLocked调用Keyboard.cpp下load()函数: 2)frameworksnativelibsinput Keyboard.cpp f) load()-probeKeyMap(): g) probeKeyMap ()-loadKeyLayout(): h) loadKeyLayout()-getPath(): 这里才确定path为:./system/usr/keylayout/Vendor_0001_Product_0001.kl 再继续调用KeyLayoutMap:load加载并解析 3) frameworksnativelibsinput KeyLayoutMap.cpp i) load()-parse() j) parse ()-parseKey() 解析Vendor_0001_Product_0001.kl得到linux层code,再调用getKeyCodeByLabel查询code对应的android层键值keyCode将两个键值存入map集合到此完成linux层键值到android的java层键值的转换并存储为map集合;后面真正扫描到 linux键值后,调用mapKey根据存储的map集成转换为android键值进行上报。2.3总结: 这个部分可以看出,其完全是个中间过程,如果我们要修改某个键在android的表现,完全不用改这其中相关的任何文件,只需要在java层(后面会讲到,keyevent.java)对收到的android键进行再转换即可。 3 Android键值上报java层核心输入 : eventhub.cpp的getEvents()和mapkey()核心输出:PhoneWindowManager.java的interceptKeyBeforeQueueing和 interceptKeyBeforeDispatching3.1流程图 太多,省略.3.2详细说明3.2.1frameworksbaseservicesinputInputReader.cpp 该文件主要负责: linux按键的读取; 转换为android键值; 通过listener启动按键上报,注意这里仅仅是启动按键上报。1)InputReader 类构造函数InputReader两个极其重要的参数: eventHub和listener,前者用来读取linux键值,后者用来分发上报按键。说明: 参数eventHub,赋值给变量mEventHub;listener作为参数创建了mQueuedListener。2) loopOnce函数及其调用的一连串函数 调用mEventHub-getEvents读取linux按键到RawEvent 类型的mEventBuffer成员变量; 调用processEventsLocked分发上报。3)重点阐述processEventsLocked是如何分发上报按键的: a)processEventsLocked调用processEventsForDeviceLockedb) processEventsForDeviceLocked从InputReader 的(InputDevice类型)变量mDevices变量中找出当前对应的device,调用其processc) process调用InputDevice的变量(InputMapper类型)mMappers的process函数d)这里的mapper是KeyboardInputMapper类 这里process开始调用eventhub类的mapKey()启动参数rawEvent中的linux键值scanCode的转换,变为android键值keyCode,继续调用processKey上传.e) processKey调用 getListener()-notifyKey(&args); 完成键值上报到其他模块 注意这里的getListener就是取得inputreader类初始化时用参数“const sp& listener”初始化的mQueuedListener。到这里,inputread.cpp模块的按键分发上报全部完成,后续只要搞清楚sp& listener”到底是谁,就知道按键分发到哪里去了。4)阐述按键分发中的关键衔接一环: 上述C)步的mMappers是如何和KeyboardInputMapper关联的? 为什么KeyboardInputMapper的getListener()是inputreader的mQueuedListener?仍然是从loopOnce 调用processEventsLocked开始:a) processEventsLocked找不到按键rawEvents的设备来源时调用addDeviceLocked: b) addDeviceLocked调用createDeviceLocked: (所以上面第3)点钟的B)步能找到有效的device)c) createDeviceLocked调用device-addMapper 到这里就完成了inputreadr-inputdevice-mappers的关联.getListener的来源: InputReader构造函数用参数sp& listener创建了mQueuedListener对象实例,mQueuedListener是InputReader的成员变量; mContext也是InputReader对象的成员,其类型是InputReader的内部类ContextImpl,该类继承自InputReaderContext,ContextImpl的getListener函数直接返回mQueuedListener。 createDeviceLocked在 添加inputdevice设备时,使用mContext转换为InputReaderContext作为参数创建了device,直接赋值给inpudevice的成员变量mContext。 createDeviceLocked继续addMapper创建了KeyboardInputMapper实例,即(new KeyboardInputMapper(device, keyboardSource, keyboardType); device用于创建InputMapper对象,device的mContext成员赋值给InputMapper的mContext;KeyboardInputMapper又继承自InputMapper。 所以KeyboardInputMapper的成员mContext等价于InputReader的mContext;getListener等价于调用InputReader的mContext-getListener即mQueuedListener。5)InputReaderThread线程类 构造函数InputReaderThread使用InputReader 类对象作为参数,赋值给变量mReader。 threadLoop方法中调用mReader-loopOnce();只要创建了InputReader实例,并以此启动InputReaderThread线程,就会反复mEventHub-getEvents读键和调用processEventsLocked分发上报。3.2.2frameworksbaseservicesinputInputDispatcher.cpp该文件是真正的按键数据上报的起点,InputReader中的listener实际就是这个InputDispatcher,该类继承自接口InputDispatcherInterface。完成3个事情: interceptKeyBeforeQueueing,按键入列前的截获处理 interceptKeyBeforeDispatching,按键从队列分发上层app前的截获处理 startDispatchCycleLocked,完成按键最终分发上报1)InputDispatcher类 a)构造函数以参数policy直接初始化成员变量mpolicy。 b) notifyKey函数被之前的inputreader调用,notifyKey调用interceptKeyBeforeQueueing 进行第一次按键上报,供上层截获按键,在按键被压入队列前进行必要的处理,如设置,桌面等在keyfuntion.xml中配置的快捷键,或待机键等的处理。 到这里完成按键进入Queue队列前的上报处理,如果interceptKeyBeforeQueueing没有处理这个按键,将会继续调用步骤c)。c) enqueueInboundEventLocked将按键结构参数entry压入队列 d) InputDispatcherThread线程类不断循环,检测到队列中的按键 InputDispatcherThread调用InputDispatcher的dispatchOnce。e) dispatchOnce调用dispatchOnceInnerLockedf) dispatchOnceInnerLocked调用dispatchKeyLockedg) dispatchKeyLocked调用doInterceptKeyBeforeDispatchingLockedInterruptibleh) doInterceptKeyBeforeDispatchingLockedInterruptible调用mPolicy-interceptKeyBeforeDispatching 到这里完成进入队列的按键在上报app前的截获处理,比如特殊处理home键,添加工装菜单的按键调用等,如果这些按键仍然没被截获,将继续进行分发,继续下面的步骤i).i) dispatchKeyLocked调用addMonitoringTargetsLocked,获取所有上层注册过需要按键的channel,创建目标通道集合inputTargets; 继续调用dispatchEventLocked开始按键分发。j) dispatchEventLocked对每一个通道获取其connection,再调用prepareDispatchCycleLockedk) prepareDispatchCycleLocked调用enqueueDispatchEntriesLockedl) enqueueDispatchEntriesLocked调用enqueueDispatchEntryLocked把按键eventEntry和目标通道inputTarget写入connection 再调用startDispatchCycleLocked开始分发m) startDispatchCycleLocked调用connection-inputPublisher.publishKeyEvent完成最终分发按键。2)InputDispatcherThread线程类构造函数InputDispatcherThread使用InputDispatcherInterface类对象作为参数,赋值给变量mDispatcher。 threadLoop方法中调用mDispatcher-dispatchOnce();只要创建了mDispatcher实例,并以此启动InputReaderThread线程,就会反复mDispatcher-dispatchOnce(),完成按键分发。3.2.3 frameworksbaseservicesinputInputManager.cpp该文件负责启动前面阐述的InputReader和InputDispatcher。1)创建InputReader和InputDispatcher实例,初始化到mDispatcher和mReader。2)创建InputReaderThread和InputDispatcherThread两个线程3)启动线程循环运行start3.2.4 frameworksbaseservicesjnicom_android_server_input_InputManagerService.cpp(InputManagerService.java的JNI)1)nativeInit()调用NativeInputManager(),后者调用new InputManager(eventHub, this, this);完成创建InputManager对象的实例mInputManager。/ NativeInputManager 是多重继承,其父类之一为虚类InputDispatcherPolicyInterface,所以最后一个this参数实际就是NativeInputManager自己; InputManager运行InputDispatcher,后者调用的interceptKeyBeforeQueueing和interceptKeyBeforeDispatching 实际就是NativeInputManager的同名函数。 也就是说从JNI初始化InputManager,启动InputReader和InputDispatcher,而InputDispatcher最终回调JNI的interceptKeyBeforeQueueing和interceptKeyBeforeDispatching完成按键截获处理。2)nativeStart调用mInputManager的start启动两个线程InputReaderThread和InputDispatcherThread.3) NativeInputManager的interceptKeyBeforeQueueing调用java层interceptKeyBeforeQueueing4)NativeInputManager的interceptKeyBeforeDispatching调用java层interceptKeyBeforeDispatching5)register_android_server_InputManager将interceptKeyBeforeQueueing和interceptKeyBeforeDispatching,与InputManagerService.java的同名函数进行关联3.2.5 frameworksbaseservicesjavacomandroidserverinput InputManagerService.java:1)构造函数InputManagerService()调用JNI函数nativeInit();2)interceptKeyBeforeQueueing()调用WindowManagerCallbacks的interceptKeyBeforeQueueing方法继续上抛按键; interceptKeyBeforeDispatching同理。3)WindowManagerCallbacks是内部类,mWindowManagerCallbacks是成员变量,通过setWindowManagerCallbacks()方法设置。4)start方法调用nativeStart,这里实现调用InputManager的start,启动mDispatcherThread和mReaderThread两个线程。3.2.6 frameworksbaseservicesjavacomandroidserver SystemServer.javainitAndLoop ()启动InputManagerService这里的setWindowManagerCallbacks设置的callback,即WindowManagerService类的getInputMonitor方法至此,底层的InputReaderThread和InputDispatcherThread全部启动完毕,现在的重点是要找到WindowManagerCallbacks的interceptKeyBeforeQueueing和interceptKeyBeforeDispatching最终指向了哪里,由于两个方法网上的映射机制是一样的,下面只讲interceptKeyBeforeQueueing。继续往下走。3.2.7 frameworksbaseservicesjavacomandroidserverwm WindowManagerService.java/InputMonitor的创建:/getInputMonitor直接返回InputMonitor:/创建mPolicy: final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();3.2.8 frameworksbaseservicesjavacomandroidserverwm InputMonitor.java:/该类继承自InputManagerService 的内部类WindowManagerCallbacks接口。/interceptKeyBeforeQueueing()函数被重载,并调用调用WindowManagerPolicy接口的interceptKeyBeforeQueueing。/ 该service由构造函数传入,实际就是WindowManagerService:mPolicy由PolicyManager类的makeNewWindowManager()创建。3.2.9 frameworksbasecorejavacomandroidinternalpolicy PolicyManager.java/makeNewWindowManager调用Policy.java的方法 makeNewWindowManager()/sPolicy的初始化:3.2.10frameworksbasepolicysrccomandroidinternalpolicyimplPolicy.javamakeNewWindowManager调用TVWindowManager.java类的构造函数创建对象实例。3.2.11frameworksbasepolicysrccomandroidinternalpolicyimplTVWindowManager.javaTVWindowManager 类自身没有intercept

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论