Android Accessibility(辅助功能) 安全相关问题

对于那些由于视力、听力或其它身体原因导致不能方便使用Android智能手机的用户,Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音、触觉反馈、手势操作、轨迹球和手柄操作。开发者可以搭建自己的Accessibility服务,这可以加强可用性,例如声音提示,物理反馈,和其他可选的操作模式。

随着Android版本的不断升级,Android Accessibility功能也越来越强大,Android 4.0版本以前,系统辅助服务功能比较单一,仅仅能过单向获取窗口元素信息,比如获取输入框用户输入内容。到Android 4.1版本以后,系统辅助服务增加了与窗口元素的双向交互,此时可以通过辅助功能服务操作窗口元素,比如点击按钮等。

由于系统辅助服务能够实时获取您当前操作应用的窗口元素信息,这有可能给你带来隐私信息的泄露风险,比如获取非密码输入框的输入内容等。同时通过辅助功能也可以模拟用户自动化点击应用内元素,也会带来一定的安全风险。

本文实现了一种通过系统辅助服务完成应用的自动安装、卸载、强行停止的功能。

1、AndroidManifest.xml文件配置自己实现的MyAccessibilityService服务。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jack.accessibility"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.jack.accessibility.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:label="@string/acc_service_name" android:name=".MyAccessibilityService" 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/phone_accessibility" />
        </service>

    </application>

</manifest>

2、在res/xml/phone_accessibility.xml配置相应的参数信息。

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service android:description="@string/accessibility_service_description"
     android:accessibilityEventTypes="typeAllMask"
     android:accessibilityFeedbackType="feedbackGeneric"
     android:notificationTimeout="100"
     android:accessibilityFlags=""
     android:canRetrieveWindowContent="true"
  xmlns:android="http://schemas.android.com/apk/res/android" />

3、MainActivity实现安装、卸载、强行停止动作的发起。

package com.jack.accessibility;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.view.View;
import android.app.Activity;
import android.content.Intent;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		this.findViewById(R.id.activeButton).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				Intent killIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
				startActivity(killIntent);
			}
		});

		this.findViewById(R.id.installButton).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				MyAccessibilityService.INVOKE_TYPE = MyAccessibilityService.TYPE_INSTALL_APP;
				String fileName = Environment.getExternalStorageDirectory() + "/test.apk";
				File installFile = new File(fileName);
				if(installFile.exists()){
					installFile.delete();
				}
				try {
					installFile.createNewFile();
					FileOutputStream out = new FileOutputStream(installFile);
					byte[] buffer = new byte[512];
					InputStream in = MainActivity.this.getAssets().open("test.apk");
					int count;
					while((count= in.read(buffer))!=-1){
						out.write(buffer, 0, count);
					}
					in.close();
					out.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				Intent intent = new Intent(Intent.ACTION_VIEW);
				intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive");
				startActivity(intent);

			}
		});
		this.findViewById(R.id.uninstallButton).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				MyAccessibilityService.INVOKE_TYPE = MyAccessibilityService.TYPE_UNINSTALL_APP;
				Uri packageURI = Uri.parse("package:com.example.test");
				Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
				startActivity(uninstallIntent);
			}
		});
		this.findViewById(R.id.killAppButton).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				MyAccessibilityService.INVOKE_TYPE = MyAccessibilityService.TYPE_KILL_APP;
				Intent killIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
				Uri packageURI = Uri.parse("package:com.example.test");
				killIntent.setData(packageURI);
				startActivity(killIntent);
			}
		});
	}
}

4、MyAccessibilityService中通过自动化点击实现应用安装、卸载、强行停止功能。

package com.jack.accessibility;

import java.util.List;

import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.util.Log;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;

@SuppressLint("NewApi")
public class MyAccessibilityService extends AccessibilityService {

	public static int INVOKE_TYPE = 0;
	public static final int TYPE_KILL_APP = 1;
	public static final int TYPE_INSTALL_APP = 2;
	public static final int TYPE_UNINSTALL_APP = 3;

	public static void reset(){
		INVOKE_TYPE = 0;
	}

	@Override
	public void onAccessibilityEvent(AccessibilityEvent event) {
		// TODO Auto-generated method stub
		this.processAccessibilityEnvent(event);
	}

