1// Copyright 2014 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 "components/feedback/feedback_data.h"
6
7#include "base/bind.h"
8#include "base/files/file_util.h"
9#include "base/json/json_string_value_serializer.h"
10#include "base/memory/ref_counted_memory.h"
11#include "base/strings/string_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/values.h"
14#include "components/feedback/feedback_util.h"
15#include "components/feedback/tracing_manager.h"
16#include "content/public/browser/browser_thread.h"
17
18using content::BrowserThread;
19
20namespace feedback {
21namespace {
22
23const char kTraceFilename[] = "tracing.zip\n";
24const char kPerformanceCategoryTag[] = "Performance";
25
26const base::FilePath::CharType kHistogramsFilename[] =
27    FILE_PATH_LITERAL("histograms.txt");
28
29const char kHistogramsAttachmentName[] = "histograms.zip";
30
31}  // namespace
32
33FeedbackData::FeedbackData()
34    : send_report_(base::Bind(&feedback_util::SendReport)), context_(NULL),
35      trace_id_(0), pending_op_count_(1), report_sent_(false) {}
36
37FeedbackData::~FeedbackData() {
38}
39
40void FeedbackData::OnFeedbackPageDataComplete() {
41  pending_op_count_--;
42  SendReport();
43}
44
45void FeedbackData::SetAndCompressSystemInfo(
46    scoped_ptr<FeedbackData::SystemLogsMap> sys_info) {
47  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
48
49  if (trace_id_ != 0) {
50    TracingManager* manager = TracingManager::Get();
51    ++pending_op_count_;
52    if (!manager ||
53        !manager->GetTraceData(
54            trace_id_,
55            base::Bind(&FeedbackData::OnGetTraceData, this, trace_id_))) {
56      pending_op_count_--;
57      trace_id_ = 0;
58    }
59  }
60
61  if (sys_info.get()) {
62    ++pending_op_count_;
63    AddLogs(sys_info.Pass());
64    BrowserThread::PostBlockingPoolTaskAndReply(
65        FROM_HERE,
66        base::Bind(&FeedbackCommon::CompressLogs, this),
67        base::Bind(&FeedbackData::OnCompressComplete, this));
68  }
69}
70
71void FeedbackData::SetAndCompressHistograms(
72    scoped_ptr<std::string> histograms) {
73  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74
75  if (!histograms.get())
76    return;
77  ++pending_op_count_;
78  BrowserThread::PostBlockingPoolTaskAndReply(
79      FROM_HERE,
80      base::Bind(&FeedbackCommon::CompressFile,
81                 this,
82                 base::FilePath(kHistogramsFilename),
83                 kHistogramsAttachmentName,
84                 base::Passed(&histograms)),
85      base::Bind(&FeedbackData::OnCompressComplete, this));
86}
87
88void FeedbackData::AttachAndCompressFileData(
89    scoped_ptr<std::string> attached_filedata) {
90  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
91
92  if (!attached_filedata.get() || attached_filedata->empty())
93    return;
94  ++pending_op_count_;
95#if defined(OS_WIN)
96  base::FilePath attached_file(base::UTF8ToWide(attached_filename_));
97#else
98  base::FilePath attached_file(attached_filename_);
99#endif
100  BrowserThread::PostBlockingPoolTaskAndReply(
101      FROM_HERE,
102      base::Bind(&FeedbackCommon::CompressFile,
103                 this,
104                 attached_file,
105                 std::string(),
106                 base::Passed(&attached_filedata)),
107      base::Bind(&FeedbackData::OnCompressComplete, this));
108}
109
110void FeedbackData::OnGetTraceData(
111    int trace_id,
112    scoped_refptr<base::RefCountedString> trace_data) {
113  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114  TracingManager* manager = TracingManager::Get();
115  if (manager)
116    manager->DiscardTraceData(trace_id);
117
118  scoped_ptr<std::string> data(new std::string);
119  data->swap(trace_data->data());
120
121  AddFile(kTraceFilename, data.Pass());
122
123  set_category_tag(kPerformanceCategoryTag);
124  --pending_op_count_;
125  trace_id_ = 0;
126  SendReport();
127}
128
129void FeedbackData::OnCompressComplete() {
130  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
131  --pending_op_count_;
132  SendReport();
133}
134
135bool FeedbackData::IsDataComplete() {
136  return pending_op_count_ == 0;
137}
138
139void FeedbackData::SendReport() {
140  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141  if (IsDataComplete() && !report_sent_) {
142    report_sent_ = true;
143    send_report_.Run(this);
144  }
145}
146
147}  // namespace feedback
148