InputMonitor筆記,enableinputmonitor

來源:互聯網
上載者:User

InputMonitor筆記,enableinputmonitor

文章僅記錄自己的一點理解,僅供自己參考。

1、mInputFocus

WMS.addWindow()-->WMS.finishUpdateFocusedWindowAfterAssignLayersLocked()-->InputMonitor.setInputFocusLw()-->mInputFocus = newWindow;

add一個window的時候會重新尋找焦點視窗,並把焦點視窗儲存在WMS.mCurrentFocus中,這個焦點視窗也會儲存到InputMonitor.mInputFocus 中。關鍵代碼:

<span style="font-size:18px;">addWindow(){            ……            boolean focusChanged = false;            if (win.canReceiveKeys()) {                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,                        false /*updateInputWindows*/);                if (focusChanged) {                    imMayMove = false;                }            }            if (imMayMove) {                moveInputMethodWindowsIfNeededLocked(false);            }            assignLayersLocked(displayContent.getWindowList());            // Don't do layout here, the window must call            // relayout to be displayed, so we'll do it there.            if (focusChanged) {                finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/);            }            mInputMonitor.updateInputWindowsLw(false /*force*/);           …………}</span>
這幾行代碼雖短,邏輯也很簡單,但是調用了很多方法。對於canReceiveKeys()函數:

<span style="font-size:18px;">public final boolean canReceiveKeys() {        return isVisibleOrAdding()                && (mViewVisibility == View.VISIBLE)                && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);    }</span>

如果視窗設定了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE屬性,那麼該視窗是不能獲得焦點的,即canReceiveKeys()會返回false,也就是說焦點視窗是不會更改的。對於懸浮的視窗一般來說是不需要獲得焦點的,故一般設定WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE屬性,不然會存在一些問題。如果該視窗可以接受key事件(這個key事件有點歧義,並不是只接受按鍵事件),那麼就調用updateFocusedWindowLocked(),這個以後再研究。如果焦點視窗發生變更,那麼就調用moveInputMethodWindowsIfNeededLocked(false)來移動IME視窗到合適的位置。

mInputFocus中儲存的視窗在調用InputMonitor.updateInputWindowsLw()時最終設定到InputDispatcher.mFocusedWindowHandle中去了。

2、mInputDispatchFrozen

凍結InputDispatcher標誌,“ When true, prevents input dispatch from proceeding until set to false again.”。

①WMS.startFreezingDisplayLocked()-->InputMonitor.freezeInputDispatchingLw()-->mInputDispatchFrozen = true; updateInputDispatchModeLw();

②WMS.stopFreezingDisplayLocked()-->InputMonitor.thawInputDispatchingLw()-->mInputDispatchFrozen = false; updateInputDispatchModeLw();-->InputManagerService.setInputDispatchMode()-->InputDispatcher.setInputDispatchMode(bool enabled, bool frozen)-->mDispatchFrozen = frozen;

<span style="font-size:18px;">void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {    nsecs_t currentTime = now();    // Reset the key repeat timer whenever we disallow key events, even if the next event    // is not a key.  This is to ensure that we abort a key repeat if the device is just coming    // out of sleep.    if (!mPolicy->isKeyRepeatEnabled()) {        resetKeyRepeatLocked();    }    // If dispatching is frozen, do not process timeouts or try to deliver any new events.    if (mDispatchFrozen) {#if DEBUG_FOCUS        ALOGD("Dispatch frozen.  Waiting some more.");#endif        return;}……….}</span>
調用dispatchOnceInnerLocked()分發事件時,直接return掉。上面的調用邏輯可以知道凍結/解凍顯示屏時,會凍結InputDispatcher的分發流程。

3、mInputDispatchEnabled

一個java層控制InputDispatcher的開關。

①WMS.setEventDispatching()-->InputMonitor.setEventDispatchingLw()

②WMS.performEnableScreen()-->InputMonitor.setEventDispatchingLw()-->mInputDispatchEnabled = enabled;updateInputDispatchModeLw();-->InputManagerService.setInputDispatchMode()-->InputDispatcher.setInputDispatchMode(bool enabled, bool frozen)-->mDispatchEnabled = enabled;

具體是怎麼使能InputDispatcher的?

<span style="font-size:18px;">if (!mDispatchEnabled) {        dropReason = DROP_REASON_DISABLED;    }</span>
在dispatchOnceInnerLocked()中會設定dropReason(放棄原因),如果dropReason不為0表示輸入事件將被放棄掉,不會分發。
google源碼是這樣解釋的:“ When true, input dispatch proceeds normally.  Otherwise all events are dropped. Initially false, so that input does not get dispatched until boot is finished at which point the ActivityManager will enable dispatching.”

4、mUpdateInputWindowsNeeded

是否需要更新視窗資訊到InputDispatcher中的標誌。在非強制性更新視窗資訊到InputDispatcher中去時,必須先調用InputMonitor.setUpdateInputWindowsNeededLw()設定該標誌,然後再調用InputMonitor.updateInputWindowsLw()。如果強制性更新視窗資訊到InputDispatcher中去時就不必設定該變數了。

5、notifyInputChannelBroken()

InputManager通知WMS輸入通道破裂函數。

<span style="font-size:18px;">    public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) {        if (inputWindowHandle == null) {            return;        }        synchronized (mService.mWindowMap) {            WindowState windowState = (WindowState) inputWindowHandle.windowState;            if (windowState != null) {                Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);                mService.removeWindowLocked(windowState.mSession, windowState);            }        }    }</span>
函數處理邏輯非常簡單,就是將輸入通道破裂的視窗直接調用removeWindowLocked()進行移除。
調用流程:InputDispatcher.startDispatchCycleLocked()--> InputDispatcher.abortBrokenDispatchCycleLocked()--> InputDispatcher.onDispatchCycleBrokenLocked()-->InputDispatcher.doNotifyInputChannelBrokenLockedInterruptible()-->NativeInputManager.notifyInputChannelBroken()-->InputManagerService.notifyInputChannelBroken()-->InputMonitor.notifyInputChannelBroken();

