Post

Why is my phone battery draining so fast? — A record of direct investigation with ADB

Analysis of why my phone battery drains quickly, using ADB to investigate the issue.

Why is my phone battery draining so fast? — A record of direct investigation with ADB

폰 배터리가 왜 이렇게 빨리 닳지? — ADB로 직접 파헤쳐본 기록

요즘 폰(갤럭시 S24) 배터리가 유난히 빨리 닳는 느낌이 들었다. 2년 반 썼으니 슬슬 배터리가 맛이 간 건가 싶기도 했고, 교체 비용을 알아봐야 하나 고민하던 참이었다.

그런데 생각해보니 굳이 서비스센터에 갈 필요가 없었다. 어차피 개발한다고 USB 디버깅은 항상 켜져 있고, 안드로이드는 dumpsys로 배터리 관련 통계를 전부 뱉어준다. 루트 권한도 필요 없다. 그래서 직접 까보기로 했다.

일단 배터리가 죽은 건지부터 확인하자

가장 먼저 의심한 건 배터리 노화였다. 2024년 1월에 산 폰이니 2년 7개월 됐고, 이 정도면 배터리 수명이 다해서 빨리 닳는 게 자연스러운 시나리오다.

1
$ adb shell dumpsys battery

출력이 꽤 긴데, 삼성 폰은 AOSP 표준 항목 외에 자체 수명 카운터를 잔뜩 들고 있어서 오히려 볼 게 많다. 눈에 들어온 값들:

1
2
3
4
5
health: 2                        # 2 = Good
mSavedBatteryAsoc: [91]          # 삼성 자체 건강도 카운터, 91%
battery FirstUseDate: [20240126] # 첫 사용일
temperature: 435                 # 43.5°C (0.1°C 단위)
mProtectBatteryMode: 0           # 배터리 보호(80% 제한) 꺼져 있음

ASOC 91%. 2년 7개월에 91%면… 오히려 잘 버틴 편이다. 연평균 3.5%p씩 떨어진 건데, 이 속도면 노화 때문에 체감될 정도로 빨리 닳을 단계는 아니다.

첫 번째 가설은 아니다. 배터리 하드웨어는 멀쩡하다. 그럼 뭔가가 전기를 먹고 있다는 얘기다. (정말 다행인 것이다. 근데 폰을 개발이나 테스트 용도로 많이 썼는데도 이정도면 잘 쓴건지 최적화를 잘한건지..참고로 업무 상 크래시 나는 앱을 많이 만든다.)

여담이지만 이 출력의 이벤트 로그를 보다가 이상한 걸 하나 발견했다:

1
2
3
4
08-29 20:44:17  ACTION_POWER_DISCONNECTED
08-29 20:45:42  ACTION_POWER_CONNECTED
08-29 20:45:52  ACTION_POWER_DISCONNECTED
08-29 20:46:21  ACTION_POWER_CONNECTED

몇십 초 간격으로 충전이 붙었다 떨어졌다를 반복하고 있다. 무선충전 패드에 폰을 대충 올려놔서 접촉이 불안정했던 것. 이건 본 주제와 별개지만 배터리 온도(43.5°C)가 높았던 이유 중 하나로 보인다.

그래서 얼마나 빨리 닳고 있는데?

느낌이 아니라 숫자로 확인할 차례다. batterystats는 마지막 완충 이후의 모든 통계를 들고 있다:

1
$ adb shell dumpsys batterystats --charged | grep -E "Discharge:|Time on battery"
1
2
3
4
5
Time on battery: 20h 14m 30s (78.0%) realtime, 10h 52m 39s (53.7%) uptime
Time on battery screen off: 15h 20m 27s realtime, 5h 58m 36s uptime
Discharge: 6441 mAh
Screen off discharge: 2867 mAh
Screen on discharge: 3573 mAh

여기서 계산기를 두드려봤다. 이 폰의 배터리 용량은 3,900mAh인데 20시간 동안 6,441mAh를 썼다. 하루도 안 돼서 배터리 1.65개분. 빨리 닳는 “느낌”이 아니라 실제로 많이 쓰고 있었다.

