am 40e5df95: Merge "Make AtomicFile a public API. It\'s about time!" into jb-mr1-dev
* commit '40e5df95ff9468cec0624ca7fb14e51c13e4b047': Make AtomicFile a public API. It's about time!
This commit is contained in:
@@ -22524,6 +22524,17 @@ package android.util {
|
||||
ctor public AndroidRuntimeException(java.lang.Exception);
|
||||
}
|
||||
|
||||
public class AtomicFile {
|
||||
ctor public AtomicFile(java.io.File);
|
||||
method public void delete();
|
||||
method public void failWrite(java.io.FileOutputStream);
|
||||
method public void finishWrite(java.io.FileOutputStream);
|
||||
method public java.io.File getBaseFile();
|
||||
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;
|
||||
}
|
||||
|
||||
public abstract interface AttributeSet {
|
||||
method public abstract boolean getAttributeBooleanValue(java.lang.String, java.lang.String, boolean);
|
||||
method public abstract boolean getAttributeBooleanValue(int, boolean);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
@@ -37,7 +36,7 @@ import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.Xml;
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Xml;
|
||||
@@ -44,7 +45,6 @@ import java.io.PrintWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
import com.google.android.collect.Maps;
|
||||
|
||||
233
core/java/android/util/AtomicFile.java
Normal file
233
core/java/android/util/AtomicFile.java
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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.os.FileUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Helper class for performing atomic operations on a file by creating a
|
||||
* backup file until a write has successfully completed. If you need this
|
||||
* on older versions of the platform you can use
|
||||
* {@link android.support.v4.util.AtomicFile} in the v4 support library.
|
||||
* <p>
|
||||
* Atomic file guarantees file integrity by ensuring that a file has
|
||||
* been completely written and sync'd to disk before removing its backup.
|
||||
* As long as the backup file exists, the original file is considered
|
||||
* to be invalid (left over from a previous attempt to write the file).
|
||||
* </p><p>
|
||||
* Atomic file does not confer any file locking semantics.
|
||||
* Do not use this class when the file may be accessed or modified concurrently
|
||||
* by multiple threads or processes. The caller is responsible for ensuring
|
||||
* appropriate mutual exclusion invariants whenever it accesses the file.
|
||||
* </p>
|
||||
*/
|
||||
public class AtomicFile {
|
||||
private final File mBaseName;
|
||||
private final File mBackupName;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
mBaseName = baseName;
|
||||
mBackupName = new File(baseName.getPath() + ".bak");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the base file. You should not generally use this,
|
||||
* as the data at that path may not be valid.
|
||||
*/
|
||||
public File getBaseFile() {
|
||||
return mBaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the atomic file. This deletes both the base and backup files.
|
||||
*/
|
||||
public void delete() {
|
||||
mBaseName.delete();
|
||||
mBackupName.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new write operation on the file. This returns a FileOutputStream
|
||||
* to which you can write the new file data. The existing file is replaced
|
||||
* with the new data. You <em>must not</em> directly close the given
|
||||
* FileOutputStream; instead call either {@link #finishWrite(FileOutputStream)}
|
||||
* or {@link #failWrite(FileOutputStream)}.
|
||||
*
|
||||
* <p>Note that if another thread is currently performing
|
||||
* a write, this will simply replace whatever that thread is writing
|
||||
* with the new file being written by this thread, and when the other
|
||||
* thread finishes the write the new write operation will no longer be
|
||||
* safe (or will be lost). You must do your own threading protection for
|
||||
* access to AtomicFile.
|
||||
*/
|
||||
public FileOutputStream startWrite() throws IOException {
|
||||
// Rename the current file so it may be used as a backup during the next read
|
||||
if (mBaseName.exists()) {
|
||||
if (!mBackupName.exists()) {
|
||||
if (!mBaseName.renameTo(mBackupName)) {
|
||||
Log.w("AtomicFile", "Couldn't rename file " + mBaseName
|
||||
+ " to backup file " + mBackupName);
|
||||
}
|
||||
} else {
|
||||
mBaseName.delete();
|
||||
}
|
||||
}
|
||||
FileOutputStream str = null;
|
||||
try {
|
||||
str = new FileOutputStream(mBaseName);
|
||||
} catch (FileNotFoundException e) {
|
||||
File parent = mBaseName.getParentFile();
|
||||
if (!parent.mkdir()) {
|
||||
throw new IOException("Couldn't create directory " + mBaseName);
|
||||
}
|
||||
FileUtils.setPermissions(
|
||||
parent.getPath(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
try {
|
||||
str = new FileOutputStream(mBaseName);
|
||||
} catch (FileNotFoundException e2) {
|
||||
throw new IOException("Couldn't create " + mBaseName);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when you have successfully finished writing to the stream
|
||||
* returned by {@link #startWrite()}. This will close, sync, and
|
||||
* commit the new data. The next attempt to read the atomic file
|
||||
* will return the new file stream.
|
||||
*/
|
||||
public void finishWrite(FileOutputStream str) {
|
||||
if (str != null) {
|
||||
FileUtils.sync(str);
|
||||
try {
|
||||
str.close();
|
||||
mBackupName.delete();
|
||||
} catch (IOException e) {
|
||||
Log.w("AtomicFile", "finishWrite: Got exception:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when you have failed for some reason at writing to the stream
|
||||
* returned by {@link #startWrite()}. This will close the current
|
||||
* write stream, and roll back to the previous state of the file.
|
||||
*/
|
||||
public void failWrite(FileOutputStream str) {
|
||||
if (str != null) {
|
||||
FileUtils.sync(str);
|
||||
try {
|
||||
str.close();
|
||||
mBaseName.delete();
|
||||
mBackupName.renameTo(mBaseName);
|
||||
} catch (IOException e) {
|
||||
Log.w("AtomicFile", "failWrite: Got exception:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide
|
||||
* @deprecated This is not safe.
|
||||
*/
|
||||
@Deprecated public void truncate() throws IOException {
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(mBaseName);
|
||||
FileUtils.sync(fos);
|
||||
fos.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IOException("Couldn't append " + mBaseName);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide
|
||||
* @deprecated This is not safe.
|
||||
*/
|
||||
@Deprecated public FileOutputStream openAppend() throws IOException {
|
||||
try {
|
||||
return new FileOutputStream(mBaseName, true);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IOException("Couldn't append " + mBaseName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the atomic file for reading. If there previously was an
|
||||
* incomplete write, this will roll back to the last good data before
|
||||
* opening for read. You should call close() on the FileInputStream when
|
||||
* you are done reading from it.
|
||||
*
|
||||
* <p>Note that if another thread is currently performing
|
||||
* a write, this will incorrectly consider it to be in the state of a bad
|
||||
* write and roll back, causing the new data currently being written to
|
||||
* be dropped. You must do your own threading protection for access to
|
||||
* AtomicFile.
|
||||
*/
|
||||
public FileInputStream openRead() throws FileNotFoundException {
|
||||
if (mBackupName.exists()) {
|
||||
mBaseName.delete();
|
||||
mBackupName.renameTo(mBaseName);
|
||||
}
|
||||
return new FileInputStream(mBaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience for {@link #openRead()} that also reads all of the
|
||||
* file contents into a byte array which is returned.
|
||||
*/
|
||||
public byte[] readFully() throws IOException {
|
||||
FileInputStream stream = openRead();
|
||||
try {
|
||||
int pos = 0;
|
||||
int avail = stream.available();
|
||||
byte[] data = new byte[avail];
|
||||
while (true) {
|
||||
int amt = stream.read(data, pos, data.length-pos);
|
||||
//Log.i("foo", "Read " + amt + " bytes at " + pos
|
||||
// + " of avail " + data.length);
|
||||
if (amt <= 0) {
|
||||
//Log.i("foo", "**** FINISHED READING: pos=" + pos
|
||||
// + " len=" + data.length);
|
||||
return data;
|
||||
}
|
||||
pos += amt;
|
||||
avail = stream.available();
|
||||
if (avail > data.length-pos) {
|
||||
byte[] newData = new byte[pos+avail];
|
||||
System.arraycopy(data, 0, newData, 0, pos);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,15 @@ package com.android.internal.util;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Deprecated Use {@link com.android.internal.os.AtomicFile} instead. It would
|
||||
* be nice to update all existing uses of this to switch to AtomicFile, but since
|
||||
* their on-file semantics are slightly different that would run the risk of losing
|
||||
* data if at the point of the platform upgrade to the new code it would need to
|
||||
* roll back to the backup file. This can be solved... but is it worth it and
|
||||
* all of the testing needed to make sure it is correct?
|
||||
*/
|
||||
@Deprecated
|
||||
public class JournaledFile {
|
||||
File mReal;
|
||||
File mTemp;
|
||||
|
||||
@@ -44,6 +44,7 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserId;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@@ -55,7 +56,6 @@ import android.view.WindowManager;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.internal.appwidget.IAppWidgetHost;
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.widget.IRemoteViewsAdapterConnection;
|
||||
import com.android.internal.widget.IRemoteViewsFactory;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.server;
|
||||
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.os.HandlerCaller;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.view.IInputContext;
|
||||
@@ -74,6 +73,7 @@ import android.provider.Settings.Secure;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.SuggestionSpan;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.EventLog;
|
||||
import android.util.LruCache;
|
||||
import android.util.Pair;
|
||||
|
||||
@@ -53,6 +53,7 @@ import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -61,7 +62,6 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -12,7 +11,6 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@@ -24,6 +22,7 @@ import android.content.res.CompatibilityInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@ import android.os.Parcel;
|
||||
import android.os.Process;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.app.IUsageStats;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.os.PkgUsageStats;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.server.input;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
@@ -25,6 +24,7 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.format.Formatter;
|
||||
import android.text.format.Time;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.NtpTrustedTime;
|
||||
import android.util.Slog;
|
||||
@@ -127,7 +128,6 @@ import android.util.TrustedTime;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Objects;
|
||||
|
||||
@@ -29,8 +29,8 @@ import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.TrafficStats;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.AtomicFile;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.FileRotator;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Objects;
|
||||
|
||||
Reference in New Issue
Block a user