/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

syntax = "proto2";

package com.android.server.job;

option java_multiple_files = true;

import "frameworks/base/core/proto/android/content/clipdata.proto";
import "frameworks/base/core/proto/android/content/component_name.proto";
import "frameworks/base/core/proto/android/content/intent.proto";
import "frameworks/base/core/proto/android/net/network.proto";
import "frameworks/base/core/proto/android/net/networkrequest.proto";
import "frameworks/base/core/proto/android/os/bundle.proto";
import "frameworks/base/core/proto/android/os/persistablebundle.proto";
import "frameworks/base/core/proto/android/server/appstatetracker.proto";
import "frameworks/base/core/proto/android/server/statlogger.proto";
import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/util/quotatracker.proto";
import "frameworks/proto_logging/stats/enums/app/job/job_enums.proto";
import "frameworks/proto_logging/stats/enums/server/job/enums.proto";

message JobSchedulerServiceDumpProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional ConstantsProto settings = 1;

    reserved 14; // current_heartbeat
    reserved 15; // next_heartbeat
    reserved 16; // last_heartbeat_time_millis
    reserved 17; // next_heartbeat_time_millis
    reserved 18; // in_parole
    optional bool in_thermal = 19;

    repeated int32 started_users = 2;

    message JobRestriction {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional .android.app.job.InternalStopReasonEnum reason = 1;
        optional bool is_restricting = 2;
    }

    message RegisteredJob {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional JobStatusShortInfoProto info = 1;
        optional JobStatusDumpProto dump = 2;

        optional bool is_job_ready_to_be_executed = 10;
        // A job is ready to be executed if:
        // is_job_ready && are_users_started && !is_job_restricted && !is_job_pending &&
        // !is_job_currently_active && !is_uid_backing_up &&
        // is_component_usable.
        optional bool is_job_ready = 3;
        optional bool are_users_started = 4;
        optional bool is_job_restricted = 11;
        optional bool is_job_pending = 5;
        optional bool is_job_currently_active = 6;
        optional bool is_uid_backing_up = 7;
        optional bool is_component_usable = 8;

        repeated JobRestriction restrictions = 12;

        reserved 9; // last_run_heartbeat

        // Next tag: 13
    }
    repeated RegisteredJob registered_jobs = 3;

    repeated StateControllerProto controllers = 4;

    // Which uids are currently in the foreground.
    message PriorityOverride {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional int32 uid = 1;
        // Use sint32 instead of an enum since priorities can technically be
        // negative.
        optional sint32 override_value = 2;
    }
    repeated PriorityOverride priority_overrides = 5;

    // UIDs that are currently performing backups, so their jobs won't be
    // allowed to run.
    repeated int32 backing_up_uids = 6;

    optional JobPackageHistoryProto history = 7;
    optional JobPackageTrackerDumpProto package_tracker = 8;

    message PendingJob {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional JobStatusShortInfoProto info = 1;
        optional JobStatusDumpProto dump = 2;
        optional sint32 evaluated_priority = 3;
        // How long this job has been pending.
        optional int64 pending_duration_ms = 4;
    }
    repeated PendingJob pending_jobs = 9;

    // From a service that has currently active or pending jobs.
    message ActiveJob {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        message InactiveJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int64 time_since_stopped_ms = 1;
            // This is not always provided.
            optional string stopped_reason = 2;
        }
        message RunningJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            // How long this job has been running for.
            optional int64 running_duration_ms = 2;
            optional int64 time_until_timeout_ms = 3;

            optional JobStatusDumpProto dump = 4;

            optional sint32 evaluated_priority = 5;

            optional int64 time_since_made_active_ms = 6;
            // How long this job was pending before it became active.
            optional int64 pending_duration_ms = 7;
        }
        oneof job {
            InactiveJob inactive = 1;
            RunningJob running = 2;
        }
    }
    repeated ActiveJob active_jobs = 10;

    // True when JobScheduler is allowed to run third party apps.
    optional bool is_ready_to_rock = 11;
    // What was last reported to DeviceIdleController about whether the device
    // is active.
    optional bool reported_active = 12;
    // The current limit on the number of concurrent JobServiceContext entries
    // we want to keep actively running a job.
    optional int32 max_active_jobs = 13;

    // Dump from JobConcurrencyManager.
    optional JobConcurrencyManagerProto concurrency_manager = 20;

    optional JobStorePersistStatsProto persist_stats = 21;

    optional .android.util.quota.CountQuotaTrackerProto quota_tracker = 22;

    // Next tag: 23
}

