• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.util;
18 
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 
22 /**
23  * {@link FileOutputStream} for {@link AtomicFile}.
24  * Allows user-code to write into file output stream backed by {@link AtomicFile}.
25  * In order to "commit" the new content to the file, call {@link #markSuccess()} then
26  * {@link #close()}. Calling{@link #markSuccess()} alone won't update the file.
27  * This class does not confer any file locking semantics. Do not use this class when the file may be
28  * accessed or modified concurrently by multiple threads or processes. The caller is responsible for
29  * ensuring appropriate mutual exclusion invariants whenever it accesses the file.
30  * @hide
31  */
32 @android.ravenwood.annotation.RavenwoodKeepWholeClass
33 public class AtomicFileOutputStream extends FileOutputStream implements AutoCloseable {
34     private static final String TAG = "AtomicFileOutputStream";
35     private final AtomicFile mFile;
36     private final FileOutputStream mOutStream;
37     private boolean mWritingSuccessful;
38     private boolean mClosed;
39 
40     /**
41      * See {@link AtomicFile#startWrite()}.
42      */
AtomicFileOutputStream(AtomicFile file)43     public AtomicFileOutputStream(AtomicFile file) throws IOException {
44         this(file, file.startWrite());
45     }
46 
AtomicFileOutputStream(AtomicFile file, FileOutputStream oStream)47     private AtomicFileOutputStream(AtomicFile file, FileOutputStream oStream) throws IOException {
48         super(oStream.getFD());
49         mFile = file;
50         mOutStream = oStream;
51     }
52 
53     /**
54      * Marks the writing as successful.
55      */
markSuccess()56     public void markSuccess() {
57         if (mWritingSuccessful) {
58             throw new IllegalStateException(TAG + " success is already marked");
59         }
60         mWritingSuccessful = true;
61     }
62 
63     /**
64      * Finishes writing to {@link #mFile}, see {@link AtomicFile#finishWrite(FileOutputStream)}
65      * and {@link AtomicFile#failWrite(FileOutputStream)}. Closes {@link #mOutStream} which
66      * is the owner of the file descriptor.
67      */
68     @Override
close()69     public void close() throws IOException {
70         super.close();
71         synchronized (mOutStream) {
72             if (mClosed) {
73                 // FileOutputStream#finalize() may call this #close() method.
74                 // We don't want to throw exceptions in this case.
75                 // CloseGuard#warnIfOpen() also called there, so no need to log warnings in
76                 // AtomicFileOutputStream#finalize().
77                 return;
78             }
79             mClosed = true;
80         }
81 
82         if (mWritingSuccessful) {
83             mFile.finishWrite(mOutStream);
84         } else {
85             mFile.failWrite(mOutStream);
86         }
87     }
88 
89     /**
90      * Creates string representation of the object.
91      */
92     @Override
toString()93     public String toString() {
94         return TAG + "["
95                 + "mFile=" + mFile
96                 + ", mWritingSuccessful=" + mWritingSuccessful
97                 + ", mClosed=" + mClosed
98                 + "]";
99     }
100 }
101