Android Instrumention.sendPointerSync發送Event失敗分析

問題場景java

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

    Android4.4正常。app

 

前置說明框架

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

 

分析過程測試

    1. 框架調用了Robotium的ClickOnScreen,源碼以下:ui

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

     clicker

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

    而引起sendPointerSync的異常是:SecurityException。在Android中,出現SecurityException異常是由於權限不足,通常的狀況是:被測試App和測試案例的簽名不一致,而這在instrumention啓動被測試app就出現,不用等到instrument.sendPointerSync,這裏是其餘的問題引起的。3d

 

    2. 繼續跟進問題。

    (1)android.app.Instrumentation

    2

    (2)android.hardware.input.InputManager

    3

    (3)android.hardware.input.IInputManager

   4

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

 

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

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

    5

    終於發現了咱們要找的SecurityException,致使INPUT_EVENT_INJECTION_PERMISSION_DENIED是jni層的nativeInjectInputEvent

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

    x

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

    7

    終於發現了INPUT_EVENT_INJECTION_PERMISSION_DENIED蹤影,繼續查看checkInjectionPermission:

    8

    查看系統日誌,發現是形成Permission驗證失敗的緣由是:當前windowHandle(被測app)->owneruid與注入者(instrument)->injectoruid不一致。而且windowHandle(被測app)的owneruid居然是1000(系統帳戶)!

    (4) 系統日誌以下:

    9

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

 

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

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

    10

   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):

11

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

    12

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

 

總結

    1. 我的認爲這是Android設計上的bug,它的instrument在極端的狀況下會失效。

    2. 除非測試案例在系統中以系統用戶啓動,不然在4.3如下系統,該問題沒法避免!

    3. 只要有mHideNavFakeWindow的存在,原則上全部的操做都會失敗,包括drag在內,但Robotium對drag的異常進行了攔截並直接丟棄,因此使用drag表面是成功的,但其實是失敗,這會致使運行中出現沒法解釋的詭異問題。

相關文章
相關標籤/搜索