// A com.android.server.job.JobSchedulerService.Constants object.
message ConstantsProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    reserved 1; // min_idle_count
    reserved 2; // min_charging_count
    reserved 3; // min_battery_not_low_count
    reserved 4; // min_storage_not_low_count
    reserved 5; // min_connectivity_count
    reserved 6; // min_content_count
    reserved 7; // min_ready_jobs_count
    // Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
    optional int32 min_ready_non_active_jobs_count = 29;
    // Don't batch a non-ACTIVE job if it's been delayed due to force batching attempts for
    // at least this amount of time.
    optional int64 max_non_active_job_batch_delay_ms = 30;
    // This is the job execution factor that is considered to be heavy use of
    // the system.
    optional double heavy_use_factor = 8;
    // This is the job execution factor that is considered to be moderate use of
    // the system.
    optional double moderate_use_factor = 9;
    // The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app.
    optional int32 fg_job_count = 10;
    // The maximum number of background jobs we allow when the system is in a
    // normal memory state.
    optional int32 bg_normal_job_count = 11;
    // The maximum number of background jobs we allow when the system is in a
    // moderate memory state.
    optional int32 bg_moderate_job_count = 12;
    // The maximum number of background jobs we allow when the system is in a
    // low memory state.
    optional int32 bg_low_job_count = 13;
    // The maximum number of background jobs we allow when the system is in a
    // critical memory state.
    optional int32 bg_critical_job_count = 14;
    reserved 15; // max_standard_reschedule_count
    reserved 16; // max_work_reschedule_count
    // The minimum backoff time to allow for linear backoff.
    optional int64 min_linear_backoff_time_ms = 17;
    // The minimum backoff time to allow for exponential backoff.
    optional int64 min_exp_backoff_time_ms = 18;
    // How often we recalculate runnability based on apps' standby bucket
    // assignment. This should be prime relative to common time interval lengths
    // such as a quarter-hour or day, so that the heartbeat drifts relative to
    // wall-clock milestones.
    reserved 19; // standby_heartbeat_time_ms
    // Mapping: standby bucket -> number of heartbeats between each sweep of
    // that bucket's jobs.
    // Bucket assignments as recorded in the JobStatus objects are normalized to
    // be indices into this array, rather than the raw constants used by
    // AppIdleHistory.
    reserved 20; // standby_beats
    // The fraction of a job's running window that must pass before we
    // consider running it when the network is congested.
    optional double conn_congestion_delay_frac = 21;
    // The fraction of a prefetch job's running window that must pass before
    // we consider matching it against a metered network.
    optional double conn_prefetch_relax_frac = 22;
    // Whether to use heartbeats or rolling window for quota management. True
    // will use heartbeats, false will use a rolling window.
    reserved 23; // use_heartbeats
    // Whether to enable quota limits on APIs.
    optional bool enable_api_quotas = 31;
    // The maximum number of schedule() calls an app can make in a set amount of time.
    optional int32 api_quota_schedule_count = 32;
    // The time window that {@link #API_QUOTA_SCHEDULE_COUNT} should be evaluated over.
    optional int64 api_quota_schedule_window_ms = 33;
    // Whether or not to throw an exception when an app hits its schedule quota limit.
    optional bool api_quota_schedule_throw_exception = 34;
    // Whether or not to return a failure result when an app hits its schedule quota limit.
    optional bool api_quota_schedule_return_failure_result = 35;

    message QuotaController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        // How much time each app will have to run jobs within their standby bucket window.
        optional int64 allowed_time_per_period_ms = 1;
        // How much time the package should have before transitioning from out-of-quota to in-quota.
        // This should not affect processing if the package is already in-quota.
        optional int64 in_quota_buffer_ms = 2;
        // The quota window size of the particular standby bucket. Apps in this standby bucket are
        // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
        // WINDOW_SIZE_MS.
        optional int64 active_window_size_ms = 3;
        // The quota window size of the particular standby bucket. Apps in this standby bucket are
        // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
        // WINDOW_SIZE_MS.
        optional int64 working_window_size_ms = 4;
        // The quota window size of the particular standby bucket. Apps in this standby bucket are
        // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
        // WINDOW_SIZE_MS.
        optional int64 frequent_window_size_ms = 5;
        // The quota window size of the particular standby bucket. Apps in this standby bucket are
        // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
        // WINDOW_SIZE_MS.
        optional int64 rare_window_size_ms = 6;
        // The quota window size of the particular standby bucket. Apps in this standby bucket are
        // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
        // WINDOW_SIZE_MS.
        optional int64 restricted_window_size_ms = 20;
        // The maximum amount of time an app can have its jobs running within a 24 hour window.
        optional int64 max_execution_time_ms = 7;
        // The maximum number of jobs an app can run within this particular standby bucket's
        // window size.
        optional int32 max_job_count_active = 8;
        // The maximum number of jobs an app can run within this particular standby bucket's
        // window size.
        optional int32 max_job_count_working = 9;
        // The maximum number of jobs an app can run within this particular standby bucket's
        // window size.
        optional int32 max_job_count_frequent = 10;
        // The maximum number of jobs an app can run within this particular standby bucket's
        // window size.
        optional int32 max_job_count_rare = 11;
        // The maximum number of jobs an app can run within this particular standby bucket's
        // window size.
        optional int32 max_job_count_restricted = 21;
        // The period of time used to rate limit recently run jobs.
        optional int32 rate_limiting_window_ms = 19;
        // The maximum number of jobs that should be allowed to run in the past
        // rate_limiting_window_ms.
        optional int32 max_job_count_per_rate_limiting_window = 12;
        // The maximum number of timing sessions an app can run within this particular standby
        // bucket's window size.
        optional int32 max_session_count_active = 13;
        // The maximum number of timing sessions an app can run within this particular standby
        // bucket's window size.
        optional int32 max_session_count_working = 14;
        // The maximum number of timing sessions an app can run within this particular standby
        // bucket's window size.
        optional int32 max_session_count_frequent = 15;
        // The maximum number of timing sessions an app can run within this particular standby
        // bucket's window size.
        optional int32 max_session_count_rare = 16;
        // The maximum number of timing sessions an app can run within this particular standby
        // bucket's window size.
        optional int32 max_session_count_restricted = 22;
        // The maximum number of timing sessions that should be allowed to run in the past
        // rate_limiting_window_ms.
        optional int32 max_session_count_per_rate_limiting_window = 17;
        // Treat two distinct {@link TimingSession}s as the same if they start and end within this
        // amount of time of each other.
        optional int64 timing_session_coalescing_duration_ms = 18;
        // The minimum amount of time between quota check alarms.
        optional int64 min_quota_check_delay_ms = 23;

        // The total expedited job session limit of the particular standby bucket. Apps in this
        // standby bucket can only have expedited job sessions totalling EJ_LIMIT (without factoring
        // in any rewards or free EJs).
        optional int64 expedited_job_limit_active_ms = 24;
        // The total expedited job session limit of the particular standby bucket. Apps in this
        // standby bucket can only have expedited job sessions totalling EJ_LIMIT (without factoring
        // in any rewards or free EJs).
        optional int64 expedited_job_limit_working_ms = 25;
        // The total expedited job session limit of the particular standby bucket. Apps in this
        // standby bucket can only have expedited job sessions totalling EJ_LIMIT (without factoring
        // in any rewards or free EJs).
        optional int64 expedited_job_limit_frequent_ms = 26;
        // The total expedited job session limit of the particular standby bucket. Apps in this
        // standby bucket can only have expedited job sessions totalling EJ_LIMIT (without factoring
        // in any rewards or free EJs).
        optional int64 expedited_job_limit_rare_ms = 27;
        // The total expedited job session limit of the particular standby bucket. Apps in this
        // standby bucket can only have expedited job sessions totalling EJ_LIMIT (without factoring
        // in any rewards or free EJs).
        optional int64 expedited_job_limit_restricted_ms = 28;
        // The period of time used to calculate expedited job sessions. Apps can only have expedited
        // job sessions totalling EJ_LIMIT_<bucket>_MS within this period of time (without factoring
        // in any rewards or free EJs).
        optional int64 expedited_job_window_size_ms = 29;
        // Length of time used to split an app's top time into chunks.
        optional int64 expedited_job_top_app_time_chunk_size_ms = 30;
        // How much EJ quota to give back to an app based on the number of top app time chunks
        // it had.
        optional int64 expedited_job_reward_top_app_ms = 31;
        // How much EJ quota to give back to an app based on each non-top user interaction.
        optional int64 expedited_job_reward_interaction_ms = 32;
        // How much EJ quota to give back to an app based on each notification seen event.
        optional int64 expedited_job_reward_notification_seen_ms = 33;

        // Next tag: 34
    }
    optional QuotaController quota_controller = 24;

    message TimeController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
        // ready now.
        reserved 1; // skip_not_ready_jobs
        // Whether or not TimeController will use a non-wakeup alarm for delay constraints.
        reserved 2; // use_non_wakeup_alarm_for_delay
    }
    optional TimeController time_controller = 25;

    // Max number of jobs, when screen is ON.
    optional MaxJobCountsPerMemoryTrimLevelProto max_job_counts_screen_on = 26;

    // Max number of jobs, when screen is OFF.
    optional MaxJobCountsPerMemoryTrimLevelProto max_job_counts_screen_off = 27;

    // In this time after screen turns on, we increase job concurrency.
    optional int32 screen_off_job_concurrency_increase_delay_ms = 28;

    // Next tag: 36
}

