android jni 按键,Android 按键framework层处理流程

上层的对按键事件的侦听和纷发处理是通过inputmanager及其组件inputreader,inputdispatch,eventhub构成的。

在system_server被创建的时候就会创建WMS,并调用inputmanager的start方法来启动read和dispatch线程。

1.      Inputmanager的创建

Systemserver的ServerThread的run函数中,会调用WMS的main方法来创建WMS

Slog.i(TAG, "WindowManager");

wm = WindowManagerService.main(context,power,

factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);

ServiceManager.addService(Context.WINDOW_SERVICE, wm);

再来看windowmanagerservice的main方法:

public static WindowManagerServicemain(Context context,

PowerManagerService pm, booleanhaveInputMethods) {

WMThread thr = new WMThread(context, pm, haveInputMethods);

thr.start();

synchronized (thr) {

while (thr.mService == null) {

try {

thr.wait();

} catch (InterruptedExceptione) {

}

}

}

return thr.mService;

}此方法很简单,就是创建了WMThread,然后调用了他的start方法。

继续看WMThread:它的构造函数很简单,就是给几个变量赋值,重点看看它的run函数:

public void run() {

Looper.prepare();

WindowManagerService s = new WindowManagerService(mContext, mPM,

mHaveInputMethods);

android.os.Process.setThreadPriority(

android.os.Process.THREAD_PRIORITY_DISPLAY);

android.os.Process.setCanSelfBackground(false);

synchronized (this) {

mService = s;

notifyAll();

}

Looper.loop();

}

此方法创建了WMS的实例,继续跟进:

private WindowManagerService(Contextcontext, PowerManagerService pm,

boolean haveInputMethods) {

//……..省略无关代码

mInputManager = newInputManager(context, this);

//……

}

看看inputmanager的构造函数:inputmanager.java中

public InputManager(Context context,WindowManagerService windowManagerService) {

this.mContext = context;

this.mWindowManagerService =windowManagerService;

this.mCallbacks = new Callbacks();

init();

}

就是给几个变量赋值,调用了init :

private void init() {

Slog.i(TAG, "Initializing inputmanager");

nativeInit(mCallbacks);

}

调用nativeInit ,此方法对应了com_android_server_inputmanager.java中的

android_server_InputManager_nativeInit(sourceinsight搜一下即可,就是inputmanger对应的JNI的部分。)

staticvoid android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,

jobject callbacks) {

if (gNativeInputManager == NULL) {

gNativeInputManager = new NativeInputManager(callbacks);

} else {

LOGE("Input manager alreadyinitialized.");

jniThrowRuntimeException(env,"Input manager already initialized.");

}

}此方法也是直接调用了NativeInputManager的构造函数:

NativeInputManager::NativeInputManager(jobjectcallbacksObj) :

mFilterTouchEvents(-1),mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),

mMaxEventsPerSecond(-1),

mDisplayWidth(-1), mDisplayHeight(-1),mDisplayOrientation(ROTATION_0) {

JNIEnv* env = jniEnv();

mCallbacksObj =env->NewGlobalRef(callbacksObj);

speventHub = new EventHub();

mInputManager = new InputManager(eventHub,this, this);

}此方法中做了两件很重要的事情,创建了EventHub并将其作为入参传入了InputManager,此处的inputmanager是native的,即是inputmanager.cpp中的。

Inputmanager.cpp

InputManager::InputManager(

const sp&eventHub,

const sp&readerPolicy,

constsp& dispatcherPolicy) {

mDispatcher = new InputDispatcher(dispatcherPolicy);

mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

initialize();

}创建了inputdispatcher和inputreader,并调用了initialize函数创建了InputReaderThread和InputDispatcherThread。

到这里,相关的组件就创建完毕了,那么这些进程是怎么跑取来的呢?

2.      关键线程的启动:

我们还是回到WMS的构造函数中:

private WindowManagerService(Contextcontext, PowerManagerService pm,

boolean haveInputMethods) {

//。。。。。。省略

mInputManager = new InputManager(context, this);

PolicyThread thr = newPolicyThread(mPolicy, this, context, pm);

thr.start();

synchronized (thr) {

while (!thr.mRunning) {

try {

thr.wait();

} catch (InterruptedExceptione) {

}

}

}

mInputManager.start();

创建完毕后,就会调用inputmanager的start函数,过程和creat相当的类似,都是用过JNI的调用到native的线程启动,下面依然一级一级的跟,首先是inputmanager的start:

public void start() {

Slog.i(TAG, "Starting inputmanager");

nativeStart();

}

直接调用了nativeStart,对应的是com_android_server_inputmanager.java中的

android_server_InputManager_nativeStart

staticvoid android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {

if (checkInputManagerUnitialized(env)) {

return;

}

status_tresult = gNativeInputManager->getInputManager()->start();

if (result) {

jniThrowRuntimeException(env,"Input manager could not be started.");

}

}

gNativeInputManager即是上面在创建的时候,通过NativeInputManager的构造函数获取的,而getInputManager的声明为:

inline spgetInputManager() const { returnmInputManager; }

直接返回mInputManager,而mInputManager也是在NativeInputManager的构造函数调用的。所以,实际调用的应该是native的inputmanager的start函数:

Inputmanager.cpp

status_tInputManager::start() {

status_t result = mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE("Could not startInputDispatcher thread due to error %d.", result);

return result;

}

result = mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE("Could not start InputReaderthread due to error %d.", result);

mDispatcherThread->requestExit();

return result;

}

