Skip to content

Latest commit

 

History

History

Shibuya.apk_4

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.md

Slide

資料内のリンクとかJobSchedulerの電波メモ

JobScheduler Code Reading

About Me

  • Shinobu Okano(@operandoOS)
  • Mercari, Inc.
  • 今週で23歳になりました!ありがとうございます!
  • 最近iPhone6s Plus買いました(笑)

Project Volta

Google I/O 2014 - Introduction to Project Volta

About JobScheduler

  • Android Lから導入されたAPI
  • 様々な条件のJobをスケジュールしてくれるAPI
  • 使うことで消費電力を意識した実装ができる
  • 開発者が頑張らなくていいAPI
  • JobSchedulerはAndroid Framework Services(System Service系)
  • マルチユーザ用にも設計されている(当たり前か)
  • Schedulerであって、Alarmではない
  • 特定の時間に実行!みたいな感じではない

JobSchedulerの使い方

JobScheduler Sample

Auto Backup - 条件

* バックアップは24時間ごとに行われる

public static void schedule(Context ctx, long minDelay) {
    JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService)
             .setRequiresDeviceIdle(true)
             .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
             .setRequiresCharging(true);
    if (minDelay > 0) {
        builder.setMinimumLatency(minDelay);
    }
    js.schedule(builder.build());
}

scheduleの流れ

JobScheduler.schedule(JobInfo)

JobSchedulerStub#schedule

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

JobSchedulerService#startTrackingJob

JobSchedulerService#maybeQueueReadyJobsForExecutionLockedH

Demo

  • JobInfo.Builder#setRequiredNetworkType(JobInfo.NETWORK_TYPE_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)で再起動後も値を引き継げる
  • 素晴らしい!

サンプル(こんな感じ)

PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("id", i);
JobInfo jobInfo = new JobInfo.Builder(i, serviceName)
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
        .setPersisted(true)
        .setExtras(persistableBundle)
        .build();
scheduler.schedule(jobInfo);

あれ?再起動後も引き継げるってことは?

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

ということで、こいつ...どこかに保存してるぞ...

/data/system/job/jobs.xml

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<job-info version="0">
    <job jobid="808" package="android" class="com.android.server.MountServiceIdler" uid="1000">
        <constraints idle="true" charging="true" />
        <one-off delay="1446660001930" />
        <extras />
    </job>
    <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="20537" package="android" class="com.android.server.backup.KeyValueBackupJob" uid="1000">
        <constraints connectivity="true" charging="true" />
        <one-off deadline="1446675931860" delay="1446604253797" />
        <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 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に書き込み処理

RAMサイズによって同時実行できるJobの数が変わる

/** The number of concurrent jobs we run at one time. */
private static final int MAX_JOB_CONTEXTS_COUNT
        = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
// ActivityManager.java
public static boolean isLowRamDeviceStatic() {
    return "true".equals(SystemProperties.get("ro.config.low_ram", "false"));
}

StateControllerの種類

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!

// GO GO GO!

関連クラス