// Next tag: 4
message MaxJobCountsProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    // Total number of jobs to run simultaneously.
    optional int32 total_jobs = 1;

    // Max number of BG (== owned by non-TOP apps) jobs to run simultaneously.
    optional int32 max_bg = 2;

    // We try to run at least this many BG (== owned by non-TOP apps) jobs, when there are any
    // pending, rather than always running the TOTAL number of FG jobs.
    optional int32 min_bg = 3;
}

// Next tag: 5
message MaxJobCountsPerMemoryTrimLevelProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional MaxJobCountsProto normal = 1;
    optional MaxJobCountsProto moderate = 2;
    optional MaxJobCountsProto low = 3;
    optional MaxJobCountsProto critical = 4;
}

message StateControllerProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    message BackgroundJobsController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional com.android.server.AppStateTrackerProto app_state_tracker = 1;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
            optional string source_package_name = 3;
            optional bool is_in_foreground = 4;
            optional bool is_whitelisted = 5;
            optional bool can_run_any_in_background = 6;
            // If the constraints are satisfied, then the controller will mark
            // the job as RUNNABLE, otherwise, it will be WAITING.
            optional bool are_constraints_satisfied = 7;
        }
        repeated TrackedJob tracked_jobs = 2;
    }
    message BatteryController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional bool is_on_stable_power = 1;
        optional bool is_battery_not_low = 2;

        // Whether or not the controller is monitoring battery changes.
        optional bool is_monitoring = 3;
        // Only valid if is_monitoring is true.
        optional int32 last_broadcast_sequence_number = 4;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
        }
        repeated TrackedJob tracked_jobs = 5;
    }
    message ConnectivityController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        reserved 1; // is_connected

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
            optional .android.net.NetworkRequestProto required_network = 3;
        }
        repeated TrackedJob tracked_jobs = 2;

        // List of the UIDs that ConnectivityController has requested that NetworkPolicyManager
        // grant an exception to in the app standby chain.
        repeated int32 requested_standby_exception_uids = 3;

        repeated .android.net.NetworkProto available_networks = 4;
    }
    message ContentObserverController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
        }
        repeated TrackedJob tracked_jobs = 1;

        message Observer {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int32 user_id = 1;

            message TriggerContentData {
                option (.android.msg_privacy).dest = DEST_AUTOMATIC;

                optional string uri = 1 [
                    (.android.privacy).dest = DEST_EXPLICIT
                ];
                optional int32 flags = 2;

                // A
                // com.android.server.job.controllers.ContentObserverController.JobInstance
                // object.
                message JobInstance {
                    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

                    optional JobStatusShortInfoProto info = 1;
                    optional int32 source_uid = 2;

                    optional int64 trigger_content_update_delay_ms = 3;
                    optional int64 trigger_content_max_delay_ms = 4;

                    repeated string changed_authorities = 5 [
                        (.android.privacy).dest = DEST_EXPLICIT
                    ];
                    repeated string changed_uris = 6 [
                        (.android.privacy).dest = DEST_EXPLICIT
                    ];
                }
                repeated JobInstance jobs = 3;
            }
            repeated TriggerContentData triggers = 2;
        }
        repeated Observer observers = 2;
    }
    message DeviceIdleJobsController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        // True when in device idle mode.
        optional bool is_device_idle_mode = 1;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
            optional string source_package_name = 3;
            // If the constraints are satisfied, then the controller will mark
            // the job as RUNNABLE, otherwise, it will be WAITING.
            optional bool are_constraints_satisfied = 4;
            optional bool is_doze_whitelisted = 5;
            // A job that is exempted from Doze when the app is temp whitelisted
            // or in the foreground.
            optional bool is_allowed_in_doze = 6;
        }
        repeated TrackedJob tracked_jobs = 2;
    }
    message IdleController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional bool is_idle = 1;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
        }
        repeated TrackedJob tracked_jobs = 2;

        message IdlenessTracker {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            message CarIdlenessTracker {
                option (.android.msg_privacy).dest = DEST_AUTOMATIC;

                optional bool is_idle = 1;
                optional bool is_garage_mode_on = 2;
            }

            message DeviceIdlenessTracker {
                option (.android.msg_privacy).dest = DEST_AUTOMATIC;

                optional bool is_idle = 1;
                optional bool is_screen_on = 2;
                optional bool is_dock_idle = 3;
                reserved 4; // in_car_mode
                optional bool projection_active = 5;
            }

            oneof active_tracker {
                DeviceIdlenessTracker device_idleness_tracker = 1;
                CarIdlenessTracker car_idleness_tracker = 2;
            }
        }
        optional IdlenessTracker idleness_tracker = 3;
    }
    message QuotaController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional bool is_charging = 1;
        reserved 2; // is_in_parole
        optional int64 elapsed_realtime = 6;

        // List of UIDs currently in the foreground.
        repeated int32 foreground_uids = 3;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
            optional JobStatusDumpProto.Bucket effective_standby_bucket = 3;
            // If the job started while the app was in the TOP state.
            optional bool is_top_started_job = 4;
            optional bool has_quota = 5;
            // The amount of time that this job has remaining in its quota. This
            // can be negative if the job is out of quota.
            optional int64 remaining_quota_ms = 6;
            // True if the app has requested that this be a foreground job.
            optional bool is_requested_foreground_job = 7;
            // True if this job is within the foreground quota bounds and is therefore allowed to
            // run as a foreground job. Valid only if is_foreground_requested_job is true.
            optional bool is_within_fg_job_quota = 8;
        }
        repeated TrackedJob tracked_jobs = 4;

        message AlarmListener {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            // Whether the listener is waiting for an alarm or not.
            optional bool is_waiting = 1;
            // The time at which the alarm should go off, in the elapsed realtime timebase. Only
            // valid if is_waiting is true.
            optional int64 trigger_time_elapsed = 2;
        }

        message ExecutionStats {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusDumpProto.Bucket standby_bucket = 1;

            // The time after which this record should be considered invalid (out of date), in the
            // elapsed realtime timebase.
            optional int64 expiration_time_elapsed = 2;
            optional int64 window_size_ms = 3;

            optional int32 job_count_limit = 14;
            optional int32 session_count_limit = 15;

            // The total amount of time the app ran in its respective bucket window size.
            optional int64 execution_time_in_window_ms = 4;
            optional int32 bg_job_count_in_window = 5;

            // The total amount of time the app ran in the last
            // {@link QuotaController#MAX_PERIOD_MS}.
            optional int64 execution_time_in_max_period_ms = 6;
            optional int32 bg_job_count_in_max_period = 7;

            // The number of {@link TimingSession}s within the bucket window size. This will include
            // sessions that started before the window as long as they end within the window.
            optional int32 session_count_in_window = 11;

            // The time after which the app will be under the bucket quota. This is only valid if
            // execution_time_in_window_ms >=
            //   ConstantsProto.QuotaController.allowed_time_per_period_ms
            // or
            // execution_time_in_max_period_ms >=
            //   ConstantsProto.QuotaController.max_execution_time_ms
            // or
            // bg_job_count_in_window >= job_count_limit
            // or
            // session_count_in_window >= session_count_limit.
            optional int64 in_quota_time_elapsed = 8;

            // The time after which job_count_in_rate_limiting_window should be considered invalid,
            // in the elapsed realtime timebase.
            optional int64 job_count_expiration_time_elapsed = 9;

            // The number of jobs that ran in at least the last
            // ConstantsProto.QuotaController.rate_limiting_window_ms.
            // It may contain a few stale entries since cleanup won't happen exactly every
            // ConstantsProto.QuotaController.rate_limiting_window_ms. This should only be
            // considered valid before elapsed realtime has reached
            // job_count_expiration_time_elapsed.
            optional int32 job_count_in_rate_limiting_window = 10;

            // The time after which {@link #timingSessionCountInAllowedTime} should be considered
            // invalid, in the elapsed realtime timebase.
            optional int64 session_count_expiration_time_elapsed = 12;

            // The number of {@link TimingSession}s that ran in at least the last
            // ConstantsProto.QuotaController.rate_limiting_window_ms. It may contain a few stale
            // entries since cleanup won't happen exactly every
            // ConstantsProto.QuotaController.rate_limiting_window_ms. This should only be considered
            // valid before elapsed realtime has reached session_count_expiration_time_elapsed.
            optional int32 session_count_in_rate_limiting_window = 13;
        }

        message Package {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int32 user_id = 1;
            optional string name = 2;
        }

        message TimingSession {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int64 start_time_elapsed = 1;
            optional int64 end_time_elapsed = 2;
            // The number of background jobs that ran during this session.
            optional int32 bg_job_count = 3;
        }

        message Timer {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional Package pkg = 1;
            // True if the Timer is actively tracking jobs.
            optional bool is_active = 2;
            // The time this timer last became active. Only valid if is_active is true.
            optional int64 start_time_elapsed = 3;
            // How many background jobs are currently running. Valid only if is_active is true.
            optional int32 bg_job_count = 4;
            // All of the jobs that the Timer is currently tracking.
            repeated JobStatusShortInfoProto running_jobs = 5;
        }

        message TopAppTimer {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional Package pkg = 1;
            // True if the Timer is actively tracking jobs.
            optional bool is_active = 2;
            // The time this timer last became active. Only valid if is_active is true.
            optional int64 start_time_elapsed = 3;
            // How many activities are currently in the RESUMED state. Valid only if is_active is
            // true.
            optional int32 activity_count = 4;
        }

        message PackageStats {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional Package pkg = 1;

            optional Timer timer = 2;

            repeated TimingSession saved_sessions = 3;

            repeated ExecutionStats execution_stats = 4;

            reserved 5; // in_quota_alarm_listener

            optional Timer fg_job_timer = 6;
        }
        repeated PackageStats package_stats = 5;

        // Set of package names for each UID.
        message UidPackageMapping {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int32 uid = 1;
            repeated string package_names = 2;
        }
        repeated UidPackageMapping uid_to_package_cache = 7;

        message InQuotaAlarmListener {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            // The time at which the alarm is set to go off, in the elapsed realtime timebase.
            optional int64 trigger_time_elapsed = 1;

            message Alarm {
                option (.android.msg_privacy).dest = DEST_AUTOMATIC;

                optional Package pkg = 1;

                // The time at which the package will be in quota, in the elapsed realtime timebase.
                optional int64 in_quota_time_elapsed = 2;
            }
            repeated Alarm alarms = 2;
        }
        optional InQuotaAlarmListener in_quota_alarm_listener = 8;

        // Next tag: 9
    }
    message StorageController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional bool is_storage_not_low = 1;
        optional int32 last_broadcast_sequence_number = 2;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;
        }
        repeated TrackedJob tracked_jobs = 3;
    }
    message TimeController {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional int64 now_elapsed_realtime = 1;
        optional int64 time_until_next_delay_alarm_ms = 2;
        optional int64 time_until_next_deadline_alarm_ms = 3;

        message TrackedJob {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional JobStatusShortInfoProto info = 1;
            optional int32 source_uid = 2;

            optional bool has_timing_delay_constraint = 3;
            // Only valid if has_timing_delay_constraint is true. Can be
            // negative if the delay is in the past.
            optional int64 delay_time_remaining_ms = 4;

            optional bool has_deadline_constraint = 5;
            // Only valid if has_timing_delay_constraint is true. Can be
            // negative in certain situations.
            optional int64 time_remaining_until_deadline_ms = 6;
        }
        repeated TrackedJob tracked_jobs = 4;
    }
    oneof controller {
        BackgroundJobsController background = 1;
        BatteryController battery = 2;
        ConnectivityController connectivity = 3;
        ContentObserverController content_observer = 4;
        DeviceIdleJobsController device_idle = 5;
        IdleController idle = 6;
        QuotaController quota = 9;
        StorageController storage = 7;
        TimeController time = 8;
        // Next tag: 10
    }
}

