分析Power key的处理流程

[kernel]

基于riogrande STE 的平台:

1. Power key的处理文件 kernel/drivers/input/misc/ab8500-ponkey.c
2. Camera,volume keys 在 kernel/arch/arm/mach-ux500/input-lotus.c
3. 当按下power key时会有中断产生触发 ab8500_ponkey_handler@kernel/drivers/input/misc/ab8500-ponkey.c, 会处理ab5500_forced_key_detect和input_report_key
3. platform_driver_register(&ab8500_ponkey_driver)@kernel/drivers/input/misc/ab8500-ponkey.c 会注册到那了???;然后ab8500_ponkey_probe-->input_register_device 注册为input?设备,最后会添加到input_dev_list中。
4. 从schematic看,volume up and PONKey1(power key) 同时按会产生HW_RESET.

基于qcom 平台

1. Power key的处理文件drivers/input/misc/pmic8xxx-pwrkey.c


5. 分析按键如何从kernel space上报给 user space
    input_report_key(info->idev, KEY_POWER, true)->input_event(dev, EV_KEY, KEY_POWER, true)@kernel/include/linux/input.c -->input_handle_event(dev, EV_KEY, KEY_POWER, true)->input_start_autorepeat(dev, KEY_POWER)和input_pass_event->??????handle->handler->event(handle, type, code, value);针对Poweron key的input device和input handler,也就是会调用 evdev_handler.evdev_event-->evdev_pass_event[将事件赋值给客户端的input_event buffer[EVDEV_BUFFER_SIZE]数组],该数组如同一个queue;而user space则会一次性从kernel读完所有的input event,然后dispactch,所以有时候的input event多,有时候少。
6. 分析kernel输入子系统 kernel/drivers/input/input.c
    a. 会注册 class_register(&input_class); -->/sys/class/input
    b. 会注册 input_proc_init(); --> /proc/bus/input,
        如果#cat /proc/bus/input/devices 会list所有的输入设备,比如
        I: Bus=0000 Vendor=0000 Product=0000 Version=0000
        N: Name="AB8500 POn(PowerOn) Key"
        P: Phys=
        S: Sysfs=/devices/platform/ab8500-i2c.0/ab8500-poweron-key.0/input/input4
        U: Uniq=
        H: Handlers=kbd event4
        B: EV=3
        B: KEY=100000 0 0 0

        #cat /proc/bus/input/handlers
        N: Number=4 Name=evdev Minor=64  [与 #define EVDEV_MINOR_BASE    64 就一致了]
    c. 会注册 register_chrdev(INPUT_MAJOR, "input", &input_fops);-->/dev/input
7. /sys/devices/platform/ab8500-i2c.0/ab8500-poweron-key.0/forcecrash_on  [sys/class/input/input4/device/sys/class/input] ?????
8. 在 kernel/drivers/input/Evdev.c中evdev_init->input_register_handler->input_attach_handler--> {handler->connect(handler, dev, id)};->evdev_connect -> input_register_handle 通过这一系列函数evdev注册关联到了input.c 中的设备static struct input_handler *input_table[8];之中,也就是input_register_handler会注册一个新的input handler,最后会添加到input_handler_list,但如何和input device相关联???
9. 注意kernel/drivers/input/Evdev.c中定义的 struct evdev->struct evdev_client *grab;->struct input_event buffer[EVDEV_BUFFER_SIZE]; 是关键,里面存放了power key 状态的具体事件

[User Space]
10. User Space然后打开这个input device, input_open_file@kernel/drivers/input/input.c-> ... ->evdev_open[创建上面的evdev_client结构] ->evdev_open_device
11. User Space读取这个input device的具体数据,其中在前面input_open_file就会对 文件操作[file->f_op = new_fops;]重新赋值,也就是关联到对应的文件操作函数上;evdev_read(..,char __user *buffer,..)@kernel/drivers/input/Evdev.c-->input_event_to_user[将数据复制到user space]
12. 已知有3个重要注册函数,三者又是如何关联起来的? 通过input_attach_handler->input_match_device比较,首先看id->driver_info有没有设置,如果设置了说明它匹配所有的id,evdev就是这个样的handler。也就是evdev_handler会关联上所有的input devices,用意何在??? 但是如joydev.c中的joydev_handler->joydev_ids就不会关联到所有input device,类似的还有mousedev.c,keyboard.c
         input_register_device    向内核注册一个input设备
         input_register_handle    向内核注册一个handle结构,具体有啥用???
    input_register_handler   注册一个事件处理器
13. 通过以上分析,一旦按下power on 键,最终该 键值和按下状态等信息会保存在kernel/drivers/input/evdev.c中的evdev_table[].grab.input_event[EVDEV_BUFFER_SIZE]中,然后user space会通过sysfs对应该device的读函数获取所有的 input_event[EVDEV_BUFFER_SIZE]. 不过这有个问题了,谁触发user space 来读取input_event的数据????
14. #getevent 可以获取当前的input event, 具体的代码位于 system/core/toolbox, bin文件位于#/system/bin; #getevent --help
15. 函数getEvent@frameworks/base/libs/ui/eventhub.cpp会读取所有的input devices的events. 需要特别说明的是getEvent从驱动读取input event的逻辑,
16. 如何从kernel读取input event到user space
    a. frameworks/base/services/jni/com_android_server_inputmanager.cpp中有NativeInputManager->mInputManager = new InputManager(eventHub, this, this);-->mReader = new InputReader(eventHub, readerPolicy, mDispatcher);[readerPolicy是NativeInputManager, mDispatcher就是InputDispatcher]
    b. 函数initialize(){ mReaderThread = new InputReaderThread(mReader);}-->然后start(){ result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);} 到此关联上了getEvent???
    c. frameworks/base/services/jni/com_android_server_inputmanager.cpp中有android_server_InputManager_nativeStart 会最终启动(InputReaderThread)mReaderThread->run(..)[会循环调用threadLoop]
    d. frameworks/base/libs/ui/inputreader.cpp中InputReaderThread.threadLoop()-->mReader->loopOnce();--> mEventHub->getEvent(& rawEvent);最终调用到了前面的getEvent@frameworks/base/libs/ui/eventhub.cpp,也就是InputReaderThread会不断从kernel读取input device的events到user space,
    e. 然后用InputReader::process分发消息到不同设备
