| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/feedback/feedback_data.h" | |
| 6 | |
| 7 #include "base/file_util.h" | |
| 8 #include "base/json/json_string_value_serializer.h" | |
| 9 #include "base/strings/string_util.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "base/values.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/chromeos/settings/cros_settings.h" | |
| 14 #include "chrome/browser/feedback/feedback_util.h" | |
| 15 #include "chrome/browser/feedback/tracing_manager.h" | |
| 16 #include "chrome/browser/profiles/profile_manager.h" | |
| 17 #include "content/public/browser/browser_thread.h" | |
| 18 | |
| 19 #if defined(USE_ASH) | |
| 20 #include "ash/shell.h" | |
| 21 #include "ash/shell_delegate.h" | |
| 22 #endif | |
| 23 | |
| 24 using content::BrowserThread; | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 const char kMultilineIndicatorString[] = "<multiline>\n"; | |
| 29 const char kMultilineStartString[] = "---------- START ----------\n"; | |
| 30 const char kMultilineEndString[] = "---------- END ----------\n\n"; | |
| 31 | |
| 32 const size_t kFeedbackMaxLength = 4 * 1024; | |
| 33 const size_t kFeedbackMaxLineCount = 40; | |
| 34 | |
| 35 const char kTraceFilename[] = "tracing.zip\n"; | |
| 36 const char kPerformanceCategoryTag[] = "Performance"; | |
| 37 | |
| 38 const char kZipExt[] = ".zip"; | |
| 39 | |
| 40 const base::FilePath::CharType kLogsFilename[] = | |
| 41 FILE_PATH_LITERAL("system_logs.txt"); | |
| 42 const base::FilePath::CharType kHistogramsFilename[] = | |
| 43 FILE_PATH_LITERAL("histograms.txt"); | |
| 44 | |
| 45 // Converts the system logs into a string that we can compress and send | |
| 46 // with the report. This method only converts those logs that we want in | |
| 47 // the compressed zip file sent with the report, hence it ignores any logs | |
| 48 // below the size threshold of what we want compressed. | |
| 49 std::string LogsToString(const FeedbackData::SystemLogsMap& sys_info) { | |
| 50 std::string syslogs_string; | |
| 51 for (FeedbackData::SystemLogsMap::const_iterator it = sys_info.begin(); | |
| 52 it != sys_info.end(); ++it) { | |
| 53 std::string key = it->first; | |
| 54 std::string value = it->second; | |
| 55 | |
| 56 if (FeedbackData::BelowCompressionThreshold(value)) | |
| 57 continue; | |
| 58 | |
| 59 base::TrimString(key, "\n ", &key); | |
| 60 base::TrimString(value, "\n ", &value); | |
| 61 | |
| 62 if (value.find("\n") != std::string::npos) { | |
| 63 syslogs_string.append( | |
| 64 key + "=" + kMultilineIndicatorString + | |
| 65 kMultilineStartString + | |
| 66 value + "\n" + | |
| 67 kMultilineEndString); | |
| 68 } else { | |
| 69 syslogs_string.append(key + "=" + value + "\n"); | |
| 70 } | |
| 71 } | |
| 72 return syslogs_string; | |
| 73 } | |
| 74 | |
| 75 void ZipFile(const base::FilePath& filename, | |
| 76 const std::string& data, std::string* compressed_data) { | |
| 77 if (!feedback_util::ZipString(filename, data, compressed_data)) | |
| 78 compressed_data->clear(); | |
| 79 } | |
| 80 | |
| 81 void ZipLogs(const FeedbackData::SystemLogsMap& sys_info, | |
| 82 std::string* compressed_logs) { | |
| 83 DCHECK(compressed_logs); | |
| 84 std::string logs_string = LogsToString(sys_info); | |
| 85 if (logs_string.empty() || | |
| 86 !feedback_util::ZipString( | |
| 87 base::FilePath(kLogsFilename), logs_string, compressed_logs)) { | |
| 88 compressed_logs->clear(); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 void ZipHistograms(const std::string& histograms, | |
| 93 std::string* compressed_histograms) { | |
| 94 DCHECK(compressed_histograms); | |
| 95 if (histograms.empty() || | |
| 96 !feedback_util::ZipString( | |
| 97 base::FilePath(kHistogramsFilename), | |
| 98 histograms, | |
| 99 compressed_histograms)) { | |
| 100 compressed_histograms->clear(); | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 } // namespace | |
| 105 | |
| 106 // static | |
| 107 bool FeedbackData::BelowCompressionThreshold(const std::string& content) { | |
| 108 if (content.length() > kFeedbackMaxLength) | |
| 109 return false; | |
| 110 const size_t line_count = std::count(content.begin(), content.end(), '\n'); | |
| 111 if (line_count > kFeedbackMaxLineCount) | |
| 112 return false; | |
| 113 return true; | |
| 114 } | |
| 115 | |
| 116 FeedbackData::FeedbackData() : profile_(NULL), | |
| 117 trace_id_(0), | |
| 118 feedback_page_data_complete_(false), | |
| 119 syslogs_compression_complete_(false), | |
| 120 histograms_compression_complete_(false), | |
| 121 attached_file_compression_complete_(false), | |
| 122 report_sent_(false) { | |
| 123 } | |
| 124 | |
| 125 FeedbackData::~FeedbackData() { | |
| 126 } | |
| 127 | |
| 128 void FeedbackData::OnFeedbackPageDataComplete() { | |
| 129 feedback_page_data_complete_ = true; | |
| 130 SendReport(); | |
| 131 } | |
| 132 | |
| 133 void FeedbackData::SetAndCompressSystemInfo( | |
| 134 scoped_ptr<FeedbackData::SystemLogsMap> sys_info) { | |
| 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 136 | |
| 137 if (trace_id_ != 0) { | |
| 138 TracingManager* manager = TracingManager::Get(); | |
| 139 if (!manager || | |
| 140 !manager->GetTraceData( | |
| 141 trace_id_, | |
| 142 base::Bind(&FeedbackData::OnGetTraceData, this, trace_id_))) { | |
| 143 trace_id_ = 0; | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 sys_info_ = sys_info.Pass(); | |
| 148 if (sys_info_.get()) { | |
| 149 std::string* compressed_logs_ptr = new std::string; | |
| 150 scoped_ptr<std::string> compressed_logs(compressed_logs_ptr); | |
| 151 BrowserThread::PostBlockingPoolTaskAndReply( | |
| 152 FROM_HERE, | |
| 153 base::Bind(&ZipLogs, | |
| 154 *sys_info_, | |
| 155 compressed_logs_ptr), | |
| 156 base::Bind(&FeedbackData::OnCompressLogsComplete, | |
| 157 this, | |
| 158 base::Passed(&compressed_logs))); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 void FeedbackData::SetAndCompressHistograms( | |
| 163 scoped_ptr<std::string> histograms) { | |
| 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 165 | |
| 166 histograms_ = histograms.Pass(); | |
| 167 if (histograms_.get()) { | |
| 168 std::string* compressed_histograms_ptr = new std::string; | |
| 169 scoped_ptr<std::string> compressed_histograms(compressed_histograms_ptr); | |
| 170 BrowserThread::PostBlockingPoolTaskAndReply( | |
| 171 FROM_HERE, | |
| 172 base::Bind(&ZipHistograms, | |
| 173 *histograms_, | |
| 174 compressed_histograms_ptr), | |
| 175 base::Bind(&FeedbackData::OnCompressHistogramsComplete, | |
| 176 this, | |
| 177 base::Passed(&compressed_histograms))); | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 void FeedbackData::AttachAndCompressFileData( | |
| 182 scoped_ptr<std::string> attached_filedata) { | |
| 183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 184 | |
| 185 attached_filedata_ = attached_filedata.Pass(); | |
| 186 | |
| 187 if (!attached_filename_.empty() && attached_filedata_.get()) { | |
| 188 std::string* compressed_file_ptr = new std::string; | |
| 189 scoped_ptr<std::string> compressed_file(compressed_file_ptr); | |
| 190 #if defined(OS_WIN) | |
| 191 base::FilePath attached_file(base::UTF8ToWide(attached_filename_)); | |
| 192 #else | |
| 193 base::FilePath attached_file(attached_filename_); | |
| 194 #endif | |
| 195 BrowserThread::PostBlockingPoolTaskAndReply( | |
| 196 FROM_HERE, | |
| 197 base::Bind(&ZipFile, | |
| 198 attached_file, | |
| 199 *(attached_filedata_.get()), | |
| 200 compressed_file_ptr), | |
| 201 base::Bind(&FeedbackData::OnCompressFileComplete, | |
| 202 this, | |
| 203 base::Passed(&compressed_file))); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 void FeedbackData::OnGetTraceData( | |
| 208 int trace_id, | |
| 209 scoped_refptr<base::RefCountedString> trace_data) { | |
| 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 211 TracingManager* manager = TracingManager::Get(); | |
| 212 if (manager) | |
| 213 manager->DiscardTraceData(trace_id); | |
| 214 | |
| 215 scoped_ptr<std::string> data(new std::string); | |
| 216 data->swap(trace_data->data()); | |
| 217 | |
| 218 attached_filename_ = kTraceFilename; | |
| 219 attached_filedata_ = data.Pass(); | |
| 220 attached_file_compression_complete_ = true; | |
| 221 trace_id_ = 0; | |
| 222 | |
| 223 set_category_tag(kPerformanceCategoryTag); | |
| 224 | |
| 225 SendReport(); | |
| 226 } | |
| 227 | |
| 228 void FeedbackData::OnCompressLogsComplete( | |
| 229 scoped_ptr<std::string> compressed_logs) { | |
| 230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 231 | |
| 232 compressed_logs_ = compressed_logs.Pass(); | |
| 233 syslogs_compression_complete_ = true; | |
| 234 | |
| 235 SendReport(); | |
| 236 } | |
| 237 | |
| 238 void FeedbackData::OnCompressHistogramsComplete( | |
| 239 scoped_ptr<std::string> compressed_histograms) { | |
| 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 241 | |
| 242 compressed_histograms_ = compressed_histograms.Pass(); | |
| 243 histograms_compression_complete_ = true; | |
| 244 | |
| 245 SendReport(); | |
| 246 } | |
| 247 | |
| 248 void FeedbackData::OnCompressFileComplete( | |
| 249 scoped_ptr<std::string> compressed_file) { | |
| 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 251 | |
| 252 if (compressed_file.get()) { | |
| 253 attached_filedata_ = compressed_file.Pass(); | |
| 254 attached_filename_.append(kZipExt); | |
| 255 attached_file_compression_complete_ = true; | |
| 256 } else { | |
| 257 attached_filename_.clear(); | |
| 258 attached_filedata_.reset(NULL); | |
| 259 } | |
| 260 | |
| 261 SendReport(); | |
| 262 } | |
| 263 | |
| 264 bool FeedbackData::IsDataComplete() { | |
| 265 return (!sys_info_.get() || syslogs_compression_complete_) && | |
| 266 (!histograms_.get() || histograms_compression_complete_) && | |
| 267 (!attached_filedata_.get() || attached_file_compression_complete_) && | |
| 268 !trace_id_ && | |
| 269 feedback_page_data_complete_; | |
| 270 } | |
| 271 | |
| 272 void FeedbackData::SendReport() { | |
| 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 274 if (IsDataComplete() && !report_sent_) { | |
| 275 report_sent_ = true; | |
| 276 feedback_util::SendReport(this); | |
| 277 } | |
| 278 } | |
| OLD | NEW |