framework學(xué)習(xí)筆記16. Input 輸入事件(2)

原計(jì)劃 input 輸入事件的學(xué)習(xí)分為兩節(jié)內(nèi)容學(xué)習(xí)并記錄毅舆,經(jīng)學(xué)習(xí)發(fā)現(xiàn)并遠(yuǎn)不止這些內(nèi)容,所以決定重新寫(xiě) input 輸入事件番外篇端逼,如需參考朗兵,請(qǐng)閱讀 input 輸入事件番外篇;造成的不便顶滩,深表抱歉余掖。

1. Window 的創(chuàng)建和 WMS的綁定
上一節(jié)中講到 dispatchMotionLocked() 向目標(biāo)窗口分發(fā)事件,這里簡(jiǎn)單介紹一下目標(biāo)窗口是如何獲取和綁定的;在 Activity 的啟動(dòng)流程中(具體可以參考 筆記14):
(1)handleLaunchActivity() 調(diào)用了 performLaunchActivity() ->
(2)performLaunchActivity() 中調(diào)用了 activity.attach()方法盐欺,之前就說(shuō)過(guò)這個(gè)是對(duì) activity進(jìn)行綁定赁豆,完成這一步activity才成為四大組件之一,未完成時(shí)都只能算一個(gè)對(duì)象(創(chuàng)建activity的第一步) ->
(3)handleLaunchActivity() 調(diào)用了 handleResumeActivity() 方法(第二步:onResume()并渲染)冗美;
窗口的獲取和綁定就在 performLaunchActivity() 調(diào)用的 activity.attach() 中完成的魔种,進(jìn)入源碼中看看:

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, IVoiceInteractor voiceInteractor) {
        attachBaseContext(context);

        mFragments.attachActivity(this, mContainer, null);
        // 創(chuàng)建 Window
        // 這里的 mWindow 時(shí) PhoneWindow,后續(xù)版本的 mWindow 初始化如下粉洼,更加直觀:
        // mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        // ...
        // 在window中創(chuàng)建時(shí) mWindowManager 其實(shí)是 WindowManagerImpl节预,代碼不復(fù)雜,可以跟進(jìn)去看看
        mWindow.setWindowManager(  // 設(shè)置 WindowManager
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();  // 這里就可以獲取 WindowManager 了
        mCurrentConfig = config;
    }

在這里記住三個(gè)知識(shí)點(diǎn)(后續(xù)講setContentView時(shí)再詳細(xì)分析):
a. Window 類是一個(gè)抽象類属韧,它的唯一實(shí)現(xiàn)類是 PhoneWindow安拟;
b. PhoneWindow 有一個(gè)內(nèi)部類 DecorView,DecorView 是 Activity 的根 View宵喂;
c. DecorView 繼承自 FramLayout糠赦;

關(guān)于創(chuàng)建Window對(duì)象:
PolicyManager為策略類,其實(shí)現(xiàn)類Policy 的makeNewWindow內(nèi)部創(chuàng)建了window對(duì)象锅棕;

// mWindow = PolicyManager.makeNewWindow(this):
public final class PolicyManager {
    private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";

    private static final IPolicy sPolicy;

    static {  // 通過(guò)反射創(chuàng)建 sPolicy
        try {
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME); 
            sPolicy = (IPolicy)policyClass.newInstance();
        } catch (ClassNotFoundException ex) {
            // ...
        }
    }

    private PolicyManager() {}

    // 創(chuàng)建PhoneWindow
    public static Window makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }

    public static LayoutInflater makeNewLayoutInflater(Context context) {
        return sPolicy.makeNewLayoutInflater(context);
    }

    public static WindowManagerPolicy makeNewWindowManager() {
        return sPolicy.makeNewWindowManager();
    }

    public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
        return sPolicy.makeNewFallbackEventHandler(context);
    }
}

// Policy.java 類中的 makeNewWindow() 方法:
public window makeNewWindow(Context context){
        return new PhoneWindow(context);
}

