incidentd: dumping jobscheduler to proto

Bug: 65750819
Test: flash device and check incident.proto output
Also test: $ cts-tradefed run cts-dev --module CtsIncidentHostTestCases --test com.android.server.cts.JobSchedulerIncidentTest
Change-Id: I4abc01ca893edcbaf4d2254e4f807e06f5cb91f8
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 9323261..94e1e2d 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -34,16 +34,18 @@
 import android.text.TextUtils;
 import android.text.style.URLSpan;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
 
+import libcore.io.IoUtils;
+
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.List;
-import libcore.io.IoUtils;
 
 /**
  * Representation of a clipped data on the clipboard.
@@ -665,6 +667,25 @@
                 b.append("NULL");
             }
         }
+
+        /** @hide */
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+
+            if (mHtmlText != null) {
+                proto.write(ClipDataProto.Item.HTML_TEXT, mHtmlText);
+            } else if (mText != null) {
+                proto.write(ClipDataProto.Item.TEXT, mText.toString());
+            } else if (mUri != null) {
+                proto.write(ClipDataProto.Item.URI, mUri.toString());
+            } else if (mIntent != null) {
+                mIntent.writeToProto(proto, ClipDataProto.Item.INTENT, true, true, true, true);
+            } else {
+                proto.write(ClipDataProto.Item.NOTHING, true);
+            }
+
+            proto.end(token);
+        }
     }
 
     /**
@@ -1048,6 +1069,26 @@
     }
 
     /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        if (mClipDescription != null) {
+            mClipDescription.writeToProto(proto, ClipDataProto.DESCRIPTION);
+        }
+        if (mIcon != null) {
+            final long iToken = proto.start(ClipDataProto.ICON);
+            proto.write(ClipDataProto.Icon.WIDTH, mIcon.getWidth());
+            proto.write(ClipDataProto.Icon.HEIGHT, mIcon.getHeight());
+            proto.end(iToken);
+        }
+        for (int i = 0; i < mItems.size(); i++) {
+            mItems.get(i).writeToProto(proto, ClipDataProto.ITEMS);
+        }
+
+        proto.end(token);
+    }
+
+    /** @hide */
     public void collectUris(List<Uri> out) {
         for (int i = 0; i < mItems.size(); ++i) {
             ClipData.Item item = getItemAt(i);
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 8e30fd6..19295fc 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -21,6 +21,7 @@
 import android.os.PersistableBundle;
 import android.text.TextUtils;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -337,6 +338,28 @@
         return !first;
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        final int size = mMimeTypes.size();
+        for (int i = 0; i < size; i++) {
+            proto.write(ClipDescriptionProto.MIME_TYPES, mMimeTypes.get(i));
+        }
+
+        if (mLabel != null) {
+            proto.write(ClipDescriptionProto.LABEL, mLabel.toString());
+        }
+        if (mExtras != null) {
+            mExtras.writeToProto(proto, ClipDescriptionProto.EXTRAS);
+        }
+        if (mTimeStamp > 0) {
+            proto.write(ClipDescriptionProto.TIMESTAMP_MS, mTimeStamp);
+        }
+
+        proto.end(token);
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 0d36bdd..ead6c25 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -284,9 +284,11 @@
     }
 
     /** Put this here so that individual services don't have to reimplement this. @hide */
-    public void toProto(ProtoOutputStream proto) {
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
         proto.write(ComponentNameProto.PACKAGE_NAME, mPackage);
         proto.write(ComponentNameProto.CLASS_NAME, mClass);
+        proto.end(token);
     }
 
     @Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e940769..6e99709 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9410,6 +9410,12 @@
     }
 
     /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        // Same input parameters that toString() gives to toShortString().
+        writeToProto(proto, fieldId, true, true, true, false);
+    }
+
+    /** @hide */
     public void writeToProto(ProtoOutputStream proto, long fieldId, boolean secure, boolean comp,
             boolean extras, boolean clip) {
         long token = proto.start(fieldId);
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 903b602..1a3ce91 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -21,6 +21,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.okhttp.internalandroidapi.Dns;
 import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
@@ -402,4 +403,11 @@
     public String toString() {
         return Integer.toString(netId);
     }
+
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        proto.write(NetworkProto.NET_ID, netId);
+        proto.end(token);
+    }
 }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index f468e5d..8b03fa8 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -20,6 +20,7 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.BitUtils;
