script-astra/Android/Sdk/sources/android-35/com/android/internal/os/MonotonicClock.java
localadmin 4380f00a78 init
2025-01-20 18:15:20 +03:00

157 lines
5.2 KiB
Java

/*
* Copyright (C) 2023 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 com.android.internal.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Xml;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* A clock that is similar to SystemClock#elapsedRealtime(), except that it is not reset
* on reboot, but keeps going.
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class MonotonicClock {
private static final String TAG = "MonotonicClock";
private static final String XML_TAG_MONOTONIC_TIME = "monotonic_time";
private static final String XML_ATTR_TIMESHIFT = "timeshift";
private final AtomicFile mFile;
private final Clock mClock;
private final long mTimeshift;
public static final long UNDEFINED = -1;
public MonotonicClock(File file) {
this (file, Clock.SYSTEM_CLOCK.elapsedRealtime(), Clock.SYSTEM_CLOCK);
}
public MonotonicClock(long monotonicTime, @NonNull Clock clock) {
this(null, monotonicTime, clock);
}
public MonotonicClock(@Nullable File file, long monotonicTime, @NonNull Clock clock) {
mClock = clock;
if (file != null) {
mFile = new AtomicFile(file);
mTimeshift = read(monotonicTime - mClock.elapsedRealtime());
} else {
mFile = null;
mTimeshift = monotonicTime - mClock.elapsedRealtime();
}
}
/**
* Returns time in milliseconds, based on SystemClock.elapsedTime, adjusted so that
* after a device reboot the time keeps increasing.
*/
public long monotonicTime() {
return monotonicTime(mClock.elapsedRealtime());
}
/**
* Like {@link #monotonicTime()}, except the elapsed time is supplied as an argument instead
* of being read from the Clock.
*/
public long monotonicTime(long elapsedRealtimeMs) {
return mTimeshift + elapsedRealtimeMs;
}
private long read(long defaultTimeshift) {
if (!mFile.exists()) {
return defaultTimeshift;
}
try {
return readXml(new ByteArrayInputStream(mFile.readFully()), Xml.newBinaryPullParser());
} catch (IOException e) {
Log.e(TAG, "Cannot load monotonic clock from " + mFile.getBaseFile(), e);
return defaultTimeshift;
}
}
/**
* Saves the timeshift into a file. Call this method just before system shutdown, after
* writing the last battery history event.
*/
public void write() {
if (mFile == null) {
return;
}
FileOutputStream out = null;
try {
out = mFile.startWrite();
writeXml(out, Xml.newBinarySerializer());
mFile.finishWrite(out);
} catch (IOException e) {
Log.e(TAG, "Cannot write monotonic clock to " + mFile.getBaseFile(), e);
mFile.failWrite(out);
}
}
/**
* Parses an XML file containing the persistent state of the monotonic clock.
*/
private long readXml(InputStream inputStream, TypedXmlPullParser parser) throws IOException {
long savedTimeshift = 0;
try {
parser.setInput(inputStream, StandardCharsets.UTF_8.name());
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG
&& parser.getName().equals(XML_TAG_MONOTONIC_TIME)) {
savedTimeshift = parser.getAttributeLong(null, XML_ATTR_TIMESHIFT);
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {
throw new IOException(e);
}
return savedTimeshift - mClock.elapsedRealtime();
}
/**
* Creates an XML file containing the persistent state of the monotonic clock.
*/
private void writeXml(OutputStream out, TypedXmlSerializer serializer) throws IOException {
serializer.setOutput(out, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
serializer.startTag(null, XML_TAG_MONOTONIC_TIME);
serializer.attributeLong(null, XML_ATTR_TIMESHIFT, monotonicTime());
serializer.endTag(null, XML_TAG_MONOTONIC_TIME);
serializer.endDocument();
}
}