2. ViewRootImpl 與 WMS 的通信

    // 第二步:
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        
        // 主要作用是調(diào)用performResumeActivity()到activity的onResume狀態(tài)拙泽,然后獲取
        // DecorView,創(chuàng)建一個(gè)關(guān)聯(lián)的ViewRootImpl對(duì)象,用來(lái)配合WindowManagerService
        // 服務(wù)來(lái)管理該Activity組件的窗口狀態(tài)裸燎,最后addView
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;
            // ...

            //activity創(chuàng)建成功顾瞻,window此時(shí)為空,進(jìn)入此分支德绿;
            if (r.window == null && !a.mFinished && willBeVisible) { 
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    // 一層層的看最終調(diào)用的是:WindowManagerGlobal.java -> addView()
                    wm.addView(decor, l);  // 這里就是測(cè)量朋其,擺放,繪制
                }

            } else if (!willBeVisible) {
                r.hideForNow = true;
            }
            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r);

            // ...
        } 
    }

2.1 wm.addView(decor, l):這里的 wm 是 WindowManagerImpl脆炎,查看一下 addView() 方法:

// WindowManagerImpl.addView():
    // 單例獲取 WindowManagerGlobal
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }


//WindowManagerGlobal.addView():
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {

        // ... 省略部分代碼:參數(shù)的校驗(yàn)
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        // ...
        ViewRootImpl root;
        View panelParentView = null;

            //...
     
            // 實(shí)例化ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);
            // 添加 view 到全局集合中
            // 如果想 hook 全部的 view 時(shí),可以通過(guò)反射獲取 WindowManagerGlobal -> mViews氓辣;
            mViews.add(view);  
            mRoots.add(root);
            mParams.add(wparams);
        }
       
        // do this last because it fires off messages to start doing things
        try {  //將view添加到ViewRootImpl中去
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
           // ...
        }
    }

ViewRootImpl.setView():

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
        // 這里先將 mView 保存了 DecorView 的實(shí)例秒裕,
        // 然后調(diào)用 requestLayout() 方法,以完成應(yīng)用程序用戶界面的初次布局钞啸。
        if (mView == null) {
            mView = view;
            // mWindowAttributes保存了窗口所對(duì)應(yīng)的LayoutParams
           mWindowAttributes.copyFrom(attrs);
            /**
            * 在添加窗口之前几蜻,先通過(guò)requestLayout方法在主線程上安排一次“遍歷”。
            * 所謂“遍歷”是指ViewRootImpl中的核心方法performTraversal()体斩。
            * 這個(gè)方法實(shí)現(xiàn)對(duì)控件樹(shù)進(jìn)行測(cè)量梭稚、布局、向WMS申請(qǐng)修改窗口屬性以及重繪的所有工作絮吵。
            */
           requestLayout();  
           /***初始化mInputChannel弧烤。InputChannel是窗口接受來(lái)自InputDispatcher 的輸入事件的管道。 
             注意蹬敲,僅當(dāng)窗口的屬性inputFeatures不含有 INPUT_FEATURE_NO_INPUT_CHANNEL時(shí)才
             會(huì)創(chuàng)建 InputChannel暇昂,否則mInputChannel 為空莺戒,從而導(dǎo)致此窗口無(wú)法接受任何輸入事件 */
           if ((mWindowAttributes.inputFeatures
                   & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
               mInputChannel = new InputChannel();  // 見(jiàn) 2.2
           }
           try {
             // ...
             /* 將窗口添加到WMS中。完成這個(gè)操作之后急波,mWindow已經(jīng)被添加到指定的Display中去
               而且mInputChannel(如果不為空)已經(jīng)準(zhǔn)備好接受事件了从铲。只是由于這個(gè)窗口沒(méi)有進(jìn)行
               過(guò)relayout(),因此它還沒(méi)有有效的Surface可以進(jìn)行繪制 */
             res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                       getHostVisibility(), mDisplay.getDisplayId(),
                       mAttachInfo.mContentInsets, mInputChannel);  // 見(jiàn)2.3 
              // 這里的 mWindowSession 是向WMS跨進(jìn)程請(qǐng)求獲取的 
           } catch (RemoteException e) {  
              // ... 
           } finally { 
              // ... 
           }

        }
    }

2.2 InputChannel的構(gòu)造函數(shù):此時(shí) mInputChannel = new InputChannel() 這里還是一個(gè) Java 的對(duì)象澄暮;

public final class InputChannel implements Parcelable {
    private static final String TAG = "InputChannel";
    
    @SuppressWarnings("unused")
    private long mPtr; // used by native code
    private static native InputChannel[] nativeOpenInputChannelPair(String name);
    
    private native void nativeDispose(boolean finalized);
    private native void nativeTransferTo(InputChannel other);
    private native void nativeReadFromParcel(Parcel parcel);
    private native void nativeWriteToParcel(Parcel parcel);
    private native void nativeDup(InputChannel target);
    