// A com.android.server.job.JobPackageTracker.DataSet object.
message DataSetProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional int64 start_clock_time_ms = 1;
    // How much time has elapsed since the DataSet was instantiated.
    optional int64 elapsed_time_ms = 2;
    optional int64 period_ms = 3;

    // Represents a com.android.server.job.JobPackageTracker.PackageEntry
    // object, but with some extra data.
    message PackageEntryProto {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional int32 uid = 1;
        optional string package_name = 2;

        message State {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional int64 duration_ms = 1;
            optional int32 count = 2;
        }
        optional State pending_state = 3;
        optional State active_state = 4;
        optional State active_top_state = 5;

        // True if the PackageEntry is currently pending or has been pending in
        // the past.
        optional bool pending = 6;
        // True if the PackageEntry is currently active or has been active in
        // the past.
        optional bool active = 7;
        // True if the PackageEntry is currently active top or has been active
        // top in the past.
        optional bool active_top = 8;

        message StopReasonCount {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            optional .android.app.job.InternalStopReasonEnum reason = 1;
            optional int32 count = 2;
        }
        repeated StopReasonCount stop_reasons = 9;
    }
    repeated PackageEntryProto package_entries = 4;

    optional int32 max_concurrency = 5;
    optional int32 max_foreground_concurrency = 6;
}

