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 } 279