1. 程式人生 > >Android 9.0原始碼學習-AccessibilityManager

Android 9.0原始碼學習-AccessibilityManager

Android Accessibility是為了幫助殘障人士更好使用手機開發出來一個模組,比如螢幕閱讀器,手勢等等,當然現在已經被玩壞了,各種外掛,比如微信搶紅包的外掛,也是基於Accessibility寫出來的。

Accessibility Architecture

先拿一個具體的例子來看,這是一個搶紅包的外掛,把WeChat稱作Target APP,就是被監控的APP,當跳出來一個紅包,觸發了一個AccessibilityEvent,system_server中的AccessibilityManagerService將AccessibilityEvent分發給有AccessibilityService

的APP,稱為Accessibility APP,這個AccessibilityService受到這個AccessibilityEvent後,會找到這個頁面的Open Button,模擬點選。(Target APP和Accessibility APP是我看別的部落格這麼取的)
在這裡插入圖片描述

Core Class

剛才舉得例子是表象,那麼程式內部,這個過程其實就是三個類之間的互動,當然實際不止這麼簡單啦,這個後面再講,現在只要記住這三個是核心的類就好了。(以下都會用縮寫代替

  • AccessibilityManager(AM):Send AccessibilityEvent
  • AccessibilityServiceManager(AMS
    ):Dispatch
  • AccessibilityService(AS):Response

在這裡插入圖片描述

File List

File Name File Path
View.java /frameworks/base/core/java/android/view/View.java
ViewRootImpl.java /frameworks/base/core/java/android/view/ViewRootImpl.java
AccessibilityManager.java /frameworks/base/core/java/android/view/accessibility/AccessibilityManager.java
AccessibilityManagerService.java /frameworks/base/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
AbstractAccessibilityServiceConnection.java /frameworks/base/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
AccessibilityServiceConnection.java /frameworks/base/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
AccessibilityManagerService.java /frameworks/base/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
AccessibilityService.java /frameworks/base/core/java/android/accessibilityservice/AccessibilityService.java

Accessibility Flow

Accessibility Flow主要有下面幾個Flow了:

  1. AMS繫結AS
  2. AM與AMS聯絡
  3. AccessibilityEvent Dispatch
  4. Response to AccessibilityEvent
    在這裡插入圖片描述

AMS繫結AS

在這裡插入圖片描述

上圖是AMS與AS聯絡的flow,下面一步一步的來說。

Step1:什麼時候AMS會繫結AS?

  • Settings->Accessibility->enable(enableAccessibilityServiceLocked()
  • Settings->Accessibility->disable(disableAccessibilityServiceLocked()
  • Some RegisterBroadcastReceivers (registerBroadcastReceivers()
    • onSomePackagesChanged()
    • onPackageUpdateFinished()
    • onHandleForceStop()
    • onPackageRemoved()
  • Others State Change

當用戶在設定->無障礙裡面選擇了開啟或關閉一個輔助功能,會導致一些系統狀態會變化;Accessibility APP的安裝狀態會以BroadcastReceivers的方式會通知狀態改變;還有其他的一些狀態改變。這些變化最終會呼叫到AMS的onUserStateChangedLocked()方法。

在這裡插入圖片描述

AccessibilityManagerService.java – enableAccessibilityServiceLocked()

		  /**
2333       * Enables accessibility service specified by {@param componentName} for the {@param userId}.
2334       */
2335      private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
2336          final SettingStringHelper setting =
2337                  new SettingStringHelper(
2338                          mContext.getContentResolver(),
2339                          Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
2340                          userId);
2341          setting.write(ComponentNameSet.add(setting.read(), componentName));
2342  
2343          UserState userState = getUserStateLocked(userId);
2344          if (userState.mEnabledServices.add(componentName)) {
2345              onUserStateChangedLocked(userState);
2346          }
2347      }

AccessibilityManagerService.java – disableAccessibilityServiceLocked()

    	 /**
2350       * Disables accessibility service specified by {@param componentName} for the {@param userId}.
2351       */
2352      private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
2353          final SettingsStringUtil.SettingStringHelper setting =
2354                  new SettingStringHelper(
2355                          mContext.getContentResolver(),
2356                          Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
2357                          userId);
2358          setting.write(ComponentNameSet.remove(setting.read(), componentName));
2359  
2360          UserState userState = getUserStateLocked(userId);
2361          if (userState.mEnabledServices.remove(componentName)) {
2362              onUserStateChangedLocked(userState);
2363          }
2364      }

AccessibilityManagerService.java – registerBroadcastReceivers()

    private void registerBroadcastReceivers() {
324          PackageMonitor monitor = new PackageMonitor() {
325              @Override
326              public void onSomePackagesChanged() {
327                  synchronized (mLock) {
328                      // Only the profile parent can install accessibility services.
329                      // Therefore we ignore packages from linked profiles.
330                      if (getChangingUserId() != mCurrentUserId) {
331                          return;
332                      }
333                      // We will update when the automation service dies.
334                      UserState userState = getCurrentUserStateLocked();
335                      // We have to reload the installed services since some services may
336                      // have different attributes, resolve info (does not support equals),
337                      // etc. Remove them then to force reload.
338                      userState.mInstalledServices.clear();
339                      if (readConfigurationForUserStateLocked(userState)) {
340                          onUserStateChangedLocked(userState);
341                      }
342                  }
343              }
344  
345              @Override
346              public void onPackageUpdateFinished(String packageName, int uid) {
347                  // Unbind all services from this package, and then update the user state to
348                  // re-bind new versions of them.
349                  synchronized (mLock) {
350                      final int userId = getChangingUserId();
351                      if (userId != mCurrentUserId) {
352                          return;
353                      }
354                      UserState userState = getUserStateLocked(userId);
355                      boolean unboundAService = false;
356                      for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
357                          AccessibilityServiceConnection boundService =
358                                  userState.mBoundServices.get(i);
359                          String servicePkg = boundService.mComponentName.getPackageName();
360                          if (servicePkg.equals(packageName)) {
361                              boundService.unbindLocked();
362                              unboundAService = true;
363                          }
364                      }
365                      if (unboundAService) {
366                          onUserStateChangedLocked(userState);
367                      }
368                  }
369              }
370  
371              @Override
372              public void onPackageRemoved(String packageName, int uid) {
373                  synchronized (mLock) {
374                      final int userId = getChangingUserId();
375                      // Only the profile parent can install accessibility services.
376                      // Therefore we ignore packages from linked profiles.
377                      if (userId != mCurrentUserId) {
378                          return;
379                      }
380                      UserState userState = getUserStateLocked(userId);
381                      Iterator<ComponentName> it = userState.mEnabledServices.iterator();
382                      while (it.hasNext()) {
383                          ComponentName comp = it.next();
384                          String compPkg = comp.getPackageName();
385                          if (compPkg.equals(packageName)) {
386                              it.remove();
387                              // Update the enabled services setting.
388                              persistComponentNamesToSettingLocked(
389                                      Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
390                                      userState.mEnabledServices, userId);
391                              // Update the touch exploration granted services setting.
392                              userState.mTouchExplorationGrantedServices.remove(comp);
393                              persistComponentNamesToSettingLocked(
394                                      Settings.Secure.
395                                      TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
396                                      userState.mTouchExplorationGrantedServices, userId);
397                              onUserStateChangedLocked(userState);
398                              return;
399                          }
400                      }
401                  }
402              }
403  
404              @Override
405              public boolean onHandleForceStop(Intent intent, String[] packages,
406                      int uid, boolean doit) {
407                  synchronized (mLock) {
408                      final int userId = getChangingUserId();
409                      // Only the profile parent can install accessibility services.
410                      // Therefore we ignore packages from linked profiles.
411                      if (userId != mCurrentUserId) {
412                          return false;
413                      }
414                      UserState userState = getUserStateLocked(userId);
415                      Iterator<ComponentName> it = userState.mEnabledServices.iterator();
416                      while (it.hasNext()) {
417                          ComponentName comp = it.next();
418                          String compPkg = comp.getPackageName();
419                          for (String pkg : packages) {
420                              if (compPkg.equals(pkg)) {
421                                  if (!doit) {
422                                      return true;
423                                  }
424                                  it.remove();
425                                  persistComponentNamesToSettingLocked(
426                                          Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
427                                          userState.mEnabledServices, userId);
428                                  onUserStateChangedLocked(userState);
429                              }
430                          }
431                      }
432                      return false;
433                  }
434              }
435          };
436  
437          // package changes
438          monitor.register(mContext, null,  UserHandle.ALL, true);
439  
440          // user change and unlock
441          IntentFilter intentFilter = new IntentFilter();
442          intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
443          intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
444          intentFilter.addAction(Intent.ACTION_USER_REMOVED);
445          intentFilter.addAction(Intent.ACTION_USER_PRESENT);
446          intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
447  
448          mContext.registerReceiverAsUser(new BroadcastReceiver() {
449              @Override
450              public void onReceive(Context context, Intent intent) {
451                  String action = intent.getAction();
452                  if (Intent.ACTION_USER_SWITCHED.equals(action)) {
453                      switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
454                  } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
455                      unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
456                  } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
457                      removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
458                  } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
459                      // We will update when the automation service dies.
460                      synchronized (mLock) {
461                          UserState userState = getCurrentUserStateLocked();
462                          if (readConfigurationForUserStateLocked(userState)) {
463                              onUserStateChangedLocked(userState);
464                          }
465                      }
466                  } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
467                      final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
468                      if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) {
469                          synchronized (mLock) {
470                              restoreEnabledAccessibilityServicesLocked(
471                                      intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
472                                      intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
473                          }
474                      }
475                  }
476              }
477          }, UserHandle.ALL, intentFilter, null, null);
478      }

