Snap for 12610777 from 199004e0d0c1c537175d3238f6a42a4016a405ef to mainline-tethering-release
Change-Id: I43489b4d2a729a4047f3955be35ee9048b02a368
diff --git a/service/java/com/android/os/profiling/DeviceConfigHelper.java b/service/java/com/android/os/profiling/DeviceConfigHelper.java
index f29de40..6a52825 100644
--- a/service/java/com/android/os/profiling/DeviceConfigHelper.java
+++ b/service/java/com/android/os/profiling/DeviceConfigHelper.java
@@ -133,6 +133,12 @@
public static final String CLEAR_TEMPORARY_DIRECTORY_BOOT_DELAY_MS =
"clear_temporary_directory_boot_delay_ms";
+ // System triggered run configs
+ public static final String SYSTEM_TRIGGERED_TRACE_MIN_PERIOD_SECONDS =
+ "system_triggered_trace_min_period_seconds";
+ public static final String SYSTEM_TRIGGERED_TRACE_MAX_PERIOD_SECONDS =
+ "system_triggered_trace_max_period_seconds";
+
// Post Processing Configs
public static final String PROFILING_RECHECK_DELAY_MS = "profiling_recheck_delay_ms";
diff --git a/service/java/com/android/os/profiling/ProfilingService.java b/service/java/com/android/os/profiling/ProfilingService.java
index e760e6a..7e1feb5 100644
--- a/service/java/com/android/os/profiling/ProfilingService.java
+++ b/service/java/com/android/os/profiling/ProfilingService.java
@@ -60,8 +60,12 @@
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+import java.util.Random;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -115,6 +119,10 @@
private static final int PERSIST_TO_DISK_DEFAULT_FREQUENCY_MS = 30 * 60 * 1000;
+ // Targeting a period of around 24 hours, so set max and min to 24 +/- 6 hours, respectively.
+ private static final int DEFAULT_SYSTEM_TRIGGERED_TRACE_MIN_PERIOD_SECONDS = 18 * 60 * 60;
+ private static final int DEFAULT_SYSTEM_TRIGGERED_TRACE_MAX_PERIOD_SECONDS = 30 * 60 * 60;
+
private final Context mContext;
private final Object mLock = new Object();
private final HandlerThread mHandlerThread = new HandlerThread("ProfilingService");
@@ -192,6 +200,18 @@
@GuardedBy("mLock")
private boolean mKeepUnredactedTrace = false;
+ /** Executor for scheduling system triggered profiling trace. */
+ private ScheduledExecutorService mScheduledExecutorService = null;
+
+ /** Future for the start system triggered trace. */
+ @VisibleForTesting
+ public ScheduledFuture<?> mStartSystemTriggeredTraceScheduledFuture = null;
+
+ @GuardedBy("mLock")
+ private AtomicInteger mSystemTriggeredTraceMinPeriodSeconds;
+ @GuardedBy("mLock")
+ private AtomicInteger mSystemTriggeredTraceMaxPeriodSeconds;
+
/**
* Package name of app being tested, or null if no app is being tested. To be used both for
* automated testing and developer manual testing.
@@ -310,6 +330,14 @@
mPersistFrequencyMs = new AtomicInteger(DeviceConfigHelper.getInt(
DeviceConfigHelper.PERSIST_TO_DISK_FREQUENCY_MS,
PERSIST_TO_DISK_DEFAULT_FREQUENCY_MS));
+
+ mSystemTriggeredTraceMinPeriodSeconds = new AtomicInteger(DeviceConfigHelper.getInt(
+ DeviceConfigHelper.SYSTEM_TRIGGERED_TRACE_MIN_PERIOD_SECONDS,
+ DEFAULT_SYSTEM_TRIGGERED_TRACE_MIN_PERIOD_SECONDS));
+
+ mSystemTriggeredTraceMaxPeriodSeconds = new AtomicInteger(DeviceConfigHelper.getInt(
+ DeviceConfigHelper.SYSTEM_TRIGGERED_TRACE_MAX_PERIOD_SECONDS,
+ DEFAULT_SYSTEM_TRIGGERED_TRACE_MAX_PERIOD_SECONDS));
}
// Now subscribe to updates on test config.
DeviceConfig.addOnPropertiesChangedListener(DeviceConfigHelper.NAMESPACE_TESTING,
@@ -369,15 +397,24 @@
mPersistFrequencyMs.set(properties.getInt(
DeviceConfigHelper.PERSIST_TO_DISK_FREQUENCY_MS,
mPersistFrequencyMs.get()));
+
+ mSystemTriggeredTraceMinPeriodSeconds.set(DeviceConfigHelper.getInt(
+ DeviceConfigHelper.SYSTEM_TRIGGERED_TRACE_MIN_PERIOD_SECONDS,
+ mSystemTriggeredTraceMinPeriodSeconds.get()));
+
+ mSystemTriggeredTraceMaxPeriodSeconds.set(DeviceConfigHelper.getInt(
+ DeviceConfigHelper.SYSTEM_TRIGGERED_TRACE_MAX_PERIOD_SECONDS,
+ mSystemTriggeredTraceMaxPeriodSeconds.get()));
}
}
});
- // Schedule initial storage cleanup after delay so as not to increase non-critical work
- // during boot.
+ // Schedule initial storage cleanup and system triggered trace start after a delay so as not
+ // to increase non-critical or work during boot.
getHandler().postDelayed(new Runnable() {
@Override
public void run() {
+ scheduleNextSystemTriggeredTraceStart();
maybeCleanupTemporaryDirectory();
}
}, mClearTemporaryDirectoryBootDelayMs);
@@ -627,6 +664,58 @@
}
/**
+ * Schedule the next start of system triggered profiling trace for a random time between min and
+ * max period.
+ */
+ @VisibleForTesting
+ public void scheduleNextSystemTriggeredTraceStart() {
+ if (!Flags.systemTriggeredProfilingNew()) {
+ // Feature disabled.
+ return;
+ }
+
+ if (mStartSystemTriggeredTraceScheduledFuture != null) {
+ // If an existing start is already scheduled, don't schedule another.
+ // This should not happen.
+ Log.e(TAG, "Attempted to schedule a system triggered trace start with one already "
+ + "scheduled.");
+ return;
+ }
+
+ if (mScheduledExecutorService == null) {
+ mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+ }
+
+ synchronized (mLock) {
+ // It's important that trace doesn't always run at the same time as this will bias the
+ // results, so grab a random number between min and max.
+ int scheduledDelaySeconds = mSystemTriggeredTraceMinPeriodSeconds.get()
+ + (new Random()).nextInt(mSystemTriggeredTraceMaxPeriodSeconds.get()
+ - mSystemTriggeredTraceMinPeriodSeconds.get());
+
+ if (DEBUG) {
+ Log.d(TAG, String.format("System triggered trace scheduled in %d seconds for params"
+ + " min %d and max %d seconds.",
+ scheduledDelaySeconds,
+ mSystemTriggeredTraceMinPeriodSeconds.get(),
+ mSystemTriggeredTraceMaxPeriodSeconds.get()));
+ }
+
+ mStartSystemTriggeredTraceScheduledFuture = mScheduledExecutorService.schedule(() -> {
+ // Start the system triggered trace.
+ startSystemTriggeredTrace();
+
+ mStartSystemTriggeredTraceScheduledFuture = null;
+
+ // In all cases, schedule again. Feature flagged off is handled earlier in this
+ // method, and all return cases in {@link #startSystemTriggeredTrace} should result
+ // in trying again at the next regularly scheduled time.
+ scheduleNextSystemTriggeredTraceStart();
+ }, scheduledDelaySeconds, TimeUnit.SECONDS);
+ }
+ }
+
+ /**
* This is the core method that keeps the profiling flow moving.
*
* This is the only way that state should be set. Do not use {@link TracingSession#setState}
@@ -1374,7 +1463,8 @@
}
/** Start a trace to be used for system triggered profiling. */
- private void startSystemTriggeredTrace() {
+ @VisibleForTesting
+ public void startSystemTriggeredTrace() {
if (!Flags.systemTriggeredProfilingNew()) {
// Flag disabled.
return;
diff --git a/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java b/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java
index 77bb9f3..a659faf 100644
--- a/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java
+++ b/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java
@@ -75,6 +75,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
/**
* Tests in this class are for testing the ProfilingService directly without the need to get a
@@ -1879,6 +1880,46 @@
assertEquals(0, newTriggerTime);
}
+ /**
+ * Test that scheduling for system triggered profiling trace start works correctly, configuring
+ * run delay for correct amount of time.
+ */
+ @Test
+ @EnableFlags(android.os.profiling.Flags.FLAG_SYSTEM_TRIGGERED_PROFILING_NEW)
+ public void testSystemTriggeredProfiling_Scheduling() throws Exception {
+ // Override system triggered trace start values so that the trace will be attempted to be
+ // started within the test duration
+ executeShellCmd(OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
+ DeviceConfigHelper.SYSTEM_TRIGGERED_TRACE_MIN_PERIOD_SECONDS, 3);
+ updateDeviceConfigAndWaitForChange(DeviceConfigHelper.NAMESPACE,
+ DeviceConfigHelper.SYSTEM_TRIGGERED_TRACE_MAX_PERIOD_SECONDS, 4);
+
+ // Cancel the already scheduled future and set to null, if applicable.
+ if (mProfilingService.mStartSystemTriggeredTraceScheduledFuture != null) {
+ mProfilingService.mStartSystemTriggeredTraceScheduledFuture.cancel(true);
+ mProfilingService.mStartSystemTriggeredTraceScheduledFuture = null;
+ }
+
+ // Schedule a start of system triggered trace.
+ mProfilingService.scheduleNextSystemTriggeredTraceStart();
+
+ // Confirm the future is scheduled and that an attempt to start the trace has not occurred
+ // yet.
+ assertNotNull(mProfilingService.mStartSystemTriggeredTraceScheduledFuture);
+ assertFalse(mProfilingService.mStartSystemTriggeredTraceScheduledFuture.isDone());
+ verify(mProfilingService, times(0)).startSystemTriggeredTrace();
+
+ // Wait for 1 second longer than the scheduled future delay so that the future can execute.
+ long delay = mProfilingService.mStartSystemTriggeredTraceScheduledFuture.getDelay(
+ TimeUnit.SECONDS);
+ sleep((delay + 1L) * 1000L);
+
+ // Finally, confirm that the future ran by confirming that an attempt to start the trace was
+ // made. We don't confirm that it actually started as we can't actually start the trace from
+ // this context.
+ verify(mProfilingService, times(1)).startSystemTriggeredTrace();
+ }
+
private File createAndConfirmFileExists(File directory, String fileName) throws Exception {
File file = new File(directory, fileName);
file.createNewFile();