    private native String nativeGetName();

    // 構(gòu)造函數(shù)中沒(méi)有任何操作名段,此時(shí) mInputChannel = new InputChannel() 只是一個(gè)普通的java對(duì)象;
    // 那么要想具有 c++ 的屬性泣懊,唯一的方法就是持有c++對(duì)象的指針伸辟,也就是將 mPtr 賦值;
    public InputChannel() {
    }
    // ...
  }

2.3 mWindowSession.addToDisplay():
首先嗅定,mWindowSession 是如何獲取到的:

// mWindowSession 的初始化:ViewRootImpl 的構(gòu)造函數(shù)中進(jìn)行初始化的自娩;
public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();  // 通過(guò) WMS 獲取
}


// 通過(guò) WMS 獲取 mWindowSession:WindowManagerGlobal類中的 getWindowSession() 方法
public static IWindowSession getWindowSession() {
    synchronized (WindowManagerGlobal.class) {
        if (sWindowSession == null) {
            try {
                InputMethodManager imm = InputMethodManager.getInstance();
                IWindowManager windowManager = getWindowManagerService();
                sWindowSession = windowManager.openSession(
                        new IWindowSessionCallback.Stub() {
                            @Override
                            public void onAnimatorScaleChanged(float scale) {
                                ValueAnimator.setDurationScale(scale);
                            }
                        },
                        imm.getClient(), imm.getInputContext());
                ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to open window session", e);
            }
        }
        return sWindowSession;
    }
}


// WMS 中openSession():
//IWindowSession :一個(gè)aidl接口,它的真的實(shí)現(xiàn)類是Session渠退,它是一個(gè)Binder對(duì)象忙迁,用來(lái)和
//WindowManagerService建立連接,在ViewRootImpl的setView中最終也是通過(guò)它和WindowManagerService
//通信完成了Window的添加的碎乃。這個(gè)Session是應(yīng)用唯一的姊扔,它的創(chuàng)建時(shí)在WindowManagerGloable中通過(guò)getWindowSession獲取的
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
        IInputContext inputContext) {
    if (client == null) throw new IllegalArgumentException("null client");
    if (inputContext == null) throw new IllegalArgumentException("null inputContext");
    Session session = new Session(this, callback, client, inputContext);
    return session;
}

這里創(chuàng)建了 Session 對(duì)象,其參數(shù) this 就是 WMS梅誓;
mWindowSession.addToDisplay() 就是 調(diào)用了Session的 addToDisplay() 方法:

// Session 的 addToDisplay() 方法:又是跨進(jìn)程通訊
    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
        // outInputChannel 是 2.2 中 mInputChannel = new InputChannel()恰梢,此時(shí)的指針還未賦值
        // mService 就是 new Session 時(shí)傳入的 WMS
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel); 
    }

WMS的addWindow() 方法:

public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }

        boolean reportNewConfig = false;
        WindowState attachedWindow = null;
        WindowState win = null;  // window 對(duì)象的信息
        long origId;
        final int type = attrs.type;

        synchronized(mWindowMap) {
            // ...
            win = new WindowState(this, session, client, token, 
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            // ...
            if (outInputChannel != null && (attrs.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                String name = win.makeInputChannelName();
                // 關(guān)鍵代碼,打開(kāi)一對(duì) InputChannel梗掰,客戶端和服務(wù)端 見(jiàn) 2.3.1
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); 
                // WMS 設(shè)置 Channel 為 inputChannels[0] 
                win.setInputChannel(inputChannels[0]); 
                // 客戶端設(shè)置 Channel 為 inputChannels[1]嵌言,此時(shí)給上面 Java層的 mInputChannel 中 mPtr 賦值
                // 經(jīng)過(guò)賦值后,Java 層 mInputChannel 才具有 c++ 的對(duì)象
                inputChannels[1].transferTo(outInputChannel);  

                // 將服務(wù)端的socket注冊(cè)到InputDispatcher中 見(jiàn) 2.3.2
                // 這里的 win.mInputWindowHandle 是在 win 初始化的時(shí)候 new 出來(lái)的及穗;
                mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
            }

            // ...
            // 每次添加都會(huì)更新摧茴,見(jiàn) 2.3.3
            mInputMonitor.updateInputWindowsLw(false /*force*/);
            // ...
        }
        // ...
}

