??Step 12.?InputChannel.openInputChannelPair
?? ? ? ?這個函數定義在frameworks/base/core/java/android/view/InputChannel.java文件中:
public?final?class?InputChannel?implements?Parcelable?{??????......???????????????????public?static?InputChannel[]?openInputChannelPair(String?name)?{??????????......????????????return?nativeOpenInputChannelPair(name);??????}????????......??}?? ?? ? ? ? 這個函數調用本地方法nativeOpenInputChannelPair來進一步執行操作。
?
?? ? ? ? Step 13.?InputChannel.nativeOpenInputChannelPair
?? ? ? ? 這個函數定義在frameworks/base/core/jni/android_view_InputChannel.cpp文件中:
static?jobjectArray?android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*?env,??????????jclass?clazz,?jstring?nameObj)?{???????const?char*?nameChars?=?env->GetStringUTFChars(nameObj,?NULL);???????String8?name(nameChars);???????env->ReleaseStringUTFChars(nameObj,?nameChars);?????????sp<InputChannel>?serverChannel;???????sp<InputChannel>?clientChannel;???????status_t?result?=?InputChannel::openInputChannelPair(name,?serverChannel,?clientChannel);?????????if?(result)?{???????????LOGE("Could?not?open?input?channel?pair.??status=%d",?result);???????????jniThrowRuntimeException(env,?"Could?not?open?input?channel?pair.");???????????return?NULL;???????}????????????????jobject?serverChannelObj?=?android_view_InputChannel_createInputChannel(env,???????????new?NativeInputChannel(serverChannel));???????jobject?clientChannelObj?=?android_view_InputChannel_createInputChannel(env,???????????new?NativeInputChannel(clientChannel));?????????jobjectArray?channelPair?=?env->NewObjectArray(2,?gInputChannelClassInfo.clazz,?NULL);???????env->SetObjectArrayElement(channelPair,?0,?serverChannelObj);???????env->SetObjectArrayElement(channelPair,?1,?clientChannelObj);???????return?channelPair;??}?? ?? ? ? ?這個函數根據傳進來的參數name在C++層分別創建兩個InputChannel,一個作為Server端使用,一個作為Client端使用,這里的Server端即是指InputManager,而Client端即是指應用程序。這兩個本地的InputChannel是通過InputChannel::openInputChannelPair函數創建的,創建完成后,再相應地在Java層創建相應的兩個InputChannel,然后返回。
?
?? ? ? ?Step 14.?InputChannel.openInputChannelPair
?? ? ? ?這個函數定義在frameworks/base/libs/ui/InputTransport.cpp文件中:
status_t?InputChannel::openInputChannelPair(const?String8&?name,??????????sp<InputChannel>&?outServerChannel,?sp<InputChannel>&?outClientChannel)?{??????status_t?result;????????int?serverAshmemFd?=?ashmem_create_region(name.string(),?DEFAULT_MESSAGE_BUFFER_SIZE);??????if?(serverAshmemFd?<?0)?{??????????......??????}?else?{??????????result?=?ashmem_set_prot_region(serverAshmemFd,?PROT_READ?|?PROT_WRITE);??????????if?(result?<?0)?{??????????????......??????????}?else?{??????????????????????????????????????????int?clientAshmemFd;??????????????clientAshmemFd?=?dup(serverAshmemFd);??????????????if?(clientAshmemFd?<?0)?{??????????????????......??????????????}?else?{??????????????????int?forward[2];??????????????????if?(pipe(forward))?{??????????????????????......??????????????????}?else?{??????????????????????int?reverse[2];??????????????????????if?(pipe(reverse))?{??????????????????????????......??????????????????????}?else?{??????????????????????????String8?serverChannelName?=?name;??????????????????????????serverChannelName.append("?(server)");??????????????????????????outServerChannel?=?new?InputChannel(serverChannelName,??????????????????????????????serverAshmemFd,?reverse[0],?forward[1]);????????????????????????????String8?clientChannelName?=?name;??????????????????????????clientChannelName.append("?(client)");??????????????????????????outClientChannel?=?new?InputChannel(clientChannelName,??????????????????????????????clientAshmemFd,?forward[0],?reverse[1]);??????????????????????????return?OK;??????????????????????}??????????????????????......??????????????????}??????????????????......??????????????}??????????}??????}??????......??}?? ?? ? ? ?在閱讀這個函數之前,我們首先了解一下C++層的InputChannel的構造函數:
InputChannel::InputChannel(const?String8&?name,?int32_t?ashmemFd,?int32_t?receivePipeFd,??????int32_t?sendPipeFd)?:??????mName(name),?mAshmemFd(ashmemFd),?mReceivePipeFd(receivePipeFd),?mSendPipeFd(sendPipeFd)?{??????......??}??? ?? ? ? ?為了創建一個InputChannel,我們需要準備四個參數,一個是輸入通道的名稱name,一個是匿名共享內存文件描述符,一個是管道的讀端文件描述符,一個是管道的寫端文件描述符。在上面的openInputChannelPair函數,輸入通道的名稱已經作為參數傳遞進來,因此,還需要創建匿名共享內存文件,還有管道。這里需要創建兩個管道,一個稱為前向管道(forward pipe),一個稱為反向管道(reverse pipe),它們交叉使用在Server端和Client端的InputChannel中,這樣就使入Server和Client可以互相通信了。
?
?? ? ? ?具體來說,Server端和Client端的InputChannel分別是這樣構成的:
?? ? ? ?Server Input Channel: ?ashmem - reverse(read) - forward(write)
?? ? ? ?Client Input Channel: ??ashmem - forward(read) - reverse(write)
?? ? ? ?前面我們在Android應用程序消息處理機制(Looper、Handler)分析一文中學習Android應用程序的消息處理機制時知道,管道可以用作進程間通信,其中一個進程在管道的讀端等待新的內空可讀,另一個進程在管道的寫端寫入新的內容以喚醒在管道讀端等待的進程,這樣就實現了進程間通信。在我們這個情景中,Client端可以在前向管道(forward pipe)的讀端睡眠等待新的內容可讀,而Server端可以通過向前向管道(forward pipe)的寫端寫入新的內容來喚醒Client端,同樣,把前向管道(forward pipe)換成反向管道(reverse pipe),也能實現Client端喚醒Server端。在后面我們分析InputDispatcher分發鍵盤消息時,會看到它們的用法。
?? ? ? ?有了這些背景知識后,相信上面的openInputChannelPair的代碼就容易理解了,這里就不再詳述了。
?? ? ? ?創建好了這兩個輸入通道后,回到Step 11中的WindowManagerService.addWindow函數中,一方面它把剛才創建的Client端的輸入通道通過outInputChannel參數返回到應用程序中:
inputChannels[1].transferToBinderOutParameter(outInputChannel);?? ?? ? ? 另一方面,它還要把剛才創建的Server端的輸入通道注冊到InputManager中:
mInputManager.registerInputChannel(win.mInputChannel);?? ?? ? ? Step 15. InputManager.registerInputChannel
?
?? ? ? 這個函數定義在frameworks/base/services/java/com/android/server/InputManager.java文件中:
public?class?InputManager?{??????......?????????????????public?void?registerInputChannel(InputChannel?inputChannel)?{??????????if?(inputChannel?==?null)?{??????????????throw?new?IllegalArgumentException("inputChannel?must?not?be?null.");??????????}????????????nativeRegisterInputChannel(inputChannel,?false);??????}????????......??}?? ?? ? ? ? 它通過調用本地方法nativeRegisterInputChannel來執行進一步的操作。
?
?? ? ? ? Step 16.?InputManager.nativeRegisterInputChannel
?? ? ? ? 這個函數定義在frameworks/base/services/jni/com_android_server_InputManager.cpp 文件中:
static?void?android_server_InputManager_nativeRegisterInputChannel(JNIEnv*?env,?jclass?clazz,??????????jobject?inputChannelObj,?jboolean?monitor)?{??????......????????sp<InputChannel>?inputChannel?=?android_view_InputChannel_getInputChannel(env,?????????inputChannelObj);??????......????????status_t?status?=?gNativeInputManager->registerInputChannel(?????????env,?inputChannel,?inputChannelObj,?monitor);????????????......??}?? ?? ? ? ?這里首先通過Java層的InputChannel對象獲得C++層的InputChannel對象,它們之間的對應關系是在前面的Step 13中設置好的,接著調用NativeInputManager的registerInputChannel執行進一步的操作。
?
?? ? ? ?Step 17. NativeInputManager.registerInputChannel
?? ? ? ?這個函數定義在frameworks/base/services/jni/com_android_server_InputManager.cpp 文件中:
status_t?NativeInputManager::registerInputChannel(JNIEnv*?env,??????????const?sp<InputChannel>&?inputChannel,?jobject?inputChannelObj,?bool?monitor)?{??????......????????status?=?mInputManager->getDispatcher()->registerInputChannel(inputChannel,?monitor);????????????......??}?? ?? ? ? ?這個函數主要是調用了InputDispatcher的registerInputChannel來真正執行注冊輸入通道的操作。?
總結
以上是生活随笔為你收集整理的Android应用程序键盘(Keyboard)消息处理机制分析(12)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。