Support logging chained WorkSources from JobScheduler.
Controller by a feature flag, which this change also introduces.
Bug: 62390666
Bug: 70892390
Test: manual, via JobSchedulerTestApp
Test: CtsJobSchedulerTestCases
Change-Id: Ic7dfb7861f7987a1b6eeb4cf3851193e9ad7da84
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index d0c2870..81d7506 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1,7 +1,10 @@
package android.os;
import android.annotation.Nullable;
+import android.content.Context;
import android.os.WorkSourceProto;
+import android.provider.Settings;
+import android.provider.Settings.Global;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -109,6 +112,17 @@
}
}
+ /**
+ * Whether system services should create {@code WorkChains} (wherever possible) in the place
+ * of flat UID lists.
+ *
+ * @hide
+ */
+ public static boolean isChainedBatteryAttributionEnabled(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED, 0) == 1;
+ }
+
/** @hide */
public int size() {
return mNum;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1ea4861..cadca24 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11248,6 +11248,16 @@
*/
public static final String OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION =
"override_settings_provider_restore_any_version";
+ /**
+ * Flag to toggle whether system services report attribution chains when they attribute
+ * battery use via a {@code WorkSource}.
+ *
+ * Type: int (0 to disable, 1 to enable)
+ *
+ * @hide
+ */
+ public static final String CHAINED_BATTERY_ATTRIBUTION_ENABLED =
+ "chained_battery_attribution_enabled";
/**
* Settings to backup. This is here so that it's in the same place as the settings
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index fd28322..27fbb24 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -394,8 +394,9 @@
optional SettingProto wifi_connected_mac_randomization_enabled = 350;
optional SettingProto show_restart_in_crash_dialog = 351;
optional SettingProto show_mute_in_crash_dialog = 352;
+ optional SettingProto chained_battery_attribution_enabled = 353;
- // Next tag = 353;
+ // Next tag = 354;
}
message SecureSettingsProto {
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 225b685..1520fb6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -444,7 +444,8 @@
Settings.Global.ZEN_MODE_CONFIG_ETAG,
Settings.Global.ZEN_MODE_RINGER_LEVEL,
Settings.Global.ZRAM_ENABLED,
- Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION);
+ Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION,
+ Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d556db4..6970c86 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.providers.settings.GlobalSettingsProto;
import android.providers.settings.SecureSettingsProto;
import android.providers.settings.SettingProto;
@@ -1137,6 +1138,12 @@
dumpSetting(s, p,
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+ dumpSetting(s, p,
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ GlobalSettingsProto.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED);
+ dumpSetting(s, p,
+ Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+ GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
}
/** Dump a single {@link SettingsState.Setting} to a proto buf */
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 83a3c19..f23147b 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -400,7 +400,7 @@
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
runningJob.getTag());
- wl.setWorkSource(new WorkSource(runningJob.getSourceUid()));
+ wl.setWorkSource(deriveWorkSource(runningJob));
wl.setReferenceCounted(false);
wl.acquire();
@@ -419,6 +419,19 @@
}
}
+ private WorkSource deriveWorkSource(JobStatus runningJob) {
+ final int jobUid = runningJob.getSourceUid();
+ if (WorkSource.isChainedBatteryAttributionEnabled(mContext)) {
+ WorkSource workSource = new WorkSource();
+ workSource.createWorkChain()
+ .addNode(jobUid, null)
+ .addNode(android.os.Process.SYSTEM_UID, "JobScheduler");
+ return workSource;
+ } else {
+ return new WorkSource(jobUid);
+ }
+ }
+
/** If the client service crashes we reschedule this job and clean up. */
@Override
public void onServiceDisconnected(ComponentName name) {
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index bbee0eb..a91f5a4 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -18,9 +18,11 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.content.Context;
+import android.os.Process;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Slog;
@@ -52,6 +54,8 @@
private long mNextJobExpiredElapsedMillis;
private long mNextDelayExpiredElapsedMillis;
+ private final boolean mChainedAttributionEnabled;
+
private AlarmManager mAlarmService = null;
/** List of tracked jobs, sorted asc. by deadline */
private final List<JobStatus> mTrackedJobs = new LinkedList<>();
@@ -71,6 +75,7 @@
mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
+ mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(context);
}
/**
@@ -113,7 +118,7 @@
maybeUpdateAlarmsLocked(
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE,
- new WorkSource(job.getSourceUid(), job.getSourcePackageName()));
+ deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
}
}
@@ -179,9 +184,8 @@
break;
}
}
- setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryPackageName != null
- ? new WorkSource(nextExpiryUid, nextExpiryPackageName)
- : new WorkSource(nextExpiryUid));
+ setDeadlineExpiredAlarmLocked(nextExpiryTime,
+ deriveWorkSource(nextExpiryUid, nextExpiryPackageName));
}
}
@@ -236,9 +240,20 @@
if (ready) {
mStateChangedListener.onControllerStateChanged();
}
- setDelayExpiredAlarmLocked(nextDelayTime, nextDelayPackageName != null
- ? new WorkSource(nextDelayUid, nextDelayPackageName)
- : new WorkSource(nextDelayUid));
+ setDelayExpiredAlarmLocked(nextDelayTime,
+ deriveWorkSource(nextDelayUid, nextDelayPackageName));
+ }
+ }
+
+ private WorkSource deriveWorkSource(int uid, @Nullable String packageName) {
+ if (mChainedAttributionEnabled) {
+ WorkSource ws = new WorkSource();
+ ws.createWorkChain()
+ .addNode(uid, packageName)
+ .addNode(Process.SYSTEM_UID, "JobScheduler");
+ return ws;
+ } else {
+ return packageName == null ? new WorkSource(uid) : new WorkSource(uid, packageName);
}
}