blob: 3c6a2f2b96176c03bf1cace71b9c030ebcc0305d [file] [log] [blame]
Joe Onorato99598ee2019-02-11 15:55:13 +00001/*
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
29namespace android {
30namespace os {
31namespace incidentd {
32
33using android::content::ComponentName;
34using android::os::IncidentReportArgs;
35using namespace std;
36
37extern const ComponentName DROPBOX_SENTINEL;
38
39class WorkDirectory;
40struct WorkDirectoryEntry;
41
42void 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 */
48class ReportFile : public virtual RefBase {
49public:
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 /**
Yao Chencbafce92019-04-01 15:56:44 -0700138 * Use the privacy and section configuration from the args parameter to filter data, write
139 * to [writeFd] and take the ownership of [writeFd].
Joe Onorato99598ee2019-02-11 15:55:13 +0000140 *
Yao Chencbafce92019-04-01 15:56:44 -0700141 * 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).
Joe Onorato99598ee2019-02-11 15:55:13 +0000144 */
Yao Chencbafce92019-04-01 15:56:44 -0700145 status_t startFilteringData(int writeFd, const IncidentReportArgs& args);
Joe Onorato99598ee2019-02-11 15:55:13 +0000146
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
178private:
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 */
197class WorkDirectory : public virtual RefBase {
198public:
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
254private:
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