// Dump from com.android.server.job.GrantedUriPermissions.
message GrantedUriPermissionsDumpProto {
    option (.android.msg_privacy).dest = DEST_EXPLICIT;

    optional int32 flags = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ];
    optional int32 source_user_id = 2 [
        (.android.privacy).dest = DEST_AUTOMATIC
    ];
    optional string tag = 3;
    optional string permission_owner = 4;
    repeated string uris = 5;
}

message JobPackageTrackerDumpProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    repeated DataSetProto historical_stats = 1;
    optional DataSetProto current_stats = 2;
}

message JobPackageHistoryProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    enum Event {
        UNKNOWN = 0;
        START_JOB = 1;
        STOP_JOB = 2;
        START_PERIODIC_JOB = 3;
        STOP_PERIODIC_JOB = 4;
    }
    message HistoryEvent {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional Event event = 1;
        optional int64 time_since_event_ms = 2;
        optional int32 uid = 3;
        // Job IDs can technically be negative.
        optional int32 job_id = 4;
        optional string tag = 5;
        // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events.
        optional .android.app.job.InternalStopReasonEnum stop_reason = 6;
    }
    repeated HistoryEvent history_event = 1;
}

message JobStatusShortInfoProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional int32 calling_uid = 1;
    // Job IDs can technically be negative.
    optional int32 job_id = 2;
    optional string battery_name = 3;
}