그런데 더 수상한 건 화면 꺼진 시간의 소모다. 화면이 꺼져 있던 15시간 20분 동안 2,867mAh가 빠졌다. 평균으로 환산하면 187mA. 폰이 잘 때의 정상 대기 전류가 20~50mA 수준이니까 4~9배다. 내가 폰을 안 보고 있는 동안에도 뭔가가 계속 전기를 태우고 있다는 뜻이다.

결정적으로 이 줄:

1
screen off: 15h 20m realtime, 5h 58m uptime

화면이 꺼져 있던 시간 중 CPU가 깨어 있던(uptime) 비율이 39%다. 폰이 잠들지를 못하고 있다. 범인이 있다.

범인 찾기: 누가 전기를 먹었나

batterystats에는 서브시스템별/앱별 전력 추정치가 mAh 단위로 나온다:

1
$ adb shell dumpsys batterystats --charged | grep -A 45 "Estimated power use"
1
2
3
4
5
6
7
8
9
Estimated power use (mAh):
  Capacity: 3900, Computed drain: 6440
  screen: 567        duration: 4h 54m
  cpu: 1500
  mobile_radio: 831  duration: 17h 13m   ← ?
  ...
  UID u0a505: 431  fg: 17.7  bg: 261     ← ??
      mobile_radio:bg=155 (3h 45m)
      wakelock=59.7 (2h 33m)

두 가지가 튄다.

하나는 mobile_radio 831mAh. 셀룰러 모뎀 혼자 전체 소모의 13%를 먹었고, 20시간 중 17시간을 활성 상태로 보냈다. 라디오가 쉬질 못했다.

다른 하나는 u0a505라는 앱. 총 431mAh인데 그중 261mAh가 백그라운드(bg)다. 내가 안 쓰는 동안 먹은 게 더 많다는 뜻. 근데 u0a505가 대체 누구일까

UID는 숫자라서 패키지명으로 바꿔줘야 한다. u0a505는 user 0의 app 505,

즉 uid 10505다:

1
2
$ adb shell cmd package list packages -U | grep "uid:10505"
package:com.kakao.talk uid:10505

카카오톡이었다.

카카오톡은 왜 안 자고 있었나

백그라운드에서 261mAh를 먹으려면 뭔가 계속 하고 있어야 한다. 폰을 못 자게 붙잡는 건 wakelock이니, wakelock 상위 목록을 뽑아봤다:

1
$ adb shell dumpsys batterystats --charged | grep -A 25 "All partial wake locks"
1
2
Wake lock u0a505 :WakeLockManagerContinuous: 1h 57m 50s (3565 times)
Wake lock u0a505 NotificationManagerService:post:com.kakao.talk: 11m 25s (7224 times)

카카오톡이 WakeLockManagerContinuous라는 wakelock을 3,565번 잡아서 합계 2시간 동안 CPU를 깨워뒀고, 알림을 7,224건 처리했다. 아까 본 “화면 꺼짐 시간의 39%가 CPU 가동”의 정체가 이거였다.

여기까지로 앱 쪽 범인은 확정. 그런데 아직 mobile_radio(LTE 데이터) 831mAh가 설명이 안 된다. 알림 7천 건을 받아도 통신량 자체는 얼마 안 될 텐데, 라디오가 왜 17시간이나 켜져 있었을까?

반전: 라디오(LTE 데이터)가 쉬지 못한 진짜 이유

처음엔 신호 불량을 의심했다. 신호가 약하면 폰이 송신 출력을 올리고 기지국을 계속 재탐색하느라 배터리가 녹는다. 흔한 패턴이다.

1
$ adb shell dumpsys batterystats --charged | grep -A 8 "Cellular Rx signal strength"
1
2
good (-108dBm to -98dBm):   8h 57m (44.3%)
great (greater than -98dBm): 10h 58m (54.2%)

98%가 good/great. 신호는 아주 좋았다. 이 가설도 아니다.

그럼 데이터가 전부 셀룰러로 나가고 있는 건 아닐까 싶어서 Wi-Fi 통계를 봤다:

1
$ adb shell dumpsys batterystats --charged | grep -i wifi
1
2
3
WiFi Sleep time: 20h 14m 30s (100.0%)
Wifi data received: 0B
Wifi data sent: 0B

Wi-Fi가 20시간 동안 단 1바이트도 안 썼다. 꺼져 있었던 거다.

이건 내 습관이었다. Wi-Fi를 켜두면 배터리를 더 먹는 줄 알고 평소에 꺼두고 다녔는데, 완전히 반대였다. Wi-Fi는 몇 미터 앞 공유기와 낮은 출력으로 통신하고 전송이 끝나면 바로 저전력 모드로 들어간다. 반면 LTE는 수백 미터 밖 기지국과 높은 출력으로 통신하는 데다, 전송이 끝나도 라디오가 한동안 활성 상태를 유지한다(tail time). 카카오톡처럼 백그라운드에서 자잘한 통신을 수천 번 하는 앱이 있으면 그때마다 LTE 라디오가 깨어나서, 소모가 눈덩이처럼 불어난다.

정리하면 이번 사건의 구조는 이렇다:

카카오톡이 배터리 최적화 예외로 등록돼 있어 백그라운드에서 마음껏 활동 -> 그 통신이 전부 (내가 꺼둔 Wi-Fi 대신) LTE로 나감 -> wakelock 2시간 + 라디오 17시간 활성 -> 화면 꺼진 상태에서 정상의 4~9배 소모

배터리가 늙은 게 아니라, 내 설정 두 개가 합작한 결과였다.

뒷정리

카카오톡이 왜 그렇게 자유로웠는지 확인해보니:

1
2
$ adb shell dumpsys deviceidle whitelist | grep kakao
user,com.kakao.talk,10505

user, 접두사 - 언젠가 내가 직접 “배터리 사용 제한 없음”으로 설정해둔 거였다. 알림 늦게 올까봐 그랬던 것 같은데, 카톡 알림은 어차피 FCM 푸시로 오기 때문에 “최적화” 상태여도 제때 온다. 해제했다:

1
2
$ adb shell dumpsys deviceidle whitelist -com.kakao.talk
Removed: com.kakao.talk

배터리 보호(80% 충전 제한)도 켜려고 설정 키를 찾아봤는데, 여기서 한 번 막혔다:

1
2
$ adb shell settings list global | grep protect
protect_battery=3

설정값은 3(최대 보호)인데 정작 배터리 서비스는 mProtectBatteryMode: 0(꺼짐)으로 동작 중이다. 값과 실제 상태가 따로 논다. 삼성이 이 키 하나로 제어하는 게 아닌 모양이라, 어설프게 ADB로 쓰다가 꼬이느니 그냥 설정 앱에서 켜기로 했다. (설정 -> 디바이스 케어 -> 배터리 -> 배터리 보호)

배운 것

  • “배터리가 빨리 닳는다”는 체감의 원인은 노화 말고도 많다. 순서대로 좁혀가면 된다: 하드웨어(health/ASOC) -> 총량과 대기 소모(discharge stats) -> 주체(앱별 mAh + UID 매핑) -> 원인(wakelock, 라디오/Wi-Fi 통계)
  • 각 단계에서 기준치와 비교하는 게 핵심이다. “2,867mAh 소모”만 보면 감이 안 오지만 “대기 전류 187mA vs 정상 20~50mA”로 놓으면 비정상임이 바로 보인다.
  • Wi-Fi를 꺼두는 건 배터리 절약이 아니라 낭비다. 적어도 백그라운드 통신이 많은 폰에서는 확실히 그렇다. 몇 년 묵은 습관이 데이터 앞에서 5분 만에 무너졌다.
  • 서비스센터 가기 전에 dumpsys 한 번 떠보자. 루트도 필요 없고, 답이 다 들어있다.
This post is licensed under CC BY 4.0 by the author.
If you find any errors, please let me know by comment or email. Thank you.

© Ruffalo. Some rights reserved.

I'm

Using the Chirpy theme for Jekyll.