startDispatchCycleLocked()中在publish event不成功,就會走下面的邏輯:

<span style="font-size:18px;">        if (status) {            if (status == WOULD_BLOCK) {                if (connection->waitQueue.isEmpty()) {                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "                            "This is unexpected because the wait queue is empty, so the pipe "                            "should be empty and we shouldn't have any problems writing an "                            "event to it, status=%d", connection->getInputChannelName(), status);                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);                } else {                    // Pipe is full and we are waiting for the app to finish process some events                    // before sending more events to it.#if DEBUG_DISPATCH_CYCLE                    ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "                            "waiting for the application to catch up",                            connection->getInputChannelName());#endif                    connection->inputPublisherBlocked = true;                }            } else {                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "                        "status=%d", connection->getInputChannelName(), status);                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);            }            return;        }</span>
在正常pipe full的情況下是不會調用abortBrokenDispatchCycleLocked()的,其他情況則調用abortBrokenDispatchCycleLocked()來處理。

<span style="font-size:18px;">void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,        const sp<Connection>& connection, bool notify) {#if DEBUG_DISPATCH_CYCLE    ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",            connection->getInputChannelName(), toString(notify));#endif    // Clear the dispatch queues.    drainDispatchQueueLocked(&connection->outboundQueue);    traceOutboundQueueLengthLocked(connection);    drainDispatchQueueLocked(&connection->waitQueue);    traceWaitQueueLengthLocked(connection);    // The connection appears to be unrecoverably broken.    // Ignore already broken or zombie connections.    if (connection->status == Connection::STATUS_NORMAL) {        connection->status = Connection::STATUS_BROKEN;        if (notify) {            // Notify other system components.            onDispatchCycleBrokenLocked(currentTime, connection);        }    }}</span>
函數中清理outboundQueue和waitQueue兩個隊列中的訊息,然後調用onDispatchCycleBrokenLocked()-->.....來通知WMS移除對應的視窗。

outboundQueue:Queue of events that need to be published to the connection.

waitQueue:Queue of events that have been published to the connection but that have not yet received a "finished" response from the application.
輸入事件只有收到應用回複的finished訊息才算真正分發成功。

6、notifyANR()

源碼對這個函數的注釋已經非常清楚:

<span style="font-size:18px;">/* Notifies the window manager about an application that is not responding.     * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.     *      * Called by the InputManager.</span>

調用流程:InputDispatcher.findFocusedWindowTargetsLocked();InputDispatcher.findTouchedWindowTargetsLocked()-->InputDispatcher.handleTargetsNotReadyLocked()--> InputDispatcher.onANRLocked()-->InputDispatcher.doNotifyANRLockedInterruptible()-->NativeInputManager.notifyANR()-->InputManagerService.notifyANR()-->InputMonitor.notifyANR();

在InputDispatcher的findFocusedWindowTargetsLocked()和findTouchedWindowTargetsLocked()函數中存在多種異常情況是目標視窗視窗還沒準備好接受事件的,這時需要調用handleTargetsNotReadyLocked()來處理,handleTargetsNotReadyLocked()中會作出一定時間的等待,如果最終逾時那麼就會調用onANRLocked()報ANR。

InputDispatcher.notifyANR()函數處理也很簡單,最終會調用ActivityManagerNative.getDefault().inputDispatchingTimedOut(windowState.mSession.mPid, aboveSystem, reason);來拉起一個ANR對話方塊。

7、interceptKeyBeforeQueueing()、interceptKeyBeforeDispatching()

①InputDispatcher.notifyKey()-->NativeInputManager.interceptKeyBeforeQueueing()--> InputManagerService.interceptKeyBeforeQueueing()-->InputMonitor.interceptKeyBeforeQueueing()-->PhoneWindowManager.interceptKeyBeforeQueueing()

②InputDispatcher.dispatchKeyLocked()-->InputDispatcher.doInterceptKeyBeforeDispatchingLockedInterruptible()-->NativeInputManager.interceptKeyBeforeDispatching()--> InputManagerService.interceptKeyBeforeDispatching()-->InputMonitor.interceptKeyBeforeDispatching()-->PhoneWindowManager.interceptKeyBeforeDispatching()

從函數名及調用流程來看,一個是在入隊之前調用,一個是分發時調用。電源鍵事件走的就是這兩個函數中的一個。

8、interceptMotionBeforeQueueingWhenScreenOff()

InputDispatcher.notifyMotion()-->NativeInputManager.interceptMotionBeforeQueueing()--> InputManagerService.interceptMotionBeforeQueueingWhenScreenOff()-->InputMonitor.interceptMotionBeforeQueueingWhenScreenOff()-->PhoneWindowManager.interceptMotionBeforeQueueingWhenScreenOff()

<span style="font-size:18px;">void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {    // Policy:    // - Ignore untrusted events and pass them along.    // - No special filtering for injected events required at this time.    // - Filter normal events based on screen state.    // - For normal events brighten (but do not wake) the screen if currently dim.    if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {        if (isScreenOn()) {            policyFlags |= POLICY_FLAG_PASS_TO_USER;            if (!isScreenBright()) {                policyFlags |= POLICY_FLAG_BRIGHT_HERE;            }        } else {            JNIEnv* env = jniEnv();            jint wmActions = env->CallIntMethod(mServiceObj,                        gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,                        policyFlags);            if (checkAndClearExceptionFromCallback(env,                    "interceptMotionBeforeQueueingWhenScreenOff")) {                wmActions = 0;            }            policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;            handleInterceptActions(wmActions, when, /*byref*/ policyFlags);        }    } else {        policyFlags |= POLICY_FLAG_PASS_TO_USER;    }}</span>
在收到的輸入事件來自裝置,而不是上層應用注入的事件時,此時如果螢幕是滅屏狀態,那麼就調用interceptMotionBeforeQueueingWhenScreenOff()函數來處理。

