Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / caps / generate_state_json.cc
blob7c6df9f8b6c345b24f93eb2e25aff6f7cfcd4353
1 // Copyright 2015 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.
5 #include "chrome/browser/caps/generate_state_json.h"
7 #include <string>
8 #include <utility>
10 #include "base/bind.h"
11 #include "base/cpu.h"
12 #include "base/files/file.h"
13 #include "base/json/json_writer.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/sys_info.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "chrome/browser/task_manager/task_manager.h"
26 namespace {
28 std::string Key(base::ProcessId pid, const char* category) {
29 return category ?
30 base::StringPrintf("process.%d.%s", pid, category) :
31 base::StringPrintf("process.%d", pid);
34 using MemoryFn1 = bool (TaskManagerModel::*)(
35 int index, size_t* result1) const;
36 using MemoryFn2 = bool (TaskManagerModel::*)(
37 int index, size_t* result1, bool*) const;
39 int InMBFromB(size_t result_in_bytes) {
40 return static_cast<int>(result_in_bytes / (1024 * 1024));
43 int InMBFromB(const TaskManagerModel* model, MemoryFn1 mfn, int index) {
44 size_t result_in_bytes = 0;
45 bool res = (model->*mfn)(index, &result_in_bytes);
46 return res ? InMBFromB(result_in_bytes) : 0;
49 int InMBFromB(const TaskManagerModel* model, MemoryFn2 mfn, int index) {
50 size_t result_in_bytes = 0;
51 bool ignored;
52 bool res = (model->*mfn)(index, &result_in_bytes, &ignored);
53 return res ? InMBFromB(result_in_bytes) : 0;
56 class TaskManagerDataDumper :
57 public base::RefCountedThreadSafe<TaskManagerDataDumper> {
58 public:
59 TaskManagerDataDumper(scoped_refptr<TaskManagerModel> model,
60 base::File file)
61 : model_(model), file_(file.Pass()) {
62 model_->RegisterOnDataReadyCallback(
63 base::Bind(&TaskManagerDataDumper::OnDataReady, this));
64 model->StartListening();
65 // Note that GenerateStateJSON 'new's this object which is reference
66 // counted.
67 AddRef();
70 private:
71 friend class base::RefCountedThreadSafe<TaskManagerDataDumper>;
72 ~TaskManagerDataDumper() {
75 void OnDataReady() {
76 // Some data (for example V8 memory) has not yet arrived, so we wait.
77 // TODO(cpu): Figure out how to make this reliable.
78 static base::TimeDelta delay = base::TimeDelta::FromMilliseconds(250);
79 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
80 FROM_HERE, base::Bind(&TaskManagerDataDumper::OnDataReadyDelayed, this),
81 delay);
84 void OnDataReadyDelayed() {
85 model_->StopListening();
86 // Task manager finally computed (most) values. Lets generate the JSON
87 // data and send it over the pipe.
88 base::DictionaryValue dict;
89 GatherComputerValues(&dict);
90 GatherChromeValues(&dict);
92 std::string json;
93 auto options = base::JSONWriter::OPTIONS_PRETTY_PRINT;
94 if (!base::JSONWriter::WriteWithOptions(dict, options, &json))
95 return;
97 file_.WriteAtCurrentPos(json.c_str(), json.size());
98 file_.Close();
99 // this Release() causes our destruction.
100 Release();
103 private:
104 // TODO(cpu): split the key names below into a separate header that both
105 // caps and chrome can use.
107 void GatherComputerValues(base::DictionaryValue* dict) {
108 base::CPU cpu;
109 dict->SetInteger("system.cpu.type", cpu.type());
110 dict->SetInteger("system.cpu.family", cpu.family());
111 dict->SetInteger("system.cpu.model", cpu.model());
112 dict->SetInteger("system.cpu.stepping", cpu.stepping());
113 dict->SetString("system.cpu.brand", cpu.cpu_brand());
114 dict->SetInteger("system.cpu.logicalprocessors",
115 base::SysInfo::NumberOfProcessors());
116 dict->SetInteger("system.cpu.logicalprocessors",
117 base::SysInfo::NumberOfProcessors());
118 int64 memory = base::SysInfo::AmountOfPhysicalMemory();
119 dict->SetInteger("system.memory.physical", InMBFromB(memory));
120 memory = base::SysInfo::AmountOfAvailablePhysicalMemory();
121 dict->SetInteger("system.memory.available", InMBFromB(memory));
122 dict->SetInteger("system.uptime", base::SysInfo::Uptime() / 1000 );
123 dict->SetString("os.name", base::SysInfo::OperatingSystemName());
124 #if !defined(OS_LINUX)
125 int32 major, minor, bugfix;
126 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
127 dict->SetInteger("os.version.major", major);
128 dict->SetInteger("os.version.minor", minor);
129 dict->SetInteger("os.version.bugfix", bugfix);
130 dict->SetString("os.arch", base::SysInfo::OperatingSystemArchitecture());
131 #endif
134 void GatherChromeValues(base::DictionaryValue* dict) {
135 for (int index = 0; index != model_->ResourceCount(); ++index) {
136 auto pid = model_->GetProcessId(index);
137 auto tabs_key = Key(pid, "tabs");
138 base::ListValue* tabs;
139 if (!dict->GetList(tabs_key, &tabs)) {
140 tabs = new base::ListValue;
141 dict->Set(tabs_key, tabs);
142 tabs->AppendString(model_->GetResourceTitle(index));
144 dict->SetInteger(Key(pid, "memory.physical"),
145 InMBFromB(model_.get(),
146 &TaskManagerModel::GetPhysicalMemory, index));
147 dict->SetInteger(Key(pid, "memory.private"),
148 InMBFromB(model_.get(),
149 &TaskManagerModel::GetPrivateMemory, index));
150 dict->SetInteger(Key(pid, "memory.shared"),
151 InMBFromB(model_.get(),
152 &TaskManagerModel::GetSharedMemory, index));
153 dict->SetInteger(Key(pid, "memory.video"),
154 InMBFromB(model_.get(),
155 &TaskManagerModel::GetVideoMemory, index));
156 dict->SetInteger(Key(pid, "memory.V8.total"),
157 InMBFromB(model_.get(),
158 &TaskManagerModel::GetV8Memory, index));
159 dict->SetInteger(Key(pid, "memory.V8.used"),
160 InMBFromB(model_.get(),
161 &TaskManagerModel::GetV8MemoryUsed, index));
162 dict->SetInteger(Key(pid, "memory.sqlite"),
163 InMBFromB(model_.get(),
164 &TaskManagerModel::GetSqliteMemoryUsedBytes, index));
165 dict->SetString(Key(pid, "uptime"),
166 ProcessUptime(model_->GetProcess(index)));
167 } else {
168 // TODO(cpu): Probably best to write the MD5 hash of the title.
169 tabs->AppendString(model_->GetResourceTitle(index));
174 std::string ProcessUptime(base::ProcessHandle process) {
175 #if defined(OS_WIN)
176 FILETIME creation_time;
177 FILETIME exit_time;
178 FILETIME kernel_time;
179 FILETIME user_time;
181 if (!GetProcessTimes(process, &creation_time, &exit_time,
182 &kernel_time, &user_time))
183 return std::string("~");
185 auto ct_delta = base::Time::Now() - base::Time::FromFileTime(creation_time);
186 return base::StringPrintf("%lld", ct_delta.InSeconds());
187 #else
188 return std::string();
189 #endif
192 scoped_refptr<TaskManagerModel> model_;
193 base::File file_;
196 } // namespace
198 namespace caps {
200 void GenerateStateJSON(
201 scoped_refptr<TaskManagerModel> model, base::File file) {
202 new TaskManagerDataDumper(model, file.Pass());