return OK;

}

到这里,这两个线程就跑起来了,mDispatcherThread负责按键事件的纷发。mReaderThread负责按键事件的获取,接下来用power键的处理作为一个例子,来过下按键事件的简单流程。

3.      按键捕获:

mReaderThread->run后会走到他的threadLoop函数:

boolInputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

调用了inputreader的looponce函数:

voidInputReader::loopOnce() {

RawEvent rawEvent;

mEventHub->getEvent(& rawEvent);

#ifDEBUG_RAW_EVENTS

LOGD("Input event: device=0x%xtype=0x%x scancode=%d keycode=%d value=%d",

rawEvent.deviceId, rawEvent.type,rawEvent.scanCode, rawEvent.keyCode,

rawEvent.value);

#endif

process(& rawEvent);

}

首先是从eventhub中获取事件,再将其传入process中,eventhub的工作机理还没搞清楚,将在下一篇中分析。

根据返回的rawevent中的类型,会做不同的处理:

voidInputReader::process(const RawEvent* rawEvent) {

switch (rawEvent->type) {

case EventHubInterface::DEVICE_ADDED:

addDevice(rawEvent->deviceId);

break;

case EventHubInterface::DEVICE_REMOVED:

removeDevice(rawEvent->deviceId);

break;

caseEventHubInterface::FINISHED_DEVICE_SCAN:

handleConfigurationChanged(rawEvent->when);

break;

default:

consumeEvent(rawEvent);

break;

}

}

如果是power键,会走到consumeEvent

voidInputReader::consumeEvent(const RawEvent* rawEvent) {

int32_t deviceId = rawEvent->deviceId;

{ // acquire device registry reader lock

RWLock::AutoRLock_rl(mDeviceRegistryLock);

ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

if (deviceIndex < 0) {

LOGW("Discarding event forunknown deviceId %d.", deviceId);

return;

}

InputDevice* device =mDevices.valueAt(deviceIndex);

if (device->isIgnored()) {

//LOGD("Discarding event forignored deviceId %d.", deviceId);

return;

}

device->process(rawEvent);

} // release device registry reader lock

}通过刚刚传入的diviceid找到对应的deviceindex,而这些device的创建和销毁正是上步中的ADD/REMOVEdevice 。

最后调用device的process

voidInputDevice::process(const RawEvent* rawEvent) {

size_t numMappers = mMappers.size();

for (size_t i = 0; i < numMappers; i++){

InputMapper* mapper = mMappers[i];

mapper->process(rawEvent);

}

}调用在creatdevice时添加的mapper的process,我们这里是power键,所以应该是KeyboardInputMapper(详见creatdevice函数)

voidKeyboardInputMapper::process(const RawEvent* rawEvent) {

switch (rawEvent->type) {

case EV_KEY: {

int32_t scanCode =rawEvent->scanCode;

if (isKeyboardOrGamepadKey(scanCode)) {

processKey(rawEvent->when,rawEvent->value != 0, rawEvent->keyCode, scanCode,

rawEvent->flags);

}

break;

}

}

}

通过判断scan code,确认是否为键盘或者游戏手柄,如果是则走到processkey:

voidKeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,

int32_t scanCode, uint32_t policyFlags) {

int32_t newMetaState;

nsecs_t downTime;

bool metaStateChanged = false;

{ // ……省略此处对按键的处理

getDispatcher()->notifyKey(when,getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,

down ? AKEY_EVENT_ACTION_DOWN :AKEY_EVENT_ACTION_UP,

AKEY_EVENT_FLAG_FROM_SYSTEM,keyCode, scanCode, newMetaState, downTime);

此处就会通知dispatch,有按键上报。

voidInputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,

uint32_t policyFlags, int32_t action,int32_t flags,

int32_t keyCode, int32_t scanCode,int32_t metaState, nsecs_t downTime) {

//,,,,,….

mPolicy->interceptKeyBeforeQueueing(eventTime,deviceId, action, /*byref*/ flags,

keyCode, scanCode, /*byref*/policyFlags);

此处的mPolicy就是创建inputdispatch的时候传入的,可以看出,这个mPolicy就是NativeInputManager的this。(NativeInputManager::NativeInputManager创建native的inputmanager的时候传入)

所以,此处的interceptKeyBeforeQueueing实际是NativeInputManager的interceptKeyBeforeQueueing:

而在此函数中会调用WMS的interceptKeyBeforeQueueing,询问其是否会对此按键做特殊处理,实际是在phonewindowmanager中处理的,接下来的流程已经在上一篇中讲过,不再赘述,下一篇中打算将eventhub的流程,尤其是按键扫描的对应搞清楚

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值