2.3.1 建立socket 通信:
InputChannel.openInputChannelPair(name) 是一個(gè)native方法,在 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;
    // 創(chuàng)建一對(duì) socket 通信
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        String8 message;
        message.appendFormat("Could not open input channel pair.  status=%d", result);
        jniThrowRuntimeException(env, message.string());
        return NULL;
    }

    // 封裝成java對(duì)象    
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

InputChannel.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)) {
        status_t result = -errno;
    // ...    
    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;
}

socketpair()函數(shù)用于創(chuàng)建一對(duì)無(wú)名的埂陆、相互連接的套接字苛白。
如果函數(shù)成功,則返回0焚虱,創(chuàng)建好的套接字分別是sv[0]和sv[1]购裙;否則返回-1,錯(cuò)誤碼保存于errno中鹃栽。

用法:
(1) 這對(duì)套接字可以用于全雙工通信躏率,每一個(gè)套接字既可以讀也可以寫(xiě)。例如,可以往sv[0]中寫(xiě)禾锤,從sv[1]中讀私股;或者從sv[1]中寫(xiě),從sv[0]中讀恩掷;
(2) 如果往一個(gè)套接字(如sv[0])中寫(xiě)入后倡鲸,再?gòu)脑撎捉幼肿x時(shí)會(huì)阻塞,只能在另一個(gè)套接字中(sv[1])上讀成功黄娘;
(3)讀峭状、寫(xiě)操作可以位于同一個(gè)進(jìn)程,也可以分別位于不同的進(jìn)程逼争,如父子進(jìn)程优床。如果是父子進(jìn)程時(shí),一般會(huì)功能分離誓焦,一個(gè)進(jìn)程用來(lái)讀胆敞,一個(gè)用來(lái)寫(xiě)。因?yàn)槲募枋龇鹲v[0]和sv[1]是進(jìn)程共享的杂伟,所以讀的進(jìn)程要關(guān)閉寫(xiě)描述符, 反之移层,寫(xiě)的進(jìn)程關(guān)閉讀描述符。

2.3.2 注冊(cè):frameworks/base/services/core/jni/
com_android_server_input_InputManagerService.cpp 中:

// nativeRegisterInputChannel():
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);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }
    // window 的一些信息
    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);  

    status_t status = im->registerInputChannel(  // 注冊(cè)的方法赫粥,如下 registerInputChannel()方法:
            env, inputChannel, inputWindowHandle, monitor);
    if (status) {
        String8 message;
        message.appendFormat("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return;
    }

    if (! monitor) {
        android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                handleInputChannelDisposed, im);
    }
}


// registerInputChannel()方法:
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    // 終于看到我們 InputDispatcher 了
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}

InputDispatcher.cpp 中的注冊(cè)方法:registerInputChannel()

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

    { // acquire lock
        AutoMutex _l(mLock);

        // 連接的媒介观话,只是一個(gè)對(duì)象,沒(méi)有跨進(jìn)程等操作越平;
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();
        // 傳入 fd 和 connection频蛔,關(guān)聯(lián) fd 和 connection;
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }

        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

2.3.3 InputMonitor
簡(jiǎn)介:實(shí)現(xiàn)了 WindowManagerCallbacks接口秦叛,在 WindowManagerService 的構(gòu)造函數(shù)中創(chuàng)建了InputMonitor 對(duì)象晦溪,并以 mInputMonitor 作為參數(shù)創(chuàng)建 InputManagerService 的對(duì)象,在 InputManagerService 構(gòu)造函數(shù)中挣跋,將 mInputMonitor 作為參數(shù)調(diào)用了 JNI 函數(shù) nativeInit() 尼变,將回調(diào)接口傳到JNI層,在需要的時(shí)候浆劲,JNI 再回調(diào) mInputMonitor中 的函數(shù),實(shí)現(xiàn)數(shù)據(jù)才傳遞哀澈。

    public interface WindowManagerCallbacks {
        public void notifyConfigurationChanged();

        // 輸入設(shè)備的配置變更
        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);        
        public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);

        // 連接InputDispatcher 與應(yīng)用程序的 socket 通道
        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
        // ANR
        public long notifyANR(InputApplicationHandle inputApplicationHandle,
                InputWindowHandle inputWindowHandle, String reason);

        // 以下三個(gè)回調(diào)牌借,是WMS在消息處理中有優(yōu)先權(quán)處理
        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
        public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
        public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                KeyEvent event, int policyFlags);

        // 按鍵事件在整個(gè)事件處理過(guò)程中沒(méi)有任何處理時(shí),發(fā)送給 WMS 
        public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
                KeyEvent event, int policyFlags);
        public int getPointerLayer();
    }
