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"
10 #include "base/bind.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"
28 std::string
Key(base::ProcessId pid
, const char* 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;
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
> {
59 TaskManagerDataDumper(scoped_refptr
<TaskManagerModel
> model
,
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
71 friend class base::RefCountedThreadSafe
<TaskManagerDataDumper
>;
72 ~TaskManagerDataDumper() {
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),
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
);
93 auto options
= base::JSONWriter::OPTIONS_PRETTY_PRINT
;
94 if (!base::JSONWriter::WriteWithOptions(dict
, options
, &json
))
97 file_
.WriteAtCurrentPos(json
.c_str(), json
.size());
99 // this Release() causes our destruction.
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
) {
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());
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
)));
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
) {
176 FILETIME creation_time
;
178 FILETIME kernel_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());
188 return std::string();
192 scoped_refptr
<TaskManagerModel
> model_
;
200 void GenerateStateJSON(
201 scoped_refptr
<TaskManagerModel
> model
, base::File file
) {
202 new TaskManagerDataDumper(model
, file
.Pass());