	private void processAccessibilityEnvent(AccessibilityEvent event) {

		Log.d("test", event.eventTypeToString(event.getEventType()));
		if (event.getSource() == null) {
			Log.d("test", "the source = null");
		} else {
			Log.d("test", "event = " + event.toString());
			switch (INVOKE_TYPE) {
			case TYPE_KILL_APP:
				processKillApplication(event);
				break;
			case TYPE_INSTALL_APP:
				processinstallApplication(event);
				break;
			case TYPE_UNINSTALL_APP:
				processUninstallApplication(event);
				break;
			default:
				break;
			}
		}
	}

	@Override
	protected boolean onKeyEvent(KeyEvent event) {
		// TODO Auto-generated method stub
		return true;

	}

	@Override
	public void onInterrupt() {
		// TODO Auto-generated method stub

	}

	private void processUninstallApplication(AccessibilityEvent event) {

		if (event.getSource() != null) {
			if (event.getPackageName().equals("com.android.packageinstaller")) {
				List<AccessibilityNodeInfo> ok_nodes = event.getSource().findAccessibilityNodeInfosByText("确定");
				if (ok_nodes!=null && !ok_nodes.isEmpty()) {
					AccessibilityNodeInfo node;
					for(int i=0; i<ok_nodes.size(); i++){
						node = ok_nodes.get(i);
						if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
							node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
						}
					}

				}
			}
		}

	}

	private void processinstallApplication(AccessibilityEvent event) {

		if (event.getSource() != null) {
			if (event.getPackageName().equals("com.android.packageinstaller")) {
				List<AccessibilityNodeInfo> unintall_nodes = event.getSource().findAccessibilityNodeInfosByText("安装");
				if (unintall_nodes!=null && !unintall_nodes.isEmpty()) {
					AccessibilityNodeInfo node;
					for(int i=0; i<unintall_nodes.size(); i++){
						node = unintall_nodes.get(i);
						if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
							node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
						}
					}
				}

				List<AccessibilityNodeInfo> next_nodes = event.getSource().findAccessibilityNodeInfosByText("下一步");
				if (next_nodes!=null && !next_nodes.isEmpty()) {
					AccessibilityNodeInfo node;
					for(int i=0; i<next_nodes.size(); i++){
						node = next_nodes.get(i);
						if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
							node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
						}
					}
				}

				List<AccessibilityNodeInfo> ok_nodes = event.getSource().findAccessibilityNodeInfosByText("打开");
				if (ok_nodes!=null && !ok_nodes.isEmpty()) {
					AccessibilityNodeInfo node;
					for(int i=0; i<ok_nodes.size(); i++){
						node = ok_nodes.get(i);
						if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
							node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
						}
					}
				}

			}
		}

	}

	private void processKillApplication(AccessibilityEvent event) {

		if (event.getSource() != null) {
			if (event.getPackageName().equals("com.android.settings")) {
				List<AccessibilityNodeInfo> stop_nodes = event.getSource().findAccessibilityNodeInfosByText("强行停止");
				if (stop_nodes!=null && !stop_nodes.isEmpty()) {
					AccessibilityNodeInfo node;
					for(int i=0; i<stop_nodes.size(); i++){
						node = stop_nodes.get(i);
						if (node.getClassName().equals("android.widget.Button")) {
							if(node.isEnabled()){
							   node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
							}
						}
					}
				}

				List<AccessibilityNodeInfo> ok_nodes = event.getSource().findAccessibilityNodeInfosByText("确定");
				if (ok_nodes!=null && !ok_nodes.isEmpty()) {
					AccessibilityNodeInfo node;
					for(int i=0; i<ok_nodes.size(); i++){
						node = ok_nodes.get(i);
						if (node.getClassName().equals("android.widget.Button")) {
							node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
							Log.d("action", "click ok");
						}
					}

				}
			}
		}
	}

}

完整DEMO下载地址:http://download.csdn.net/detail/jiazhijun/8251277

时间: 2024-10-16 06:25:57

Android Accessibility(辅助功能) 安全相关问题的相关文章

Android Accessibility使用及原理简介