@@ -1016,6 +1017,31 @@
         return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        for (int transport : getTransportTypes()) {
+            proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport);
+        }
+
+        for (int capability : getCapabilities()) {
+            proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability);
+        }
+
+        proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps);
+        proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps);
+
+        if (mNetworkSpecifier != null) {
+            proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
+        }
+
+        proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
+        proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
+
+        proto.end(token);
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 97ded2d..a072409 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.Objects;
 
@@ -389,6 +390,35 @@
                 ", " + networkCapabilities.toString() + " ]";
     }
 
+    private int typeToProtoEnum(Type t) {
+        switch (t) {
+            case NONE:
+                return NetworkRequestProto.TYPE_NONE;
+            case LISTEN:
+                return NetworkRequestProto.TYPE_LISTEN;
+            case TRACK_DEFAULT:
+                return NetworkRequestProto.TYPE_TRACK_DEFAULT;
+            case REQUEST:
+                return NetworkRequestProto.TYPE_REQUEST;
+            case BACKGROUND_REQUEST:
+                return NetworkRequestProto.TYPE_BACKGROUND_REQUEST;
+            default:
+                return NetworkRequestProto.TYPE_UNKNOWN;
+        }
+    }
+
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
+        proto.write(NetworkRequestProto.REQUEST_ID, requestId);
+        proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
+        networkCapabilities.writeToProto(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
+
+        proto.end(token);
+    }
+
     public boolean equals(Object obj) {
         if (obj instanceof NetworkRequest == false) return false;
         NetworkRequest that = (NetworkRequest)obj;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c58153a..7ae5a67 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -21,6 +21,7 @@
 import android.util.Size;
 import android.util.SizeF;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -1272,4 +1273,21 @@
         }
         return mMap.toString();
     }
+
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        if (mParcelledData != null) {
+            if (isEmptyParcel()) {
+                proto.write(BundleProto.PARCELLED_DATA_SIZE, 0);
+            } else {
+                proto.write(BundleProto.PARCELLED_DATA_SIZE, mParcelledData.dataSize());
+            }
+        } else {
+            proto.write(BundleProto.MAP_DATA, mMap.toString());
+        }
+
+        proto.end(token);
+    }
 }
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 3ed5b17..40eceb8 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.XmlUtils;
 
@@ -321,4 +322,21 @@
         }
         return mMap.toString();
     }
+
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        if (mParcelledData != null) {
+            if (isEmptyParcel()) {
+                proto.write(PersistableBundleProto.PARCELLED_DATA_SIZE, 0);
+            } else {
+                proto.write(PersistableBundleProto.PARCELLED_DATA_SIZE, mParcelledData.dataSize());
+            }
+        } else {
+            proto.write(PersistableBundleProto.MAP_DATA, mMap.toString());
+        }
+
+        proto.end(token);
+    }
 }
