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/values.h" 11 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/chromeos/settings/cros_settings.h" 13 #include "chrome/browser/feedback/feedback_util.h" 14 #include "chrome/browser/feedback/tracing_manager.h" 15 #include "chrome/browser/profiles/profile_manager.h" 16 #include "content/public/browser/browser_thread.h" 17 18 #if defined(USE_ASH) 19 #include "ash/shell.h" 20 #include "ash/shell_delegate.h" 21 #endif 22 23 using content::BrowserThread; 24 25 #if defined(OS_CHROMEOS) 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 char kTraceFilename[] = "tracing.log\n"; 33 34 std::string LogsToString(chromeos::SystemLogsResponse* sys_info) { 35 std::string syslogs_string; 36 for (chromeos::SystemLogsResponse::const_iterator it = sys_info->begin(); 37 it != sys_info->end(); ++it) { 38 std::string key = it->first; 39 std::string value = it->second; 40 41 TrimString(key, "\n ", &key); 42 TrimString(value, "\n ", &value); 43 44 if (value.find("\n") != std::string::npos) { 45 syslogs_string.append( 46 key + "=" + kMultilineIndicatorString + 47 kMultilineStartString + 48 value + "\n" + 49 kMultilineEndString); 50 } else { 51 syslogs_string.append(key + "=" + value + "\n"); 52 } 53 } 54 return syslogs_string; 55 } 56 57 void ZipLogs(chromeos::SystemLogsResponse* sys_info, 58 std::string* compressed_logs) { 59 DCHECK(compressed_logs); 60 std::string logs_string = LogsToString(sys_info); 61 if (!FeedbackUtil::ZipString(logs_string, compressed_logs)) { 62 compressed_logs->clear(); 63 } 64 } 65 66 } // namespace 67 #endif // OS_CHROMEOS 68 69 FeedbackData::FeedbackData() : profile_(NULL), 70 feedback_page_data_complete_(false) { 71 #if defined(OS_CHROMEOS) 72 sys_info_.reset(NULL); 73 trace_id_ = 0; 74 attached_filedata_.reset(NULL); 75 send_sys_info_ = true; 76 read_attached_file_complete_ = false; 77 syslogs_collection_complete_ = false; 78 #endif 79 } 80 81 FeedbackData::~FeedbackData() { 82 } 83 84 bool FeedbackData::DataCollectionComplete() { 85 #if defined(OS_CHROMEOS) 86 return (syslogs_collection_complete_ || !send_sys_info_) && 87 read_attached_file_complete_ && 88 feedback_page_data_complete_; 89 #else 90 return feedback_page_data_complete_; 91 #endif 92 } 93 void FeedbackData::SendReport() { 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 95 if (DataCollectionComplete()) 96 FeedbackUtil::SendReport(this); 97 } 98 99 void FeedbackData::FeedbackPageDataComplete() { 100 #if defined(OS_CHROMEOS) 101 if (trace_id_ != 0) { 102 TracingManager* manager = TracingManager::Get(); 103 // When there is a trace id attached to this report, fetch it and attach it 104 // as a file. In this case, return early and retry this function later. 105 if (manager && 106 manager->GetTraceData( 107 trace_id_, 108 base::Bind(&FeedbackData::OnGetTraceData, this))) { 109 return; 110 } else { 111 trace_id_ = 0; 112 } 113 } 114 if (attached_filename_.size() && 115 base::FilePath::IsSeparator(attached_filename_[0]) && 116 !attached_filedata_.get()) { 117 // Read the attached file and then send this report. The allocated string 118 // will be freed in FeedbackUtil::SendReport. 119 attached_filedata_.reset(new std::string); 120 121 base::FilePath root = 122 ash::Shell::GetInstance()->delegate()-> 123 GetCurrentBrowserContext()->GetPath(); 124 base::FilePath filepath = root.Append(attached_filename_.substr(1)); 125 attached_filename_ = filepath.BaseName().value(); 126 127 // Read the file into file_data, then call send report again with the 128 // stripped filename and file data (which will skip this code path). 129 content::BrowserThread::PostTaskAndReply( 130 content::BrowserThread::FILE, FROM_HERE, 131 base::Bind(&FeedbackData::ReadAttachedFile, this, filepath), 132 base::Bind(&FeedbackData::ReadFileComplete, this)); 133 } else { 134 read_attached_file_complete_ = true; 135 } 136 #endif 137 feedback_page_data_complete_ = true; 138 SendReport(); 139 } 140 141 #if defined(OS_CHROMEOS) 142 void FeedbackData::set_sys_info( 143 scoped_ptr<chromeos::SystemLogsResponse> sys_info) { 144 if (sys_info.get()) 145 CompressSyslogs(sys_info.Pass()); 146 } 147 148 void FeedbackData::CompressSyslogs( 149 scoped_ptr<chromeos::SystemLogsResponse> sys_info) { 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 151 152 // We get the pointer first since base::Passed will nullify the scoper, hence 153 // it's not safe to use <scoper>.get() as a parameter to PostTaskAndReply. 154 chromeos::SystemLogsResponse* sys_info_ptr = sys_info.get(); 155 std::string* compressed_logs_ptr = new std::string; 156 scoped_ptr<std::string> compressed_logs(compressed_logs_ptr); 157 BrowserThread::PostBlockingPoolTaskAndReply( 158 FROM_HERE, 159 base::Bind(&ZipLogs, 160 sys_info_ptr, 161 compressed_logs_ptr), 162 base::Bind(&FeedbackData::SyslogsComplete, 163 this, 164 base::Passed(&sys_info), 165 base::Passed(&compressed_logs))); 166 } 167 168 void FeedbackData::SyslogsComplete( 169 scoped_ptr<chromeos::SystemLogsResponse> sys_info, 170 scoped_ptr<std::string> compressed_logs) { 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 172 173 if (send_sys_info_) { 174 sys_info_ = sys_info.Pass(); 175 compressed_logs_ = compressed_logs.Pass(); 176 syslogs_collection_complete_ = true; 177 SendReport(); 178 } 179 } 180 181 void FeedbackData::ReadFileComplete() { 182 read_attached_file_complete_ = true; 183 SendReport(); 184 } 185 186 void FeedbackData::StartSyslogsCollection() { 187 chromeos::ScrubbedSystemLogsFetcher* fetcher = 188 new chromeos::ScrubbedSystemLogsFetcher(); 189 fetcher->Fetch(base::Bind(&FeedbackData::CompressSyslogs, this)); 190 } 191 192 // private 193 void FeedbackData::ReadAttachedFile(const base::FilePath& from) { 194 if (!file_util::ReadFileToString(from, attached_filedata_.get())) { 195 if (attached_filedata_.get()) 196 attached_filedata_->clear(); 197 } 198 } 199 200 void FeedbackData::OnGetTraceData( 201 scoped_refptr<base::RefCountedString> trace_data) { 202 scoped_ptr<std::string> data(new std::string(trace_data->data())); 203 204 set_attached_filename(kTraceFilename); 205 set_attached_filedata(data.Pass()); 206 trace_id_ = 0; 207 FeedbackPageDataComplete(); 208 } 209 210 #endif 211