ごめんなさい
資料完成しませんでした。。。
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買いました(笑)
まったりAndroid 

Framework Code Reading #2
メルカリでやります!きてね!
https://mandroidfcr.doorkeeper.jp/events/33925
Did you know Project Volta?
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開発者も作りたくない
• こいつはどうしようもない...
とにかく今まで辛かったよな!!
• その気持ちわかるぞ!
• 辛い!辛い!
俺はこんな辛い気持ちを

愚痴りにきたわけではない!
救世主? JobScheduler
Did you know JobScheduler?
Do you use JobScheduler?
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
Frameworkでは

JobSchedulerは使われている
• Auto Bakcup
• Download
• Dex Opt
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
ココらへんにそれっぽい処理が書いてある
Inside JobScheduler
JobService#onStartJob
• MainThreadで実行される
• なので重い処理はAnother Threadを作って処
理する
• jobFinishedしないとjobがはけないから気を
つけて。新しいjobが実行できなくなる
JobService#onStopJob
• 戻り値でtrueを返せばjob作成時に、指定された再試行の基
準に基づいてjobを再スケジューリング
• 戻り値でfalseを返せばjobは止まる
• onStopJobが呼ばれるのは、保留中・実行中のjobが何かに
より(登録したjobの更新)cancelされた際に呼ばれるっぽい
• job実行中にcancelAllとかすれば呼ばれる
scheduleの流れ
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#startTr
ackingJob
• 基本的に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#maybeQueu
eReadyJobsForExecutionLockedH
• 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
Demo
• JobInfo.Builder#setRequiredNetworkType(JobInfo.NETWO
RK_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)で再起動後も

値を引き継げる
• 素晴らしい!
あれ?

再起動後も引き継げるってことは?
• Jobの情報を再起動時のためにどこかに保持する
必要がある
• ということは、ファイルとかに書き出さないと
だよね?
• おぉ!これは面白そう!
ということで

こいつ...どこかに保存してるぞ...
• /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
ココらへんにそれっぽい処理が書いてある
Demo
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
Android M
Doze and App Standby
http://developer.android.com/about/versions/marshmallow/android-6.0-
changes.html#behavior-power
• JobSchedulerってココらへんの話とも絡むよね?
• 深掘りしたい!!
• 省電力頑張りたい!
• DrodiKaigiで話したい!(このテーマで??
Thanks!

JobScheduler Code Reading