summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kweku Adams <kwekua@google.com> 2023-04-28 20:40:07 +0000
committer Kweku Adams <kwekua@google.com> 2023-05-03 19:14:18 +0000
commit72a334cae0dbed73fccb382e77aeb74fb90e7349 (patch)
tree268be584cb5889e67ed52a81679202fbb0a7ae72
parent0f59388c3a0e1d40753115d119beb0d61168794d (diff)
Add express logs for several JobScheduler events.
Add express logs to track: 1. How apps interact with the updateEstimatedNetworkBytes() API 2. How apps interact with the updateTransferredNetworkBytes() API 3. How apps interact with the setNotification() API 4. How apps interact with the setEstimatedNetworkBytes() API 5. How apps interact with the setMinimumChunkBytes() API 6. How often apps hit the max scheduled job limit 7. How often apps are too slow in responding to JobService API calls 8. How many times apps crash (or otherwise unexpectedly lose their connection) while running a JobService 9. How many JobWorkItems apps enqueue at a time 10. Job execution concurrency Bug: 138239687 Bug: 279935506 Test: atest CtsJobSchedulerTestCases:ConnectivityConstraintTest Test: atest CtsJobSchedulerTestCases:JobSchedulingTest Test: atest CtsJobSchedulerTestCases:NotificationTest Test: atest FrameworksMockingServicesTests:JobNotificationCoordinatorTest Change-Id: I153eef1120fcdbf64c241707287233c422fa66db
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java37
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java66
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java106
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java48
6 files changed, 241 insertions, 26 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index b9b825c9f75c..a0634f0e74eb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -62,6 +62,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.StatLogger;
+import com.android.modules.expresslog.Histogram;
import com.android.server.AppSchedulingModuleThread;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
@@ -471,6 +472,13 @@ class JobConcurrencyManager {
private final Consumer<PackageStats> mPackageStatsStagingCountClearer =
PackageStats::resetStagedCount;
+ private static final Histogram sConcurrencyHistogramLogger = new Histogram(
+ "job_scheduler.value_hist_job_concurrency",
+ // Create a histogram that expects values in the range [0, 99].
+ // Include more buckets than MAX_CONCURRENCY_LIMIT to account for/identify the cases
+ // where we may create additional slots for TOP-started EJs and UIJs
+ new Histogram.UniformOptions(100, 0, 99));
+
private final StatLogger mStatLogger = new StatLogger(new String[]{
"assignJobsToContexts",
"refreshSystemState",
@@ -1433,6 +1441,7 @@ class JobConcurrencyManager {
mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
// TODO: log per type instead of only TOP
mWorkCountTracker.getRunningJobCount(WORK_TYPE_TOP));
+ sConcurrencyHistogramLogger.logSample(mActiveServices.size());
}
@GuardedBy("mLock")
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
index d94674b5cab0..8a5d09404ebb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobNotificationCoordinator.java
@@ -33,6 +33,7 @@ import android.util.SparseArrayMap;
import android.util.SparseSetArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.expresslog.Counter;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.notification.NotificationManagerInternal;
@@ -114,11 +115,39 @@ class JobNotificationCoordinator {
@JobService.JobEndNotificationPolicy int jobEndNotificationPolicy) {
validateNotification(packageName, callingUid, notification, jobEndNotificationPolicy);
final JobStatus jobStatus = hostingContext.getRunningJobLocked();
+ if (jobStatus == null) {
+ Slog.wtfStack(TAG, "enqueueNotification called with no running job");
+ return;
+ }
final NotificationDetails oldDetails = mNotificationDetails.get(hostingContext);
- if (oldDetails != null && oldDetails.notificationId != notificationId) {
- // App is switching notification IDs. Remove association with the old one.
- removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED,
- jobStatus);
+ if (oldDetails == null) {
+ if (jobStatus.startedAsUserInitiatedJob) {
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_initial_setNotification_call_required",
+ jobStatus.getUid());
+ } else {
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_initial_setNotification_call_optional",
+ jobStatus.getUid());
+ }
+ } else {
+ if (jobStatus.startedAsUserInitiatedJob) {
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_subsequent_setNotification_call_required",
+ jobStatus.getUid());
+ } else {
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_subsequent_setNotification_call_optional",
+ jobStatus.getUid());
+ }
+ if (oldDetails.notificationId != notificationId) {
+ // App is switching notification IDs. Remove association with the old one.
+ removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED,
+ jobStatus);
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_setNotification_changed_notification_ids",
+ jobStatus.getUid());
+ }
}
final int userId = UserHandle.getUserId(callingUid);
if (jobStatus != null && jobStatus.startedAsUserInitiatedJob) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 8a4b4647f94b..72e66450d339 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -106,6 +106,8 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.modules.expresslog.Counter;
+import com.android.modules.expresslog.Histogram;
import com.android.server.AppSchedulingModuleThread;
import com.android.server.AppStateTracker;
import com.android.server.AppStateTrackerImpl;
@@ -378,6 +380,28 @@ public class JobSchedulerService extends com.android.server.SystemService
private final long[] mLastCancelledJobTimeElapsed =
new long[DEBUG ? NUM_COMPLETED_JOB_HISTORY : 0];
+ private static final Histogram sEnqueuedJwiHighWaterMarkLogger = new Histogram(
+ "job_scheduler.value_hist_w_uid_enqueued_work_items_high_water_mark",
+ new Histogram.ScaledRangeOptions(25, 0, 5, 1.4f));
+ private static final Histogram sInitialJobEstimatedNetworkDownloadKBLogger = new Histogram(
+ "job_scheduler.value_hist_initial_job_estimated_network_download_kilobytes",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sInitialJwiEstimatedNetworkDownloadKBLogger = new Histogram(
+ "job_scheduler.value_hist_initial_jwi_estimated_network_download_kilobytes",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sInitialJobEstimatedNetworkUploadKBLogger = new Histogram(
+ "job_scheduler.value_hist_initial_job_estimated_network_upload_kilobytes",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sInitialJwiEstimatedNetworkUploadKBLogger = new Histogram(
+ "job_scheduler.value_hist_initial_jwi_estimated_network_upload_kilobytes",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sJobMinimumChunkKBLogger = new Histogram(
+ "job_scheduler.value_hist_w_uid_job_minimum_chunk_kilobytes",
+ new Histogram.ScaledRangeOptions(25, 0, 5 /* 5 KB */, 1.76f));
+ private static final Histogram sJwiMinimumChunkKBLogger = new Histogram(
+ "job_scheduler.value_hist_w_uid_jwi_minimum_chunk_kilobytes",
+ new Histogram.ScaledRangeOptions(25, 0, 5 /* 5 KB */, 1.76f));
+
/**
* A mapping of which uids are currently in the foreground to their effective bias.
*/
@@ -1422,6 +1446,32 @@ public class JobSchedulerService extends com.android.server.SystemService
return JobScheduler.RESULT_FAILURE;
}
+ if (job.getRequiredNetwork() != null) {
+ sInitialJobEstimatedNetworkDownloadKBLogger.logSample(
+ safelyScaleBytesToKBForHistogram(
+ job.getEstimatedNetworkDownloadBytes()));
+ sInitialJobEstimatedNetworkUploadKBLogger.logSample(
+ safelyScaleBytesToKBForHistogram(job.getEstimatedNetworkUploadBytes()));
+ sJobMinimumChunkKBLogger.logSampleWithUid(uId,
+ safelyScaleBytesToKBForHistogram(job.getMinimumNetworkChunkBytes()));
+ if (work != null) {
+ sInitialJwiEstimatedNetworkDownloadKBLogger.logSample(
+ safelyScaleBytesToKBForHistogram(
+ work.getEstimatedNetworkDownloadBytes()));
+ sInitialJwiEstimatedNetworkUploadKBLogger.logSample(
+ safelyScaleBytesToKBForHistogram(
+ work.getEstimatedNetworkUploadBytes()));
+ sJwiMinimumChunkKBLogger.logSampleWithUid(uId,
+ safelyScaleBytesToKBForHistogram(
+ work.getMinimumNetworkChunkBytes()));
+ }
+ }
+
+ if (work != null) {
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_job_work_items_enqueued", uId);
+ }
+
synchronized (mLock) {
final JobStatus toCancel = mJobs.getJobByUidAndJobId(uId, namespace, job.getId());
@@ -1451,6 +1501,7 @@ public class JobSchedulerService extends com.android.server.SystemService
toCancel.enqueueWorkLocked(work);
mJobs.touchJob(toCancel);
+ sEnqueuedJwiHighWaterMarkLogger.logSampleWithUid(uId, toCancel.getWorkCount());
// If any of work item is enqueued when the source is in the foreground,
// exempt the entire job.
@@ -1483,6 +1534,8 @@ public class JobSchedulerService extends com.android.server.SystemService
if (packageName == null) {
if (mJobs.countJobsForUid(uId) > MAX_JOBS_PER_APP) {
Slog.w(TAG, "Too many jobs for uid " + uId);
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_max_scheduling_limit_hit", uId);
throw new IllegalStateException("Apps may not schedule more than "
+ MAX_JOBS_PER_APP + " distinct jobs");
}
@@ -1522,6 +1575,7 @@ public class JobSchedulerService extends com.android.server.SystemService
if (work != null) {
// If work has been supplied, enqueue it into the new job.
jobStatus.enqueueWorkLocked(work);
+ sEnqueuedJwiHighWaterMarkLogger.logSampleWithUid(uId, jobStatus.getWorkCount());
}
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
@@ -3834,6 +3888,18 @@ public class JobSchedulerService extends com.android.server.SystemService
return bucket;
}
+ static int safelyScaleBytesToKBForHistogram(long bytes) {
+ long kilobytes = bytes / 1000;
+ // Anything over Integer.MAX_VALUE or under Integer.MIN_VALUE isn't expected and will
+ // be put into the overflow buckets.
+ if (kilobytes > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ } else if (kilobytes < Integer.MIN_VALUE) {
+ return Integer.MIN_VALUE;
+ }
+ return (int) kilobytes;
+ }
+
private class CloudProviderChangeListener implements
StorageManagerInternal.CloudProviderChangeListener {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index f95df4471c29..2841226f0132 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -20,6 +20,7 @@ import static android.app.job.JobInfo.getPriorityString;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.safelyScaleBytesToKBForHistogram;
import android.Manifest;
import android.annotation.BytesLong;
@@ -66,6 +67,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.modules.expresslog.Counter;
+import com.android.modules.expresslog.Histogram;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
@@ -111,6 +114,22 @@ public final class JobServiceContext implements ServiceConnection {
private static final long NOTIFICATION_TIMEOUT_MILLIS = 10_000L * Build.HW_TIMEOUT_MULTIPLIER;
private static final long EXECUTION_DURATION_STAMP_PERIOD_MILLIS = 5 * 60_000L;
+ private static final Histogram sEnqueuedJwiAtJobStart = new Histogram(
+ "job_scheduler.value_hist_w_uid_enqueued_work_items_at_job_start",
+ new Histogram.ScaledRangeOptions(20, 1, 3, 1.4f));
+ private static final Histogram sTransferredNetworkDownloadKBHighWaterMarkLogger = new Histogram(
+ "job_scheduler.value_hist_transferred_network_download_kilobytes_high_water_mark",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sTransferredNetworkUploadKBHighWaterMarkLogger = new Histogram(
+ "job_scheduler.value_hist_transferred_network_upload_kilobytes_high_water_mark",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sUpdatedEstimatedNetworkDownloadKBLogger = new Histogram(
+ "job_scheduler.value_hist_updated_estimated_network_download_kilobytes",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+ private static final Histogram sUpdatedEstimatedNetworkUploadKBLogger = new Histogram(
+ "job_scheduler.value_hist_updated_estimated_network_upload_kilobytes",
+ new Histogram.ScaledRangeOptions(50, 0, 32 /* 32 KB */, 1.31f));
+
private static final String[] VERB_STRINGS = {
"VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED"
};
@@ -479,6 +498,7 @@ public final class JobServiceContext implements ServiceConnection {
job.getEstimatedNetworkUploadBytes(),
job.getWorkCount(),
ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid())));
+ sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount());
final String sourcePackage = job.getSourcePackageName();
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
final String componentPackage = job.getServiceComponent().getPackageName();
@@ -815,6 +835,41 @@ public final class JobServiceContext implements ServiceConnection {
if (!verifyCallerLocked(cb)) {
return;
}
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_estimated_network_bytes_updated",
+ mRunningJob.getUid());
+ sUpdatedEstimatedNetworkDownloadKBLogger.logSample(
+ safelyScaleBytesToKBForHistogram(downloadBytes));
+ sUpdatedEstimatedNetworkUploadKBLogger.logSample(
+ safelyScaleBytesToKBForHistogram(uploadBytes));
+ if (mEstimatedDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN
+ && downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ if (mEstimatedDownloadBytes < downloadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler."
+ + "value_cntr_w_uid_estimated_network_download_bytes_increased",
+ mRunningJob.getUid());
+ } else if (mEstimatedDownloadBytes > downloadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler."
+ + "value_cntr_w_uid_estimated_network_download_bytes_decreased",
+ mRunningJob.getUid());
+ }
+ }
+ if (mEstimatedUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN
+ && uploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ if (mEstimatedUploadBytes < uploadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler"
+ + ".value_cntr_w_uid_estimated_network_upload_bytes_increased",
+ mRunningJob.getUid());
+ } else if (mEstimatedUploadBytes > uploadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler"
+ + ".value_cntr_w_uid_estimated_network_upload_bytes_decreased",
+ mRunningJob.getUid());
+ }
+ }
mEstimatedDownloadBytes = downloadBytes;
mEstimatedUploadBytes = uploadBytes;
}
@@ -827,6 +882,41 @@ public final class JobServiceContext implements ServiceConnection {
if (!verifyCallerLocked(cb)) {
return;
}
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_transferred_network_bytes_updated",
+ mRunningJob.getUid());
+ sTransferredNetworkDownloadKBHighWaterMarkLogger.logSample(
+ safelyScaleBytesToKBForHistogram(downloadBytes));
+ sTransferredNetworkUploadKBHighWaterMarkLogger.logSample(
+ safelyScaleBytesToKBForHistogram(uploadBytes));
+ if (mTransferredDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN
+ && downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ if (mTransferredDownloadBytes < downloadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler."
+ + "value_cntr_w_uid_transferred_network_download_bytes_increased",
+ mRunningJob.getUid());
+ } else if (mTransferredDownloadBytes > downloadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler."
+ + "value_cntr_w_uid_transferred_network_download_bytes_decreased",
+ mRunningJob.getUid());
+ }
+ }
+ if (mTransferredUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN
+ && uploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
+ if (mTransferredUploadBytes < uploadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler."
+ + "value_cntr_w_uid_transferred_network_upload_bytes_increased",
+ mRunningJob.getUid());
+ } else if (mTransferredUploadBytes > uploadBytes) {
+ Counter.logIncrementWithUid(
+ "job_scheduler."
+ + "value_cntr_w_uid_transferred_network_upload_bytes_decreased",
+ mRunningJob.getUid());
+ }
+ }
mTransferredDownloadBytes = downloadBytes;
mTransferredUploadBytes = uploadBytes;
}
@@ -897,6 +987,11 @@ public final class JobServiceContext implements ServiceConnection {
// Use that as the stop reason for logging/debugging purposes.
mParams.setStopReason(
mDeathMarkStopReason, mDeathMarkInternalStopReason, mDeathMarkDebugReason);
+ } else if (mRunningJob != null) {
+ Counter.logIncrementWithUid(
+ "job_scheduler.value_cntr_w_uid_unexpected_service_disconnects",
+ // Use the calling UID since that's the one this context was connected to.
+ mRunningJob.getUid());
}
closeAndCleanupJobLocked(true /* needsReschedule */, "unexpectedly disconnected");
}
@@ -1223,6 +1318,8 @@ public final class JobServiceContext implements ServiceConnection {
switch (mVerb) {
case VERB_BINDING:
onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true,
+ /* texCounterMetricId */
+ "job_scheduler.value_cntr_w_uid_slow_app_response_binding",
/* debugReason */ "timed out while binding",
/* anrMessage */ "Timed out while trying to bind",
CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES,
@@ -1233,6 +1330,8 @@ public final class JobServiceContext implements ServiceConnection {
// know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
onSlowAppResponseLocked(/* reschedule */ false, /* updateStopReasons */ true,
+ /* texCounterMetricId */
+ "job_scheduler.value_cntr_w_uid_slow_app_response_onStartJob",
/* debugReason */ "timed out while starting",
/* anrMessage */ "No response to onStartJob",
CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES,
@@ -1243,6 +1342,8 @@ public final class JobServiceContext implements ServiceConnection {
// Don't update the stop reasons since we were already stopping the job for some
// other reason.
onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ false,
+ /* texCounterMetricId */
+ "job_scheduler.value_cntr_w_uid_slow_app_response_onStopJob",
/* debugReason */ "timed out while stopping",
/* anrMessage */ "No response to onStopJob",
CompatChanges.isChangeEnabled(ANR_PRE_UDC_APIS_ON_SLOW_RESPONSES,
@@ -1298,6 +1399,8 @@ public final class JobServiceContext implements ServiceConnection {
}
} else if (mAwaitingNotification) {
onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true,
+ /* texCounterMetricId */
+ "job_scheduler.value_cntr_w_uid_slow_app_response_setNotification",
/* debugReason */ "timed out while stopping",
/* anrMessage */ "required notification not provided",
/* triggerAnr */ true);
@@ -1347,8 +1450,11 @@ public final class JobServiceContext implements ServiceConnection {
@GuardedBy("mLock")
private void onSlowAppResponseLocked(boolean reschedule, boolean updateStopReasons,
+ @NonNull String texCounterMetricId,
@NonNull String debugReason, @NonNull String anrMessage, boolean triggerAnr) {
Slog.w(TAG, anrMessage + " for " + getRunningJobNameLocked());
+ // Use the calling UID since that's the one this context was connected to.
+ Counter.logIncrementWithUid(texCounterMetricId, mRunningJob.getUid());
if (updateStopReasons) {
mParams.setStopReason(
JobParameters.STOP_REASON_UNDEFINED,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index ba62e96b2a32..c272af00f040 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -90,6 +90,7 @@ public final class TimeController extends StateController {
final long nowElapsedMillis = sElapsedRealtimeClock.millis();
if (job.hasDeadlineConstraint() && evaluateDeadlineConstraint(job, nowElapsedMillis)) {
// We're intentionally excluding jobs whose deadlines have passed
+ // from the job_scheduler.value_job_scheduler_job_deadline_expired_counter count
// (mostly like deadlines of 0) when the job was scheduled.
return;
} else if (job.hasTimingDelayConstraint() && evaluateTimingDelayConstraint(job,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java
index e24354f26d8b..27a3adc4ace7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobNotificationCoordinatorTest.java
@@ -90,7 +90,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testParameterValidation() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final int uid = 10123;
final int pid = 42;
final int notificationId = 23;
@@ -137,7 +137,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testSingleJob_DetachOnStop() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification = createValidNotification();
final int uid = 10123;
final int pid = 42;
@@ -159,7 +159,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testSingleJob_RemoveOnStop() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification = createValidNotification();
final int uid = 10123;
final int pid = 42;
@@ -181,7 +181,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testSingleJob_EnqueueDifferentNotificationId_DetachOnStop() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -210,7 +210,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testSingleJob_EnqueueDifferentNotificationId_RemoveOnStop() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -239,7 +239,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testSingleJob_EnqueueSameNotificationId() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -267,8 +267,8 @@ public class JobNotificationCoordinatorTest {
@Test
public void testMultipleJobs_sameApp_EnqueueDifferentNotificationId() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc1 = mock(JobServiceContext.class);
- final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final JobServiceContext jsc1 = createJobServiceContext();
+ final JobServiceContext jsc2 = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -313,8 +313,8 @@ public class JobNotificationCoordinatorTest {
@Test
public void testMultipleJobs_sameApp_EnqueueSameNotificationId() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc1 = mock(JobServiceContext.class);
- final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final JobServiceContext jsc1 = createJobServiceContext();
+ final JobServiceContext jsc2 = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -355,8 +355,8 @@ public class JobNotificationCoordinatorTest {
@Test
public void testMultipleJobs_sameApp_DifferentUsers() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc1 = mock(JobServiceContext.class);
- final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final JobServiceContext jsc1 = createJobServiceContext();
+ final JobServiceContext jsc2 = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid1 = 10123;
@@ -403,8 +403,8 @@ public class JobNotificationCoordinatorTest {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
final String pkg1 = "pkg1";
final String pkg2 = "pkg2";
- final JobServiceContext jsc1 = mock(JobServiceContext.class);
- final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final JobServiceContext jsc1 = createJobServiceContext();
+ final JobServiceContext jsc2 = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -448,7 +448,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testUserStop_SingleJob_DetachOnStop() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification = createValidNotification();
final int uid = 10123;
final int pid = 42;
@@ -470,8 +470,8 @@ public class JobNotificationCoordinatorTest {
@Test
public void testUserStop_MultipleJobs_sameApp_EnqueueSameNotificationId_DetachOnStop() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc1 = mock(JobServiceContext.class);
- final JobServiceContext jsc2 = mock(JobServiceContext.class);
+ final JobServiceContext jsc1 = createJobServiceContext();
+ final JobServiceContext jsc2 = createJobServiceContext();
final Notification notification1 = createValidNotification();
final Notification notification2 = createValidNotification();
final int uid = 10123;
@@ -512,10 +512,9 @@ public class JobNotificationCoordinatorTest {
@Test
public void testUserInitiatedJob_hasNotificationFlag() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
- final JobStatus js = mock(JobStatus.class);
+ final JobServiceContext jsc = createJobServiceContext();
+ final JobStatus js = jsc.getRunningJobLocked();
js.startedAsUserInitiatedJob = true;
- doReturn(js).when(jsc).getRunningJobLocked();
final Notification notification = createValidNotification();
final int uid = 10123;
final int pid = 42;
@@ -532,8 +531,7 @@ public class JobNotificationCoordinatorTest {
@Test
public void testNonUserInitiatedJob_doesNotHaveNotificationFlag() {
final JobNotificationCoordinator coordinator = new JobNotificationCoordinator();
- final JobServiceContext jsc = mock(JobServiceContext.class);
- doReturn(mock(JobStatus.class)).when(jsc).getRunningJobLocked();
+ final JobServiceContext jsc = createJobServiceContext();
final Notification notification = createValidNotification();
final int uid = 10123;
final int pid = 42;
@@ -547,6 +545,12 @@ public class JobNotificationCoordinatorTest {
assertEquals(notification.flags & Notification.FLAG_USER_INITIATED_JOB, 0);
}
+ private JobServiceContext createJobServiceContext() {
+ final JobServiceContext jsc = mock(JobServiceContext.class);
+ doReturn(mock(JobStatus.class)).when(jsc).getRunningJobLocked();
+ return jsc;
+ }
+
private Notification createValidNotification() {
final Notification notification = mock(Notification.class);
doReturn(mock(Icon.class)).when(notification).getSmallIcon();