9、pauseDispatchingLw()、resumeDispatchingLw()

這兩個函數非常簡單,就是設定WindowToken.paused,並強制更新到InputDispatcher中去。

<span style="font-size:18px;">    public void pauseDispatchingLw(WindowToken window) {        if (! window.paused) {            if (WindowManagerService.DEBUG_INPUT) {                Slog.v(WindowManagerService.TAG, "Pausing WindowToken " + window);            }                        window.paused = true;            updateInputWindowsLw(true /*force*/);        }    }        public void resumeDispatchingLw(WindowToken window) {        if (window.paused) {            if (WindowManagerService.DEBUG_INPUT) {                Slog.v(WindowManagerService.TAG, "Resuming WindowToken " + window);            }                        window.paused = false;            updateInputWindowsLw(true /*force*/);        }    }</span>
在InputDispatcher中,findFocusedWindowTargetsLocked()和 findTouchedWindowTargetsLocked()中尋找到的目標視窗如果狀態為paused,那麼就會調用handleTargetsNotReadyLocked()進行等待。
<span style="font-size:18px;">if (touchedWindow.windowHandle->getInfo()->paused) {                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,                        NULL, touchedWindow.windowHandle, nextWakeupTime,                        "Waiting because the touched window is paused.");                goto Unresponsive;            }</span>
完。


筆記本需要串連電視,電視上只有這些介面VIDEMO,AV1,AV2,MONITOR,AUDIO,SVHS,INPUT,OUT PUT,應該怎辦?

筆記本上有SVIDEO介面,你找根VIDEO線,一般電視或筆記本有配的,一頭插筆記本的SVIDEO介面,一頭插到MONITOR好像,如果不行你換其他插孔試試,我記不清了,應該就可以了
 
input monitor不可以調節!!

你是HD音效卡嗎

下載一個這個補丁安裝就好了

:微軟HD Audio 匯流排驅動程式(kb888111)

www.52z.com/soft/12900.html
 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.