天天看點

Android Instrumention.sendPointerSync發送Event失敗分析

問題場景

    Android4.3,進入被測app某個Activity後,測試案例ClickOnScreen出現異常(Click can not be completed!)。

    Android4.4正常。

前置說明

    測試案例使用的是本人實作的測試架構,它底層調用了Robotium。

分析過程

    1. 架構調用了Robotium的ClickOnScreen,源碼如下:

    (com.jayway.android.robotium.solo.Clicker)

Android Instrumention.sendPointerSync發送Event失敗分析

    當sendPointerSync(發送點選事件給被測app)10次都失敗,便會斷言異常:Click can not be completed。

    而引發sendPointerSync的異常是:SecurityException。在Android中,出現SecurityException異常是因為權限不足,一般的情況是:被測試App和測試案例的簽名不一緻,而這在instrumention啟動被測試app就出現,不用等到instrument.sendPointerSync,這裡是其他的問題引發的。

    2. 繼續跟進問題。

    (1)android.app.Instrumentation

Android Instrumention.sendPointerSync發送Event失敗分析

    (2)android.hardware.input.InputManager

Android Instrumention.sendPointerSync發送Event失敗分析

    (3)android.hardware.input.IInputManager

Android Instrumention.sendPointerSync發送Event失敗分析

    最後是調用Binder.transect進行跨程序調用。

   3. 被調用者是系統服務,可追朔到InputManagerService的injectInputEvent。

   (1)/frameworks/base/services/java/com/android/server/input/InputManagerService.java

Android Instrumention.sendPointerSync發送Event失敗分析

    終于發現了我們要找的SecurityException,導緻INPUT_EVENT_INJECTION_PERMISSION_DENIED是jni層的nativeInjectInputEvent。

   (2)/frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

Android Instrumention.sendPointerSync發送Event失敗分析

   (3)/frameworks/base/services/input/InputDispatcher.cpp

Android Instrumention.sendPointerSync發送Event失敗分析

    終于發現了INPUT_EVENT_INJECTION_PERMISSION_DENIED蹤迹,繼續檢視checkInjectionPermission:

Android Instrumention.sendPointerSync發送Event失敗分析

    檢視系統日志,發現是造成Permission驗證失敗的原因是:目前windowHandle(被測app)->owneruid與注入者(instrument)->injectoruid不一緻。并且windowHandle(被測app)的owneruid竟然是1000(系統賬戶)!

    (4) 系統日志如下:

Android Instrumention.sendPointerSync發送Event失敗分析

    同時,根據windowHandle->getName().string(),我意外發現“兇手”的Name是:hidden nav(隐藏的nav??….)。

    4. 在 被測app源碼 和 Android源碼中分别查找,最終發在“兇手”匿藏在PhoneWindowManager中……

    (1)/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

Android Instrumention.sendPointerSync發送Event失敗分析

   mHideNavFakeWindow的建立了addFackWindow,mHideNavFakeWindow的owneruid=Process.getmyid()(這裡不列代碼了), 而PhoneWindowManager是内部服務PhoneWindowService的政策類,屬于系統使用者。是以mHideNavFakeWindow這個透明的視窗,也是系統使用者級别了(mHideNavFakeWindow為了滿足某特殊需要,不得不設定為系統使用者)…

而執行這個分支,需要滿足一個條件:在重渲染ui界面時,被設定了标記:View.SYSTEM_UI_FLAG_HIDE_NAVIGATION。

    在被測App源碼代碼中search,終于發現疑似兇手:view.getRootView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); 而它确實就在出現ClickOnScreen異常的Activity裡。最後經調試,确認問題确實如此。

4.3 與 4.4表現不一緻的原因

    對比PhoneWindowManager 4.3和4.4的代碼,發4.4做了改進,如下(右為4.4):

Android Instrumention.sendPointerSync發送Event失敗分析

    而在被測app的代碼中…..

Android Instrumention.sendPointerSync發送Event失敗分析

   就是 被測試App 在4.4時,會增加一個flag,導緻了它撞大運般地在4.4中執行流程發生了改變,避免了mHideNavFakeWindow建立,進而也避免異常的發生。

總結

    1. 個人認為這是Android設計上的bug,它的instrument在極端的情況下會失效。

    2. 除非測試案例在系統中以系統使用者啟動,否則在4.3以下系統,該問題無法避免!

    3. 隻要有mHideNavFakeWindow的存在,原則上所有的操作都會失敗,包括drag在内,但Robotium對drag的異常進行了攔截并直接丢棄,是以使用drag表面是成功的,但實際上是失敗,這會導緻運作中出現無法解釋的詭異問題。

<b></b>

<b>本文轉自hyddd部落格園部落格,原文連結:http://www.cnblogs.com/hyddd/p/3995281.html,如需轉載請自行聯系原作者。</b>

繼續閱讀