ハウツー

バッテリーの技術的品質の適用開始: 一般的な wake lock のユースケースを最適化する方法

所要時間: 8 分
Alice Yuan
デベロッパー リレーション エンジニア

Android ユーザーにとってバッテリーの過度の消耗が最優先事項であることを踏まえ、Google はデベロッパーが電力効率の高いアプリを構築できるよう、さまざまな取り組みを行っています。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 を最適化するための推奨事項について説明します。WHOOP などのパートナーは、これらの推奨事項を活用してバックグラウンド動作を最適化し、すでに目覚ましい成果を上げています。

フォアグラウンド サービスと部分的な wake lock の使用

バックグラウンド実行を行う際に、フォアグラウンド サービスと部分的な wake lock という 2 つのコンセプトの違いを理解するのに苦労しているデベロッパーがよく見られます。

フォアグラウンド サービスは、アプリがユーザーに認識できる処理を実行しており、メモリを解放するために強制終了すべきではないことをシステムに通知するライフサイクル API ですが、画面がオフになったときに CPU が自動的にスリープ状態になるのを防ぐことはできません。一方、部分的な wake lock は、画面がオフになっている間も CPU を動作させ続けるように特別に設計されたメカニズムです。

ユーザー アクションを続行するにはフォアグラウンド サービスが必要になることがよくありますが、部分的な wake lock の手動取得は、CPU がアクティブな間、フォアグラウンド サービスと組み合わせてのみ必要です。また、デバイスをスリープ状態にしない API をすでに使用している場合は、wake lock を使用する必要はありません。

_デバイスをスリープ状態にしない適切な API を選択する_のフローチャートを参照して、wake lock が不要なシナリオで wake lock を取得しないようにするためのツールをしっかりと理解してください。

サードパーティ ライブラリによる wake lock の取得

アプリが、サードパーティ SDK またはシステム API がアプリに代わって保持している過度の wake lock のためにフラグが設定されていることに気づくことはよくあります。これらの wake lock を特定して解決するには、次の手順をおすすめします。

  • Android Vitals を確認する: 過度の部分的な wake lock のダッシュボードで、問題のある wake lock の正確な名前を確認します。この名前を 他の API によって作成された wake lock を特定するのガイダンスと相互参照して、既知のシステム API または Jetpack ライブラリによって作成されたかどうかを確認します。作成された場合は、API の使用を最適化する必要があるかもしれません。推奨されるガイダンスを参照してください。
  • システム トレースをキャプチャする: wake lock を簡単に特定できない場合は、システム トレースを使用して wake lock の問題をローカルで再現し、Perfetto UI で検査します。これを行う方法について詳しくは、このブログ投稿の その他の種類の過度の wake lock のデバッグ セクションをご覧ください
  • 代替手段を評価する: 非効率的なサードパーティ ライブラリが原因で、バッテリー寿命を考慮するように構成できない場合は、SDK のオーナーに問題を伝え、代替の SDK を見つけるか、機能を自社で構築することを検討してください。

一般的な wake lock のシナリオ

以下に、Google が確認した特定のユースケースの内訳と、wake lock の実装を最適化するための推奨パスを示します。

ユーザーが開始したアップロードまたはダウンロード

ユースケースの例:

  • ユーザーがオフライン アクセス用に大容量ファイルのダウンロードをトリガーする動画ストリーミング アプリ。
  • ユーザーが通知プロンプトから最近の写真をアップロードするメディア バックアップ アプリ。

wake lock を減らす方法: 

  • 手動で wake lock を取得しないでください。代わりに、UIDT(User-Initiated Data Transfer)API を使用します。これは、ユーザーが開始した長時間実行のデータ転送タスクの指定パスであり、過度の wake lock の計算から除外されます。

1 回限りまたは定期的なバックグラウンド同期

ユースケースの例:

  • アプリが定期的なバックグラウンド同期を実行して、オフライン アクセス用のデータを取得する。 
  • 歩数を定期的に取得する歩数計アプリ。

wake lock を減らす方法:

  • 手動で wake lock を取得しないでください。1 回限りまたは定期的な処理用に構成された 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 の影響を大幅に軽減することができました。

Bluetooth 通信

ユースケースの例:

  • コンパニオン デバイス アプリが、Bluetooth 外部デバイスをペア設定するようユーザーに促す。
  • コンパニオン デバイス アプリが、外部デバイスのハードウェア イベントと、通知のユーザーに表示される変更をリッスンする。
  • コンパニオン デバイス アプリのユーザーが、モバイル デバイスと Bluetooth デバイス間でファイル転送を開始する。
  • コンパニオン デバイス アプリが、Bluetooth 経由で外部デバイスのファームウェアを定期的に更新する。

wake lock を減らす方法:

  • _コンパニオン デバイスのペア設定_を使用して Bluetooth デバイスをペア設定し、Bluetooth のペア設定中に手動で wake lock を取得しないようにします。 
  •  バックグラウンドで通信するのガイダンスを参照して、バックグラウンドで Bluetooth 通信を行う方法を確認してください。 
  • 通信の遅延がユーザーに影響しない場合は、WorkManager を使用するだけで十分なことがよくあります。手動で wake lock を取得する必要がある場合は、Bluetooth アクティビティの期間またはアクティビティ データの処理期間のみ 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 でセンサーを登録する場合は、maxReportLatencyUs を 30 秒以上に指定してセンサーのバッチ処理 を活用し、CPU 割り込みの頻度を最小限に抑えます。その後、ユーザー インタラクション、位置情報の取得、スケジュールされたジョブなどの別のトリガーによってデバイスが起動すると、キャッシュに保存されたセンサーデータがすぐにディスパッチされます。
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 のドキュメントも参照してください。技術リソースの改善にご協力いただくため、ドキュメントのフィードバック アンケートでガイダンスに関する追加のフィードバックをお寄せください。

作成者:

続きを読む