WakeLockは、CPUまたは画面をアクティブに保つことでデバイスがスリープモードに入るのを防ぐAndroidの仕組みです。ファイルのダウンロード、オーディオ再生、データ記録などのバックグラウンドタスクは、中断なく確実に実行するためにWakeLockを必要とします。Android Developers, 2025の仕様によると、WakeLockの不適切な使用はバッテリーの急速な消耗を招き、Google Playでアプリがブロックされる原因となり得ます。
重要なポイント
WakeLockは、Androidがデバイスを低電力モードにするのを防ぐシステムロックです。通常、ユーザーが操作しない状態が数秒続くと、Androidは画面をオフにし、CPUをディープスリープ状態にして、バックグラウンドスレッドを停止します。WakeLockはCPUをアクティブに保つことで、この移行を防ぎます。
WakeLockの仕組みは、システムサービスのPowerManagerを介して管理され、getSystemService(Context.POWER_SERVICE)メソッドでアクセスします。開発者はロックの種類を指定してWakeLockオブジェクトを作成し、タスク完了後に確実に解放する必要があります。そうしないと、デバイスのバッテリーが急速に消耗します。システムはWakeLockを自動的に解放しません — これはアプリの責任です。
Androidのメジャーリリースごとに、GoogleはWakeLockの管理を強化しています。Android 9(API 28)以降、バックグラウンドのアプリは正当な理由なしにWakeLockを取得できなくなり、システムはロックを乱用するアプリを監視し、強制的に解放できます。Android 12+では、バックグラウンドアプリのPowerManagerアクセスに追加の制限が導入されました。
WakeLockは、デバイスがスリープ状態になることでタスクが中断されてはならないシナリオで必要です:不安定な接続での大容量ファイルのダウンロード、ビデオ録画、ユーザー操作なしでの長時間の計算処理など。スリープロックがないと、CPUはディープスリープに入り、すべてのスレッドがフリーズし、タスクは未完了のままになります。
ただし、GoogleはWakeLockの使用を最小限にすることを強く推奨しています。ほとんどの場合、同じタスクは通知付きのForeground Service、WorkManager、またはJobSchedulerで解決できます。これらの仕組みはバッテリーとネットワークの状態を考慮し、デバイスのバッテリー寿命を延ばします。
WakeLockは、デバイスの電源状態を管理するPowerManagerシステムサービスを介して動作します。アプリがpowerManager.newWakeLock()でロックを要求すると、システムはCPUのアクティビティレベルを上げ、ディープスリープを防ぎます。wakeLock.release()を呼び出した後、システムは通常の省電力モードに戻ります。
WakeLockがすべての省電力モードを防ぐわけではないことを理解することが重要です。Dozeモード(Android 6+のスリープモード)は特定のフェーズでWakeLockを無視することがあります — WakeLockを保持しているアプリは、Dozeのメンテナンスウィンドウ中にネットワークアクセスを取得できません。つまり、アクティブなWakeLockでも、Dozeの第2フェーズ中のネットワーク操作は保証されません。
各WakeLockはフレームワーク側のPowerManager.WakeLockに関連付けられています。システムはプロセスレベルでアクティブなロックをカウントします:1つのプロセスが複数のWakeLockを保持している場合、それらは累積され、各ロックに対してrelease()を呼び出した後にのみ解放されます。Androidはウェイクロックタイムアウトもサポートしています — 指定された間隔後の自動解放です。ただし、タイムアウトに依存することは推奨されません:タスクが早く完了する可能性があり、余分な保持時間がバッテリー寿命を縮めます。
デバイスがスリープ状態になると(電源ボタン)、AndroidはすべてのSCREEN_DIM_WAKE_LOCKとSCREEN_BRIGHT_WAKE_LOCKを強制的に解放しますが、PARTIAL_WAKE_LOCKは保持します。つまり、画面ロックはディスプレイをオンに保つことができず、PARTIAL_WAKE_LOCKのみが電源ボタンを押した後も動作を続けられます。
Androidにはいくつかの種類のWakeLockがあり、それぞれが特定のデバイスコンポーネントを制御します。種類の選択により、ロック後にどのハードウェアコンポーネントがアクティブのままになるかが決まります。誤った種類を選択すると、不要なモジュールがオンになり、過剰な電力消費につながります。
| 種類 | CPU | 画面 | キーボード | 使用時 |
|---|---|---|---|---|
| PARTIAL_WAKE_LOCK | オン | オフ | オフ | ファイルダウンロード、計算処理 |
| SCREEN_DIM_WAKE_LOCK | オン | 暗い | オフ | ビデオプレーヤー、プレゼンテーション |
| SCREEN_BRIGHT_WAKE_LOCK | オン | 明るい | オフ | ゲーム(非推奨) |
| FULL_WAKE_LOCK | オン | 明るい | 明るい | 非推奨(deprecated) |
PARTIAL_WAKE_LOCKは最もよく使われ、推奨される種類です。CPUをアクティブに保ちますが、画面とキーボードのバックライトはオフにできます。これはバックグラウンドタスクに最適な選択肢です:データ読み込み、画像処理、同期など。画面はシステムのタイムアウト後に消灯し、ユーザーに見えない作業を行いながらバッテリーを節約します。
SCREEN_DIM_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK、およびFULL_WAKE_LOCKはAndroid 7(API 24)以降非推奨です。これらは画面をオンに保つため、バッテリーを大幅に消費します。Googleは代わりにActivity.getWindow().addFlags()を介したFLAG_KEEP_SCREEN_ONの使用を推奨しています — このフラグはActivityがアクティブな場合のみ機能し、WAKE_LOCK許可を必要とせず、システムが画面の保持時間を自動的に管理します。
WakeLockはAndroidにおけるバッテリー消費の主要な原因の1つです。スリープロックを保持する毎秒、CPUが省電力のC-stateに移行できないため、余分な電力を消費します。Google Power Dashboardの調査によると、WakeLockを適切に解放していないアプリは、デバイスの消費電力をスタンバイモードで30~50%増加させる可能性があります。
システムはBattery Historianコンポーネントを介してWakeLockを乱用するアプリを追跡します。開発者は電力消費プロファイルを分析し、ロックリーク(WakeLockが作成されたが解放されていない状況)を特定できます。Google Play Consoleは公開されたアプリのWakeLock統計を表示し、保持時間が長いとレビューが悪くなる原因となります。
DozeモードとApp StandbyはWakeLockの動作をさらに制限します。最初のDozeフェーズ(Light Doze)では、システムは短いメンテナンスウィンドウでWakeLockを許可します。第2フェーズ(Deep Doze)では、WakeLockは他のロックと統合され、共通のウィンドウで実行されます。アプリがユーザー操作なしで10分以上WakeLockを保持している場合、システムは強制的に解放し、アプリをバッテリー最適化のブラックリストに追加する可能性があります。
WakeLockの適切な使用は、タスクを完了する必要性とデバイスのバッテリーへの配慮のバランスです。Googleはいくつかの原則に従うことを推奨しています:常にfinallyブロックまたはacquire(timeout)でWakeLockを解放し、必要最小限のロック種類を使用し、極端な必要がない限り長時間の保持を避けます。
WakeLockは作成された同じコードブロックで解放する必要があります。例外発生時の解放を保証するために、try-finally構文またはKotlinのuseブロックを使用します。Android 10+では、WakeLockが60秒以上保持されると、システムはlogcatに警告を表示します:"WakeLock held for more than 60 seconds" — これはリークの可能性を示します。
acquire(long timeout)メソッドは、指定されたミリ秒後に自動的にWakeLockを解放します。これは、例外やバグによって解放コードが実行されない場合の安全策です。タスクの最大実行予定時間に10~20%のマージンを加えたタイムアウトを常に指定することを推奨します。
release()を呼び出す前に、WakeLockが現在保持されているか確認する必要があります。事前のacquire()なしで再度release()を呼び出すと、RuntimeException: WakeLock under-lockedが発生します。状態フラグ(isHeld)を保存し、解放前にwakeLock.isHeld()を確認することを推奨します。
KotlinでのWakeLockの正しい作成と解放を見てみましょう。例では、PARTIAL_WAKE_LOCKを保持した非同期データ読み込み、try-finallyブロックでの確実な解放、およびリーク防止のためのタイムアウト指定を示しています。サービスはバックグラウンドタスク実行のためにIOディスパッチャを使用したCoroutineScopeを利用しています。
class DownloadService : Service() {
private lateinit var wakeLock: PowerManager.WakeLock
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
override fun onCreate() {
super.onCreate()
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"download:wakelock"
)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
wakeLock.acquire(60000)
scope.launch {
try {
downloadFile()
} finally {
if (wakeLock.isHeld()) {
wakeLock.release()
}
}
}
return START_NOT_STICKY
}
private suspend fun downloadFile() {
// ファイルダウンロードのシミュレーション
delay(30000)
}
override fun onDestroy() {
super.onDestroy()
scope.cancel()
if (wakeLock.isHeld()) {
wakeLock.release()
}
}
override fun onBind(intent: Intent): IBinder? = null
}
WakeLockを使用するには、AndroidManifest.xmlに許可を追加する必要があります。WAKE_LOCK許可は通常の許可であり、ユーザーへの実行時要求は不要で、アプリのインストール時に自動的に付与されます。ただし、アプリにWakeLockの明確な使用ケースがない場合、Google Playは公開を拒否する可能性があります。
<uses-permission
android:name="android.permission.WAKE_LOCK" />
<uses-permission
android:name="android.permission.DEVICE_POWER" />
WakeLockは低レベルの仕組みであり、Googleは可能な限りより最新のAPIに置き換えることを推奨しています。主な代替手段は通知付きのForeground Serviceで、サービスの期間中自動的にCPUロックを保持します。システムがForeground ServiceのWakeLockを管理するため、開発者は明示的な取得と解放から解放されます。
WorkManagerはバックグラウンドタスクにおける2番目に重要なツールです。デバイスがDozeモードに入った後や再起動後でもタスクの実行を保証します。WorkManagerは内部でホールドロックをサポートしており、開発者はPowerManagerを明示的に操作する必要がありません。タスクは自動スリープロック管理とともにDozeメンテナンスウィンドウで実行されます。
正確なタイミングが必要な定期的なタスクには、setAndAllowWhileIdle()を使用したAlarmManagerを使用します。これによりデバイスをDozeから起動できます。ただし、AlarmManagerは短い操作にのみ適しています — 長時間のWakeLock保持用には設計されていません。タスクが10秒以上かかる場合は、AlarmManagerをForeground Serviceを起動するBroadcastReceiverと組み合わせて使用します。
よくある質問
WakeLockは、Androidデバイスがスリープモードに入るのを防ぐシステムロックです。CPUまたは画面をアクティブに保ち、バックグラウンドタスク(ダウンロード、計算)を中断なく実行できるようにします。PowerManagerシステムサービスを介して管理されます。
主な種類は次のとおりです:PARTIAL_WAKE_LOCK(CPUアクティブ、画面オフ)— 推奨;SCREEN_DIM_WAKE_LOCK(CPU + 暗い画面);SCREEN_BRIGHT_WAKE_LOCK(CPU + 明るい画面)。SCREEN_DIM、SCREEN_BRIGHT、FULL_WAKE_LOCKは非推奨で、FLAG_KEEP_SCREEN_ONに置き換えられました。
はい、マニフェストでandroid.permission.WAKE_LOCKを宣言する必要があります。これは通常の許可であり、インストール時に自動的に付与されるため、実行時の要求は不要です。この許可がないと、newWakeLock()の呼び出しはnullを返すか、SecurityExceptionをスローします。
release()を呼び出さないと、デバイスはスリープモードに入れません。バッテリーは大幅に速く消耗します(最大50%の追加消費)。システムはlogcatにリークを記録し、Battery Historianは異常なWakeLock保持時間を表示し、ユーザーレビューの悪化につながります。
長時間のタスクには通知付きのForeground Serviceを使用します — システムがWakeLockを管理します。遅延タスクや確実な実行が必要なタスクには、内部でWakeLockをサポートするWorkManagerを使用します。短いスケジュールタスクにはAlarmManagerを使用します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。