InputManagerService分析(1)

初始化

在SystemServer中实例化InputManagerService,注册WMS.callback,之后就启动InputManagerService。

sequenceDiagram
SystemServer->> InputManagerService: new InputManagerService
SystemServer->>WindowManagerService: new WindowManagerService with IMS 
ActivityManagerService->>WindowManagerService:setWindowManager
InputManagerService->>WindowManagerService:setWindowManagerCallbacks
WindowManagerService->>InputManagerService:getInputMonitor
InputManagerService->>InputManagerService:start

inputManager = new InputManagerService(context);
wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
sequenceDiagram
InputManagerService->>  NativeInputManager: nativeInit
NativeInputManager->>InputDispatcher:new
NativeInputManager->>EventHub:new
NativeInputManager->>InputReader:new
InputReader->>InputReader:loopOnce
InputReader->>EventHub:getEvents
EventHub->>EventHub:epoll /dev/input/fd
InputReader->>KeyboardInputMapper:process
InputReader->>InputDispatcher:notifyKey
InputDispatcher->>NativeInputManager:interceptKeyBeforeQueueing
NativeInputManager->>InputManagerService:interceptKeyBeforeQueueing
InputManagerService->>InputMonitor:interceptKeyBeforeQueueing
InputMonitor->>PhoneWindowManager:interceptKeyBeforeQueueing

下面看一下InputManagerService的初始化流程:

public InputManagerService(Context context) {

        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());//初始化一个handler。究竟什么作用之后分析。

        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());//初始化native层。

        LocalServices.addService(InputManagerInternal.class, new LocalService());//将service注册到系统当中,这个在此不做分析。
    }

看一下native层做了什么东西

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());//这里初始化native层的一个manager

}

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {

    sp<EventHub> eventHub = new EventHub();//初始化一个eventhub,用来接收event
    mInputManager = new InputManager(eventHub, this, this);//将上面实例化的eventhub注册到manager中,并且注册listener,即NativeInputManager,用来与framework层进行通讯。
}

InputManager这个类很简单,只是开启两个线程去检测event事件,以及dispatch这些event。

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);//初始化event分发者
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);//初始化事件的读取者。
    initialize();
}

//开机新的线程去检测这些事件
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

至此初始化流程基本结束。下面看一下是如何运行起来的呢?
在systemserver里面有inputManager.start();看一下干了啥

    public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);
    }
	
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();//启动InputManager
}
//启动这两个thread
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);

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

之后就是监听按键,处理按键,分发按键的过程了。

事件的获取

在调用nativeStart时InputReader的启动
frameworks/native/services/inputflinger/InputReader.cpp

bool InputReaderThread::threadLoop() {
   mReader->loopOnce();
   return true;
}

void InputReader::loopOnce() {
//从EventHub中获取event
   size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

   { // acquire lock

       if (count) {//
           processEventsLocked(mEventBuffer, count);
       }

   } // release lock

   // Send out a message that the describes the changed input devices.
   if (inputDevicesChanged) {
       mPolicy->notifyInputDevicesChanged(inputDevices);//通知framework
   }

   mQueuedListener->flush();
}

事件的接收比较简单。下面介绍一下event是如何处理的以及如何传给framework层处理的。

