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