AccessibilityService首先你要继承AccessibilityService,你会被要求复写 onKeyEvent、onIntercept、onAccessibilityEvent等方法。我们看这些方法在AccessibilityService中是如何实现的。
public class AccessBackKeyService extends AccessibilityService {
private static final String TAG = "jason";
@Override
protected boolean onKeyEvent(KeyEvent event) {
Log.i(TAG, "onKeyEvent");
if(event.getAction() == KeyEvent.ACTION_DOWN){
return super.onKeyEvent(event);
}
Log.i(TAG, "onKeyEvent ACTION_DOWN");
int key = event.getKeyCode();
switch(key){
case KeyEvent.KEYCODE_VOLUME_DOWN:
Log.i(TAG, "KEYCODE_VOLUME_DOWN");
break;
case KeyEvent.KEYCODE_VOLUME_UP:
Log.i(TAG, "KEYCODE_VOLUME_UP");
Toast.makeText(this, "KEYCODE_VOLUME_UP", Toast.LENGTH_SHORT).show();
break;
case KeyEvent.KEYCODE_BACK:
Log.i(TAG, "KEYCODE_BACK");
Toast.makeText(this, "KEYCODE_BACK, source:"+event.getSource(), Toast.LENGTH_SHORT).show();
break;
case KeyEvent.KEYCODE_ESCAPE:
Log.i(TAG, "KEYCODE_ESCAPE");
Toast.makeText(this, "KEYCODE_ESCAPE", Toast.LENGTH_SHORT).show();
break;
}
return super.onKeyEvent(event);
}
@Override
public void onInterrupt() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// TODO Auto-generated method stub
}
@Override
protected boolean onGesture(int gestureId) {
Log.i("jason", "onGesture:"+gestureId);
return super.onGesture(gestureId);
}
}
我们看到AccessibilityService中有一个接口
/**
* @hide
*/
public interface Callbacks {
public void onAccessibilityEvent(AccessibilityEvent event);
public void onInterrupt();
public void onServiceConnected();
public void init(int connectionId, IBinder windowToken);
public boolean onGesture(int gestureId);
public boolean onKeyEvent(KeyEvent event);
public void onMagnificationChanged(@NonNull Region region,
float scale, float centerX, float centerY);
public void onSoftKeyboardShowModeChanged(int showMode);
public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
AccessibilityService利用观察者模式的形式将自己封装进一个IAccessibilityServiceClientWrapper内部类中,在onBind方法中实现,猜测在辅助功能打开开关的时候,onBind这个方法将被调用,一会我们从源码分析,先分析一下
IAccessibilityServiceClientWrapper
。
@Override
public final IBinder onBind(Intent intent) {
return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
@Override
public void onServiceConnected() {
AccessibilityService.this.dispatchServiceConnected();
}
@Override
public void onInterrupt() {
AccessibilityService.this.onInterrupt();
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityService.this.onAccessibilityEvent(event);
}
@Override
public void init(int connectionId, IBinder windowToken) {
mConnectionId = connectionId;
mWindowToken = windowToken;
// The client may have already obtained the window manager, so
// update the default token on whatever manager we gave them.
final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
wm.setDefaultToken(windowToken);
}
@Override
public boolean onGesture(int gestureId) {
return AccessibilityService.this.onGesture(gestureId);
}
@Override
public boolean onKeyEvent(KeyEvent event) {
return AccessibilityService.this.onKeyEvent(event);
}
@Override
public void onMagnificationChanged(@NonNull Region region,
float scale, float centerX, float centerY) {
AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
}
@Override
public void onSoftKeyboardShowModeChanged(int showMode) {
AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
}
@Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
}
});
}
IAccessibilityServiceClientWrapper采用了AIDL的方式,通过继承
IAccessibilityServiceClient.Stub方式,将自己设为进程间通信的服务端,那么代理Proxy在哪里?
public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
implements HandlerCaller.Callback {
...
private final HandlerCaller mCaller;
private final Callbacks mCallback;
private int mConnectionId;
public IAccessibilityServiceClientWrapper(Context context, Looper looper,
Callbacks callback) {
mCallback = callback;
mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
}
public void init(IAccessibilityServiceConnection connection, int connectionId,
IBinder windowToken) {
Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
connection, windowToken);
mCaller.sendMessage(message);
}
public void onInterrupt() {
Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
mCaller.sendMessage(message);
}
public void onAccessibilityEvent(AccessibilityEvent event) {
Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
mCaller.sendMessage(message);
}
...
@Override
public void onKeyEvent(KeyEvent event, int sequence) {
Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
mCaller.sendMessage(message);
}
搜索源码我们在AccessibilityManagerService中找到了实现,在init中connectId返回给AccessibilityService,AccessibilityManagerService是在SystemService中启动的系统服务,和ActivityManagerService是一个等级的系统服务。
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
synchronized (mLock) {
if (mService != service) {
if (mService != null) {
mService.unlinkToDeath(this, 0);
}
mService = service;
try {
mService.linkToDeath(this, 0);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed registering death link");
binderDied();
return;
}
}
mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
UserState userState = getUserStateLocked(mUserId);
addServiceLocked(this, userState);
if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) {
userState.mBindingServices.remove(mComponentName);
mWasConnectedAndDied = false;
try {
mServiceInterface.init(this, mId, mOverlayWindowToken);
onUserStateChangedLocked(userState);
} catch (RemoteException re) {
Slog.w(LOG_TAG, "Error while setting connection for service: "
+ service, re);
binderDied();
}
} else {
binderDied();
}
}
}
它是
IAccessibilityManager进程间通信
的服务端,那么Proxy端一定就是我们要找的产生AccessibilityService事件的地方。
public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void tryConnectToServiceLocked(IAccessibilityManager service) {
if (service == null) {
IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
if (iBinder == null) {
return;
}
service = IAccessibilityManager.Stub.asInterface(iBinder);
}
try {
final int stateFlags = service.addClient(mClient, mUserId);
setStateLocked(stateFlags);
mService = service;
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
}
}
我们找到了AccessibilityManager,
AccessibilityManager这个类在所有的View属性的类中都能找到它的影子,View的变化都会通过这个类来通知AccessibilityManagerService这里,再通过内部对象mServiceInterface回调给我们的AccessibilityService,过程分析完毕。
下面我们再验证一下前面留下的一个坑,AccessibilityService的onBind方法是在哪里调用的。
每当我们在辅助功能里打开或者关闭时,我们是怎么通知AccessibilityManagerService呢,AccessibilityManagerService肯定不可能轮询,而应该是采用观察者的模式,我们找到注册广播的地方。
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
synchronized (mLock) {
// Only the profile parent can install accessibility services.
// Therefore we ignore packages from linked profiles.
if (getChangingUserId() != mCurrentUserId) {
return;
}
// We will update when the automation service dies.
UserState userState = getCurrentUserStateLocked();
// We have to reload the installed services since some services may
// have different attributes, resolve info (does not support equals),
// etc. Remove them then to force reload.
userState.mInstalledServices.clear();
if (!userState.isUiAutomationSuppressingOtherServices()) {
if (readConfigurationForUserStateLocked(userState)) {
onUserStateChangedLocked(userState);
}
}
}
}
发现有一个PackageMonitor的类,每当发生了变化,都会调用onUserStateChangedLocked这个方法
/**
* Called when any property of the user state has changed.
*
* @param userState the new user state
*/
private void onUserStateChangedLocked(UserState userState) {
// TODO: Remove this hack
mInitialized = true;
updateLegacyCapabilitiesLocked(userState);
updateServicesLocked(userState);
updateWindowsForAccessibilityCallbackLocked(userState);
updateAccessibilityFocusBehaviorLocked(userState);
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
updatePerformGesturesLocked(userState);
updateEnhancedWebAccessibilityLocked(userState);
updateDisplayDaltonizerLocked(userState);
updateDisplayInversionLocked(userState);
updateMagnificationLocked(userState);
updateSoftKeyboardShowModeLocked(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
}
之后updateServicesLocked直到调用了mContext.bindServiceAsUser,之后我们定义的AccessibilityService的onBind就被调用,之后就建立了通信,填坑完毕。
private void updateServicesLocked(UserState userState) {
Map<ComponentName, Service> componentNameToServiceMap =
userState.mComponentNameToServiceMap;
boolean isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class)
.isUserUnlockingOrUnlocked(userState.mUserId);
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
ComponentName componentName = ComponentName.unflattenFromString(
installedService.getId());
Service service = componentNameToServiceMap.get(componentName);
// Ignore non-encryption-aware services until user is unlocked
if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) {
Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
continue;
}
// Wait for the binding if it is in process.
if (userState.mBindingServices.contains(componentName)) {
continue;
}
if (userState.mEnabledServices.contains(componentName)) {
if (service == null) {
service = new Service(userState.mUserId, componentName, installedService);
} else if (userState.mBoundServices.contains(service)) {
continue;
}
service.bindLocked();
} else {
if (service != null) {
service.unbindLocked();
}
}
}
updateAccessibilityEnabledSetting(userState);
}
public boolean bindLocked() {
UserState userState = getUserStateLocked(mUserId);
if (!mIsAutomation) {
final long identity = Binder.clearCallingIdentity();
try {
if (mService == null && mContext.bindServiceAsUser(
mIntent, this,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
new UserHandle(mUserId))) {
userState.mBindingServices.add(mComponentName);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
} else {
userState.mBindingServices.add(mComponentName);
mMainHandler.post(new Runnable() {
@Override
public void run() {
// Simulate asynchronous connection since in onServiceConnected
// we may modify the state data in case of an error but bind is
// called while iterating over the data and bad things can happen.
onServiceConnected(mComponentName,
userState.mUiAutomationServiceClient.asBinder());
}
});
userState.mUiAutomationService = this;
}
return false;
}