事件的处理

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);//处理event
        } else {
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    InputDevice* device = mDevices.valueAt(deviceIndex);//查找对应的device

    device->process(rawEvents, count);//调用device的process函数去处理event
}

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // Process all of the events in order for each mapper.
    // We cannot simply ask each mapper to process them in bulk because mappers may
    // have side-effects that must be interleaved.  For example, joystick movement events and
    // gamepad button presses are handled by different mappers but they should be dispatched
    // in the order received.
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
            } else {
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
        } else {
            for (size_t i = 0; i < numMappers; i++) {//查找对应的mapper去处理这个按键信息
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

这里以KeyboardInputMapper为例:

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
   switch (rawEvent->type) {
   case EV_KEY: {//处理keyevent
       int32_t scanCode = rawEvent->code;
       int32_t usageCode = mCurrentHidUsage;
       mCurrentHidUsage = 0;

       if (isKeyboardOrGamepadKey(scanCode)) {
           >==processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);==<
       }
       break;
   }
   case EV_MSC:
   case EV_SYN: 
   }
}

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
       int32_t usageCode) {
   int32_t keyCode;
   int32_t keyMetaState;
   uint32_t policyFlags;
   //获取scanCode 
   if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                             &keyCode, &keyMetaState, &policyFlags)) {
       keyCode = AKEYCODE_UNKNOWN;
       keyMetaState = mMetaState;
       policyFlags = 0;
   }

   NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
           down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
           AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
   getListener()->notifyKey(&args);//调用之前注册进来的listener
}

InputListenerInterface* InputReader::ContextImpl::getListener() {
   return mReader->mQueuedListener.get();//在native_init的时候注册进来的listener
}

InputReader::InputReader(const sp<EventHubInterface>& eventHub,
       const sp<InputReaderPolicyInterface>& policy,
       const sp<InputListenerInterface>& listener) :
       mContext(this), mEventHub(eventHub), mPolicy(policy),
       mGlobalMetaState(0), mGeneration(1),
       mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
       mConfigurationChangesToRefresh(0) {
   >==mQueuedListener = new QueuedInputListener(listener);==<//在native_init的时候注册进来的listener,InputDispatcher。

}

下面看一下InputDispatcher.

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

   if (!validateKeyEvent(args->action)) {//判断按键是否有效
       return;
   }

   uint32_t policyFlags = args->policyFlags;
   int32_t flags = args->flags;
   int32_t metaState = args->metaState;
   if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
       policyFlags |= POLICY_FLAG_VIRTUAL;
       flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
   }
   if (policyFlags & POLICY_FLAG_FUNCTION) {
       metaState |= AMETA_FUNCTION_ON;
   }

   policyFlags |= POLICY_FLAG_TRUSTED;

   int32_t keyCode = args->keyCode;
   if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {
       int32_t newKeyCode = AKEYCODE_UNKNOWN;
       if (keyCode == AKEYCODE_DEL) {
           newKeyCode = AKEYCODE_BACK;
       } else if (keyCode == AKEYCODE_ENTER) {
           newKeyCode = AKEYCODE_HOME;
       }
       if (newKeyCode != AKEYCODE_UNKNOWN) {
           AutoMutex _l(mLock);
           struct KeyReplacement replacement = {keyCode, args->deviceId};
           mReplacedKeys.add(replacement, newKeyCode);
           keyCode = newKeyCode;
           metaState &= ~AMETA_META_ON;
       }
   } else if (args->action == AKEY_EVENT_ACTION_UP) {
       // In order to maintain a consistent stream of up and down events, check to see if the key
       // going up is one we've replaced in a down event and haven't yet replaced in an up event,
       // even if the modifier was released between the down and the up events.
       AutoMutex _l(mLock);
       struct KeyReplacement replacement = {keyCode, args->deviceId};
       ssize_t index = mReplacedKeys.indexOfKey(replacement);
       if (index >= 0) {
           keyCode = mReplacedKeys.valueAt(index);
           mReplacedKeys.removeItemsAt(index);
           metaState &= ~AMETA_META_ON;
       }
   }

   KeyEvent event;
   event.initialize(args->deviceId, args->source, args->action,
           flags, keyCode, args->scanCode, metaState, 0,
           args->downTime, args->eventTime);

   >>==mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);==<<//调用policy,加入到framework层的event队列中
}

