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