主頁 > 移動端開發 > 搶紅包軟體背后的 Accessibility 服務及啟動原理

搶紅包軟體背后的 Accessibility 服務及啟動原理

2021-09-20 12:32:25 移動端開發

在這里插入圖片描述

前言

最近開發的一款設備使用到了Accessibility 功能,Android 提供了Accessibility功能和服務幫助這些用戶更加簡單地操作設備,

需要實作AccessibilityService,AccessibilityService是一個系統服務,它運行在后臺,并且能夠收到由系統發出的一些事件,比如通知狀態、view 的一些相關事件,指紋,touch 等,

界面中產生的任何變化都會由系統通知給 AccessibilityService,大家熟知的搶紅包軟體,Talkback 都是使用AccessibilityService 實作的,自動化測驗等等,都是基于 Accessibility,

后面幾篇文章,將慢慢揭開Accessibility的神秘的面紗,請大家多多關注,

AccessibilityService 是 Service 嗎

簡單例子這里面就不講了,大家可以網上搜索下,

AndroidManifest.xml 配置如下

 <service
        android:name="XXX.Service"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessible_service_config" />//對AccessibilityService 的組態檔
    </service>
</application>

AccessibilityService 寫法就是 Serviceandroid:permissionintent-filter 都是必要配置,

貌似還是 Service 那一套,但又不僅限于此,后面的內容可以發現它是不一般的 Servcie,

AccessibilityService 如何啟動的

雖作為 Servcie,App 本身并沒有啟動和停止它,完全由系統調度,這是第一個不一樣的地方,

在 AOSP 中類似的由系統調度的 App Service 有很多,比如 JobServiceAutoFillServiceNotificationAssistantService

下面將將具體解答這兩個問題:

  1. 誰啟動和停止 AccessibilityService ?
  2. 設備重啟了,AccessbilityService 也會啟動嗎,不會被kill嗎?

1. 誰啟動了 AccessibilityService

安裝AccessibilityService 的應用,會出現在設定-無障礙-應用串列中,選擇打開,應用中的AccessibilityService 就啟動,

代碼上,設定應用 會將AccessibilityService 的 ComponentName 資訊 存入 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES

AccessibilityManagerService 系統服務將監聽該 Map 的變化,啟動或者關閉相應 ComponentName 的 AccessibilityService,

流程如下:

  1. 監聽 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
  2. 更新 AccessibilityUserState
  3. 遍歷 mEnableServices ,如果沒有bind 則呼叫 bindService 啟動它

2、重啟會AccessbilityService 會啟動嗎,不會被kill?

AccessibilityManagerService 是 SystemService 行程,開機自啟動,所以 AccessbilityService 的開機啟動就簡單了,原始碼是監聽 unlock 廣播,

bindService 則使用 Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE FLAG 來啟動前臺級別的 service,所以不會被Kill,

frameworks/baseservices/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
public void bindLocked() {
    AccessibilityUserState userState = mUserStateWeakReference.get();
    if (userState == null) return;
    final long identity = Binder.clearCallingIdentity();
    try {
        int flags = Context.BIND_AUTO_CREATE
                | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE  //前臺service,所以不會被Kill
                | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
                | Context.BIND_INCLUDE_CAPABILITIES;
        if (userState.getBindInstantServiceAllowedLocked()) {
            flags |= Context.BIND_ALLOW_INSTANT;
        }
        if (mService == null && mContext.bindServiceAsUser(
                mIntent, this, flags, new UserHandle(userState.mUserId))) {
            userState.getBindingServicesLocked().add(mComponentName);
        }
    } finally {
        Binder.restoreCallingIdentity(identity);
    }
    mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(),
            mAccessibilityServiceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
            userState.mUserId);
}

注意:開發中遇到過一種情況 AccessibilityService 不會啟動,設定 App 中會顯示無法運行,點按可查看相關資訊的提示,這題由于 AccessibilityService 所在的 App 發生了 crash,而 crash 資訊會記錄在AccessibilityUserState中,不再自動 bind,

以上流程AccessibilityManagerService 與 應用中AccessibilityService通信,

AccessibilityService 和 AccessibilityManagerService 的關系

分析完以上流程,可以看到

  • AccessibilityManagerService 充當了 client
  • AccessibilityService 則是 service

所以呼叫程序的本質上是AccessibilityManagerService -> AccessibilityService,

可能有朋友會有疑惑:AccessibilityService 雖然本質上是 Service ,但分明又提供了 onServiceConnected 的方法,那它到除錯于 client 還是 service?

從以上時序圖可以看出,AccessibilityManagerService 系結 AccessibilityService 成功后,會立即呼叫 IAccessibilityServiceClient#init(),

init() 的目的很簡單:將 AccessibilityManagerService 側的 IAccessibilityServiceConnection 介面回呼回來,可以方便AccessibilityService 反過來呼叫 AccessibilityManagerService,回呼過來的介面正常的話會呼叫上述提供的 onServiceConnected(),

簡言之,這個 onServiceConnected() 指的是 AccessibilityManagerService 的 IAccessibilityServiceConnection 服務準備好了,