那么jni是如何将这些事件传递给framework的呢?下面看一下这个函数的具体实现

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
       uint32_t& policyFlags) {

   bool interactive = mInteractive.load();
   if (interactive) {
       policyFlags |= POLICY_FLAG_INTERACTIVE;
   }
   if ((policyFlags & POLICY_FLAG_TRUSTED)) {
       nsecs_t when = keyEvent->getEventTime();
       JNIEnv* env = jniEnv();
       jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
       jint wmActions;
       if (keyEventObj) {
          //通过jni去调用framework中的函数interceptKeyBeforeQueueing
          >>== wmActions = env->CallIntMethod(mServiceObj,
                   gServiceClassInfo.interceptKeyBeforeQueueing,
                   keyEventObj, policyFlags);==<<
           if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
               wmActions = 0;
           }
           android_view_KeyEvent_recycle(env, keyEventObj);
           env->DeleteLocalRef(keyEventObj);
       } else {
           ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
           wmActions = 0;
       }

       handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
   } else {
       if (interactive) {
           policyFlags |= POLICY_FLAG_PASS_TO_USER;
       }
   }
}

这样的话就把event抛给framework层了。之后就是framework层处理按键event了。

那么到目前为止就把keyevent的收取,分发以及传递给framework层的流程分析完了。当然里面有许多细节的问题没有详细介绍。比如scancode和keycode之间的映射关系等。之后再补充。

framework对按键的处理流程

private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
       return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
   }

还记得在SystemServer中创建InputManagerService吗?

inputManager.setWindowManagerCallbacks(wm.getInputMonitor());

public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
       mWindowManagerCallbacks = callbacks;
}

public InputMonitor getInputMonitor() {
       return mInputMonitor;
   }

final InputMonitor mInputMonitor = new InputMonitor(this);
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
       return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}

final WindowManagerPolicy mPolicy = new PhoneWindowManager();

就是在InputManagerService中接收到的keyevent会传给wm中,再传递给PhoneWindowManager去处理。这个函数太长,这里就不再贴出来了,文件位置:frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

键值存放的地方:
frameworks/base/data/keyboards/Generic.kl

android 中键值间的映射关系。
在寻找android和Generic.kl之间的映射关系的时候,遇到c语言中的###的用法、
#用于将参数转换为字符串
##用于将宏两个参数链接在一起
看一下getKeyCodeByLabel

#include <android/keycodes.h>

static int32_t getKeyCodeByLabel(const char* label) {
   return int32_t(lookupValueByLabel(label, KEYCODES));
}

static const char* lookupLabelByValue(int value, const InputEventLabel* list) {
   while (list->literal) {
       if (list->value == value) {
           return list->literal;
       }
       list++;
   }
   return NULL;
}

struct InputEventLabel {
   const char *literal;
   int value;
};


static const InputEventLabel KEYCODES[] = {
DEFINE_KEYCODE(L),
}

#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }

这里只是以字母L来进行分析。
如果宏展开的话

static const InputEventLabel KEYCODES[] = {
{"L",AKEYCODE_L }
}

如果单纯这样看的话返回值肯定不会是int32_t,但是从log看返回的keycode确实是40。那是如何转换过来的呢?
其实一个很重要的信息被忘记了。看一下包含进来的头文件android/keycodes.h
在ndk中可以找到AKEYCODE_L这个宏的定义AKEYCODE_L= 40。记得如果添加一个特殊的键值得时候有可能需要在编译的ndk中添加键值的定义哦~~

键值的解析流程