// 簡(jiǎn)化代碼:
final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
    private final WindowManagerService mService;
    private WindowState mInputFocus;
    private boolean mUpdateInputWindowsNeeded = true;
    private InputWindowHandle[] mInputWindowHandles;


    private final Object mInputDevicesReadyMonitor = new Object();
    private boolean mInputDevicesReady;
    Rect mTmpRect = new Rect();
    public InputMonitor(WindowManagerService service) {
        mService = service;
    }

    public void updateInputWindowsLw(boolean force) {
        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
            WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                // ...
                // 加入到 mInputWindowHandles 數(shù)組中
                if (child.mWinAnimator != universeBackground) {
                    addInputWindowHandleLw(inputWindowHandle, child, flags, privateFlags, type,
                            isVisible, hasFocus, hasWallpaper);
                }
        }
            
        // 發(fā)送窗口到本地方法割按;
        mService.mInputManager.setInputWindows(mInputWindowHandles);
        // Clear the list in preparation for the next round.
        clearInputWindowHandlesLw();
    }
}


// InputServiceManager.java中:調(diào)用的是 native 方法膨报;
  public void setInputWindows(InputWindowHandle[] windowHandles) {
      nativeSetInputWindows(mPtr, windowHandles);
  }

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp 中 nativeSetInputWindows() 方法:

// com_android_server_input_InputManagerService.cpp 中:
static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
        jlong ptr, jobjectArray windowHandleObjArray) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    im->setInputWindows(env, windowHandleObjArray);
}


// com_android_server_input_InputManagerService.cpp 中:
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
    Vector<sp<InputWindowHandle> > windowHandles;
    // ...   
    // 調(diào)用InputDispatcher 中 setInputWindows()
    mInputManager->getDispatcher()->setInputWindows(windowHandles);
    // ...
}

// InputDispatcher.cpp 中的 setInputWindows():
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
    { // acquire lock
        Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
        // 把 inputWindowHandles 賦值給 mWindowHandles,這里就知道分發(fā)的目標(biāo)窗口是哪個(gè)窗口了;
        // input 事件就是根據(jù)匹配 InputWindowHandle 來(lái)進(jìn)行分發(fā)的现柠;
        mWindowHandles = inputWindowHandles;
    }    

    // ... 一些窗口的更新等操作
    // Wake up poll loop since it may need to make new input dispatching choices.
    mLooper->wake();
}

由于篇幅過(guò)長(zhǎng)院领,input 輸入事件篇未完成,請(qǐng)參考更為詳細(xì)的 input 輸入事件番外篇够吩;造成的不便比然,深表抱歉;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載周循,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者强法。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市湾笛,隨后出現(xiàn)的幾起案子饮怯,更是在濱河造成了極大的恐慌,老刑警劉巖嚎研,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蓖墅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡临扮,警方通過(guò)查閱死者的電腦和手機(jī)论矾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)公条,“玉大人拇囊,你說(shuō)我怎么就攤上這事“谐鳎” “怎么了寥袭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)关霸。 經(jīng)常有香客問(wèn)我传黄,道長(zhǎng),這世上最難降的妖魔是什么队寇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任膘掰,我火速辦了婚禮,結(jié)果婚禮上佳遣,老公的妹妹穿的比我還像新娘识埋。我一直安慰自己,他們只是感情好零渐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布窒舟。 她就那樣靜靜地躺著,像睡著了一般诵盼。 火紅的嫁衣襯著肌膚如雪惠豺。 梳的紋絲不亂的頭發(fā)上银还,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音洁墙,去河邊找鬼蛹疯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛热监,可吹牛的內(nèi)容都是我干的捺弦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狼纬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼羹呵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起疗琉,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤冈欢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后盈简,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體凑耻,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年柠贤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了香浩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡臼勉,死狀恐怖邻吭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宴霸,我是刑警寧澤囱晴,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站瓢谢,受9級(jí)特大地震影響畸写,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氓扛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一枯芬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧采郎,春花似錦千所、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至理茎,卻和暖如春黑界,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皂林。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工朗鸠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人础倍。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓烛占,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親沟启。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忆家,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容