這些狀態的變化都會呼叫到AMS的onUserStateChangedLocked()

onUserStateChangedLocked()中,我們關注updateServicesLocked(userState)這個函式,其他的函式是一些特定狀態的更新。

AccessibilityManagerService.java – onUserStateChangedLocked()

     	  /**
1765       * Called when any property of the user state has changed.
1766       *
1767       * @param userState the new user state
1768       */
1769      private void onUserStateChangedLocked(UserState userState) {
1770          // TODO: Remove this hack
1771          mInitialized = true;
1772          updateLegacyCapabilitiesLocked(userState);
1773          updateServicesLocked(userState);
1774          updateAccessibilityShortcutLocked(userState);
1775          updateWindowsForAccessibilityCallbackLocked(userState);
1776          updateAccessibilityFocusBehaviorLocked(userState);
1777          updateFilterKeyEventsLocked(userState);
1778          updateTouchExplorationLocked(userState);
1779          updatePerformGesturesLocked(userState);
1780          updateDisplayDaltonizerLocked(userState);
1781          updateDisplayInversionLocked(userState);
1782          updateMagnificationLocked(userState);
1783          updateSoftKeyboardShowModeLocked(userState);
1784          scheduleUpdateFingerprintGestureHandling(userState);
1785          scheduleUpdateInputFilter(userState);
1786          scheduleUpdateClientsIfNeededLocked(userState);
1787          updateRelevantEventsLocked(userState);
1788          updateAccessibilityButtonTargetsLocked(userState);
1789      }

