From 8845d01b72dc07f2fd9804eb6aa70ab5bf5abdc7 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Tue, 11 Dec 2018 20:06:45 -0800 Subject: [PATCH] Add logging to statsd for job constraint changes. Bug: 117846754 Bug: 111423978 Bug: 120941744 Test: `make statsd_testdrive && ./out/host/linux-x86/bin/statsd_testdrive 150` and check output Change-Id: Iadfdb07171b8d4f99b8f57008cc7c1fc2865bb8e --- cmds/statsd/src/atoms.proto | 23 +++++ core/proto/android/app/job/enums.proto | 3 + core/proto/android/server/job/enums.proto | 43 ++++++++++ core/proto/android/server/jobscheduler.proto | 19 +---- .../server/job/controllers/JobStatus.java | 83 ++++++++++++++++--- 5 files changed, 146 insertions(+), 25 deletions(-) create mode 100644 core/proto/android/server/job/enums.proto diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 8e56bef6856ed..e84eced8bb1af 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -33,6 +33,7 @@ import "frameworks/base/core/proto/android/net/networkcapabilities.proto"; import "frameworks/base/core/proto/android/os/enums.proto"; import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto"; import "frameworks/base/core/proto/android/server/enums.proto"; +import "frameworks/base/core/proto/android/server/job/enums.proto"; import "frameworks/base/core/proto/android/server/location/enums.proto"; import "frameworks/base/core/proto/android/service/procstats_enum.proto"; import "frameworks/base/core/proto/android/service/usb.proto"; @@ -213,6 +214,7 @@ message Atom { WatchdogRollbackOccurred watchdog_rollback_occurred = 147; BiometricHalDeathReported biometric_hal_death_reported = 148; BubbleUIChanged bubble_ui_changed = 149; + ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150; } // Pulled events will start at field 10000. @@ -4699,3 +4701,24 @@ message BubbleUIChanged { optional float normalized_x_position = 7; optional float normalized_y_position = 8; } + +/** + * Logs that a constraint for a scheduled job has changed. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java + */ +message ScheduledJobConstraintChanged { + repeated AttributionNode attribution_node = 1; + + // Name of the job. + optional string job_name = 2; + + optional com.android.server.job.ConstraintEnum constraint = 3; + + enum State { + UNSATISFIED = 0; + SATISFIED = 1; + } + optional State state = 4; +} diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto index bba8328806692..f702b3e37bda5 100644 --- a/core/proto/android/app/job/enums.proto +++ b/core/proto/android/app/job/enums.proto @@ -18,6 +18,9 @@ syntax = "proto2"; package android.app.job; +// This file is for JobScheduler enums inside the app directory. If you're +// adding enums for system-server-side code, use the file in +// frameworks/base/core/proto/android/server/job. option java_outer_classname = "JobProtoEnums"; option java_multiple_files = true; diff --git a/core/proto/android/server/job/enums.proto b/core/proto/android/server/job/enums.proto new file mode 100644 index 0000000000000..50fc0310ad996 --- /dev/null +++ b/core/proto/android/server/job/enums.proto @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 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; + +// This file is for JobScheduler enums inside the server directory. If you're +// adding enums for app-side code, use the file in +// frameworks/base/core/proto/android/app/job. +option java_outer_classname = "JobServerProtoEnums"; +option java_multiple_files = true; + +// Set of constraints that a job potentially needs satisfied before it can run. +// Defined in +// frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java +enum ConstraintEnum { + CONSTRAINT_UNKNOWN = 0; + 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_CONTENT_TRIGGER = 8; + CONSTRAINT_DEVICE_NOT_DOZING = 9; + CONSTRAINT_WITHIN_QUOTA = 10; + CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 11; +} diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 188769d930d16..6c9d13a572eee 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -29,6 +29,7 @@ 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"; +import "frameworks/base/core/proto/android/server/job/enums.proto"; import "frameworks/base/libs/incident/proto/android/privacy.proto"; // Next tag: 21 @@ -757,21 +758,9 @@ message JobStatusDumpProto { } 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_CONTENT_TRIGGER = 8; - CONSTRAINT_DEVICE_NOT_DOZING = 9; - CONSTRAINT_WITHIN_QUOTA = 10; - } - repeated Constraint required_constraints = 7; - repeated Constraint satisfied_constraints = 8; - repeated Constraint unsatisfied_constraints = 9; + repeated ConstraintEnum required_constraints = 7; + repeated ConstraintEnum satisfied_constraints = 8; + repeated ConstraintEnum unsatisfied_constraints = 9; optional bool is_doze_whitelisted = 10; optional bool is_uid_active = 26; diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 82bfa511507f4..ed1a6d0beabf5 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -33,6 +33,7 @@ import android.text.format.Time; import android.util.ArraySet; import android.util.Pair; import android.util.Slog; +import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -40,6 +41,7 @@ import com.android.server.LocalServices; import com.android.server.job.GrantedUriPermissions; import com.android.server.job.JobSchedulerInternal; import com.android.server.job.JobSchedulerService; +import com.android.server.job.JobServerProtoEnums; import com.android.server.job.JobStatusDumpProto; import com.android.server.job.JobStatusShortInfoProto; @@ -80,6 +82,28 @@ public final class JobStatus { static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22; + /** + * The constraints that we want to log to statsd. + * + * Constraints that can be inferred from other atoms have been excluded to avoid logging too + * much information and to reduce redundancy: + * + * * CONSTRAINT_CHARGING can be inferred with PluggedStateChanged (Atom #32) + * * CONSTRAINT_BATTERY_NOT_LOW can be inferred with BatteryLevelChanged (Atom #30) + * * CONSTRAINT_CONNECTIVITY can be partially inferred with ConnectivityStateChanged + * (Atom #98) and BatterySaverModeStateChanged (Atom #20). + * * CONSTRAINT_DEVICE_NOT_DOZING can be mostly inferred with DeviceIdleModeStateChanged + * (Atom #21) + * * CONSTRAINT_BACKGROUND_NOT_RESTRICTED can be inferred with BatterySaverModeStateChanged + * (Atom #20) + */ + private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER + | CONSTRAINT_DEADLINE + | CONSTRAINT_IDLE + | CONSTRAINT_STORAGE_NOT_LOW + | CONSTRAINT_TIMING_DELAY + | CONSTRAINT_WITHIN_QUOTA; + // Soft override: ignore constraints like time that don't affect API availability public static final int OVERRIDE_SOFT = 1; // Full override: ignore all constraints including API-affecting like connectivity @@ -976,6 +1000,12 @@ public final class JobStatus { } satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0); mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; + if ((STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) { + StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED, + sourceUid, null, getBatteryName(), getProtoConstraint(constraint), + state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED + : StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED); + } return true; } @@ -1228,37 +1258,70 @@ public final class JobStatus { } } + /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */ + private int getProtoConstraint(int constraint) { + switch (constraint) { + case CONSTRAINT_BACKGROUND_NOT_RESTRICTED: + return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED; + case CONSTRAINT_BATTERY_NOT_LOW: + return JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW; + case CONSTRAINT_CHARGING: + return JobServerProtoEnums.CONSTRAINT_CHARGING; + case CONSTRAINT_CONNECTIVITY: + return JobServerProtoEnums.CONSTRAINT_CONNECTIVITY; + case CONSTRAINT_CONTENT_TRIGGER: + return JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER; + case CONSTRAINT_DEADLINE: + return JobServerProtoEnums.CONSTRAINT_DEADLINE; + case CONSTRAINT_DEVICE_NOT_DOZING: + return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING; + case CONSTRAINT_IDLE: + return JobServerProtoEnums.CONSTRAINT_IDLE; + case CONSTRAINT_STORAGE_NOT_LOW: + return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW; + case CONSTRAINT_TIMING_DELAY: + return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY; + case CONSTRAINT_WITHIN_QUOTA: + return JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA; + default: + return JobServerProtoEnums.CONSTRAINT_UNKNOWN; + } + } + /** Writes constraints to the given repeating proto field. */ void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) { if ((constraints & CONSTRAINT_CHARGING) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CHARGING); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CHARGING); } if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_BATTERY_NOT_LOW); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW); } if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_STORAGE_NOT_LOW); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW); } if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_TIMING_DELAY); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_TIMING_DELAY); } if ((constraints & CONSTRAINT_DEADLINE) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEADLINE); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEADLINE); } if ((constraints & CONSTRAINT_IDLE) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_IDLE); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_IDLE); } if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONNECTIVITY); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONNECTIVITY); } if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONTENT_TRIGGER); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER); } if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEVICE_NOT_DOZING); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING); } if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) { - proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_WITHIN_QUOTA); + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA); + } + if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) { + proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED); } }