Add SystemApi(MODULE_LIBRARIES) to AtomicFile API
Cleaning up the API in the process
Test: atest android.jobscheduler.cts
Bug: 142281756
Change-Id: Ia52dc6fda867f3015ecbf068a0a69cc0f17cd92a
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 2f5f555..f2a5580 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -36,6 +36,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SystemConfigFileCommitEventLogger;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -102,6 +103,7 @@
private boolean mWriteInProgress;
private static final Object sSingletonLock = new Object();
+ private final SystemConfigFileCommitEventLogger mEventLogger;
private final AtomicFile mJobsFile;
/** Handler backed by IoThread for writing to disk. */
private final Handler mIoHandler = IoThread.getHandler();
@@ -141,7 +143,8 @@
File systemDir = new File(dataDir, "system");
File jobDir = new File(systemDir, "job");
jobDir.mkdirs();
- mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"), "jobs");
+ mEventLogger = new SystemConfigFileCommitEventLogger("jobs");
+ mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"), mEventLogger);
mJobSet = new JobSet();
@@ -426,7 +429,7 @@
int numSystemJobs = 0;
int numSyncJobs = 0;
try {
- final long startTime = SystemClock.uptimeMillis();
+ mEventLogger.setStartTime(SystemClock.uptimeMillis());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(baos, StandardCharsets.UTF_8.name());
@@ -459,7 +462,7 @@
out.endDocument();
// Write out to disk in one fell swoop.
- FileOutputStream fos = mJobsFile.startWrite(startTime);
+ FileOutputStream fos = mJobsFile.startWrite();
fos.write(baos.toByteArray());
mJobsFile.finishWrite(fos);
} catch (IOException e) {
diff --git a/api/current.txt b/api/current.txt
index d897c8b..533734b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -51408,6 +51408,7 @@
method public void failWrite(java.io.FileOutputStream);
method public void finishWrite(java.io.FileOutputStream);
method public java.io.File getBaseFile();
+ method public long getLastModifiedTime();
method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
method public byte[] readFully() throws java.io.IOException;
method public java.io.FileOutputStream startWrite() throws java.io.IOException;
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 032e30c..b505ce9 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -183,9 +183,18 @@
package android.util {
+ public class AtomicFile {
+ ctor public AtomicFile(@NonNull java.io.File, @Nullable android.util.SystemConfigFileCommitEventLogger);
+ }
+
public final class Log {
method public static int logToRadioBuffer(int, @Nullable String, @Nullable String);
}
+ public class SystemConfigFileCommitEventLogger {
+ ctor public SystemConfigFileCommitEventLogger(@NonNull String);
+ method public void setStartTime(long);
+ }
+
}
diff --git a/core/java/android/annotation/UptimeMillisLong.java b/core/java/android/annotation/UptimeMillisLong.java
new file mode 100644
index 0000000..8946eea
--- /dev/null
+++ b/core/java/android/annotation/UptimeMillisLong.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.os.SystemClock;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc Value is a non-negative timestamp in the
+ * {@link SystemClock#uptimeMillis()} time base.
+ * @paramDoc Value is a non-negative timestamp in the
+ * {@link SystemClock#uptimeMillis()} time base.
+ * @returnDoc Value is a non-negative timestamp in the
+ * {@link SystemClock#uptimeMillis()} time base.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface UptimeMillisLong {
+}
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index cf7ed9b..944d7ba 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -16,6 +16,11 @@
package android.util;
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.os.FileUtils;
import android.os.SystemClock;
@@ -48,15 +53,14 @@
public class AtomicFile {
private final File mBaseName;
private final File mBackupName;
- private final String mCommitTag;
- private long mStartTime;
+ private SystemConfigFileCommitEventLogger mCommitEventLogger;
/**
* Create a new AtomicFile for a file located at the given File path.
* The secondary backup file will be the same file path with ".bak" appended.
*/
public AtomicFile(File baseName) {
- this(baseName, null);
+ this(baseName, (SystemConfigFileCommitEventLogger) null);
}
/**
@@ -64,9 +68,22 @@
* automatically log commit events.
*/
public AtomicFile(File baseName, String commitTag) {
+ this(baseName, new SystemConfigFileCommitEventLogger(commitTag));
+ }
+
+ /**
+ * Internal constructor that also allows you to have the class
+ * automatically log commit events.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("StreamFiles")
+ public AtomicFile(@NonNull File baseName,
+ @Nullable SystemConfigFileCommitEventLogger commitEventLogger) {
mBaseName = baseName;
mBackupName = new File(baseName.getPath() + ".bak");
- mCommitTag = commitTag;
+ mCommitEventLogger = commitEventLogger;
}
/**
@@ -100,7 +117,7 @@
* access to AtomicFile.
*/
public FileOutputStream startWrite() throws IOException {
- return startWrite(mCommitTag != null ? SystemClock.uptimeMillis() : 0);
+ return startWrite(0);
}
/**
@@ -108,9 +125,19 @@
* start time of the operation to adjust how the commit is logged.
* @param startTime The effective start time of the operation, in the time
* base of {@link SystemClock#uptimeMillis()}.
+ *
+ * @deprecated Use {@link SystemConfigFileCommitEventLogger#setStartTime} followed
+ * by {@link #startWrite()}
*/
+ @Deprecated
public FileOutputStream startWrite(long startTime) throws IOException {
- mStartTime = startTime;
+ if (mCommitEventLogger != null) {
+ if (startTime != 0) {
+ mCommitEventLogger.setStartTime(startTime);
+ }
+
+ mCommitEventLogger.onStartWrite();
+ }
// Rename the current file so it may be used as a backup during the next read
if (mBaseName.exists()) {
@@ -159,9 +186,8 @@
} catch (IOException e) {
Log.w("AtomicFile", "finishWrite: Got exception:", e);
}
- if (mCommitTag != null) {
- com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
- mCommitTag, SystemClock.uptimeMillis() - mStartTime);
+ if (mCommitEventLogger != null) {
+ mCommitEventLogger.onFinishWrite();
}
}
}
@@ -240,11 +266,11 @@
/**
* Gets the last modified time of the atomic file.
- * {@hide}
*
* @return last modified time in milliseconds since epoch. Returns zero if
* the file does not exist or an I/O error is encountered.
*/
+ @CurrentTimeMillisLong
public long getLastModifiedTime() {
if (mBackupName.exists()) {
return mBackupName.lastModified();
diff --git a/core/java/android/util/SystemConfigFileCommitEventLogger.java b/core/java/android/util/SystemConfigFileCommitEventLogger.java
new file mode 100644
index 0000000..04d72fb
--- /dev/null
+++ b/core/java/android/util/SystemConfigFileCommitEventLogger.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.util;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.UptimeMillisLong;
+import android.os.SystemClock;
+
+/**
+ * Writes an EventLog event capturing the performance of system config file writes.
+ * The event log entry is formatted like this:
+ * <code>525000 commit_sys_config_file (name|3),(time|2|3)</code>, where <code>name</code> is
+ * a short unique name representing the type of configuration file and <code>time</code> is
+ * duration in the {@link SystemClock#uptimeMillis()} time base.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class SystemConfigFileCommitEventLogger {
+ private final String mName;
+ private long mStartTime;
+
+ /**
+ * @param name The short name of the config file that is included in the event log event,
+ * e.g. "jobs", "appops", "uri-grants" etc.
+ */
+ public SystemConfigFileCommitEventLogger(@NonNull String name) {
+ mName = name;
+ }
+
+ /**
+ * Override the start timestamp. Use this method when it's desired to include the time
+ * taken by the preparation of the configuration data in the overall duration of the
+ * "commitSysConfigFile" event.
+ *
+ * @param startTime Overridden start time, in system uptime milliseconds
+ */
+ public void setStartTime(@UptimeMillisLong long startTime) {
+ mStartTime = startTime;
+ }
+
+ /**
+ * Invoked just before the configuration file writing begins.
+ */
+ void onStartWrite() {
+ if (mStartTime == 0) {
+ mStartTime = SystemClock.uptimeMillis();
+ }
+ }
+
+ /**
+ * Invoked just after the configuration file writing ends.
+ */
+ void onFinishWrite() {
+ com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(mName,
+ SystemClock.uptimeMillis() - mStartTime);
+ }
+}