本开发者指南介绍了设备政策控制器 (DPC) 可以如何代表设备用户管理 Android 系统更新。
简介
Android 设备可以接收和安装系统和应用软件的无线下载 (OTA) 更新。Android 会通知设备用户有可用的系统更新,并且设备用户可以立即安装更新,也可以稍后安装。
IT 管理员可以使用您的 DPC 为设备用户管理系统更新。DPC 可以拥有全代管式设备(称为设备所有者),也可以拥有工作资料(称为资料所有者)。表 1 显示了设备所有者可以如何管理系统更新,而资料所有者只能报告有关系统更新的信息。
表 1:DPC 可用的任务取决于所有者模式
任务 | 设备所有者 | 个人资料所有者 |
---|---|---|
检查是否存在待处理的系统更新 | ||
在有新的系统更新时接收回调 | ||
设置本地更新政策以控制 Android 何时安装系统更新 | ||
在关键时间段冻结操作系统版本 |
检查是否有待处理的更新
待处理更新是指针对尚未安装的设备的系统更新。 您的 DPC 可帮助 IT 管理员检查哪些设备有待处理的系统更新,并且也许可以要求设备用户立即安装重要更新。
在 Android 8.0(API 级别 26)或更高版本中运行的设备所有者和资料所有者可以检查设备是否有待处理的系统更新。调用 DevicePolicyManager.getPendingSystemUpdate()
,如果设备为最新版本,则返回 null
。如果系统更新待处理,该方法会返回有关更新的信息。
详细了解待处理的更新
调用 getPendingSystemUpdate()
后,您可以检查返回的 SystemUpdateInfo 值,以详细了解待处理的更新。以下示例展示了如何确定待处理更新首次可供设备使用的时间:
Kotlin
val firstAvailable = dpm.getPendingSystemUpdate(adminName)?.receivedTime firstAvailable?.let { Log.i(TAG, "Update first available: ${Date(firstAvailable)}") }
Java
SystemUpdateInfo updateInfo = dpm.getPendingSystemUpdate(adminName); if (updateInfo != null) { Long firstAvailable = updateInfo.getReceivedTime(); Log.i(TAG, "Update first available: " + new Date(firstAvailable)); }
系统回调
当有可用的更新时,Android 系统会通知设备所有者有新的更新。在 Android 8.0 或更高版本中,系统还会通知个人资料所有者。
在 DeviceAdminReceiver
子类中,替换 onSystemUpdatePending()
回调。您无需注册或通告您的 DPC 即可接收回调。系统可能会针对单次更新多次调用此方法,因此请在响应之前检查更新的状态。可通过回调调用 getPendingSystemUpdate()
来了解有关系统更新的更多信息。以下示例展示如何执行此操作:
Kotlin
/** * Called when a new update is available. */ override fun onSystemUpdatePending(context: Context?, intent: Intent?, receivedTime: Long) { // System update information is supported in API level 26 or higher. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { return } val updateInfo = getManager(context) .getPendingSystemUpdate(getWho(context)) ?: return if (updateInfo.securityPatchState == SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE) { // Perhaps install because this is a security patch. // ... } }
Java
/** * Called when a new update is available. */ public void onSystemUpdatePending (Context context, Intent intent, long receivedTime) { // System update information is supported in API level 26 or higher. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { return; } SystemUpdateInfo updateInfo = getManager(context) .getPendingSystemUpdate(getWho(context)); if (updateInfo == null) { return; } if (updateInfo.getSecurityPatchState() == SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE) { // Perhaps install because this is a security patch. // ... } }
如果系统有多个 DPC(例如完全受管设备上的工作资料),设备所有者和资料所有者都会收到回调。
更新政策
设备所有者可以通过为设备设置本地系统更新政策来控制何时安装更新。系统更新政策可以是以下三种类型之一:
- 自动
- 系统更新可用时立即安装(无需用户互动)。设置此政策类型后,系统会立即安装所有可能推迟或等待维护期的待处理更新。
- 窗口化
- 在每日维护期内(无用户互动)安装系统更新。在创建新的窗口政策时,将每日维护期的开始和结束设置为一天中的分钟数。
- 已延期
- 将系统更新安装延后 30 天。30 天过后,系统会提示设备用户安装更新。
推迟期
系统会将每次更新推迟 30 天。此期限从系统首次推迟更新时开始,而设置新的推迟政策不会延长此期限。
除推迟外,Android 可能还由于其他原因(例如无连接、磁盘空间不足或电池电量不足)无法安装更新。
如果这段时间内有其他更新可用,系统会重置 30 天的推迟计时器,让 IT 管理员有机会试用合并后的系统更新。如果 30 天后没有新的更新,系统会提示用户安装所有待处理的更新。之后,当新的系统更新可用时,30 天的期限会再次开始。
如何设置政策
您可以在 Android 8.0(API 级别 26)或更高版本中设置更新政策。如需指定设备应何时安装系统更新,请使用上述三种类型之一创建 SystemUpdatePolicy
实例。如需设置政策,设备所有者需要调用 DevicePolicyManager
方法 setSystemUpdatePolicy()
。以下代码示例展示了如何执行此操作。如需查看窗口政策示例,请参阅 SystemUpdatePolicy
文档。
Kotlin
// Create the system update policy to postpone installation for 30 days. val policy = SystemUpdatePolicy.createPostponeInstallPolicy() // Get a DevicePolicyManager instance to set the policy on the device. val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager val adminName = getComponentName(context) // Set the policy. dpm.setSystemUpdatePolicy(adminName, policy)
Java
// Create the system update policy to postpone installation for 30 days. SystemUpdatePolicy policy = SystemUpdatePolicy.createPostponeInstallPolicy(); // Get a DevicePolicyManager instance to set the policy on the device. DevicePolicyManager dpm = (DevicePolicyManager) context .getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName adminName = getComponentName(context); // Set the policy. dpm.setSystemUpdatePolicy(adminName, policy);
政策实例一经创建便无法更改。如需更改设备安装更新的时间,您可以创建并设置新政策。如需从设备中移除政策,请调用 setSystemUpdatePolicy()
,并以 policy
参数的形式传递 null
。DPC 移除政策后,设备用户会看到任何可用系统更新的通知。
应用可以调用 getSystemUpdatePolicy()
来获取设备的当前政策。如果此方法返回 null
,则表示当前未设置政策。
冻结期
如需在重要时段(如节假日或其他繁忙时段)冻结操作系统版本,设备所有者可以将系统更新暂停长达 90 天。当设备处于冻结时段时,其行为如下:
- 设备不会收到任何关于待处理系统更新的通知。
- 未安装操作系统的系统更新。
- 设备用户无法在“设置”中手动检查系统更新。
系统会在任何定义的冻结期之后强制执行 60 天的缓冲期,以防止无限期冻结设备。请注意,冻结系统更新可能会导致设备无法接收重要更新。
您可以为更新政策设置冻结期。如果不设置政策,就不能设置冻结期。当设备处于您设置的任何冻结期之外时,系统会应用正常的政策行为(自动、窗口化或推迟)。
如何设置冻结期
您可以在 Android 9(API 级别 28)或更高版本中设置冻结期。设备所有者在为设备设置政策之前,会为系统更新政策设置冻结期。步骤如下:
- 创建新的(或获取当前的)系统更新政策。
- 通过调用
setFreezePeriods()
在政策上设置冻结期。 - 通过调用
setSystemUpdatePolicy()
为设备设置政策和冻结期。
由于冻结期每年重复,因此时间段的开始日期和结束日期由月份值和日期值表示。开始日期必须至少在上一个冻结期结束后的 60 天内开始。以下示例展示了如何为现有系统更新政策设置两个冻结期:
Kotlin
// Get the existing policy from the DevicePolicyController instance. val policy = dpm.systemUpdatePolicy ?: return try { // Set the two annual freeze periods on the policy for our retail // point-of-sale devices. val summerSale = FreezePeriod( MonthDay.of(6, 1), MonthDay.of(7, 31)) // Jun 1 - Jul 31 inclusive val winterSale = FreezePeriod( MonthDay.of(11, 20), MonthDay.of(1, 12)) // Nov 20 - Jan 12 inclusive policy.freezePeriods = Arrays.asList(summerSale, winterSale) // Set the policy again to activate the freeze periods. dpm.setSystemUpdatePolicy(adminName, policy) } catch (e: SystemUpdatePolicy.ValidationFailedException) { // There must be previous periods recorded on the device because // summerSale and winterSale don’t overlap and are separated by more // than 60 days. Report the overlap ... }
Java
// Get the existing policy from the DevicePolicyController instance. SystemUpdatePolicy policy = dpm.getSystemUpdatePolicy(); try { // Set the two annual freeze periods on the policy for our // retail point-of-sale devices. FreezePeriod summerSale = new FreezePeriod( MonthDay.of(6, 1), MonthDay.of(7, 31)); // Jun 1 - Jul 31 inclusive FreezePeriod winterSale = new FreezePeriod( MonthDay.of(11, 20), MonthDay.of(1, 12)); // Nov 20 - Jan 12 inclusive policy.setFreezePeriods(Arrays.asList(summerSale, winterSale)); // Don’t forget to set the policy again to activate the freeze periods. dpm.setSystemUpdatePolicy(adminName, policy); } catch (SystemUpdatePolicy.ValidationFailedException e) { // There must be previous periods recorded on the device because summerSale // and winterSale don’t overlap and are separated by more than 60 days. // Report the overlap ... }
开始日期和结束日期均包含在内。如果起始日期大于结束日期(如上例中的 winterSale
),则冻结期会延长到下一年。
在系统更新政策上设置冻结期时,Android 会针对以下要求进行测试:
- 冻结期不超过 90 天。
- 冻结期之间的间隔至少为 60 天。
- 冻结期不重叠。
- 没有重复的冻结期。
为设备设置系统更新政策时,Android 会重复这些测试,并包括设备当前或过去的任何冻结期。
如果其中任何测试失败,Android 会抛出 SystemUpdatePolicy.ValidationFailedException
。
如需获取之前在系统更新政策对象上设置的冻结期列表,所有已安装的应用都可以调用 SystemUpdatePolicy.getFreezePeriods()
。以下示例会调用此方法来记录设备的冻结时段:
Kotlin
// Log any freeze periods that might be set on a system update policy. dpm.systemUpdatePolicy?.freezePeriods?.forEach { Log.i(TAG, "Freeze period: $it") }
Java
// Log any freeze periods that might be set on a system update policy. SystemUpdatePolicy currentPolicy = dpm.getSystemUpdatePolicy(); if (currentPolicy != null) { // A policy might not be set. for (FreezePeriod freezePeriod : currentPolicy.getFreezePeriods()) { Log.i(TAG, "Freeze period: " + freezePeriod.toString()); } }
闰年
Android 使用 ISO 8601 日历(也称为公历)来计算冻结期,并且会忽略闰年。这意味着 2 月 29 日不是有效日期,而是被视为 2 月 28 日。因此,在计算冻结期的时长时,系统不会计算 2 月 29 日。
开发和测试
在开发和测试 DPC 的系统更新功能时,您可能需要创建多个冻结期。由于 Android 会检查过去冻结期之间 60 天的间隔时间,因此您必须先清除过往冻结期的记录,然后才能设置新的冻结期。如需清除设备的冻结期记录,请在 Android 调试桥 (adb) shell 中运行以下命令:
adb shell dpm clear-freeze-period-record
您可以通过检查系统更新界面是否已停用,确认设备是否处于冻结时段。
其他资源
如需详细了解系统更新,请参阅 Android 开源项目的 OTA 更新文档。