1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17syntax = "proto2";
18
19package com.android.server.job;
20
21option java_multiple_files = true;
22
23import "frameworks/base/core/proto/android/app/job/enums.proto";
24import "frameworks/base/core/proto/android/content/clipdata.proto";
25import "frameworks/base/core/proto/android/content/component_name.proto";
26import "frameworks/base/core/proto/android/content/intent.proto";
27import "frameworks/base/core/proto/android/net/network.proto";
28import "frameworks/base/core/proto/android/net/networkrequest.proto";
29import "frameworks/base/core/proto/android/os/bundle.proto";
30import "frameworks/base/core/proto/android/os/persistablebundle.proto";
31import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
32import "frameworks/base/libs/incident/proto/android/privacy.proto";
33
34message JobSchedulerServiceDumpProto {
35    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
36
37    optional ConstantsProto settings = 1;
38
39    optional int32 current_heartbeat = 14;
40    repeated int32 next_heartbeat = 15;
41    optional int64 last_heartbeat_time_millis = 16;
42    optional int64 next_heartbeat_time_millis = 17;
43    optional bool in_parole = 18;
44
45    repeated int32 started_users = 2;
46
47    message RegisteredJob {
48        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
49
50        optional JobStatusShortInfoProto info = 1;
51        optional JobStatusDumpProto dump = 2;
52
53        // A job is ready to be executed if:
54        // is_job_ready && is_user_started && !is_job_pending &&
55        // !is_job_currently_active && !is_uid_backing_up &&
56        // is_component_present.
57        optional bool is_job_ready = 3;
58        optional bool is_user_started = 4;
59        optional bool is_job_pending = 5;
60        optional bool is_job_currently_active = 6;
61        optional bool is_uid_backing_up = 7;
62        optional bool is_component_present = 8;
63
64        optional int64 last_run_heartbeat = 9;
65    }
66    repeated RegisteredJob registered_jobs = 3;
67
68    repeated StateControllerProto controllers = 4;
69
70    // Which uids are currently in the foreground.
71    message PriorityOverride {
72        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
73
74        optional int32 uid = 1;
75        // Use sint32 instead of an enum since priorities can technically be
76        // negative.
77        optional sint32 override_value = 2;
78    }
79    repeated PriorityOverride priority_overrides = 5;
80
81    // UIDs that are currently performing backups, so their jobs won't be
82    // allowed to run.
83    repeated int32 backing_up_uids = 6;
84
85    optional JobPackageHistoryProto history = 7;
86    optional JobPackageTrackerDumpProto package_tracker = 8;
87
88    message PendingJob {
89        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
90
91        optional JobStatusShortInfoProto info = 1;
92        optional JobStatusDumpProto dump = 2;
93        optional sint32 evaluated_priority = 3;
94        // How long this job has been pending.
95        optional int64 enqueued_duration_ms = 4;
96    }
97    repeated PendingJob pending_jobs = 9;
98
99    // From a service that has currently active or pending jobs.
100    message ActiveJob {
101        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
102
103        message InactiveJob {
104            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
105
106            optional int64 time_since_stopped_ms = 1;
107            // This is not always provided.
108            optional string stopped_reason = 2;
109        }
110        message RunningJob {
111            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
112
113            optional JobStatusShortInfoProto info = 1;
114            // How long this job has been running for.
115            optional int64 running_duration_ms = 2;
116            optional int64 time_until_timeout_ms = 3;
117
118            optional JobStatusDumpProto dump = 4;
119
120            optional sint32 evaluated_priority = 5;
121
122            optional int64 time_since_made_active_ms = 6;
123            // How long this job has been pending.
124            optional int64 pending_duration_ms = 7;
125        }
126        oneof job {
127            InactiveJob inactive = 1;
128            RunningJob running = 2;
129        }
130    }
131    repeated ActiveJob active_jobs = 10;
132
133    // True when JobScheduler is allowed to run third party apps.
134    optional bool is_ready_to_rock = 11;
135    // What was last reported to DeviceIdleController about whether the device
136    // is active.
137    optional bool reported_active = 12;
138    // The current limit on the number of concurrent JobServiceContext entries
139    // we want to keep actively running a job.
140    optional int32 max_active_jobs = 13;
141}
142
143// A com.android.server.job.JobSchedulerService.Constants object.
144message ConstantsProto {
145    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
146
147    // Minimum # of idle jobs that must be ready in order to force the JMS to
148    // schedule things early.
149    optional int32 min_idle_count = 1;
150    // Minimum # of charging jobs that must be ready in order to force the JMS
151    // to schedule things early.
152    optional int32 min_charging_count = 2;
153    // Minimum # of "battery not low" jobs that must be ready in order to force
154    // the JMS to schedule things early.
155    optional int32 min_battery_not_low_count = 3;
156    // Minimum # of "storage not low" jobs that must be ready in order to force
157    // the JMS to schedule things early.
158    optional int32 min_storage_not_low_count = 4;
159    // Minimum # of connectivity jobs that must be ready in order to force the
160    // JMS to schedule things early. 1 == Run connectivity jobs as soon as
161    // ready.
162    optional int32 min_connectivity_count = 5;
163    // Minimum # of content trigger jobs that must be ready in order to force
164    // the JMS to schedule things early.
165    optional int32 min_content_count = 6;
166    // Minimum # of jobs (with no particular constraints) for which the JMS will
167    // be happy running some work early. This (and thus the other min counts)
168    // is now set to 1, to prevent any batching at this level. Since we now do
169    // batching through doze, that is a much better mechanism.
170    optional int32 min_ready_jobs_count = 7;
171    // This is the job execution factor that is considered to be heavy use of
172    // the system.
173    optional double heavy_use_factor = 8;
174    // This is the job execution factor that is considered to be moderate use of
175    // the system.
176    optional double moderate_use_factor = 9;
177    // The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app.
178    optional int32 fg_job_count = 10;
179    // The maximum number of background jobs we allow when the system is in a
180    // normal memory state.
181    optional int32 bg_normal_job_count = 11;
182    // The maximum number of background jobs we allow when the system is in a
183    // moderate memory state.
184    optional int32 bg_moderate_job_count = 12;
185    // The maximum number of background jobs we allow when the system is in a
186    // low memory state.
187    optional int32 bg_low_job_count = 13;
188    // The maximum number of background jobs we allow when the system is in a
189    // critical memory state.
190    optional int32 bg_critical_job_count = 14;
191    // The maximum number of times we allow a job to have itself rescheduled
192    // before giving up on it, for standard jobs.
193    optional int32 max_standard_reschedule_count = 15;
194    // The maximum number of times we allow a job to have itself rescheduled
195    // before giving up on it, for jobs that are executing work.
196    optional int32 max_work_reschedule_count = 16;
197    // The minimum backoff time to allow for linear backoff.
198    optional int64 min_linear_backoff_time_ms = 17;
199    // The minimum backoff time to allow for exponential backoff.
200    optional int64 min_exp_backoff_time_ms = 18;
201    // How often we recalculate runnability based on apps' standby bucket
202    // assignment. This should be prime relative to common time interval lengths
203    // such as a quarter-hour or day, so that the heartbeat drifts relative to
204    // wall-clock milestones.
205    optional int64 standby_heartbeat_time_ms = 19;
206    // Mapping: standby bucket -> number of heartbeats between each sweep of
207    // that bucket's jobs.
208    // Bucket assignments as recorded in the JobStatus objects are normalized to
209    // be indices into this array, rather than the raw constants used by
210    // AppIdleHistory.
211    repeated int32 standby_beats = 20;
212    // The fraction of a job's running window that must pass before we
213    // consider running it when the network is congested.
214    optional double conn_congestion_delay_frac = 21;
215    // The fraction of a prefetch job's running window that must pass before
216    // we consider matching it against a metered network.
217    optional double conn_prefetch_relax_frac = 22;
218}
219
220message StateControllerProto {
221    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
222
223    message BackgroundJobsController {
224        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
225
226        optional com.android.server.ForceAppStandbyTrackerProto force_app_standby_tracker = 1;
227
228        message TrackedJob {
229            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
230
231            optional JobStatusShortInfoProto info = 1;
232            optional int32 source_uid = 2;
233            optional string source_package_name = 3;
234            optional bool is_in_foreground = 4;
235            optional bool is_whitelisted = 5;
236            optional bool can_run_any_in_background = 6;
237            // If the constraints are satisfied, then the controller will mark
238            // the job as RUNNABLE, otherwise, it will be WAITING.
239            optional bool are_constraints_satisfied = 7;
240        }
241        repeated TrackedJob tracked_jobs = 2;
242    }
243    message BatteryController {
244        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
245
246        optional bool is_on_stable_power = 1;
247        optional bool is_battery_not_low = 2;
248
249        // Whether or not the controller is monitoring battery changes.
250        optional bool is_monitoring = 3;
251        // Only valid if is_monitoring is true.
252        optional int32 last_broadcast_sequence_number = 4;
253
254        message TrackedJob {
255            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
256
257            optional JobStatusShortInfoProto info = 1;
258            optional int32 source_uid = 2;
259        }
260        repeated TrackedJob tracked_jobs = 5;
261    }
262    message ConnectivityController {
263        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
264
265        optional bool is_connected = 1;
266
267        message TrackedJob {
268            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
269
270            optional JobStatusShortInfoProto info = 1;
271            optional int32 source_uid = 2;
272            optional .android.net.NetworkRequestProto required_network = 3;
273        }
274        repeated TrackedJob tracked_jobs = 2;
275    }
276    message ContentObserverController {
277        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
278
279        message TrackedJob {
280            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
281
282            optional JobStatusShortInfoProto info = 1;
283            optional int32 source_uid = 2;
284        }
285        repeated TrackedJob tracked_jobs = 1;
286
287        message Observer {
288            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
289
290            optional int32 user_id = 1;
291
292            message TriggerContentData {
293                option (.android.msg_privacy).dest = DEST_AUTOMATIC;
294
295                optional string uri = 1 [
296                    (.android.privacy).dest = DEST_EXPLICIT
297                ];
298                optional int32 flags = 2;
299
300                // A
301                // com.android.server.job.controllers.ContentObserverController.JobInstance
302                // object.
303                message JobInstance {
304                    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
305
306                    optional JobStatusShortInfoProto info = 1;
307                    optional int32 source_uid = 2;
308
309                    optional int64 trigger_content_update_delay_ms = 3;
310                    optional int64 trigger_content_max_delay_ms = 4;
311
312                    repeated string changed_authorities = 5 [
313                        (.android.privacy).dest = DEST_EXPLICIT
314                    ];
315                    repeated string changed_uris = 6 [
316                        (.android.privacy).dest = DEST_EXPLICIT
317                    ];
318                }
319                repeated JobInstance jobs = 3;
320            }
321            repeated TriggerContentData triggers = 2;
322        }
323        repeated Observer observers = 2;
324    }
325    message DeviceIdleJobsController {
326        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
327
328        // True when in device idle mode.
329        optional bool is_device_idle_mode = 1;
330
331        message TrackedJob {
332            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
333
334            optional JobStatusShortInfoProto info = 1;
335            optional int32 source_uid = 2;
336            optional string source_package_name = 3;
337            // If the constraints are satisfied, then the controller will mark
338            // the job as RUNNABLE, otherwise, it will be WAITING.
339            optional bool are_constraints_satisfied = 4;
340            optional bool is_doze_whitelisted = 5;
341            // A job that is exempted from Doze when the app is temp whitelisted
342            // or in the foreground.
343            optional bool is_allowed_in_doze = 6;
344        }
345        repeated TrackedJob tracked_jobs = 2;
346    }
347    message IdleController {
348        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
349
350        optional bool is_idle = 1;
351
352        message TrackedJob {
353            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
354
355            optional JobStatusShortInfoProto info = 1;
356            optional int32 source_uid = 2;
357        }
358        repeated TrackedJob tracked_jobs = 2;
359    }
360    message StorageController {
361        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
362
363        optional bool is_storage_not_low = 1;
364        optional int32 last_broadcast_sequence_number = 2;
365
366        message TrackedJob {
367            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
368
369            optional JobStatusShortInfoProto info = 1;
370            optional int32 source_uid = 2;
371        }
372        repeated TrackedJob tracked_jobs = 3;
373    }
374    message TimeController {
375        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
376
377        optional int64 now_elapsed_realtime = 1;
378        optional int64 time_until_next_delay_alarm_ms = 2;
379        optional int64 time_until_next_deadline_alarm_ms = 3;
380
381        message TrackedJob {
382            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
383
384            optional JobStatusShortInfoProto info = 1;
385            optional int32 source_uid = 2;
386
387            optional bool has_timing_delay_constraint = 3;
388            // Only valid if has_timing_delay_constraint is true. Can be
389            // negative if the delay is in the past.
390            optional int64 delay_time_remaining_ms = 4;
391
392            optional bool has_deadline_constraint = 5;
393            // Only valid if has_timing_delay_constraint is true. Can be
394            // negative in certain situations.
395            optional int64 time_remaining_until_deadline_ms = 6;
396        }
397        repeated TrackedJob tracked_jobs = 4;
398    }
399    oneof controller {
400        BackgroundJobsController background = 1;
401        BatteryController battery = 2;
402        ConnectivityController connectivity = 3;
403        ContentObserverController content_observer = 4;
404        DeviceIdleJobsController device_idle = 5;
405        IdleController idle = 6;
406        StorageController storage = 7;
407        TimeController time = 8;
408    }
409}
410
411// A com.android.server.job.JobPackageTracker.DataSet object.
412message DataSetProto {
413    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
414
415    optional int64 start_clock_time_ms = 1;
416    // How much time has elapsed since the DataSet was instantiated.
417    optional int64 elapsed_time_ms = 2;
418    optional int64 period_ms = 3;
419
420    // Represents a com.android.server.job.JobPackageTracker.PackageEntry
421    // object, but with some extra data.
422    message PackageEntryProto {
423        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
424
425        optional int32 uid = 1;
426        optional string package_name = 2;
427
428        message State {
429            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
430
431            optional int64 duration_ms = 1;
432            optional int32 count = 2;
433        }
434        optional State pending_state = 3;
435        optional State active_state = 4;
436        optional State active_top_state = 5;
437
438        // True if the PackageEntry is currently pending or has been pending in
439        // the past.
440        optional bool pending = 6;
441        // True if the PackageEntry is currently active or has been active in
442        // the past.
443        optional bool active = 7;
444        // True if the PackageEntry is currently active top or has been active
445        // top in the past.
446        optional bool active_top = 8;
447
448        message StopReasonCount {
449            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
450
451            optional .android.app.job.StopReasonEnum reason = 1;
452            optional int32 count = 2;
453        }
454        repeated StopReasonCount stop_reasons = 9;
455    }
456    repeated PackageEntryProto package_entries = 4;
457
458    optional int32 max_concurrency = 5;
459    optional int32 max_foreground_concurrency = 6;
460}
461
462// Dump from com.android.server.job.GrantedUriPermissions.
463message GrantedUriPermissionsDumpProto {
464    option (.android.msg_privacy).dest = DEST_EXPLICIT;
465
466    optional int32 flags = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ];
467    optional int32 source_user_id = 2 [
468        (.android.privacy).dest = DEST_AUTOMATIC
469    ];
470    optional string tag = 3;
471    optional string permission_owner = 4;
472    repeated string uris = 5;
473}
474
475message JobPackageTrackerDumpProto {
476    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
477
478    repeated DataSetProto historical_stats = 1;
479    optional DataSetProto current_stats = 2;
480}
481
482message JobPackageHistoryProto {
483    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
484
485    enum Event {
486        UNKNOWN = 0;
487        START_JOB = 1;
488        STOP_JOB = 2;
489        START_PERIODIC_JOB = 3;
490        STOP_PERIODIC_JOB = 4;
491    }
492    message HistoryEvent {
493        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
494
495        optional Event event = 1;
496        optional int64 time_since_event_ms = 2;
497        optional int32 uid = 3;
498        // Job IDs can technically be negative.
499        optional int32 job_id = 4;
500        optional string tag = 5;
501        // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events.
502        optional .android.app.job.StopReasonEnum stop_reason = 6;
503    }
504    repeated HistoryEvent history_event = 1;
505}
506
507message JobStatusShortInfoProto {
508    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
509
510    optional int32 calling_uid = 1;
511    // Job IDs can technically be negative.
512    optional int32 job_id = 2;
513    optional string battery_name = 3;
514}
515
516// Dump from a com.android.server.job.controllers.JobStatus object.
517message JobStatusDumpProto {
518    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
519
520    // The UID that scheduled the job.
521    optional int32 calling_uid = 1;
522    optional string tag = 2;
523
524    // The UID for which the job is being run.
525    optional int32 source_uid = 3;
526    optional int32 source_user_id = 4;
527    // The package for which the job is being run.
528    optional string source_package_name = 5;
529
530    // Custom dump of android.app.job.JobInfo object.
531    message JobInfo {
532        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
533
534        optional .android.content.ComponentNameProto service = 1;
535
536        optional bool is_periodic = 2;
537        // Only valid if is_periodic is true.
538        optional int64 period_interval_ms = 3;
539        // Only valid if is_periodic is true.
540        optional int64 period_flex_ms = 4;
541
542        optional bool is_persisted = 5;
543        optional sint32 priority = 6;
544        optional int32 flags = 7;
545
546        optional bool requires_charging = 8;
547        optional bool requires_battery_not_low = 9;
548        optional bool requires_device_idle = 10;
549
550        message TriggerContentUri {
551            optional int32 flags = 1 [
552                (.android.privacy).dest = DEST_AUTOMATIC
553            ];
554            optional string uri = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
555        }
556        repeated TriggerContentUri trigger_content_uris = 11;
557        optional int64 trigger_content_update_delay_ms = 12;
558        optional int64 trigger_content_max_delay_ms = 13;
559
560        optional .android.os.PersistableBundleProto extras = 14;
561        optional .android.os.BundleProto transient_extras = 15;
562        // ClipData of information that is returned to the application at
563        // execution time, but not persisted by the system. This is provided by
564        // the app and the main purpose of providing a ClipData is to allow
565        // granting of URI permissions for data associated with the clip.  The
566        // exact kind of permission grant to perform is specified in the flags
567        // field.
568        optional .android.content.ClipDataProto clip_data = 16;
569
570        optional GrantedUriPermissionsDumpProto granted_uri_permissions = 17;
571
572        optional .android.net.NetworkRequestProto required_network = 18;
573
574        optional int64 total_network_bytes = 19;
575
576        optional int64 min_latency_ms = 20;
577        optional int64 max_execution_delay_ms = 21;
578
579        message Backoff {
580            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
581
582            enum Policy {
583                BACKOFF_POLICY_LINEAR = 0;
584                BACKOFF_POLICY_EXPONENTIAL = 1;
585            }
586            optional Policy policy = 1;
587            optional int64 initial_backoff_ms = 2;
588        }
589        optional Backoff backoff_policy = 22;
590
591        optional bool has_early_constraint = 23;
592        optional bool has_late_constraint = 24;
593    }
594    optional JobInfo job_info = 6;
595
596    enum Constraint {
597        CONSTRAINT_CHARGING = 1;
598        CONSTRAINT_BATTERY_NOT_LOW = 2;
599        CONSTRAINT_STORAGE_NOT_LOW = 3;
600        CONSTRAINT_TIMING_DELAY = 4;
601        CONSTRAINT_DEADLINE = 5;
602        CONSTRAINT_IDLE = 6;
603        CONSTRAINT_CONNECTIVITY = 7;
604        CONSTRAINT_CONTENT_TRIGGER = 8;
605        CONSTRAINT_DEVICE_NOT_DOZING = 9;
606    }
607    repeated Constraint required_constraints = 7;
608    repeated Constraint satisfied_constraints = 8;
609    repeated Constraint unsatisfied_constraints = 9;
610    optional bool is_doze_whitelisted = 10;
611
612    enum TrackingController {
613        TRACKING_BATTERY = 0;
614        TRACKING_CONNECTIVITY = 1;
615        TRACKING_CONTENT = 2;
616        TRACKING_IDLE = 3;
617        TRACKING_STORAGE = 4;
618        TRACKING_TIME = 5;
619    }
620    // Controllers that are currently tracking the job.
621    repeated TrackingController tracking_controllers = 11;
622
623    repeated string changed_authorities = 12 [
624        (.android.privacy).dest = DEST_EXPLICIT
625    ];
626    repeated string changed_uris = 13 [
627        (.android.privacy).dest = DEST_EXPLICIT
628    ];
629
630    optional .android.net.NetworkProto network = 14;
631
632    // Only the desired data from an android.app.job.JobWorkItem object.
633    message JobWorkItem {
634        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
635
636        optional int32 work_id = 1;
637        optional int32 delivery_count = 2;
638        optional .android.content.IntentProto intent = 3;
639        optional GrantedUriPermissionsDumpProto uri_grants = 4;
640    }
641    repeated JobWorkItem pending_work = 15;
642    repeated JobWorkItem executing_work = 16;
643
644    enum Bucket {
645        ACTIVE = 0;
646        WORKING_SET = 1;
647        FREQUENT = 2;
648        RARE = 3;
649        NEVER = 4;
650    }
651    optional Bucket standby_bucket = 17;
652
653    optional int64 enqueue_duration_ms = 18;
654    // Can be negative if the earliest runtime deadline has passed.
655    optional sint64 time_until_earliest_runtime_ms = 19;
656    // Can be negative if the latest runtime deadline has passed.
657    optional sint64 time_until_latest_runtime_ms = 20;
658
659    optional int32 num_failures = 21;
660
661    optional int64 last_successful_run_time = 22;
662    optional int64 last_failed_run_time = 23;
663
664    optional int64 internal_flags = 24;
665}
666