3

我正面临一个有趣的情况,我不知道如何解决。当用户首次以 Android for Work 用户身份登录我的应用时,我有义务确保该应用已注册为设备管理器。我通过调用检查是否是这种情况DevicePolicyManager#isAdminActive,如果返回false,然后我启动一个Intentwithaction=DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN,以启动将启用设备管理的 Android 控件。一旦发生这种情况,当我的应用程序再次启动时(或从设备管理流程返回时),DevicePolicyManager#isAdminActive再次检查 的值。如果用户启用了设备管理,那么一切都很好,应用程序会继续运行。

有趣的是,当用户第一次通过我们的流程时,这完全符合预期。不幸的是,重新启动后,当用户启动我的应用程序时,它会检查以确保设备管理仍然处于打开状态,通过DevicePolicyManager#isAdminActive,这里变得有趣了。DevicePolicyManager#isAdminActive将报告false,这是通过查看设备安全设置来验证的。然而,更糟糕的是,尝试启用设备管理将导致以下异常:

W/DeviceAdminAdd:尝试激活管理员时出现异常 ComponentInfo{com.mysoft.myapp/com.mysoft.core.receivers.MyAppAdminReceiver} java.lang.IllegalArgumentException:管理员已添加到 android.os.Parcel.readException(Parcel.java:第 1550 章.java:720) 在 com.android.settings.DeviceAdminAdd.addAndFinish(DeviceAdminAdd.java:346) 在 com.android.settings.DeviceAdminAdd$3.onClick(DeviceAdminAdd.java:313) 在 android.view.View.performClick(View .java:5242) 在 android.widget.TextView.performClick(TextView.java:10571) 在 android.os.Handler.handleCallback(Handler.java:739) 在 android.os.Handler.dispatchMessage(Handler.java:95) 在 android.view.View$PerformClick.run(View.java:21196) 在android.os.Looper.loop(Looper.java:145) 在 android.app.ActivityThread.main(ActivityThread.java:6938) 在 java.lang.reflect.Method.invoke(Native Method) 在 java.lang.reflect。 Method.invoke(Method.java:372) 在...在 java.lang.reflect.Method.invoke(Method.java:372) 在 ...在 java.lang.reflect.Method.invoke(Method.java:372) 在 ...

即使我尝试通过系统安全设置页面手动启用设备管理,这个确切的异常也会出现在我的 logcat 控制台上,所以我不认为原来的Intent文件格式不正确。

所以,这是我的问题:对 Android 设备管理 API 的一次调用告诉我我的设备管理员未激活,但对同一 API 的另一次调用告诉我它是。我相信第二个实际上是错误的,但是由于无法激活管理,我的用户陷入了循环并且无法使用我的应用程序。

有没有其他人遇到过这个错误,如果是这样,你如何围绕它编写代码?

4

1 回答 1

2

我已经分析了DevicePolicyManagerService.java. 在这种情况下失败的函数被调用setActiveAdmin(),它抛出一个异常,因为它声称我们的应用程序已经被添加为设备管理员。setActiveAdmin在调用返回有效对象后抛出此异常getActiveAdminUncheckedLocked(),表明请求的设备管理员处于活动状态:

final ActiveAdmin existingAdmin
    = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (!refreshing && existingAdmin != null) {
    throw new IllegalArgumentException("Admin is already added");
}
if (policy.mRemovingAdmins.contains(adminReceiver)) {
    throw new IllegalArgumentException(
            "Trying to set an admin which is being removed");
}

但是,在此之前,我们已经调用了DevicePolicyManager.isAdminActive,其中包含以下逻辑:

return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;

这可以; 这正是我们想要的。但是,这是 AOSP 代码。我推测在受影响的设备上可能存在不同的实现,其中 的逻辑存在错误 DevicePolicyManager#isAdminActive(),因此调用在应该返回 true 时返回 false。

在部署仪器以在生产中捕获这种情况后,我已经验证了这个假设是正确的。从我的指标推断,Android 设备群体中存在这样的实现,即返回的值isAdminActive(X)将返回 false,即使 X将在返回的枚举活动管理员列表中找到getActiveAdmins()。幸运的是,这种情况并不常见,但确实存在。我会建议任何依赖这些调用的编码人员针对这种情况强化他们的代码。

于 2018-02-28T19:43:40.197 回答