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/chromeos/system_logs/debug_daemon_log_source.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/files/file_util.h" 10 #include "base/logging.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/weak_ptr.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_util.h" 15 #include "chrome/browser/chromeos/profiles/profile_helper.h" 16 #include "chrome/common/chrome_switches.h" 17 #include "chromeos/dbus/dbus_thread_manager.h" 18 #include "chromeos/dbus/debug_daemon_client.h" 19 #include "components/user_manager/user.h" 20 #include "components/user_manager/user_manager.h" 21 #include "content/public/browser/browser_thread.h" 22 23 const char kNotAvailable[] = "<not available>"; 24 const char kRoutesKeyName[] = "routes"; 25 const char kNetworkStatusKeyName[] = "network-status"; 26 const char kModemStatusKeyName[] = "modem-status"; 27 const char kWiMaxStatusKeyName[] = "wimax-status"; 28 const char kUserLogFileKeyName[] = "user_log_files"; 29 30 namespace system_logs { 31 32 DebugDaemonLogSource::DebugDaemonLogSource(bool scrub) 33 : response_(new SystemLogsResponse()), 34 num_pending_requests_(0), 35 scrub_(scrub), 36 weak_ptr_factory_(this) {} 37 38 DebugDaemonLogSource::~DebugDaemonLogSource() {} 39 40 void DebugDaemonLogSource::Fetch(const SysLogsSourceCallback& callback) { 41 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 42 DCHECK(!callback.is_null()); 43 DCHECK(callback_.is_null()); 44 45 callback_ = callback; 46 chromeos::DebugDaemonClient* client = 47 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); 48 49 client->GetRoutes(true, // Numeric 50 false, // No IPv6 51 base::Bind(&DebugDaemonLogSource::OnGetRoutes, 52 weak_ptr_factory_.GetWeakPtr())); 53 ++num_pending_requests_; 54 client->GetNetworkStatus(base::Bind(&DebugDaemonLogSource::OnGetNetworkStatus, 55 weak_ptr_factory_.GetWeakPtr())); 56 ++num_pending_requests_; 57 client->GetModemStatus(base::Bind(&DebugDaemonLogSource::OnGetModemStatus, 58 weak_ptr_factory_.GetWeakPtr())); 59 ++num_pending_requests_; 60 client->GetWiMaxStatus(base::Bind(&DebugDaemonLogSource::OnGetWiMaxStatus, 61 weak_ptr_factory_.GetWeakPtr())); 62 ++num_pending_requests_; 63 client->GetUserLogFiles(base::Bind(&DebugDaemonLogSource::OnGetUserLogFiles, 64 weak_ptr_factory_.GetWeakPtr())); 65 ++num_pending_requests_; 66 67 if (scrub_) { 68 client->GetScrubbedLogs(base::Bind(&DebugDaemonLogSource::OnGetLogs, 69 weak_ptr_factory_.GetWeakPtr())); 70 } else { 71 client->GetAllLogs(base::Bind(&DebugDaemonLogSource::OnGetLogs, 72 weak_ptr_factory_.GetWeakPtr())); 73 } 74 ++num_pending_requests_; 75 } 76 77 void DebugDaemonLogSource::OnGetRoutes(bool succeeded, 78 const std::vector<std::string>& routes) { 79 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 80 81 if (succeeded) 82 (*response_)[kRoutesKeyName] = JoinString(routes, '\n'); 83 else 84 (*response_)[kRoutesKeyName] = kNotAvailable; 85 RequestCompleted(); 86 } 87 88 void DebugDaemonLogSource::OnGetNetworkStatus(bool succeeded, 89 const std::string& status) { 90 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 91 92 if (succeeded) 93 (*response_)[kNetworkStatusKeyName] = status; 94 else 95 (*response_)[kNetworkStatusKeyName] = kNotAvailable; 96 RequestCompleted(); 97 } 98 99 void DebugDaemonLogSource::OnGetModemStatus(bool succeeded, 100 const std::string& status) { 101 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 102 103 if (succeeded) 104 (*response_)[kModemStatusKeyName] = status; 105 else 106 (*response_)[kModemStatusKeyName] = kNotAvailable; 107 RequestCompleted(); 108 } 109 110 void DebugDaemonLogSource::OnGetWiMaxStatus(bool succeeded, 111 const std::string& status) { 112 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 113 114 if (succeeded) 115 (*response_)[kWiMaxStatusKeyName] = status; 116 else 117 (*response_)[kWiMaxStatusKeyName] = kNotAvailable; 118 RequestCompleted(); 119 } 120 121 void DebugDaemonLogSource::OnGetLogs(bool /* succeeded */, 122 const KeyValueMap& logs) { 123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 124 125 // We ignore 'succeeded' for this callback - we want to display as much of the 126 // debug info as we can even if we failed partway through parsing, and if we 127 // couldn't fetch any of it, none of the fields will even appear. 128 response_->insert(logs.begin(), logs.end()); 129 RequestCompleted(); 130 } 131 132 void DebugDaemonLogSource::OnGetUserLogFiles( 133 bool succeeded, 134 const KeyValueMap& user_log_files) { 135 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 136 if (succeeded) { 137 SystemLogsResponse* response = new SystemLogsResponse; 138 139 const user_manager::UserList& users = 140 user_manager::UserManager::Get()->GetLoggedInUsers(); 141 std::vector<base::FilePath> profile_dirs; 142 for (user_manager::UserList::const_iterator it = users.begin(); 143 it != users.end(); 144 ++it) { 145 if ((*it)->username_hash().empty()) 146 continue; 147 profile_dirs.push_back( 148 chromeos::ProfileHelper::GetProfilePathByUserIdHash( 149 (*it)->username_hash())); 150 } 151 152 content::BrowserThread::PostBlockingPoolTaskAndReply( 153 FROM_HERE, 154 base::Bind(&DebugDaemonLogSource::ReadUserLogFiles, 155 user_log_files, profile_dirs, response), 156 base::Bind(&DebugDaemonLogSource::MergeResponse, 157 weak_ptr_factory_.GetWeakPtr(), 158 base::Owned(response))); 159 } else { 160 (*response_)[kUserLogFileKeyName] = kNotAvailable; 161 RequestCompleted(); 162 } 163 } 164 165 // static 166 void DebugDaemonLogSource::ReadUserLogFiles( 167 const KeyValueMap& user_log_files, 168 const std::vector<base::FilePath>& profile_dirs, 169 SystemLogsResponse* response) { 170 for (size_t i = 0; i < profile_dirs.size(); ++i) { 171 std::string profile_prefix = "Profile[" + base::UintToString(i) + "] "; 172 for (KeyValueMap::const_iterator it = user_log_files.begin(); 173 it != user_log_files.end(); 174 ++it) { 175 std::string key = it->first; 176 std::string value; 177 std::string filename = it->second; 178 bool read_success = base::ReadFileToString( 179 profile_dirs[i].Append(filename), &value); 180 181 if (read_success && !value.empty()) 182 (*response)[profile_prefix + key] = value; 183 else 184 (*response)[profile_prefix + filename] = kNotAvailable; 185 } 186 } 187 } 188 189 void DebugDaemonLogSource::MergeResponse(SystemLogsResponse* response) { 190 for (SystemLogsResponse::const_iterator it = response->begin(); 191 it != response->end(); ++it) 192 response_->insert(*it); 193 RequestCompleted(); 194 } 195 196 void DebugDaemonLogSource::RequestCompleted() { 197 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 198 DCHECK(!callback_.is_null()); 199 200 --num_pending_requests_; 201 if (num_pending_requests_ > 0) 202 return; 203 callback_.Run(response_.get()); 204 } 205 206 } // namespace system_logs 207