시스템 업데이트 관리

이 개발자 가이드에서는 기기 정책 컨트롤러 (DPC)가 기기 사용자를 대신하여 Android 시스템 업데이트를 관리하는 방법을 설명합니다.

소개

Android 기기는 OTA (over-the-air) 업데이트를 수신하여 시스템 및 애플리케이션 소프트웨어에 설치할 수 있습니다. Android는 시스템 업데이트를 사용할 수 있으며 기기 사용자가 업데이트를 즉시 또는 나중에 설치할 수 있다고 기기 사용자에게 알립니다.

IT 관리자는 DPC를 사용하여 기기 사용자를 위한 시스템 업데이트를 관리할 수 있습니다. DPC는 완전 관리형 기기 (기기 소유자라고 함)를 소유하거나 직장 프로필(프로필 소유자라고 함)을 소유할 수 있습니다. 표 1은 기기 소유자가 시스템 업데이트를 관리하는 반면 프로필 소유자는 시스템 업데이트에 관한 정보만 보고할 수 있는 방법을 보여줍니다.

표 1: DPC에서 사용할 수 있는 작업은 소유자 모드에 따라 다름

작업 기기 소유자 프로필 소유자
대기 중인 시스템 업데이트 확인하기
새로운 시스템 업데이트가 있을 때 콜백 받기
로컬 업데이트 정책을 설정하여 Android에서 시스템 업데이트를 설치하는 시기 제어
중요한 기간 동안 OS 버전 고정

대기 중인 업데이트 확인

대기 중인 업데이트는 아직 설치되지 않은 기기의 시스템 업데이트입니다. DPC를 사용하면 IT 관리자가 시스템 업데이트가 대기 중인 기기를 확인하고 기기 사용자에게 중요 업데이트를 즉시 설치하도록 요청할 수 있습니다.

Android 8.0 (API 수준 26) 이상에서 실행되는 기기 소유자 및 프로필 소유자는 기기에 대기 중인 시스템 업데이트가 있는지 확인할 수 있습니다. 기기가 최신 상태라면 null를 반환하는 DevicePolicyManager.getPendingSystemUpdate()를 호출합니다. 시스템 업데이트가 대기 중인 경우 이 메서드는 업데이트에 관한 정보를 반환합니다.

대기 중인 업데이트에 관해 자세히 알아보기

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일이 지나면 시스템은 기기 사용자에게 업데이트를 설치하라는 메시지를 표시합니다.

연기 기간

시스템에서는 각 업데이트를 1회 연기할 수 있도록 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);

정책 인스턴스를 만든 후에는 변경할 수 없습니다. 기기가 업데이트를 설치하는 시점을 변경하려면 새 정책을 만들고 설정하면 됩니다. 기기에서 정책을 삭제하려면 nullpolicy 인수로 전달하는 setSystemUpdatePolicy()를 호출합니다. DPC에서 정책을 삭제하면 사용 가능한 시스템 업데이트에 관한 알림이 기기 사용자에게 표시됩니다.

앱은 getSystemUpdatePolicy()를 호출하여 기기의 현재 정책을 가져올 수 있습니다. 이 메서드가 null를 반환하면 정책이 현재 설정되지 않은 것입니다.

정지 기간

중요한 기간(예: 휴일 또는 기타 사용량이 많은 시간)에 OS 버전을 고정하기 위해 기기 소유자는 최대 90일 동안 시스템 업데이트를 정지할 수 있습니다. 기기가 정지 기간 내에 있으면 다음과 같이 작동합니다.

  • 기기가 대기 중인 시스템 업데이트에 관한 알림을 수신하지 않습니다.
  • OS의 시스템 업데이트가 설치되지 않았습니다.
  • 기기 사용자는 설정에서 시스템 업데이트를 수동으로 확인할 수 없습니다.

시스템은 정의된 정지 기간 후 60일의 필수 버퍼 기간을 적용하여 기기가 무기한 정지되는 것을 방지합니다. 시스템 업데이트를 중단하면 기기가 중요 업데이트를 받지 못할 수 있습니다.

그림 1. 기기에 설정된 두 개의 정지 기간
1년 기준 두 번의 정지 기간과 60일 버퍼를 보여주는 캘린더

업데이트 정책에 정지 기간을 설정했습니다. 정책을 설정하지 않으면 정지 기간을 설정할 수 없습니다. 설정한 정지 기간이 지난 경우 기기가 일반적인 정책 동작 (자동, 기간 설정 또는 연기됨)이 적용됩니다.

정지 기간 설정 방법

Android 9 (API 수준 28) 이상에서 정지 기간을 설정할 수 있습니다. 기기 소유자는 기기의 정책을 설정하기 전에 시스템 업데이트 정책의 정지 기간을 설정합니다. 단계는 다음과 같습니다.

  1. 새 시스템 업데이트 정책을 만들거나 현재 시스템 업데이트 정책을 가져옵니다.
  2. setFreezePeriods()를 호출하여 정책의 정지 기간을 설정합니다.
  3. 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) 셸에서 다음 명령어를 실행합니다.

adb shell dpm clear-freeze-period-record

시스템 업데이트를 위한 사용자 인터페이스가 사용 중지되어 있는지 확인하여 기기가 정지 기간인지 확인할 수 있습니다.

추가 리소스

시스템 업데이트에 관한 자세한 내용은 Android 오픈소스 프로젝트의 OTA 업데이트 문서를 참고하세요.