Loading api/current.txt +11 −0 Original line number Diff line number Diff line Loading @@ -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); core/java/android/content/SyncStorageEngine.java +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading core/java/android/content/pm/RegisteredServicesCache.java +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading core/java/android/util/AtomicFile.java 0 → 100644 +233 −0 Original line number Diff line number Diff line /* * 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(); } } } core/java/com/android/internal/util/JournaledFile.java +9 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading
api/current.txt +11 −0 Original line number Diff line number Diff line Loading @@ -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);
core/java/android/content/SyncStorageEngine.java +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading
core/java/android/content/pm/RegisteredServicesCache.java +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading
core/java/android/util/AtomicFile.java 0 → 100644 +233 −0 Original line number Diff line number Diff line /* * 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(); } } }
core/java/com/android/internal/util/JournaledFile.java +9 −0 Original line number Diff line number Diff line Loading @@ -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; Loading