public abstract class AccessibilityService extends Service {
    ...
    public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
            implements HandlerCaller.Callback {
        ...
        public void init(IAccessibilityServiceConnection connection, int connectionId,
                IBinder windowToken) {
            // Binder 執行緒切換到 Main 執行緒
            // 傳遞 id 和 AccessibilityManagerService 回傳的 connection 介面
            Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
                    connection, windowToken);
            mCaller.sendMessage(message);
        }
        ...

        @Override
        public void executeMessage(Message message) {
            switch (message.what) {
                ...
                case DO_INIT: {
                    mConnectionId = message.arg1;
                    SomeArgs args = (SomeArgs) message.obj;
                    IAccessibilityServiceConnection connection =
                            (IAccessibilityServiceConnection) args.arg1;
                    IBinder windowToken = (IBinder) args.arg2;
                    args.recycle();
                    // 如果系統回傳的 connection 沒有問題
                    // 回呼 AccessibilityService 自己的初始化
                    // 并回呼提供的 onServiceConnected()
                    if (connection != null) {
                        AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
                                connection);
                        mCallback.init(mConnectionId, windowToken);
                        mCallback.onServiceConnected();
                    } else {
                        AccessibilityInteractionClient.getInstance().removeConnection(
                                mConnectionId);
                        mConnectionId = AccessibilityInteractionClient.NO_ID;
                        AccessibilityInteractionClient.getInstance().clearCache();
                        mCallback.init(AccessibilityInteractionClient.NO_ID, null);
                    }
                    return;
                    ...
                }
            }
        }
    }
}

所以說:AccessibilityService 這種特殊的 Service,既是供 AccessibilityManagerService 傳遞無障礙事件的 service,同時又是會反向呼叫 AccessibilityManagerService 的 client

那 AccessibilityService 什么時候需要反向呼叫 AccessibilityManagerService 呢?

其實這種的場景很多,這構成了 AccessibilityService 功能的重要部分,包括:

  • 動態更新 Accessibility 的配置(serServiceInfo())
  • 發出具體的手勢(dispatchGesture())
  • 發出截圖的請求(takeScreenshot())
  • 發出螢屏縮放的請求(setMagnificationScaleAndCenter())
  • 等等

下面提及的 Accessibility 配置的動態更新正是這個場景之一!

Accessibility 配置的加載

AccessibilityService 支持很多配置,但是很多配置在實際開發中都是用不到的,配置的方式有靜態動態兩種,

  • 靜態配置(更為推薦)
    就像文章開頭在 meta-data 里配置資訊

  • 動態配置
    運行中呼叫 serServiceInfo() 根據需要動態更新配置

從上圖可以看出,

  • 靜態配置:AccessibilityManagerService 通過 PackageManager 獲取 xml 的配置資訊,就轉化為 AccessibilityServiceInfo,AccessibilityServiceInfo 保存在 System Server行程

  • 動態配置:app 使用 IAccessbilityServiceConnection 介面作為橋梁,去呼叫 System Server ,設定 AccessibilityServiceInfo

具體配置的內容,這里就不多講了,整個Accessibility 的內容是很龐大的,所以相關配置也比較多,后面文章會結合功能跟大家分享,這樣也更容易懂,這里就跟大家賣個關子吧,

AccessibilityService 的除錯

上面說過開啟的 AccessibilityService 會存在 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES 中,通過相應的 adb 命令可以實時列印這些資訊,高效除錯,

adb shell settings get secure enabled_accessibility_services

可以讀當然也可以寫,免去了到 Settings App 里手動打開:

adb shell settings put secure enabled_accessibility_services <com.example.xxx/.xxxService>

注意:引數是所有打開的 Service 串列,新寫入的 Service 名稱要在已有的 Service 后面追加,用:隔開,不然會清除其他 開啟的Servcie,

adb shell settings put secure enabled_accessibility_services <xxx/.xxxService:xxx/.xxxService:xxx/.xxxService>

除了查看開啟,同時還有個命令可以觀察 AccessibilityService 的 boundunboundcrash 等詳細資訊,

adb shell dumpsys accessibility

總結

本次主要分享了AccessibilityService 是如何啟動, AccessibilityService 如何與SystemServer 中 AccessibilityManagerService 如何相互呼叫,

大概關系如圖所示:

總結如下:

  • AccessibityManagerService 創建和管理 AccessibilityServiceConnection
  • AccessibilityServiceConnection 與 App 中的 AccessibilityService 一 一對應
  • AccessibilityService 將 IAccessibilityServiceClient 介面暴露給 AccessibityManagerService 調度
  • AccessibityManagerService 將 IAccessibilityServiceConnection 介面傳遞給 AccessibilityService 回呼

再次梳理下 AccessibilityService 的特點:

  1. AccessibityManagerService bind 和 unbind
  2. 設備重啟會自行啟動
  3. 擁有前臺 Service 的 Flag,優先級高不會被 kill 掉
  4. 接受 AccessibityManagerService 的調度,同時會反向呼叫,既是 service 又是 client

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/301561.html

標籤:其他

上一篇:關于華為手機無線除錯

下一篇:Uniapp+UviewUI實作購物商城

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more