diff --git a/core/proto/android/content/clipdata.proto b/core/proto/android/content/clipdata.proto
new file mode 100644
index 0000000..6967b69
--- /dev/null
+++ b/core/proto/android/content/clipdata.proto
@@ -0,0 +1,47 @@
+/*
+ * 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 android.content;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/content/clipdescription.proto";
+import "frameworks/base/core/proto/android/content/intent.proto";
+
+// An android.content.ClipData object.
+message ClipDataProto {
+    optional android.content.ClipDescriptionProto description = 1;
+
+    // Custom dump of an android.graphics.Bitmap object.
+    message Icon {
+        optional int32 width = 1;
+        optional int32 height = 2;
+    }
+    optional Icon icon = 2;
+
+    // An android.content.ClipData.Item object.
+    message Item {
+        oneof data {
+            string html_text = 1;
+            string text = 2;
+            string uri = 3;
+            android.content.IntentProto intent = 4;
+            bool nothing = 5;
+        }
+    }
+    repeated Item items = 3;
+}
diff --git a/core/proto/android/content/clipdescription.proto b/core/proto/android/content/clipdescription.proto
new file mode 100644
index 0000000..40f4ad3
--- /dev/null
+++ b/core/proto/android/content/clipdescription.proto
@@ -0,0 +1,30 @@
+/*
+ * 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 android.content;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/persistablebundle.proto";
+
+// An android.content.ClipDescription object.
+message ClipDescriptionProto {
+    repeated string mime_types = 1;
+    optional string label = 2;
+    optional android.os.PersistableBundleProto extras = 3;
+    optional int64 timestamp_ms = 4;
+}
diff --git a/core/proto/android/net/network.proto b/core/proto/android/net/network.proto
new file mode 100644
index 0000000..9c7ea5d
--- /dev/null
+++ b/core/proto/android/net/network.proto
@@ -0,0 +1,27 @@
+/*
+ * 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";
+option java_multiple_files = true;
+
+package android.net;
+
+/**
+ * An android.net.Network object.
+ */
+message NetworkProto {
+    optional int32 net_id = 1;
+}
diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto
new file mode 100644
index 0000000..e1c2af1
--- /dev/null
+++ b/core/proto/android/net/networkcapabilities.proto
@@ -0,0 +1,129 @@
+/*
+ * 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 android.net;
+
+option java_multiple_files = true;
+
+/**
+ * An android.net.NetworkCapabilities object.
+ */
+message NetworkCapabilitiesProto {
+    enum Transport {
+        // Indicates this network uses a Cellular transport.
+        TRANSPORT_CELLULAR = 0;
+        // Indicates this network uses a Wi-Fi transport.
+        TRANSPORT_WIFI = 1;
+        // Indicates this network uses a Bluetooth transport.
+        TRANSPORT_BLUETOOTH = 2;
+        // Indicates this network uses an Ethernet transport.
+        TRANSPORT_ETHERNET = 3;
+        // Indicates this network uses a VPN transport.
+        TRANSPORT_VPN = 4;
+        // Indicates this network uses a Wi-Fi Aware transport.
+        TRANSPORT_WIFI_AWARE = 5;
+        // Indicates this network uses a LoWPAN transport.
+        TRANSPORT_LOWPAN = 6;
+    }
+    repeated Transport transports = 1;
+
+    enum NetCapability {
+        // Indicates this is a network that has the ability to reach the
+        // carrier's MMSC for sending and receiving MMS messages.
+        NET_CAPABILITY_MMS = 0;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's SUPL server, used to retrieve GPS information.
+        NET_CAPABILITY_SUPL = 1;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's DUN or tethering gateway.
+        NET_CAPABILITY_DUN = 2;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's FOTA portal, used for over the air updates.
+        NET_CAPABILITY_FOTA = 3;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's IMS servers, used for network registration and signaling.
+        NET_CAPABILITY_IMS = 4;
+        // Indicates this is a network that has the ability to reach the
+        // carrier's CBS servers, used for carrier specific services.
+        NET_CAPABILITY_CBS = 5;
+        // Indicates this is a network that has the ability to reach a Wi-Fi
+        // direct peer.
+        NET_CAPABILITY_WIFI_P2P = 6;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // Initial Attach servers.
+        NET_CAPABILITY_IA = 7;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // RCS servers, used for Rich Communication Services.
+        NET_CAPABILITY_RCS = 8;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // XCAP servers, used for configuration and control.
+        NET_CAPABILITY_XCAP = 9;
+        // Indicates this is a network that has the ability to reach a carrier's
+        // Emergency IMS servers or other services, used for network signaling
+        // during emergency calls.
+        NET_CAPABILITY_EIMS = 10;
+        // Indicates that this network is unmetered.
+        NET_CAPABILITY_NOT_METERED = 11;
+        // Indicates that this network should be able to reach the internet.
+        NET_CAPABILITY_INTERNET = 12;
+        // Indicates that this network is available for general use. If this is
+        // not set applications should not attempt to communicate on this
+        // network. Note that this is simply informative and not enforcement -
+        // enforcement is handled via other means. Set by default.
+        NET_CAPABILITY_NOT_RESTRICTED = 13;
+        // Indicates that the user has indicated implicit trust of this network.
+        // This generally means it's a sim-selected carrier, a plugged in
+        // ethernet, a paired BT device or a wifi the user asked to connect to.
+        // Untrusted networks are probably limited to unknown wifi AP. Set by
+        // default.
+        NET_CAPABILITY_TRUSTED = 14;
+        // Indicates that this network is not a VPN.  This capability is set by
+        // default and should be explicitly cleared for VPN networks.
+        NET_CAPABILITY_NOT_VPN = 15;
+        // Indicates that connectivity on this network was successfully
+        // validated. For example, for a network with NET_CAPABILITY_INTERNET,
+        // it means that Internet connectivity was successfully detected.
+        NET_CAPABILITY_VALIDATED = 16;
+        // Indicates that this network was found to have a captive portal in
+        // place last time it was probed.
+        NET_CAPABILITY_CAPTIVE_PORTAL = 17;
+        // Indicates that this network is not roaming.
+        NET_CAPABILITY_NOT_ROAMING = 18;
+        // Indicates that this network is available for use by apps, and not a
+        // network that is being kept up in the background to facilitate fast
+        // network switching.
+        NET_CAPABILITY_FOREGROUND = 19;
+    }
+    repeated NetCapability capabilities = 2;
+
+    // Passive link bandwidth. This is a rough guide of the expected peak
+    // bandwidth for the first hop on the given transport.  It is not measured,
+    // but may take into account link parameters (Radio technology, allocated
+    // channels, etc).
+    optional int32 link_up_bandwidth_kbps = 3;
+    optional int32 link_down_bandwidth_kbps = 4;
+
+    optional string network_specifier = 5;
+
+    // True if this object specifies a signal strength.
+    optional bool can_report_signal_strength = 6;
+    // This is a signed integer, and higher values indicate better signal. The
+    // exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
+    // Only valid if can_report_signal_strength is true.
+    optional sint32 signal_strength = 7;
+}
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
new file mode 100644
index 0000000..9884464
--- /dev/null
+++ b/core/proto/android/net/networkrequest.proto
@@ -0,0 +1,72 @@
+/*
+ * 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 android.net;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
+
+/**
+ * An android.net.NetworkRequest object.
+ */
+message NetworkRequestProto {
+    enum Type {
+        TYPE_UNKNOWN = 0;
+        // Only used by applications. When an application creates a
+        // NetworkRequest, it does not have a type; the type is set by the
+        // system depending on the method used to file the request
+        // (requestNetwork, registerNetworkCallback, etc.).
+        TYPE_NONE = 1;
+        // The framework will issue callbacks about any and all networks that
+        // match the specified NetworkCapabilities.
+        TYPE_LISTEN = 2;
+        // A hybrid of the two designed such that the framework will issue
+        // callbacks for the single, highest scoring current network (if any)
+        // that matches the capabilities of the default Internet request
+        // (mDefaultRequest), but which cannot cause the framework to either
+        // create or retain the existence of any specific network. Note that
+        // from the point of view of the request matching code, TRACK_DEFAULT is
+        // identical to REQUEST: its special behaviour is not due to different
+        // semantics, but to the fact that the system will only ever create a
+        // TRACK_DEFAULT with capabilities that are identical to the default
+        // request's capabilities, thus causing it to share fate in every way
+        // with the default request.
+        TYPE_TRACK_DEFAULT = 3;
+        // Capable of causing a specific network to be created first (e.g. a
+        // telephony DUN request), the framework will issue callbacks about the
+        // single, highest scoring current network (if any) that matches the
+        // specified NetworkCapabilities.
+        TYPE_REQUEST = 4;
+        // Like REQUEST but does not cause any networks to retain the
+        // NET_CAPABILITY_FOREGROUND capability. A network with no foreground
+        // requests is in the background. A network that has one or more
+        // background requests and loses its last foreground request to a
+        // higher-scoring network will not go into the background immediately,
+        // but will linger and go into the background after the linger timeout.
+        TYPE_BACKGROUND_REQUEST = 5;
+    }
+    // The type of the request. This is only used by the system and is always
+    // NONE elsewhere.
+    optional Type type = 1;
+    // Identifies the request.
+    optional int32 request_id = 2;
+    // Set for legacy requests and the default.
+    optional int32 legacy_type = 3;
+    optional NetworkCapabilitiesProto network_capabilities = 4;
+}
diff --git a/core/proto/android/os/bundle.proto b/core/proto/android/os/bundle.proto
new file mode 100644
index 0000000..6990281
--- /dev/null
+++ b/core/proto/android/os/bundle.proto
@@ -0,0 +1,28 @@
+/*
+ * 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 android.os;
+
+option java_multiple_files = true;
+
+// An android.os.Bundle object.
+message BundleProto {
+    oneof data {
+        int32 parcelled_data_size = 1;
+        string map_data = 2;
+    }
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 2f856ab..2752a7e 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -31,6 +31,7 @@
 import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
 import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
 import "frameworks/base/core/proto/android/server/fingerprint.proto";
+import "frameworks/base/core/proto/android/server/jobscheduler.proto";
 import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
 import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 import "frameworks/base/core/proto/android/service/appwidget.proto";
@@ -247,4 +248,8 @@
         (section).args = "graphicsstats --proto"
     ];
 
+    optional com.android.server.job.JobSchedulerServiceDumpProto jobscheduler = 3020 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "jobscheduler --proto"
+    ];
 }
diff --git a/core/proto/android/os/persistablebundle.proto b/core/proto/android/os/persistablebundle.proto
new file mode 100644
index 0000000..75ff787
--- /dev/null
+++ b/core/proto/android/os/persistablebundle.proto
@@ -0,0 +1,28 @@
+/*
+ * 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 android.os;
+
+option java_multiple_files = true;
+
+// An android.os.PersistableBundle object.
+message PersistableBundleProto {
+    oneof data {
+        int32 parcelled_data_size = 1;
+        string map_data = 2;
+    }
+}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
new file mode 100644
index 0000000..f72ca62
--- /dev/null
+++ b/core/proto/android/server/jobscheduler.proto
@@ -0,0 +1,561 @@
+/*
+ * 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/app/jobparameters.proto";
+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/forceappstandbytracker.proto";
+
+message JobSchedulerServiceDumpProto {
+    optional ConstantsProto settings = 1;
+
+    repeated int32 started_users = 2;
+
+    message RegisteredJob {
+        optional JobStatusShortInfoProto info = 1;
+        optional JobStatusDumpProto dump = 2;
+
+        // A job is ready to be executed if:
+        // is_job_ready && is_user_started && !is_job_pending &&
+        // !is_job_currently_active && !is_uid_backing_up &&
+        // is_component_present.
+        optional bool is_job_ready = 3;
+        optional bool is_user_started = 4;
+        optional bool is_job_pending = 5;
+        optional bool is_job_currently_active = 6;
+        optional bool is_uid_backing_up = 7;
+        optional bool is_component_present = 8;
+    }
+    repeated RegisteredJob registered_jobs = 3;
+
+    repeated StateControllerProto controllers = 4;
+
+    // Which uids are currently in the foreground.
+    message PriorityOverride {
+        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 {
+        optional JobStatusShortInfoProto info = 1;
+        optional JobStatusDumpProto dump = 2;
+        optional sint32 evaluated_priority = 3;
+        // How long this job has been pending.
+        optional int64 enqueued_duration_ms = 4;
+    }
+    repeated PendingJob pending_jobs = 9;
+
+    // From a service that has currently active or pending jobs.
+    message ActiveJob {
+        message InactiveJob {
+            optional int64 time_since_stopped_ms = 1;
+            // This is not always provided.
+            optional string stopped_reason = 2;
+        }
+        message RunningJob {
+            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 has been pending.
+            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;
+}
+
+// A com.android.server.job.JobSchedulerService.Constants object.
+message ConstantsProto {
+    // Minimum # of idle jobs that must be ready in order to force the JMS to
+    // schedule things early.
+    optional int32 min_idle_count = 1;
+    // Minimum # of charging jobs that must be ready in order to force the JMS
+    // to schedule things early.
+    optional int32 min_charging_count = 2;
+    // Minimum # of "battery not low" jobs that must be ready in order to force
+    // the JMS to schedule things early.
+    optional int32 min_battery_not_low_count = 3;
+    // Minimum # of "storage not low" jobs that must be ready in order to force
+    // the JMS to schedule things early.
+    optional int32 min_storage_not_low_count = 4;
+    // Minimum # of connectivity jobs that must be ready in order to force the
+    // JMS to schedule things early. 1 == Run connectivity jobs as soon as
+    // ready.
+    optional int32 min_connectivity_count = 5;
+    // Minimum # of content trigger jobs that must be ready in order to force
+    // the JMS to schedule things early.
+    optional int32 min_content_count = 6;
+    // Minimum # of jobs (with no particular constraints) for which the JMS will
+    // be happy running some work early. This (and thus the other min counts)
+    // is now set to 1, to prevent any batching at this level. Since we now do
+    // batching through doze, that is a much better mechanism.
+    optional int32 min_ready_jobs_count = 7;
+    // 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;
+    // The maximum number of times we allow a job to have itself rescheduled
+    // before giving up on it, for standard jobs.
+    optional int32 max_standard_reschedule_count = 15;
+    // The maximum number of times we allow a job to have itself rescheduled
+    // before giving up on it, for jobs that are executing work.
+    optional int32 max_work_reschedule_count = 16;
+    // 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.
+    optional int64 standby_heartbeat_time_ms = 19;
+    // 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.
+    repeated int32 standby_beats = 20;
+}
+
+message StateControllerProto {
+    message AppIdleController {
+        optional bool is_parole_on = 1;
+
+        message TrackedJob {
+            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;
+        }
+        repeated TrackedJob tracked_jobs = 2;
+    }
+    message BackgroundJobsController {
+        optional com.android.server.ForceAppStandbyTrackerProto force_app_standby_tracker = 1;
+
+        message TrackedJob {
+            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 {
+        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 {
+            optional JobStatusShortInfoProto info = 1;
+            optional int32 source_uid = 2;
+        }
+        repeated TrackedJob tracked_jobs = 5;
+    }
+    message ConnectivityController {
+        optional bool is_connected = 1;
+
+        message TrackedJob {
+            optional JobStatusShortInfoProto info = 1;
+            optional int32 source_uid = 2;
+            optional .android.net.NetworkRequestProto required_network = 3;
+        }
+        repeated TrackedJob tracked_jobs = 2;
+    }
+    message ContentObserverController {
+        message TrackedJob {
+            optional JobStatusShortInfoProto info = 1;
+            optional int32 source_uid = 2;
+        }
+        repeated TrackedJob tracked_jobs = 1;
+
+        message Observer {
+            optional int32 user_id = 1;
+
+            message TriggerContentData {
+                optional string uri = 1;
+                optional int32 flags = 2;
+
+                // A
+                // com.android.server.job.controllers.ContentObserverController.JobInstance
+                // object.
+                message JobInstance {
+                    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;
+                    repeated string changed_uris = 6;
+                }
+                repeated JobInstance jobs = 3;
+            }
+            repeated TriggerContentData triggers = 2;
+        }
+        repeated Observer observers = 2;
+    }
+    message DeviceIdleJobsController {
+        // True when in device idle mode.
+        optional bool is_device_idle_mode = 1;
+
+        message TrackedJob {
+            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 {
+        optional bool is_idle = 1;
+
+        message TrackedJob {
+            optional JobStatusShortInfoProto info = 1;
+            optional int32 source_uid = 2;
+        }
+        repeated TrackedJob tracked_jobs = 2;
+    }
+    message StorageController {
+        optional bool is_storage_not_low = 1;
+        optional int32 last_broadcast_sequence_number = 2;
+
+        message TrackedJob {
+            optional JobStatusShortInfoProto info = 1;
+            optional int32 source_uid = 2;
+        }
+        repeated TrackedJob tracked_jobs = 3;
+    }
+    message TimeController {
+        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 {
+            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 {
+        AppIdleController app_idle = 1;
+        BackgroundJobsController background = 2;
+        BatteryController battery = 3;
+        ConnectivityController connectivity = 4;
+        ContentObserverController content_observer = 5;
+        DeviceIdleJobsController device_idle = 6;
+        IdleController idle = 7;
+        StorageController storage = 8;
+        TimeController time = 9;
+    }
+}
+
+// A com.android.server.job.JobPackageTracker.DataSet object.
+message DataSetProto {
+    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 {
+        optional int32 uid = 1;
+        optional string package_name = 2;
+
+        message State {
+            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 {
+            optional .android.app.JobParametersProto.CancelReason 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 {
+    optional int32 flags = 1;
+    optional int32 source_user_id = 2;
+    optional string tag = 3;
+    optional string permission_owner = 4;
+    repeated string uris = 5;
+}
+
+message JobPackageTrackerDumpProto {
+    repeated DataSetProto historical_stats = 1;
+    optional DataSetProto current_stats = 2;
+}
+
+message JobPackageHistoryProto {
+    enum Event {
+        UNKNOWN = 0;
+        START_JOB = 1;
+        STOP_JOB = 2;
+        START_PERIODIC_JOB = 3;
+        STOP_PERIODIC_JOB = 4;
+    }
+    message HistoryEvent {
+        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.JobParametersProto.CancelReason stop_reason = 6;
+    }
+    repeated HistoryEvent history_event = 1;
+}
+
+message JobStatusShortInfoProto {
+    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 {
+    // 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 {
+        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;
+            optional string uri = 2;
+        }
+        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;
+        optional .android.content.ClipDataProto clip_data = 16;
+
+        optional GrantedUriPermissionsDumpProto granted_uri_permissions = 17;
+
+        optional .android.net.NetworkRequestProto required_network = 18;
+
+        optional int64 total_network_bytes = 19;
+
+        optional int64 min_latency_ms = 20;
+        optional int64 max_execution_delay_ms = 21;
+
+        message Backoff {
+            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;
+    }
+    optional JobInfo job_info = 6;
+
+    enum Constraint {
+        CONSTRAINT_CHARGING = 1;
+        CONSTRAINT_BATTERY_NOT_LOW = 2;
+        CONSTRAINT_STORAGE_NOT_LOW = 3;
+        CONSTRAINT_TIMING_DELAY = 4;
+        CONSTRAINT_DEADLINE = 5;
+        CONSTRAINT_IDLE = 6;
+        CONSTRAINT_CONNECTIVITY = 7;
+        CONSTRAINT_APP_NOT_IDLE = 8;
+        CONSTRAINT_CONTENT_TRIGGER = 9;
+        CONSTRAINT_DEVICE_NOT_DOZING = 10;
+    }
+    repeated Constraint required_constraints = 7;
+    repeated Constraint satisfied_constraints = 8;
+    repeated Constraint unsatisfied_constraints = 9;
+    optional bool is_doze_whitelisted = 10;
+
+    enum TrackingController {
+        TRACKING_BATTERY = 0;
+        TRACKING_CONNECTIVITY = 1;
+        TRACKING_CONTENT = 2;
+        TRACKING_IDLE = 3;
+        TRACKING_STORAGE = 4;
+        TRACKING_TIME = 5;
+    }
+    // Controllers that are currently tracking the job.
+    repeated TrackingController tracking_controllers = 11;
+
+    repeated string changed_authorities = 12;
+    repeated string changed_uris = 13;
+
+    optional .android.net.NetworkProto network = 14;
+
+    // Only the desired data from an android.app.job.JobWorkItem object.
+    message JobWorkItem {
+        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;
+    }
+    optional Bucket standby_bucket = 17;
+
+    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;
+
+    optional int32 num_failures = 21;
+
+    optional int64 last_successful_run_time = 22;
+    optional int64 last_failed_run_time = 23;
+}