방법

배터리 기술 품질 시행: 일반적인 Wake lock 사용 사례를 최적화하는 방법

8분 읽기
Alice Yuan
개발자 관계팀 엔지니어

Google은 Android 사용자가 배터리 소모를 가장 중요하게 생각한다는 점을 인식하고 개발자가 더 전력 효율적인 앱을 빌드할 수 있도록 지원하기 위해 상당한 조치를 취해 왔습니다. 2026년 3월 1일부터 Google Play 스토어에서 배터리 소모를 개선하기 위해 Wake lock 기술 품질 처리를 출시하기 시작했습니다. 이 처리는 다음 몇 주에 걸쳐 영향을 받는 앱에 점진적으로 출시됩니다. Android vitals에서 '불필요한 부분적인 Wake lock' 기준을 지속적으로 초과하는 앱은 스토어 등록정보에 경고 가 표시되고 추천과 같은 검색 노출 영역에서 제외되는 등 스토어 노출에 실질적인 영향을 받을 수 있습니다.

appDetails.png

앱이 비정상적인 동작 기준을 초과하면 스토어 등록정보에 경고가 표시될 수 있습니다. 

이 이니셔티브는 배터리 효율성을 비정상 종료 및 ANR과 같은 안정성 측정항목과 함께 핵심 vitals 측정항목으로 격상시켰습니다. '비정상적인 동작 기준'은 **지난 28일** 동안 **5% 이상의 사용자 세션** 에서 화면이 꺼져 있는 동안 평균 **2시간** 이상 면제되지 않은 부분적인 Wake lock을 유지하는 것으로 정의됩니다. Wake lock은 오디오 재생, 위치 액세스 또는 사용자가 시작한 데이터 전송과 같이 더 이상 최적화할 수 없는 명확한 사용자 이점을 제공하는 시스템 유지 Wake lock인 경우 면제됩니다. 불필요한 Wake lock의 전체 정의는 Android vitals 문서에서 확인할 수 있습니다.

Android 생태계 전반에서 배터리 수명을 개선하기 위한 지속적인 이니셔티브의 일환으로 Google은 수천 개의 앱과 앱에서 부분적인 Wake lock을 사용하는 방식을 분석했습니다. Wake lock이 필요한 경우도 있지만, 더 효율적인 솔루션이 있음에도 불구하고 앱에서 비효율적이거나 불필요하게 Wake lock을 유지하는 경우가 많습니다. 이 블로그에서는 불필요한 Wake lock이 발생하는 가장 일반적인 시나리오와 Wake lock 최적화를 위한 권장사항을 살펴봅니다.Google은 이미 이러한 권장사항을 활용하여 백그라운드 동작을 최적화한 WHOOP과 같은 파트너의 상당한 성공을 확인했습니다.

포그라운드 서비스와 부분적인 Wake lock 사용

개발자가 백그라운드 실행을 할 때 포그라운드 서비스와 부분적인 Wake lock이라는 두 가지 개념의 차이점을 이해하는 데 어려움을 겪는 경우가 많습니다.

포그라운드 서비스는 앱이 사용자에게 인식되는 작업을 실행 중이며 메모리를 확보하기 위해 종료해서는 안 된다는 신호를 시스템에 보내는 수명 주기 API이지만, 화면이 꺼질 때 CPU가 절전 모드로 전환되는 것을 자동으로 방지하지는 않습니다. 반면 부분적인 Wake lock은 화면이 꺼져 있는 동안에도 CPU를 계속 실행하도록 특별히 설계된 메커니즘입니다. 

포그라운드 서비스는 사용자 작업을 계속하는 데 필요한 경우가 많지만, 부분적인 Wake lock의 수동 획득은 CPU 활동 기간 동안 포그라운드 서비스와 함께만 필요합니다. 또한 기기를 절전 모드로 전환하지 않는 API를 이미 사용하고 있다면 Wake lock을 사용할 필요가 없습니다. 

_기기를 절전 모드로 전환하지 않는 올바른 API 선택_의 순서도를 참조하여 필요하지 않은 시나리오에서 Wake lock을 획득하지 않도록 어떤 도구를 사용해야 하는지 확실히 이해하세요.

Wake lock을 획득하는 서드 파티 라이브러리

앱이 서드 파티 SDK 또는 시스템 API가 앱을 대신하여 보유한 불필요한 Wake lock으로 인해 플래그가 지정되었다는 것을 발견하는 것은 일반적입니다. 이러한 Wake lock을 식별하고 해결하려면 다음 단계를 따르는 것이 좋습니다.

일반적인 Wake lock 시나리오

다음은 검토한 몇 가지 구체적인 사용 사례와 Wake lock 구현을 최적화하기 위한 권장 경로를 분석한 것입니다.

사용자가 시작한 업로드 또는 다운로드

사용 사례 예시:

  • 사용자가 오프라인 액세스를 위해 대용량 파일 다운로드를 트리거하는 동영상 스트리밍 앱
  • 사용자가 알림 메시지를 통해 최근 사진 업로드를 트리거하는 미디어 백업 앱