Accessibility是Android从API 4开始提供的一个功能,它主要目的是帮助一些因为有视觉,听觉,身体障碍而无法完全使用触摸屏或铃声等的用户来使用Android的.而实际上现在很多开发者都用它来实现一些其他功能了,比如说微信抢红包,自动安装APK,强制停止应用等.下面来简单介绍一下它的相关使用及原理. AccessibilityService 它最主要的接口是类AccessibilityService.AccessibilityService是Service的子类,我们可以继承这个

Android系统辅助功能中的放大手势机制介绍(Magnification Gesture Mechanism)

前言: Magnification Gesture是Android系统辅助设置中提供的一种功能,它能够提供全局任意窗口的放大浏览功能,以帮助视力不是特别好的用户也能无障碍的使用,提升用户体验.本文档基于Android4.2.2进行分析,包括从设置中开启.用户触发到机制运行一整套流程. 文章目录: 一.关于Magnification Gesture 二.与Magnification Gesture相关的系统服务启动流程 三.来自用户的操作--打开Magnification Gesture开关的执行

[Android Pro] Android 4.1 使用 Accessibility实现免Root自动批量安装功能

reference to  :  http://www.infoq.com/cn/articles/android-accessibility-installing?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global 对于国内Android设备,应用的自动批量安装/更新一直是一个痛点,在之前,第三方应用商店通常要求设备Root,然后调用系统的 PackageManagerServic

Android自动化之AccessibilityService

简介demo示例说明Manifest声明AccessibilityService的XML配置文件创建继承自AccessibilityService的服务类MainActivity检测服务是否开启UiAutomatorViewer参考 简介 由于许多Android用户由于某些原因(视力,身体,年龄)要求他们以不同的方式与手机设备交互. 安卓提供了辅助功能特性和服务来帮助这些用户更容易的操作他们的设备,包括文字转语音(原生不支持中文,国内ROM可能会有,我的测试OPPO自带中文哟!),触觉反馈,手势

Android:布局实例之常见用户设置界面

实现效果: 整理思路: 1.控件:文字TextView 和 右箭头ImageView 2.因为考虑到点击效果,设计为:最外层为全圆角,内层有四种情况,分别为上圆角.无圆角.下圆角和全圆角. 3.内层样式效果:需要初始样式.和点击样式 4.需要知识:结合style.shake.selector组合样式 布局: 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android=

Android cts4.2 windows环境搭建说明

最近由于工作需要,要对我们的智能手机进行兼容性测试,在网上关于windows下测试环境搭建的介绍都比较凌乱,这里总结一下我的androidCTS测试windows下环境搭建,分享给大家,希望对大家有用. 工具/原料 Android SDK :android_sdk_windows Java开发工具包:jdk 手机驱动:usb_driver Cts : android-cts-4.2_r4-linux_x86-arm.zip cts 测试使用的所有APK CTS media:android-cts

android设置界面preferences的使用

部分借鉴:http://blog.csdn.net/flowingflying/article/details/6671548,谢谢作者 步骤1:编写preference XML,在res/xml/下加入我们的preference XML文件,例如名字叫preference.xml(不是上图的布局文件) 1 <?xml version="1.0" encoding="utf-8"?> 2 <PreferenceScreen 3 xmlns:andr

你有没有试过“闭上眼”使用:京东、滴滴、QQ、支付宝?

正在看这篇文章的同学,也许是幸运的. 互联网的发展,让我们的生活越来越便利,但这个“我们”,也许并不包括那些残障人士.正常人眼里来说再简单不过的页面操作,对于盲人来说都是不可攀越的高墙.换句话说,越行越快的互联网列车,让视觉障碍人士和正常人的生活越来越远. 好消息是,这个问题也许正在得到改善.在今年的 MDCC 移动开发者大会上,专门开设了“信息无障碍专场”. 在现场的演讲中,一位视觉有障碍的程序员沈广荣为现场的观众展示了“一个盲人的一天”——他如何与这些 App 相处. 看似友好的 App,盲

中文Appium API 文档

该文档是Testerhome官方翻译的源地址:https://github.com/appium/appium/tree/master/docs/cn官方网站上的:http://appium.io/slate/cn/master/?ruby#about-appium 中文Appium API 文档 第一章:关于appium1.1 appium客户端客户端类库列表及Appium服务端支持 这些类库封装了标准Selenium客户端类库,为用户提供所有常见的JSON 格式selenium命令以及额外的