// Dump from a com.android.server.job.controllers.JobStatus object.
message JobStatusDumpProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    // The UID that scheduled the job.
    optional int32 calling_uid = 1;
    optional string tag = 2;

    // The UID for which the job is being run.
    optional int32 source_uid = 3;
    optional int32 source_user_id = 4;
    // The package for which the job is being run.
    optional string source_package_name = 5;

    // Custom dump of android.app.job.JobInfo object.
    message JobInfo {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional .android.content.ComponentNameProto service = 1;

        optional bool is_periodic = 2;
        // Only valid if is_periodic is true.
        optional int64 period_interval_ms = 3;
        // Only valid if is_periodic is true.
        optional int64 period_flex_ms = 4;

        optional bool is_persisted = 5;
        optional sint32 priority = 6;
        optional int32 flags = 7;

        optional bool requires_charging = 8;
        optional bool requires_battery_not_low = 9;
        optional bool requires_device_idle = 10;

        message TriggerContentUri {
            optional int32 flags = 1 [
                (.android.privacy).dest = DEST_AUTOMATIC
            ];
            optional string uri = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
        }
        repeated TriggerContentUri trigger_content_uris = 11;
        optional int64 trigger_content_update_delay_ms = 12;
        optional int64 trigger_content_max_delay_ms = 13;

        optional .android.os.PersistableBundleProto extras = 14;
        optional .android.os.BundleProto transient_extras = 15;
        // ClipData of information that is returned to the application at
        // execution time, but not persisted by the system. This is provided by
        // the app and the main purpose of providing a ClipData is to allow
        // granting of URI permissions for data associated with the clip.  The
        // exact kind of permission grant to perform is specified in the flags
        // field.
        optional .android.content.ClipDataProto clip_data = 16;

        optional GrantedUriPermissionsDumpProto granted_uri_permissions = 17;

        optional .android.net.NetworkRequestProto required_network = 18;

        reserved 19; // total_network_bytes

        // The estimated download bytes of the job. Will have a value of
        // {@link JobInfo.NETWORK_BYTES_UNKNOWN} if any part of the job download is unknown.
        optional int64 total_network_download_bytes = 25;

        // The estimated upload bytes of the job. Will have a value of
        // {@link JobInfo.NETWORK_BYTES_UNKNOWN} if any part of the job upload is unknown.
        optional int64 total_network_upload_bytes = 26;

        optional int64 min_latency_ms = 20;
        optional int64 max_execution_delay_ms = 21;

        message Backoff {
            option (.android.msg_privacy).dest = DEST_AUTOMATIC;

            enum Policy {
                BACKOFF_POLICY_LINEAR = 0;
                BACKOFF_POLICY_EXPONENTIAL = 1;
            }
            optional Policy policy = 1;
            optional int64 initial_backoff_ms = 2;
        }
        optional Backoff backoff_policy = 22;

        optional bool has_early_constraint = 23;
        optional bool has_late_constraint = 24;

        // Next tag: 27
    }
    optional JobInfo job_info = 6;

    repeated ConstraintEnum required_constraints = 7;
    // Dynamic constraints are additional constraints imposed by the system that MUST be met before
    // the app can run if the app does not have quota.
    repeated ConstraintEnum dynamic_constraints = 31;
    repeated ConstraintEnum satisfied_constraints = 8;
    repeated ConstraintEnum unsatisfied_constraints = 9;
    optional bool is_doze_whitelisted = 10;
    optional bool is_uid_active = 26;

    message ImplicitConstraints {
        // The device isn't Dozing or this job will be in the foreground. This
        // implicit constraint must be satisfied for the job to run.
        optional bool is_not_dozing = 1;
        // The job is not restricted from running in the background (due to
        // Battery Saver). This implicit constraint must be satisfied for the
        // job to run.
        optional bool is_not_restricted_in_bg = 2;
        // True if dynamic constraints have been satisfied.
        optional bool is_dynamic_satisfied = 3;
    }
    optional ImplicitConstraints implicit_constraints = 25;

    enum TrackingController {
        TRACKING_BATTERY = 0;
        TRACKING_CONNECTIVITY = 1;
        TRACKING_CONTENT = 2;
        TRACKING_IDLE = 3;
        TRACKING_STORAGE = 4;
        TRACKING_TIME = 5;
        TRACKING_QUOTA = 6;
    }
    // Controllers that are currently tracking the job.
    repeated TrackingController tracking_controllers = 11;

    repeated string changed_authorities = 12 [
        (.android.privacy).dest = DEST_EXPLICIT
    ];
    repeated string changed_uris = 13 [
        (.android.privacy).dest = DEST_EXPLICIT
    ];

    optional .android.net.NetworkProto network = 14;

    // Only the desired data from an android.app.job.JobWorkItem object.
    message JobWorkItem {
        option (.android.msg_privacy).dest = DEST_AUTOMATIC;

        optional int32 work_id = 1;
        optional int32 delivery_count = 2;
        optional .android.content.IntentProto intent = 3;
        optional GrantedUriPermissionsDumpProto uri_grants = 4;
    }
    repeated JobWorkItem pending_work = 15;
    repeated JobWorkItem executing_work = 16;

    enum Bucket {
        ACTIVE = 0;
        WORKING_SET = 1;
        FREQUENT = 2;
        RARE = 3;
        NEVER = 4;
        RESTRICTED = 5;
        EXEMPTED = 6;
    }
    optional Bucket standby_bucket = 17;
    optional bool is_exempted_from_app_standby = 27;

    optional int64 enqueue_duration_ms = 18;
    // Can be negative if the earliest runtime deadline has passed.
    optional sint64 time_until_earliest_runtime_ms = 19;
    // Can be negative if the latest runtime deadline has passed.
    optional sint64 time_until_latest_runtime_ms = 20;
    // The original latest runtime value, in the elapsed realtime timebase. Valid only for periodic
    // jobs.
    optional uint64 original_latest_runtime_elapsed = 30;

    optional int32 num_failures = 21;

    // Last time a job finished successfully for a periodic job, in currentTimeMillis time.
    optional int64 last_successful_run_time = 22;
    // Last time a job finished unsuccessfully, in currentTimeMillis time.
    optional int64 last_failed_run_time = 23;

    optional int64 internal_flags = 24;

    // Amount of time since this job was first deferred due to standby bucketing policy. Will be
    // 0 if this job was never deferred.
    optional int64 time_since_first_deferral_ms = 28;

    // Amount of time since JobScheduler first tried to force batch this job. Will be 0 if there
    // was no attempt.
    optional int64 time_since_first_force_batch_attempt_ms = 29;

    // Next tag: 32
}