17. 得到的一个rawEvent会如何处理?
    a. InputReader::loopOnce()@frameworks/base/libs/ui/inputreader.cpp-> process(& rawEvent);
    b. consumeEvent(rawEvent);--> device->process(rawEvent);
    c. 首先要分析如何在inputreader中注册需要获取指定input event的设备,InputReader::mDevices中会保存设备信息, InputReader::addDevice->createDevice
    d. device->addMapper(new KeyboardInputMapper..){针对power on key},然后在如何处理???如何dispatch
    c. [KeyboardInputMapper@inputreader.cpp的]mapper->process(rawEvent);
    e. KeyboardInputMapper.processKey
    f. getDispatcher()->notifyKey;   //getDispatcher()得到的是inputdispatcher
18. Power key on/off事件如何从frameworks/base/libs/ui/inputreader.cpp中函数KeyboardInputMapper->processKey 到 interceptPowerKeyDown@frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java?????
    a. notifykey@frameworks/base/libs/ui/inputdispatcher.cpp
    b. mPolicy{NativeInputManager@frameworks/base/services/jni/com_android_server_inputmanager.cpp}->interceptKeyBeforeQueueing //
    c. interceptKeyBeforeQueueing@frameworks/base/services/jni/com_android_server_inputmanager.cpp
    d. interceptKeyBeforeQueueing@frameworks/base/services/java/com/android/server/inputmanager.java
    e. inputmonitor::interceptKeyBeforeQueueing@frameworks/base/services/java/com/android/server/windowmanagerservice.java-->mPolicy.interceptKeyBeforeDispatching
    f. 其中有final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); 会调用makeNewWindowManager@frameworks/base/core/java/com/android/internal/policy/PolicyManager.java 然后调用sPolicy.makeNewWindowManager(),而sPolicy装载的是"com.android.internal.policy.impl.Policy"class,即frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java
    g. makeNewWindowManager@frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java-->return new PhoneWindowManager();
    h. 所以上面e 步骤会调用到PhoneWindowManager::interceptKeyBeforeQueueing@frameworks/base/policy/src/com/android/internal/policy/impl/phonewindowmanager.java[判断该按键是否应该送给上层,还是在此层进行截取,如关机待机休眠唤醒则在此层进行截取,处理camera key,volume up/down key]
    i. 到此为止input event就传到了phonewindowmanager.java
19. 手机手动关机的过程
    [JAVA framework]interceptPowerKeyDown和Runnable mPowerLongPress@frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java, 其中GLOBAL_ACTIONS_KEY_TIMEOUT = 500为常按延时;然后sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);和showGlobalActionsDialog
    [JAVA framework]shutdown dialog 在frameworks/policies/base/phone/com/android/internal/policy/impl/GlobalActions.java,实际上就是常按power key后弹出的dialog.
    [JAVA framework]Shutdown process 在frameworks/base/core/java/com/android/internal/app/ShutdownThread.java
        Through beginShutdownSequence(), actual shutdown process is done in run().
            Broadcasts ACTION_SHUTDOWN Intent
            Calls shutdown of ActivityManager service
            Calls disable of Bluetooth service
            Calls Radio(false) of Phone service
            Calls shutdown of Mount service
            Vibrate for a while
            Calls Power.shutdown(); //这个是关键
   
20. 没有被PhoneWindowManager::interceptKeyBeforeQueueing处理的input event,也就是需要传到user app的input event,如何做下一步处理
    a. 根据恰面 getDispatcher()->notifyKey;   //getDispatcher()得到的是inputdispatcher
      b. notifyKey中处理完 mPolicy->interceptKeyBeforeQueueing 后会enqueueInboundEventLocked(newEntry);-->添加到mInboundQueue中
    c. InputDispatcher::dispatchOnce()-->dispatchOnceInnerLocked
    d. InputDispatcherThread::threadLoop()-->mDispatcher->dispatchOnce();//mDispatcher就是InputDispatcher
    e. InputDispatcherThread在哪启动? initialize@frameworks/base/libs/ui/inputmanager.cpp中有mDispatcherThread = new InputDispatcherThread(mDispatcher); 并且在InputManager::start()--> status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);启动了该线程
    f. dispatchOnceInnerLocked@frameworks/base/libs/ui/inputdispatcher.cpp, 就是具体分发input event的函数了,至于如何分发到windows,这需要更深入分析了??????

21. WindowManagerService.java主要有两个线程,一个负责分发按键的InputDispatcherThread,另一个负责从底层读取按键消息InputReaderThread
21. frameworks/base/services/jni/com_android_server_inputmanager.cpp中有android_server_InputManager_nativeStart的JNI函数为nativeStart,于是查到对应的frameworks/base/services/java/com/android/server/inputmanager.java中有InputManager.start()-->nativeStart;
22. 在frameworks/base/services/java/com/android/server/windowmanagerservice.java会管理inputmanager.java
23. kernel/drivers/input/evdev.c中    #define EVDEV_BUFFER_SIZE    64
    frameworks/base/include/ui/eventhub.h 中有 static const int INPUT_BUFFER_SIZE = 64;  两者必须一致

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值