如何检查辅助功能服务是否崩溃(Android Pie现在在设置中显示此信息)?

时间:2019-03-08 10:47:11

标签: android accessibilityservice android-accessibility accessibility-api

我发现Android 9现在shows info if accessibility service stopped working

对于尝试利用可访问性API的开发人员而言,这始终是一个痛苦。

  • 辅助功能似乎已启用,但服务已停止。为了使其恢复正常工作,需要关闭并重新打开辅助功能。

  • 如果Google能够完全解决该问题,我会很高兴,但是现在他们只是暗示手动禁用它会很好。

不是最好的东西,但至少是一些东西。

  • 因此,我试图找出系统如何知道服务是否崩溃。碰巧有一个名为AccessibilityUtil的类,它包含DataSet方法。

  • 不幸的是,它会检查AccessibilityNodeInfo中的隐藏字段hasServiceCrashed,该字段对于第三方开发人员(由于拒绝反射)以及以前的android版本均不可用。

因此,我想知道是否还有其他方法可以从系统中获取信息,从而阐明我的可访问性服务已崩溃/停止工作并且需要用户采取措施。从棒棒糖开始。提示表示赞赏。

3 个答案:

答案 0 :(得分:2)

我想出了一个想法,即使用一个静态布尔值来指示无障碍服务的状态,并将其与 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES 进行比较。我已经在多台设备上测试过,没有发现这种方法有任何问题。

1.在无障碍服务中声明一个静态布尔值。

private static boolean bServiceRunning = false;

2.在无障碍服务中,设置onServiceConnectedonUnbind

中的布尔值
@Override
protected void onServiceConnected() {

    super.onServiceConnected();
    bServiceRunning = true; //put this at the very beginning to reduce time gap
}

@Override
public boolean onUnbind(Intent intent) {
        
   bServiceRunning = false;
   return super.onUnbind(intent);
}

3.在无障碍服务中创建一个静态函数

public static boolean bGetServiceStatus(){
    return bServiceRunning;
}

使用布尔标志,我可以知道无障碍服务是否在所需状态下运行。当服务被强制停止时,将调用 onUnbind 使布尔值变为 false。

4.我们使用Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES获取无障碍服务切换状态

public static boolean bIsAccessibilityServiceEnabled(Context context, Class<?> accessibilityService) {

        ComponentName expectedComponentName = new ComponentName(context, accessibilityService);
        String strServicesSettingResult = Settings.Secure.getString(context.getContentResolver(),  Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
        if (strServicesSettingResult == null){
            return false;
        }

        TextUtils.SimpleStringSplitter colonSplitter = new TextUtils.SimpleStringSplitter(':');
        colonSplitter.setString(strServicesSettingResult);

        while (colonSplitter.hasNext()) {
            String strComponentName = colonSplitter.next();
            ComponentName enabledService = ComponentName.unflattenFromString(strComponentName);

            if (enabledService != null && enabledService.equals(expectedComponentName))
                return true;
        }

        return false;
    }

5.这就是我们想要的,我们通过以上两种方法来判断无障碍服务的真实状态。

public static int intIsAccessibilityServiceEnabled_WithCrashCheck(Context context, Class<?> accessibilityService){
        //return 0 if Accessibility Service enabled and running
        //return -1 if Accessibility Service disabled and not running
        //return -2 if Accessibility Service enabled but stopped working or crashed

        //first check Accessibility Service boolean

        if(bGetServiceStatus()){
            //service is running
            return 0;
        }else{
            //service not running, now double check with Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
            boolean bResult = bIsAccessibilityServiceEnabled(context, accessibilityService);

            if(!bResult){
                //Accessibility Service is disabled
                return -1;
            }else{
                //Accessibility Service is enabled, but service is not actually running, Accessibility Service is crashed
                return -2;
            }
        }

    }

使用“AccessibilityManager”也有同样的效果,但我更喜欢带有静态布尔值的更“轻量级”版本以获得更好的性能。


注意:使用 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES 而不进行双重检查会导致错误。该值未同步。结果并不总是代表真实的服务状态。以下步骤可以创建这样的案例:

  1. 启动无障碍服务,然后转到应用设置强制停止应用。
  2. 现在您可以看到无障碍服务开关已关闭。 (目前看起来足够了,但下一步会产生问题)
  3. 再次启动无障碍服务,在 Android 9.0+ 设备上,您会发现开关已打开,但该服务实际上并未运行,现在显示“Not 在职的。点按获取信息。”

答案 1 :(得分:0)

Android通常会阻止应用程序反复崩溃而无法运行。可访问性服务的这种行为显然可以影响依赖该服务的用户,但是由于这些服务可以有效地控制UI,因此反复崩溃会导致该设备不可用。

在我看来,没有其他人会对AccessibilityServiceInfo中崩溃的字段感兴趣。不幸的是,我使用仅适用于系统的数据填充了该字段。我将启用的服务列表与绑定的服务列表进行比较。

如果您对阻止服务运行感兴趣,可以通过跟踪何时调用onBind和onUnbind并从AccessibilityManager查看启用的服务列表来做类似的事情。

答案 2 :(得分:0)

我不知道这是否是解决方案。但是我确实发现它什么时候不起作用:如果我使用“ dumpsys可访问性”,则服务部分为空,如下所示:

User state[attributes:{id=0, 
                       currentUser=true, 
                       touchExplorationEnabled=false,  
                       displayMagnificationEnabled=false,   
                       navBarMagnificationEnabled=false,  
                       autoclickEnabled=false}
           services:{}]

也许您可以检查服务是否为空。