Wake lock을 줄이는 방법: 

  • 수동 Wake lock을 획득하지 마세요. 대신 사용자 시작 데이터 전송 (UIDT) API를 사용하세요. 이는 사용자가 시작한 장기 실행 데이터 전송 작업을 위한 지정된 경로이며 불필요한 Wake lock 계산에서 제외됩니다.

일회성 또는 주기적 백그라운드 동기화

사용 사례 예시:

  • 앱이 오프라인 액세스를 위해 데이터를 가져오는 주기적 백그라운드 동기화를 실행합니다. 
  • 걸음 수를 주기적으로 가져오는 만보계 앱

Wake lock을 줄이는 방법:

  • 수동 Wake lock을 획득하지 마세요. 일회성 또는 주기적 작업에 맞게 구성된 WorkManager를 사용하세요. WorkManager는 작업을 일괄 처리하여 시스템 상태를 고려하며 최소 주기적 간격 (15분)이 있어 일반적으로 백그라운드 업데이트에 충분합니다. 
  • Wake lock 사용량이 많은 WorkManager 또는 JobScheduler에서 생성된 Wake lock을 식별하는 경우 특정 시나리오에서 완료되지 않도록 작업자를 잘못 구성했을 수 있습니다. 작업자 중지 이유를 분석해 보세요. 특히 STOP_REASON_TIMEOUT이 자주 발생하는 경우에 말이죠.
  workManager.getWorkInfoByIdFlow(syncWorker.id)
  .collect { workInfo ->
      if (workInfo != null) {
        val stopReason = workInfo.stopReason
        logStopReason(syncWorker.id, stopReason)
      }
  }
  • 작업자 중지 이유를 로깅하는 것 외에도 작업자 디버깅에 관한 문서를 참조하세요. 또한 Wake lock이 획득되고 해제되는 시점을 파악하기 위해 시스템 트레이스 를 수집하고 분석하는 것을 고려해 보세요.
  • 마지막으로 WHOOP의 사례 연구를 확인해 보세요. WHOOP은 작업자 구성 문제를 발견하고 Wake lock 영향을 크게 줄일 수 있었습니다.

블루투스 통신

사용 사례 예시:

  • 컴패니언 기기 앱에서 사용자에게 블루투스 외부 기기를 페어링하라는 메시지를 표시합니다.
  • 컴패니언 기기 앱이 외부 기기의 하드웨어 이벤트와 알림의 사용자에게 표시되는 변경사항을 수신 대기합니다.
  • 컴패니언 기기 앱의 사용자가 휴대기기와 블루투스 기기 간에 파일 전송을 시작합니다.
  • 컴패니언 기기 앱이 블루투스를 통해 외부 기기에 가끔 펌웨어 업데이트를 실행합니다.

Wake lock을 줄이는 방법:

  • _컴패니언 기기 페어링_을 사용하여 블루투스 기기를 페어링하여 블루투스 페어링 중에 수동 Wake lock을 획득하지 않도록 합니다. 
  •  백그라운드에서 통신 안내를 참조하여 백그라운드 블루투스 통신을 실행하는 방법을 알아보세요. 
  • 지연된 통신에 사용자 영향이 없는 경우 WorkManager를 사용하는 것으로 충분한 경우가 많습니다. 수동 Wake lock이 필요하다고 판단되는 경우 블루투스 활동 또는 활동 데이터 처리 기간 동안만 Wake lock을 유지하세요.

위치 추적

사용 사례 예시:

  • 실행 경로를 표시하는 것과 같이 나중에 업로드할 위치 데이터를 캐시하는 피트니스 앱
  • 알림 또는 위젯 UI에서 배송 진행 상황을 업데이트하기 위해 높은 빈도로 위치 데이터를 가져오는 음식 배달 앱

Wake lock을 줄이는 방법:

  • 위치 사용 최적화에 관한 안내를 참조하세요. 제한 시간 구현, 위치 요청 일괄 처리 활용 또는 수동 위치 업데이트 활용을 고려하여 배터리 효율성을 보장하세요.
  • FusedLocationProvider 또는 LocationManager API를 사용하여 위치 업데이트를 요청하면 시스템에서 위치 이벤트 콜백 중에 기기 절전 모드 해제를 자동으로 트리거합니다. 이 짧은 시스템 관리 Wake lock은 불필요한 부분적인 Wake lock 계산에서 제외됩니다.
  • 위치 데이터를 캐싱하기 위해 별도의 연속 Wake lock을 획득하는 것은 중복되므로 피하세요. 대신 위치 이벤트를 메모리 또는 로컬 저장소에 유지하고 WorkManager를 활용하여 주기적으로 처리하세요.
  override fun onCreate(savedInstanceState: Bundle?) {
    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult ?: return
            // System wakes up CPU for short duration
            for (location in locationResult.locations){
                // Store data in memory to process at another time
            }
        }
    }
}

