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