if (device) {
        // Check the key character map first.
        sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
        if (kcm != NULL) {
            ALOGD("LIYANG Check the key character map first");
            if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {//第一次解析,如果解析失败就调用device的layout去解析
                *outFlags = 0;
                status = NO_ERROR;
            }
        }

        // Check the key layout next.
        if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {//调用device的layout去解析键值。
        ALOGD("LIYANG Check the key layout next.");
            if (!device->keyMap.keyLayoutMap->mapKey(
                    scanCode, usageCode, outKeycode, outFlags)) {
                status = NO_ERROR;
            }
        }

例如:
点击enter键

01-04 06:27:03.802  1612  3545 D InputReader: liang scanCode: 28, usageCode: 0
01-04 06:27:03.802  1612  3545 D KeyCharacterMap: mapKey: scanCode=28, usageCode=0x00000000 ~ Failed.//第一次解析失败
01-04 06:27:03.802  1612  3545 D KeyCharacterMap: tryRemapKey: keyCode=66, metaState=0x00000000 ~ replacement keyCode=66, replacement metaState=0x00000000.//第二次解析成功,返回keycode 66
01-04 06:27:03.802  1612  3545 D InputReader: liyang scanCode 28, usageCode:0, keyCode:66

scancode和keycode的对应关系在Generic.kl中。

key 28    ENTER

之后再android/keycodes.h中可以找到AKEYCODE_ENTER = 66。之后就将keycode返回给framework了。

上面只是介绍了InputManagerService中的流程,在SystemServer中还有一个service与InputManagerService有关,那就是WindowManagerService。接下来在看一下WindowManagerService的初始化流程。
文件位置:
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);

    public static WindowManagerService main(final Context context,
            final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs,
            final boolean onlyCore) {
        final WindowManagerService[] holder = new WindowManagerService[1];
        DisplayThread.getHandler().runWithScissors(new Runnable() {
            @Override
            public void run() {
                holder[0] = new WindowManagerService(context, im,
                        haveInputMethods, showBootMsgs, onlyCore);
            }
        }, 0);
        return holder[0];
    }
	
	private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
        ···
        mInputManager = inputManager; // Must be before createDisplayContentLocked.
        LocalServices.addService(WindowManagerPolicy.class, mPolicy);//PhoneWindowManager

        mPointerEventDispatcher = new  PointerEventDispatcher(mInputManager.monitorInput(TAG));
        ···
        mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);

        ···
    }

这里面多数就是读取配置,这里面省略掉了。
看一下PointerEventDispatcher的初始化做了什么东西。
我们看到初始化PointerEventDispatcher的时候,从ims中获取了一个monitor
先来看一下monitor是啥以及是什么作用
InputManagerService.java

    public InputChannel monitorInput(String inputChannelName) {
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
        nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);//socket 0
        inputChannels[0].dispose(); // don't need to retain the Java object reference
        return inputChannels[1];
    }

通过上面,可以看到,总共做了两件事:1.建立两个channel;2.将channel[0]注册进去
先看一下两个channel是如何建立的

	    public static InputChannel[] openInputChannelPair(String name) {
        return nativeOpenInputChannelPair(name);
    }
	
	frameworks/base/core/jni/android_view_InputChannel.cpp
	static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    ···
    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    ···
    }
	
	frameworks/native/libs/input/InputTransport.cpp
	
	status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {

    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

InputChannel::InputChannel(const String8& name, int fd) :
        mName(name), mFd(fd) {

    int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
}

这里主要是通过调用socketpair建立两个socket 名称为WindowManager(server),WindowManager(client),并且设置一些属性。

接下来就是将这两个channel注册进去。我们知道socket0 是server端。所以需要注册socket0.

下面是将socket0注册进去,这里需要注意的是,socket0的作用不是去接收键值,主要是为了处理framework中处理完按键之后的流程。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    }
	//因为传进来的是空,所以这里inputWindowHandle也是空
    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
}

frameworks/base/core/jni/android_view_InputChannel.cpp
通过加载inputChanne这个类的方式获取到channel。
sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
    return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
}

之后就是将上面获取到的channel也就是socket0注册到NativeInputManager中。
下面看一下是如何注册的

status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}

通过上面的学习知道这里面的dispatcher就是frameworks/native/services/inputflinger/InputDispatcher.cpp

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {

    { // acquire lock
        AutoMutex _l(mLock);
		//这里首先检查一下这个channel是否注册过,如果注册过就返回错误
        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
            return BAD_VALUE;
        }

        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
		//如果之前没有注册过就放入到mConnectionsByFd中,然后加入到looper中。如过有ALOOPER_EVENT_INPUT事件进来的话就调用handleReceiveCallback
		//这里要区分一下,此处的mLooper是在Dispatcher中重新new的对象。
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值