높은 빈도 센서 모니터링

사용 사례 예시:

  • 걸음 수 또는 이동 거리를 수동으로 수집하는 만보계 앱
  • 비정상 종료 감지 또는 낙상 감지와 같은 기능을 제공하기 위해 기기 센서의 급격한 변경사항을 실시간으로 모니터링하는 안전 앱

Wake lock을 줄이는 방법:

  • SensorManager를 사용하는 경우 사용자가 UI 상호작용을 통해 명시적으로 액세스 권한을 부여한 경우에만 주기적 간격으로 사용을 줄입니다. 높은 빈도 센서 모니터링은 발생하는 CPU 절전 모드 해제 및 처리 수로 인해 배터리를 크게 소모할 수 있습니다.
  • 이동한 걸음 수 또는 거리를 추적하는 경우 SensorManager를 사용하는 대신 Recording API를 활용하거나 Health Connect를 활용하여 이전 및 집계된 기기 걸음 수에 액세스하여 배터리 효율적인 방식으로 데이터를 캡처하는 것을 고려해 보세요.
  • SensorManager로 센서를 등록하는 경우 **센서 일괄 처리** 를 활용하여 CPU 인터럽트 빈도를 최소화하려면 30초 이상의 maxReportLatencyUs를 지정하세요. 이후 사용자 상호작용, 위치 검색 또는 예약된 작업과 같은 다른 트리거에 의해 기기가 절전 모드 해제되면 시스템에서 캐시된 센서 데이터를 즉시 디스패치합니다.
  val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

sensorManager.registerListener(this,
                 accelerometer,
                 samplingPeriodUs, // How often to sample data
                 maxReportLatencyUs // Key for sensor batching 
              )
  • 앱에 위치 데이터와 센서 데이터가 모두 필요한 경우 이벤트 검색 및 처리를 동기화합니다. 센서 판독값을 시스템에서 위치 업데이트를 위해 보유하는 짧은 Wake lock에 연결하면 CPU를 절전 모드로 전환하지 않기 위해 Wake lock이 필요하지 않습니다. 작업자 또는 짧은 기간 Wake lock을 사용하여 이 결합된 데이터의 업로드 및 처리를 처리합니다.

원격 메시지

사용 사례 예시:

  • 로컬 네트워크를 사용하여 연결된 외부 기기에서 발생하는 이벤트를 모니터링해야 하는 동영상 또는 사운드 모니터링 컴패니언 앱
  • 데스크톱 버전과의 네트워크 소켓 연결을 유지하는 메시지 앱

Wake lock을 줄이는 방법:

  • 네트워크 이벤트를 서버 측에서 처리할 수 있는 경우 FCM을 사용하여 클라이언트에서 정보를 수신합니다. FCM 데이터의 추가 처리가 필요한 경우 신속한 작업자를 예약하도록 선택할 수 있습니다. 
  • 소켓 연결을 통해 클라이언트 측에서 이벤트를 처리해야 하는 경우 이벤트 인터럽트를 수신 대기하는 데 Wake lock이 필요하지 않습니다. 데이터 패킷이 Wi-Fi 또는 셀룰러 라디오에 도착하면 라디오 하드웨어에서 커널 Wake lock 형식으로 하드웨어 인터럽트를 트리거합니다. 그런 다음 작업자를 예약하거나 Wake lock을 획득하여 데이터를 처리하도록 선택할 수 있습니다.
  • 예를 들어 ktor-network를 사용하여 네트워크 소켓에서 데이터 패킷을 수신 대기하는 경우 패킷이 클라이언트에 전송되어 처리해야 할 때만 Wake lock을 획득해야 합니다.
  val readChannel = socket.openReadChannel()
while (!readChannel.isClosedForRead) {
    // CPU can safely sleep here while waiting for the next packet
    val packet = readChannel.readRemaining(1024) 
    if (!packet.isEmpty) {
         // Data Arrived: The system woke the CPU and we should keep it awake via manual wake lock (urgent) or scheduling a worker (non-urgent)
         performWorkWithWakeLock { 
              val data = packet.readBytes()
              // Additional logic to process data packets
         }
    }
}

요약

개발자는 백그라운드 동기화, 위치 추적, 센서 모니터링, 네트워크 통신과 같은 일반적인 사용 사례에 권장되는 솔루션을 채택하여 불필요한 Wake lock 사용을 줄일 수 있습니다. 계속 학습하려면 다른 기술 블로그 게시물을 읽거나 Wake lock을 발견하고 디버깅하는 방법을 설명하는 기술 동영상(Android vitals Wake lock 측정항목을 사용하여 앱 배터리 최적화)을 시청하세요. 또한 업데이트된 Wake lock 문서를 참조하세요. Google에서 기술 리소스를 계속 개선할 수 있도록 문서 의견 설문조사에서 안내에 관한 추가 의견을 공유해 주세요.

작성자:

계속 읽기