Android-AccessibilityService
概述
AccessibilityService用于提供辅助功能服务,其在后台运行,并在触发AccessibilityEvents时由系统接收回调。此类事件表示用户界面中的某些状态转换,例如,焦点更改,按钮被单击等。此类服务可以可选地请求查询活动窗口内容的功能。
AccessibilityServiceInfo描述一个AccessibilityService,系统根据封装在此类中的信息将AccessibilityEvent通知给AccessibilityService。
AccessibilityService的生命周期仅由系统管理,并遵循Service的生命周期,用户只能通过在设备设置中显式打开服务来触发启动无障碍服务。系统绑定到服务后,它将调用AccessibilityService#onServiceConnected()。当用户在设备设置中将其关闭或调用AccessibilityService#disableSelf()时,AccessibilityService即会停止。
每个AccessibilityService在都是由AccessibilityManagerService注册的,当用户开启辅助服务后,系统会发送广播到AccessibilityManagerService,AccessibilityManagerService会注册AccessibilityService。当受到监控的App某个View发生了改变时,其内部会调用AccessibilityManager来发送Event。
声明
在Manifest文件中配置:
1 |
<service android:name=".MyAccessibilityService" |
配置
可以将AccessibilityService配置为接收特定类型的事件,仅侦听特定的程序包,在给定的时间范围内仅从每种类型获取事件一次,检索Window内容,指定设置Activity等。有两种配置的方法:
在Manifest中配置:
1
2
3
4
5
6<service android:name=".MyAccessibilityService">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" />
</service>在res目录下新建xml目录,配置accessibilityservice.xml如下:
1
2
3
4
5
6
7
8
9<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews|flagReportViewIds|flagRequestTouchExplorationMode"
android:canRetrieveWindowContent="true"
android:description="@string/description"
android:notificationTimeout="100"
android:packageNames="com.tencent.mm,com.eg.android.AlipayGphone" />与配置相关的可以参考官网:AccessibilityService
调用AccessibilityService#setServiceInfo(AccessibilityServiceInfo)进行配置,该方法任意时候都可以调用,用来动态改变该Service的配置。此方法仅允许设置动态可配置属性:
- AccessibilityServiceInfo#eventTypes
- AccessibilityServiceInfo#feedbackType
- AccessibilityServiceInfo#flags
- AccessibilityServiceInfo#notificationTimeout
- AccessibilityServiceInfo#packageNames
Service Meta Data
属性 | 描述 |
---|---|
android:description | Descriptive text for the associated data |
android:summary | The summary for the item |
android:settingsActivity | Activity的Component name,允许用户修改此Service的设置 |
android:accessibilityEventTypes | 监视的动作,见AccessibilityEvent |
android:packageNames | 监控的软件包名,使用逗号隔开 |
android:accessibilityFeedbackType | 提供反馈类型,语音震动等等,见AccessibilityServiceInfo |
android:notificationTimeout | 两次相同类型的事件之间的间隔(以毫秒为单位) |
android:accessibilityFlags | 监视的view的状态,见AccessibilityServiceInfo |
android:canRetrieveWindowContent | 是否要能够检索活动窗口的内容,此设置不能在运行时改变 |
android:canRequestTouchExplorationMode | 请求触摸模式的属性,在这种模式下,可以通过手势浏览UI |
android:canRequestEnhancedWebAccessibility | 请求增强的Web可访问性增强功能的属性 |
android:canRequestFilterKeyEvents | 请求过滤关键事件的属性 |
android:canControlMagnification | 控制显示倍率的属性 |
android:canPerformGestures | 能否执行手势的属性 |
android:canRequestFingerprintGestures | 能否从指纹传感器捕获手势的属性 |
android:nonInteractiveUiTimeout | AccessibilityManager.getRecommendedTimeoutMillis(int,int)中使用的建议超时(以毫秒为单位),为不包含交互式控件的UI返回合适的值 |
android:interactiveUiTimeout | AccessibilityManager.getRecommendedTimeoutMillis(int,int)中使用的建议超时(以毫秒为单位),为交互式控件的UI返回合适的值 |
Event types
- AccessibilityEvent#TYPES_ALL_MASK
- AccessibilityEvent#TYPE_VIEW_CLICKED
- AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
- AccessibilityEvent#TYPE_VIEW_FOCUSED
- AccessibilityEvent#TYPE_VIEW_SELECTED
- AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
- AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
- AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
- AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
- AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
- AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
- AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
- AccessibilityEvent#TYPE_VIEW_SCROLLED
- AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
- AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
- AccessibilityEvent#TYPE_ANNOUNCEMENT
- AccessibilityEvent#TYPE_GESTURE_DETECTION_START
- AccessibilityEvent#TYPE_GESTURE_DETECTION_END
- AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
- AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
- AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
- AccessibilityEvent#TYPE_WINDOWS_CHANGED
- AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
Feedback types
- AccessibilityServiceInfo#FEEDBACK_ALL_MASK
- AccessibilityServiceInfo#FEEDBACK_AUDIBLE:表示可听(非语音)反馈
- AccessibilityServiceInfo#FEEDBACK_HAPTIC:表示触觉反馈
- AccessibilityServiceInfo#FEEDBACK_SPOKEN:表示语音反馈
- AccessibilityServiceInfo#FEEDBACK_VISUAL:表示视觉反馈
- AccessibilityServiceInfo#FEEDBACK_GENERIC:表示一般反馈
- AccessibilityServiceInfo#FEEDBACK_BRAILLE:表示盲文反馈
Flags
- AccessibilityServiceInfo#FLAG_ENABLE_ACCESSIBILITY_VOLUME:此标志请求由AudioManager.STREAM_ACCESSIBILITY控制系统范围内所有具有AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY的音频轨道。
- AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:如果设置了此标志,通过View#IMPORTANT_FOR_ACCESSIBILITY_NO或View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS标记为对accessibility不重要的View,以及通过View#IMPORTANT_FOR_ACCESSIBILITY_AUTO标记为对accessibility潜在重要的View,在查询窗口内容时被报告,并且AccessibilityService也将从中接收事件。对于Android 4.1(API级别16)或更高版本的AccessibilityService,必须显式设置相关标志。
- AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS:该标志请求AccessibilityService获得的包含源视图ID的AccessibilityNodeInfos。ID格式为
"package:id/name"
的标准资源名称,默认情况下未设置此标志。 - AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON:系统的导航区域中将显示一个辅助功能按钮。
- AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS:该标志要求系统过滤关键事件。
- AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES:将所有指纹手势发送到AccessibilityService。想要设置此标志的服务必须声明具有检索窗口内容的功能,在meta-data中配置R.attr.canRequestFingerprintGestures,见SERVICE_META_DATA。
- AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK。
- AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE:该标志请求系统进入触摸浏览模式,系统将检测在触摸屏上执行的某些手势并通知此Service。在Android 4.3以上的设备必须声明canRequestTouchExplorationMode,见SERVICE_META_DATA。
- AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS:访问所有交互式窗口的内容。如果未设置此标志,服务将不会收到AccessibilityEvent.TYPE_WINDOWS_CHANGED事件,调用AccessibilityServiceAccessibilityService#getWindows()将返回一个空列表,而AccessibilityNodeInfo#getWindow()将返回null。必须声明canRetrieveWindowContent,见SERVICE_META_DATA。
AccessibilityService
disableSelf
public final void disableSelf()
- 关闭AccessibilityService服务。
findFocus
public AccessibilityNodeInfo findFocus(int focus)
- 查找具有指定焦点类型的视图。
- focus取值:AccessibilityNodeInfo#FOCUS_INPUT/AccessibilityNodeInfo#FOCUS_ACCESSIBILITY。
getAccessibilityButtonController
public final AccessibilityButtonController getAccessibilityButtonController()
- 返回系统导航区域中的辅助功能按钮的控制器。
- 见AccessibilityButtonController
getFingerprintGestureController
public final FingerprintGestureController getFingerprintGestureController()
- 获取指纹手势的控制器。
- 见FingerprintGestureController
getServiceInfo
public final AccessibilityServiceInfo getServiceInfo()
getRootInActiveWindow
public AccessibilityNodeInfo getRootInActiveWindow()
- 获取当前活动窗口中的根节点。
AccessibilityNodeInfo
概述
此类表示Window Content中的一个Node。
addAction
public void addAction(AccessibilityNodeInfo.AccessibilityAction action)
- 添加可以在节点上执行的操作。
- 见AccessibilityAction
performAction
public boolean performAction(int action)
public boolean performAction(int action, Bundle arguments)
findAccessibilityNodeInfosByText
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text)
- 客户有责任调用AccessibilityNodeInfo#recycle()来回收接收到的信息,以避免创建多个实例。
- 这里的text不单单是TextView的Text,还包括一些组件的ContentDescription。
findAccessibilityNodeInfosByViewId
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId)
- 客户有责任调用AccessibilityNodeInfo#recycle()来回收接收到的信息,以避免创建多个实例。
- 组件的id获取可以通过Android Studio内置的工具Layout Inspector查看。
- viewId:pkg:id/name,例如
com.miui.securitycenter:id/am_detail_perm
。
AccessibilityEvent
概述
继承自AccessibilityRecord,表示当用户界面中发生了关注事件时系统发送的事件。
obtain
public static AccessibilityEvent obtain()
public static AccessibilityEvent obtain(int eventType)
public static AccessibilityEvent obtain(AccessibilityEvent event)
- 返回一个缓存的实例(如果有)或实例化一个新实例。
recycle
public void recycle()
AccessibilityRecord
概述
表示AccessibilityEvent中的一条记录,并包含有关其Source View的状态更改的信息。
原理解析
概述
AccessibilityService相关类图如下:
AccessibilityService
在AccessibilityService的onBind方法中返回了一个IAccessibilityServiceClientWrapper对象。
1 |
@Override |
Callbacks
该接口定义的方法与IAccessibilityServiceClient中是对应的:
1 |
public interface Callbacks { |
IAccessibilityServiceClient
IAccessibilityServiceClient是一个aidl接口,其方法如下:
1 |
oneway interface IAccessibilityServiceClient { |
IAccessibilityServiceClientWrapper
IAccessibilityServiceClientWrapper继承自IAccessibilityServiceClient.Stub,且实现了HandlerCaller.Callback接口,很显然与Binder IPC相关。其代码如下:
1 |
// IAccessibilityServiceClientWrapper |
AccessibilityInteractionClient
AccessibilityService用来进程跨进程通信,最终执行findAccessibilityNodeInfosByXXX和performAction的是AccessibilityInteractionClient。
其执行流程总结如下:
- AccessibilityInteractionClient没做什么操作,直接通过Binder调用了AccessibilityManagerService对应的方法。
- AccessibilityManagerService最终还是通过Binder调用了ViewRootImpl对应的方法。
- ViewRootImpl仅作为Binder中的服务端接收调用,真正的操作交给AccessibilityInteractionController来做。
- AccessibilityInteractionController对应的方法被调用之后,并没有直接进行操作,而是通过Handler做了一次转发,以便从Binder线程转到UI线程。
- 以performAction(ACTION_CLICK)点击事件为例,最终调用的实际是View的mOnClickListener。
- 以findAccessibilityNodeInfosByText为例,最终调用的实际是View的findViewsWithText方法,其方法内部实际对比的值是mContentDescription。需要特别说明的是TextView重写了该方法,其内部实际对比的值是mText。
流程总结
当View发生改变时,会发出一个AccessibilityEvent出来,这个Event会通过Binder驱动发送给IAccessibilityServiceClientWrapper,调用他的onAccessibilityEvent(AccessibilityEvent)
方法,这个方法通过Handler发送了一个Message给自己,目的是为了从Binder线程转回主线程。然后调用了mCallback.onAccessibilityEvent(event)
,间接的调用了AccessibilityService.this.onAccessibilityEvent(event)
,即我们自己实现的方法。
其外部调用的流程如下:
- 用户在设置页面启动了某个辅助模式服务;
- 系统发送了一条广播到AccessibilityManagerService,收到广播后,AccessibilityManagerService绑定了我们写的AccessibilityService,就这样调用了onBind方法。AIDL的Server端准备好了,AccessibilityManagerService是一个系统服务,由SystemService启动。
- 受到监控的App某个View发生了改变,其内部都会调用AccessibilityManager来发送event,其具体发送的对象是ViewRootImpl类来做的。
- 发出event后会通过Binder驱动调用到AccessibilityService,最终调用了我们复写的onAccessibilityEvent方法。
- 每一个View在AccessibilityService中都会被映射为一个AccessibilityNodeInfo对象,我们通过这个对象去查找具体View、触发事件,其本质是调用了AccessibilityInteractionClient类的对应方法。
- AccessibilityInteractionClient是一个可以执行accessibility交互的单例对象,它查询远程视图层次结构,查看视图的快照,以及来自这些层次结构的请求,以便在视图上执行某些操作。
- 如果利用AccessibilityInteractionClient操作正在被监控的App,比如点击按钮,那么View发生变化,又发送出一个Event,这样便形成一个循环。
防御措施
检测辅助模式的开启
可以通过AccessibilityManagerService提供的方法获取所有的辅助模式应用:
1 |
public class AccessibilityManagerService extends IAccessibilityManager.Stub { |
AccessibilityManagerService是com.android.server.accessibility包下的类,没有办法直接使用,可以通过AccessibilityManager来间接的操作AccessibilityManagerService,其内部利用Binder间接的调用了AccessibilityManagerService。代码如下:
1 |
/** |
当info.packageNames为null时,表示监控所有包名。外挂有可能蒙混其中,但如果一刀切,也有可能误杀正常软件。
Event干扰
随机发送外挂感兴趣的Event出来,干扰其允许。代码如下:
1 |
textView.sendAccessibilityEvent(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); |
屏蔽AccessibilityServices文案检查
在了解AccessibilityServices源码之后,我们知道其内部核心原理就是调用TextView的findViewsWithText方法,因此可以复写这个方法:
1 |
public class DefensiveTextView extends android.support.v7.widget.AppCompatTextView { |
屏蔽AccessibilityServices点击事件
像上面一样,通过源码了解原理之后,我们知道AccessibilityServices执行点击事件最终在调用View的mOnClickListener。因此可以利用onTouch代替onClick。
使用实例
开启辅助权限
1 |
public class AccessibilityHelper { |
实现AccessibilityService
1 |
public class CallAccessibilityService extends AccessibilityService { |
声明AccessibilityService
1 |
<service |
配置
1 |
<?xml version="1.0" encoding="utf-8"?> |
Android-AccessibilityService的更多相关文章
- Android AccessibilityService(辅助服务) 使用示例
1.前言 网上关于Android辅助服务的使用方式已经非常丰富了,所以也不在乎再多我这一篇了:-D.有同学说这是重复造轮子,题主很同意,但反过来说,如果自己没有能力造出轮子,还对重复造轮子嗤之以鼻,那 ...
- Andorid API Package ---> android.accessibilityservice
包名: android.accessibilityservice Added in API level 4 URL:http://developer.andro ...
- Android辅助功能原理与基本使用详解-AccessibilityService
辅助功能原理与基本使用详解 本文主要介绍辅助功能的使用 辅助功能基本原理 辅助功能基本配置和框架搭建 辅助功能实战解析 辅助功能基本原理 辅助功能(AccessibilityService)其实是 ...
- 利用AccessibilityService自动获取微信号(Android)
前言: 最近遇到一个需求,要求写一个小插件,能够自动在微信的页面弹出一个窗口,展示用户的相关信息(与我们公司有关的信息,方便运营快速了解用户信息). 当时我第一反应是不可能,如果能够在别的app中获取 ...
- 【Android】解析AccessibilityService(辅助服务)的使用
辅助功能是Android系统提供的一种服务,派生自Service类.这个服务提供了增强的用户界面,目的是为了帮助残障人士.它一般提供了页面元素查找功能和元素点击功能. 通过辅助功能,开发者可以实现一些 ...
- Android自动化测试中AccessibilityService获取控件信息(1)
Android自动化测试中AccessibilityService获取控件信息(1) 分类: android自动化测试2014-03-24 15:31 3455人阅读 评论(16) 收藏 举报 and ...
- android基础---->AccessibilityService的简单使用(一)
AccessibilityService类可以帮助我们实现监听手机上别的应用,以下做一个简单的总结.我总是勇敢的离开一个人 却不懂如何巧妙的靠近一个人. AccessibilityService的使用 ...
- Android自动化之AccessibilityService
简介demo示例说明Manifest声明AccessibilityService的XML配置文件创建继承自AccessibilityService的服务类MainActivity检测服务是否开启UiA ...
- 最新详解android自动化无障碍服务accessibilityservice以及高版本问题_1_如何开启获得无障碍
前言 无障碍服务accessibilityservice是什么 简单来说 无障碍服务就是一个为残障人士 尤其是视觉障碍人士提供的一个帮助服务.具体就是可以识别控件 文字 可以配合语音助手 操作和 使用 ...
- Android N开发 你需要知道的一切
title: Android N开发 你需要知道的一切 tags: Android N,Android7.0,Android --- 转载请注明出处:http://www.cnblogs.com/yi ...
随机推荐
- Ubuntu20.04 安装RabbitMQ 亲测可行
添加Erlang repository: sudo add-apt-repository -y ppa:rabbitmq/rabbitmq-erlang 添加RabbitMQ repository: ...
- Python 获取磁盘使用
import psutil def get_disk_info(): content = "" for disk in psutil.disk_partitions(): if ' ...
- C++ 手动创建二叉树,并实现前序、中序、后序、层次遍历
二叉树的创建是个麻烦事,我的思路是:首先将一个普通的二叉树转化为满二叉树,其中的空节点用一些标识数据来代替,如此一来,就可以用数组索引来描述数据在二叉树的什么位置了. 比如,数组[2,4,3,1,5, ...
- 一个比较全的C++农历算法(转)
这以前本是一个MFC代码,我在这个基础上修改成了标准C++的.. 即可以在VC里用,也可以在C++Builder里用..所以一并放到这里来, 希望有人喜欢..喜欢的就给点鼓励啊~~ 示例代码: 代码: ...
- Java基础-类型转换、变量、变量命名规范
类型转换 强制转换 (类型)变量名 高-->低 自动转换 低-->高 注意点 不能对布尔值进行转换 不能把对象类型转换为不相干的类型 在把高容量转换到低容量的时候,强制转换 转换的时候可能 ...
- js,php中的面向对象
面向对象 js中的面向对象: 面向对象(OOP):通过函数封装得到的一个类 1.类的本质还是函数 每个类(函数)天生有一个prototype的属性,这个prototype又是一个对象,这个对象里有个c ...
- docker-swarm轻量集群
使用docker swarm搭建docker轻量集群服务 当前流行的k8s集群搭建无疑是很好的docker集群管理服务,但是对于像我这种仅自己学习的玩家有些过于重量,所以今天使用docker自带的do ...
- springboot外部部署官方文档说明复制版
官方文档地址为: https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/#boot-features-e ...
- (0403)位运算符+interface
1)interface 2)位运算符
- 无界面Linux系统和Windows系统使用selenium爬取CNVD数据
因为CNVD官网采用了反爬机制,所以使用selenium能够更容易的爬取漏洞数据 1.在Windows中使用 注意根据chrome版本下载对应chromedriver 2.在无界面的Linux中使用 ...