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