Home | History | Annotate | Download | only in feedback
      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