// Dump from com.android.server.job.JobConcurrencyManager.
// Next tag: 7
message JobConcurrencyManagerProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    // Whether the device is interactive (== screen on) now or not.
    optional bool current_interactive_state = 1;
    // Similar to current_interactive_state, screen on or not, but it takes into account the off timeout.
    optional bool effective_interactive_state = 2;
    // How many milliseconds have passed since the last screen on. (i.e. 1000 == 1 sec ago)
    optional int64 time_since_last_screen_on_ms = 3;
    // How many milliseconds have passed since the last screen off. (i.e. 1000 == 1 sec ago)
    optional int64 time_since_last_screen_off_ms = 4;
    // Current max number of jobs.
    optional JobCountTrackerProto job_count_tracker = 5;
    // Current memory trim level.
    optional int32 memory_trim_level = 6;
    // Performance stats.
    optional StatLoggerProto stats = 7;
}

// Dump from com.android.server.job.JobConcurrencyManager.JobCountTracker.
// Next tag: 8
message JobCountTrackerProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    // Number of total jos that can run simultaneously.
    optional int32 config_num_max_total_jobs = 1;
    // Number of background jos that can run simultaneously.
    optional int32 config_num_max_bg_jobs = 2;
    // Out of total jobs, this many background jobs should be guaranteed to be executed, even if
    // there are the config_num_max_total_jobs count of foreground jobs pending.
    optional int32 config_num_min_bg_jobs = 3;

    // Number of running foreground jobs.
    optional int32 num_running_fg_jobs = 4;
    // Number of running background jobs.
    optional int32 num_running_bg_jobs = 5;

    // Number of pending foreground jobs.
    optional int32 num_pending_fg_jobs = 6;
    // Number of pending background jobs.
    optional int32 num_pending_bg_jobs = 7;

    optional int32 num_actual_max_fg_jobs = 8;
    optional int32 num_actual_max_bg_jobs = 9;

    optional int32 num_reserved_for_bg = 10;

    optional int32 num_starting_fg_jobs = 11;
    optional int32 num_starting_bg_jobs = 12;
}

message JobStorePersistStatsProto {
    message Stats {
        optional int32 num_total_jobs = 1;
        optional int32 num_system_server_jobs = 2;
        optional int32 num_system_sync_manager_jobs = 3;
    }

    optional Stats first_load = 1;
    optional Stats last_save = 2;
}