AccessibilityManagerService.java – updateServicesLocked(userState)

1541    	private void updateServicesLocked(UserState userState) {
1542          Map<ComponentName, AccessibilityServiceConnection> componentNameToServiceMap =
1543                  userState.mComponentNameToServiceMap;
1544          boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class)
1545                      .isUserUnlockingOrUnlocked(userState.mUserId);
1546  
1547          for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
1548              AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
1549              ComponentName componentName = ComponentName.unflattenFromString(
1550                      installedService.getId());
1551  
1552              AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName);
1553  
1554              // Ignore non-encryption-aware services until user is unlocked
1555              if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) {
1556                  Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
1557                  continue;
1558              }
1559  
1560              // Wait for the binding if it is in process.
1561              if (userState.mBindingServices.contains(componentName)) {
1562                  continue;
1563              }
1564              if (userState.mEnabledServices.contains(componentName)
1565                      && !mUiAutomationManager.suppressingAccessibilityServicesLocked()) {
1566                  if (service == null) {
1567                      service = new AccessibilityServiceConnection(userState, mContext, componentName,
1568                              installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
1569                              this, mWindowManagerService, mGlobalActionPerformer);
1570                  } else if (userState.mBoundServices.contains(service)
            
           

相關推薦

Android 9.0原始碼學習-AccessibilityManager

Android Accessibility是為了幫助殘障人士更好使用手機開發出來一個模組,比如螢幕閱讀器,手勢等等,當然現在已經被玩壞了,各種外掛,比如微信搶紅包的外掛,也是基於Accessibility寫出來的。 Accessibility Architec

學習Android 9.0/P http 網路請求的問題

今天在網上看文章的時候看到了這一篇文章,說是Android9.0網路請求會有問題,然後好奇就仔細看了一下。看完之後感覺對自己以後可能有用處就寫這篇文章來記錄一下。以後用到的話可以拿來用一下。 為什麼特意注意了一下這篇文章呢,因為我們公司的請求一直用的是Http而不是用的Https,所以感覺以後升

(Android) OkHttp3.11 原始碼學習筆記 9 CallServerInterceptor分析

這個攔截器主要負責向伺服器發起真正的網路請求,並接收到response,再返回,下面為主要的intercept方法原始碼 @Override public Response intercept(Chain chain) throws IOException { RealIntercept

(Android) OkHttp3.10 原始碼學習筆記 9 ConnectInterceptor分析

首先我們還是去看它的intercept方法 @Override public Response intercept(Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChai

深入原始碼分析non-sdk並繞過Android 9.0反射限制

Android 9.0終於來了,non-sdk或許是我們最大的適配點。本文將分析non-sdk的原理以及如何繞過它繼續反射呼叫系統私有API。 先看一段簡單的反射程式碼: Class<?> activityThreadClass =

Android 9.0)Activity啟動流程原始碼分析

前言 熟悉Activity的啟動流程和執行原理是一個合格的應用開發人員所應該具備的基本素質,其重要程度就

Android 9.0新特性

進入 估算 電話 定制化 看電影 時間 體驗 cati adapt 1、全面屏支持,Android P加入了對劉海屏的支持,谷歌稱之為凹口屏幕(display with a cutout)。借助最新的提供的DisplayCutout類,開發者可以找到非功能區域的位置和形狀,

Android 9.0更新

調用 附近 drm 字節 解碼 產品 emf NPU 2018年 北京時間2018年8月7日上午,Google 發布了 Android 9.0 操作系統。並宣布系統版本 Android P 被正式命名為代號“Pie”。 Android 9.0 利用人工智能技術,讓手機變得更

Android 9.0/P http 網路請求的問題

Google表示,為保證使用者資料和裝置的安全,針對下一代 Android 系統(Android P) 的應用程式,將要求預設使用加密連線,這意味著 Android P 將禁止 App 使用所有未加密的連線,因此執行 Android P 系統的安卓裝置無論是接收或者傳送流量,未來都不能明碼傳輸,需要使用下一代

Android : 為系統服務新增 SeLinux 許可權 (Android 9.0)

一、SElinux在Android 8.0後的差異:   從Android 4.4到Android 7.0的SELinux策略構建方式合併了所有sepolicy片段(平臺和非平臺),然後在根目錄生成單一檔案,而Android 8.0開始關於selinux架構也類似於HIDL想把系統平臺的selinux策略和

[電池]Android 9.0 電池未充電與充電字串提示資訊

1. 電池電量提醒 1.1 未充電提醒 若沒有預估時間,則提示顯示電池百分比 若預估時間小於7分鐘,則提示手機可能即將關機 若預估時間小於15分鐘,則提示剩餘電池續航時間不到15分鐘 若15分鐘<預估時間<1天,則提示估計大約還能用到xx h

Android 9.0 功能和 API概覽(中文版)

Android 9 功能和 API 官方搬運: Android 9(API 級別 28)為使用者和開發者引入了眾多新特性和新功能。 本文重點介紹面向開發者的新功能。 利用 Wi-Fi RTT 進行室內定位 Android 9 添加了對 IEEE 802.1

Android 9.0 (P版本) SystemServer中的服務配置se linux許可權

## 1. SystemServer 的服務定義 Android P_9.0\frameworks\base\services\java\com\android\server\SystemServer.java /** * Starts a m

Android 9.0 (P版本) MTK平臺原生的待機智慧省電功能

1. 原生介面UI 2. 原始碼檢視 2.1 字串 Z:\9.1\vendor\mediatek\proprietary\packages\apps\MtkSettings_Eclipse\res_ext\values-zh-rCN\mtk_strings.x

Android 9.0 優勢探討

我們來談論一下 Android。儘管 Android 只是一款核心經過修改的 Linux,但經過多年的發展,Android 開發者們(或許包括正在閱讀這篇文章的你)已經為這個平臺的演變做出了很多值得稱道的貢獻。當然,可能很多人都已經知道,但我們還是要說,Android 並不完全開源,當你使用 G

android 9.0 獲取Uri許可權並且轉換成path輸出

原文地址: Write  by  cdsn @包羅萬碼 At 2018/10/26 需要許可權:  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 一個工具

Mac上下載編譯Android 6.0原始碼詳細記錄

第一步: 使用命令建立一個字尾為.dmg或.dmg.sparseimage的映象檔案 $ hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 80g ~/

[Android 編譯(一)] Ubuntu 16.04 LTS 成功編譯 Android 6.0 原始碼教程

1 前言 經過3天奮戰,終於在Ubuntu 16.04上把Android 6.0的原始碼編譯出來了,各種配置,各種error,各種爬坑,特寫此部落格記錄爬坑經歷。先上圖,Ubuntu上編譯完後成功執行模擬器,如圖: 2 編譯環境 UbuntuKy

Android GreenDao3.0入門學習

1. 什麼是greenDao 弄明白greenDao之前我們應該先了解什麼是ORM(Object Relation Mapping 即 物件關係對映),說白了就是將面向物件程式語言裡的物件與資料庫關聯起來的一種技術,而greenDao就是實現這種技術之一,所以說greenDao其實就是一

Android 6.0原始碼的角度剖析Activity的啟動過程

在從Android 6.0原始碼的角度剖析Window內部機制原理文章中,我們詳細剖析了Android Window的內部工作機制,瞭解到每一個Activity都對應著一個Window,Activity的檢視(View)都是依附在Window來呈現的,