Upload
shinobu-okano
View
1.435
Download
2
Embed Size (px)
Citation preview
https://github.com/operando/Notes/tree/master/Shibuya.apk_4
https://github.com/operando/JobScheduler-Code-Reading
資料内のリンクとか JobSchedulerの電波メモ
About Me
• Shinobu Okano (@operandoOS)
• Mercari, Inc.
• 今週で23歳になりました!ありがとうございます!
• 最近iPhone6s Plus買いました(笑)
Project Volta
• 簡単に言ってバッテリー消費を削減するプロジェクト
• Android Lで行われたもの
• Battery Historian
• JobScheduler
• AlarmManagerが省電力化(4.4 KitKat)
Google I/O 2014 Introduction to Project Volta
https://www.youtube.com/watch?v=KzSKIpJepUw
定期処理って今までこんな感じ
• AlarmManager + IntentService
• BroadcastReceiver + Service
• Timer,ScheduledExecutorService
• 方法は様々...
条件付きで実行したいってなると...
• とりあえずIntentService動かす
• でも条件(Wi-Fiにつながってるとか)に合致してなくて処理を断念...
• とにかく動かしてみないとわからない...
AlarmManagerって大変だよね...
• 再起動/アプリのアップデートするとAlarmがクリアされる
• BroadcastCastでACTION_BOOT_COMPLETED拾ってAlarmセットしなおし
• COMPLETED拾って、Alarmセットしなおし
• cancelめんどくさい , 同じようなAlarm作るのだるい
• とにかく辛い… 俺は辛い...
ずっと生きてるService嫌だよね...
• 死んでほしいのにずっと生きてるService
• Killしてもすぐ蘇る
• そんなService開発者も作りたくない
• こいつはどうしようもない...
About JobScheduler
• Android Lから導入されたAPI
• 様々な条件のJobをスケジュールしてくれるAPI
• 使うことで消費電力を意識した実装ができる
• 開発者が頑張らなくていいAPI
About JobScheduler
• Android Framework Services
• マルチユーザ用にも設計されている(当たり前か)
• Schedulerであって、Alarmではない
• 特定の時間に実行!みたいな感じではない
JobSchedulerの使い方
• Android API21から追加されたJobSchedulerに慣れていこう
• goo.gl/OMBCrl
• Using the JobScheduler API on Android Lollipop
• code.tutsplus.com/tutorials/using-the-jobscheduler-api-on-android-lollipop--cms-23562
Auto Backup - Android M
• ユーザの操作コストを極力かけずにアプリのユーザデータの自動バックアップを作成する
• 今までBackupの実装必要だったけどいらない
• 細かいことは割愛
Auto Backup - 条件
• バックアップは24時間ごとに行われる
• バックアップは充電中、WiFi接続、アイドル状態の3つの条件が満たされた時に行われる
• この条件(24時間,充電中,WiFi接続,アイドル状態)
を制御してるのがJobScheduler
Auto Backup - 条件
http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/backup/java/com/android/server/backup/
FullBackupJob.java
ココらへんにそれっぽい処理が書いてある
JobService#onStartJob
• MainThreadで実行される
• なので重い処理はAnother Threadを作って処理する
• jobFinishedしないとjobがはけないから気をつけて。新しいjobが実行できなくなる
JobService#onStopJob
• 戻り値でtrueを返せばjob作成時に、指定された再試行の基準に基づいてjobを再スケジューリング
• 戻り値でfalseを返せばjobは止まる
• onStopJobが呼ばれるのは、保留中・実行中のjobが何かにより(登録したjobの更新)cancelされた際に呼ばれるっぽい
• job実行中にcancelAllとかすれば呼ばれる
JobScheduler.schedule(JobInfo)
• JobScheduler.schedule(JobInfo)
• プロセス間通信でJobSchedulerStub#scheduleを呼び出す
• Jobの登録ができればJobScheduler.RESULT
• FAILUREが返ってくる。
• なので、Jobの登録ができたかどうかしっかり見てあげよう
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/app/JobSchedulerImpl.java#schedule
JobSchedulerStub#schedule
• JobSchedulerStub#schedule
• enforceValidJobRequestやcanPersistJobsでJob登録ができるかどうかとチェック
• JobSchedulerService#scheduleを呼び出す
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#813
JobSchedulerService#schedule
• JobSchedulerService#schedule
• JobInfoとアプリのUIDでJobStatusを生成。Framework側ではJobInfoはJobStatusとして管理される
• cancelJob + cancelJobImplで同じJobが登録されていたらcancelする(Job ID + UIDが同じJobStatus)
• pendingとしてqueueに溜まってるJobもcancel。ActiveServices(実際に動いてるJob)を全部チェックして、同じJobがあればcancel処理を行う。
JobSchedulerService#stopTrackingJobs
• JobStoreにある同じJobをremove
• 各StateControllerから同じJobをremove(removeするにもJobStatus
が各StateControllerの条件にあっているかどうかをチェックしてる)
• 全JobStatusを管理するクラスとしてJobStoreが使われている
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#190
JobSchedulerService#startTrackingJob• 基本的にJobSchedulerService#stopTrackingJobと逆のことする
(JobStatusのadd)
• 各StateControllerにJobStatusをaddする(addするにもJobStatusが各StateControllerの条件にあっているかどうかをチェックしてる)
• mReadyToRock(JobSchedulerの準備??)がtrueになっていないと、基本的にはaddもremoveもできない
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#373
JobSchedulerService#maybeQueueReadyJobsForExecutionLockedH
• The state of at least one job has changed.(少なくとも一つのジョブの状態が変更された)
• ready(実行可能)になっているjobがいくつ存在するかで決めているっぽい
• Right now the policy is such:
• If >1 of the ready jobs is idle mode we send all of them off
• if more than 2 network connectivity jobs are ready we send them all off.
• If more than 4 jobs total are ready we send them all off.
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#622
Demo
• JobInfo.Builder#setRequiredNetworkType(JobInfo.NETWORK_ANY)のjobを1つずつ登録
• 1個目のjobを登録したら、jobはREADYのままで止まっている(Pendingにも入ってない)
• 2個目のjobを登録したら、jobがActiveになった
• 上の条件に合致したので、jobをpending queueに移動させて、実行したのだと推測
再起動後も動くJobが作れる
• JobInfo.Builder#setPersisted(true)でJobが再起動後も実行される
• 開発者が再起動後に自分でまたJobを登録する必要がない
• JobInfo.Builder#setExtras(PersistableBundle)で再起動後も値を引き継げる
• 素晴らしい!
ということでこいつ...どこかに保存してるぞ...• /data/system/job/jobs.xml
• JobStoreというクラスがそこら辺管理してる
• JobSchedulerにJob(Persisted = true)が
追加された or 削除された際に内容がSyncされる
ということでこいつ...どこかに保存してるぞ...
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java
• 書き込み処理は主にこれ
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java#WriteJobsMapToDiskRunnable
ココらへんにそれっぽい処理が書いてある
/data/system/job/jobs.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?><job-info version="0"> <job jobid="0" package="com.os.operando.jobschedulersample" class="com.os.operando.jobschedulersample.services.MyJobService" uid="10054"> <constraints connectivity="true" /> <periodic period="1000" deadline="1446590637790" delay="1446590636790" /> <extras /> </job> <job jobid="20536" package="android" class="com.android.server.backup.FullBackupJob" uid="1000"> <constraints unmetered="true" idle="true" charging="true" /> <one-off /> <extras /> </job> <job jobid="1" package="com.android.providers.downloads" class="com.android.providers.downloads.DownloadIdleService" uid="10005"> <constraints idle="true" charging="true" /> <periodic period="86400000" deadline="1446675936870" delay="1446589536870" /> <extras /> </job> <job jobid="800" package="android" class="com.android.server.pm.BackgroundDexOptService" uid="1000"> <constraints idle="true" charging="true" /> <one-off delay="1446589526460" /> <extras /> </job></job-info>
PersistableBundleの中身
• JobにセットしたPersistableBundleの中身も書き込まれます
• xmlへの書き込み処理はここでやってる
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/os/PersistableBundle.java#restoreFromXml
• 書き込み処理はJobStore内から呼び出される
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobStore.java#608
PersistableBundleの中身
<job jobid="0" package="com.os.operando.jobschedulersample" class="com.os.operando.jobschedulersample.services.MyJobService" uid="10059"> <constraints connectivity="true" idle="true" charging="true" /> <periodic period="1000" deadline="1446648619790" delay="1446648618790" /> <extras> <int name="id" value="0" /> </extras></job>
PersistableBundleの書き込み
• PersistableBundleの情報を保存する処理は、保存するXMLだけ用意してあげれば、どんなものでも使える汎用的なものっぽい。
• PersistableBundle#restoreFromXmlがhideなので、サードパーティからは使えないけど・・・。
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/core/java/android/os/PersistableBundle.java#restoreFromXml
RAMサイズによって同時実行できるJobの数が変わる!?• System propertyのro.config.low_ram=true場合
• 同時実行できるJobの数は1つ
• System propertyのro.config.low_ram=faseの場合
• 同時実行できるJobの数は3つ
• ro.config.low_ramはAndroid4.4で導入された、メモリ搭載量が少ないターゲット向けの設定
• Android Wearとかはro.config.low_ram=trueかな?
RAMサイズによって同時実行できるJobの数が変わる!?• え、じゃ同時に3つのJobしかできないじゃん
• はい、そうです。
• すいません・・・。(別に俺が実装したわけじゃない
• 大きなJobが走ると他のJobが実行できない
• どんまい…
RAMサイズによって同時実行できるJobの数が変わる!?
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#77
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#352
• https://source.android.com/devices/tech/config/low-ram.html
ココらへんにそれっぽい処理が書いてある
StateControllerの種類
• JobManager
• 各条件の監視をして、Jobの状態をコントロールする
• Controllerの生成箇所
• http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#313
Debugging JobScheduler
• adb shell dumpsys jobscheduler
• JobSchedulerに登録されているJobをDumpする。めっちゃ使う
• adb logcat -s JobSchedulerService
• JobSchedulerServiceのログ。あんまり出ないけど...
• idle状態にするコマンド
• adb shell dumpsys battery unplug
• adb shell dumpsys deviceidle enable
• adb shell dumpsys deviceidle step
• adb shell dumpsys deviceidle force-idle
// Let's go!
http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#348
// GO GO GO!
http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java#367
Doze and App Standby
http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-power
• JobSchedulerってココらへんの話とも絡むよね?
• 深掘りしたい!!
• 省電力頑張りたい!
• DrodiKaigiで話したい!(このテーマで??