1 /*
2  * Copyright (C) 2019 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 #pragma once
18 
19 #include <android/content/ComponentName.h>
20 #include <android/os/IncidentReportArgs.h>
21 #include <frameworks/base/core/proto/android/os/metadata.pb.h>
22 #include <frameworks/base/cmds/incidentd/src/report_file.pb.h>
23 
24 #include <utils/RefBase.h>
25 
26 #include <mutex>
27 #include <string>
28 
29 namespace android {
30 namespace os {
31 namespace incidentd {
32 
33 using android::content::ComponentName;
34 using android::os::IncidentReportArgs;
35 using namespace std;
36 
37 extern const ComponentName DROPBOX_SENTINEL;
38 
39 class WorkDirectory;
40 struct WorkDirectoryEntry;
41 
42 void get_args_from_report(IncidentReportArgs* out, const ReportFileProto_Report& report);
43 
44 /**
45  * A ReportFile object is backed by two files.
46  *   - A metadata file, which contains a
47  */
48 class ReportFile : public virtual RefBase {
49 public:
50     ReportFile(const sp<WorkDirectory>& workDirectory, int64_t timestampNs,
51             const string& envelopeFileName, const string& dataFileName);
52 
53     virtual ~ReportFile();
54 
55     /**
56      * Get the timestamp from when this file was added.
57      */
58     int64_t getTimestampNs() const;
59 
60     /**
61      * Add an additional report to this ReportFile.
62      */
63     void addReport(const IncidentReportArgs& args);
64 
65     /**
66      * Remove the reports for pkg/cls from this file.
67      */
68     void removeReport(const string& pkg, const string& cls);
69 
70     /**
71      * Remove all reports for pkg from this file.
72      */
73     void removeReports(const string& pkg);
74 
75     /**
76      * Set the metadata for this incident report.
77      */
78     void setMetadata(const IncidentMetadata& metadata);
79 
80     /*
81      * Mark this incident report as finished and ready for broadcast.
82      */
83     void markCompleted();
84 
85     /*
86      * Mark this incident report as finished and ready for broadcast.
87      */
88     status_t markApproved(const string& pkg, const string& cls);
89 
90     /**
91      * Set the privacy policy that is being used to pre-filter the data
92      * going to disk.
93      */
94     void setMaxPersistedPrivacyPolicy(int persistedPrivacyPolicy);
95 
96     /**
97      * Save the metadata (envelope) information about the incident
98      * report.  Must be called after addReport, setMetadata markCompleted
99      * markApproved to save those changes to disk.
100      */
101     status_t saveEnvelope();
102 
103     /**
104      * Like saveEnvelope() but will not clean up if there is an error.
105      */
106     status_t trySaveEnvelope();
107 
108     /**
109      * Read the envelope information from disk.  If there was an error, the envelope and
110      * data file will be removed.  If the proto can't be loaded, the whole file is deleted.
111      */
112     status_t loadEnvelope();
113 
114     /**
115      * Like loadEnvelope() but will not clean up if there is an error.
116      */
117     status_t tryLoadEnvelope();
118 
119     /**
120      * Get the envelope information.
121      */
122     const ReportFileProto& getEnvelope();
123 
124     /**
125      * Open the file that will contain the contents of the incident report.  Call
126      * close() or closeDataFile() on the result of getDataFileFd() when you're done.
127      * This is not done automatically in the desctructor.   If there is an error, returns
128      * it and you will not get an fd.
129      */
130     status_t startWritingDataFile();
131 
132     /**
133      * Close the data file.
134      */
135     void closeDataFile();
136 
137     /**
138      * Use the privacy and section configuration from the args parameter to filter data, write
139      * to [writeFd] and take the ownership of [writeFd].
140      *
141      * Note: this call is blocking. When the writeFd is a pipe fd for IPC, caller should make sure
142      * it's called on a separate thread so that reader can start to read without waiting for writer
143      * to finish writing (which may not happen due to pipe buffer overflow).
144      */
145     status_t startFilteringData(int writeFd, const IncidentReportArgs& args);
146 
147     /**
148      * Get the name of the data file on disk.
149      */
150     string getDataFileName() const;
151 
152     /**
153      * Get the name of the envelope file on disk.
154      */
155     string getEnvelopeFileName() const;
156 
157     /**
158      * Return the file descriptor for the data file, or -1 if it is not
159      * currently open.
160      */
161     int getDataFileFd();
162 
163     /**
164      * Record that there was an error writing to the data file.
165      */
166     void setWriteError(status_t err);
167 
168     /**
169      * Get whether there was previously an error writing to the data file.
170      */
171     status_t getWriteError();
172 
173     /**
174      * Get the unique identifier for this file.
175      */
176     string getId();
177 
178 private:
179     sp<WorkDirectory> mWorkDirectory;
180     int64_t mTimestampNs;
181     string mEnvelopeFileName;
182     string mDataFileName;
183     ReportFileProto mEnvelope;
184     int mDataFd;
185     status_t mError;
186 
187     status_t save_envelope_impl(bool cleanup);
188     status_t load_envelope_impl(bool cleanup);
189 };
190 
191 /**
192  * For directory cleanup to work, WorkDirectory must be kept
193  * alive for the duration of all of the ReportFiles.  In the real
194  * incidentd, WorkDirectory is a singleton.  In tests, it may
195  * have a shorter duration.
196  */
197 class WorkDirectory : public virtual RefBase {
198 public:
199     /**
200      * Save files to the default location.
201      */
202     WorkDirectory();
203 
204     /**
205      * Save files to a specific location (primarily for testing).
206      */
207     WorkDirectory(const string& dir, int maxFileCount, long maxDiskUsageBytes);
208 
209     /**
210      * Return a new report file.  Creating this object won't fail, but
211      * subsequent actions on the file could, if the disk is full, permissions
212      * aren't set correctly, etc.
213      */
214     sp<ReportFile> createReportFile();
215 
216     /**
217      * Get the reports that are saved on-disk, with the time after (>) than the
218      * given timestamp.  Pass 0 to start at the beginning.  These files
219      * will be sorted by timestamp.  The envelope will not have been loaded.
220      */
221     status_t getReports(vector<sp<ReportFile>>* files, int64_t after);
222 
223     /**
224      * Get the report with the given package, class and id. Returns nullptr if
225      * that can't be found.  The envelope will have been loaded.  Returns the
226      * original IncidentReportArgs in *args if args != nullptr.
227      */
228     sp<ReportFile> getReport(const string& pkg, const string& cls, const string& id,
229             IncidentReportArgs* args);
230 
231     /**
232      * Returns whether there are more reports after the given timestamp.
233      */
234     bool hasMore(int64_t after);
235 
236     /**
237      * Confirm that a particular broadcast receiver has received the data.  When all
238      * broadcast receivers for a particular report file have finished, the envelope
239      * and data files will be deleted.
240      */
241     void commit(const sp<ReportFile>& report, const string& pkg, const string& cls);
242 
243     /**
244      * Commit all reports the given package.
245      */
246     void commitAll(const string& pkg);
247 
248     /**
249      * Remove the envelope and data file from disk, regardless of whether there are
250      * more pending readers or broadcasts, for example in response to an error.
251      */
252     void remove(const sp<ReportFile>& report);
253 
254 private:
255     string mDirectory;
256     int mMaxFileCount;
257     long mMaxDiskUsageBytes;
258 
259     // Held while creating or removing envelope files, which are the file that keeps
260     // the directory consistent.
261     mutex mLock;
262 
263     int64_t make_timestamp_ns_locked();
264     bool file_exists_locked(int64_t timestampNs);
265     off_t get_directory_contents_locked(map<string,WorkDirectoryEntry>* files, int64_t after);
266     void clean_directory_locked();
267     void delete_files_for_report_if_necessary(const sp<ReportFile>& report);
268 
269     string make_filename(int64_t timestampNs, const string& extension);
270 };
271 
272 
273 }  // namespace incidentd
274 }  // namespace os
275 }  // namespace android
276 
277