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/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/sys_info.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "base/time/time.h"
21 #include "base/values.h"
22 #include "chrome/browser/task_manager/task_manager.h"
26 std::string
Key(base::ProcessId pid
, const char* category
) {
28 base::StringPrintf("process.%d.%s", pid
, category
) :
29 base::StringPrintf("process.%d", pid
);
32 using MemoryFn1
= bool (TaskManagerModel::*)(
33 int index
, size_t* result1
) const;
34 using MemoryFn2
= bool (TaskManagerModel::*)(
35 int index
, size_t* result1
, bool*) const;
37 int InMBFromB(size_t result_in_bytes
) {
38 return static_cast<int>(result_in_bytes
/ (1024 * 1024));
41 int InMBFromB(const TaskManagerModel
* model
, MemoryFn1 mfn
, int index
) {
42 size_t result_in_bytes
= 0;
43 bool res
= (model
->*mfn
)(index
, &result_in_bytes
);
44 return res
? InMBFromB(result_in_bytes
) : 0;
47 int InMBFromB(const TaskManagerModel
* model
, MemoryFn2 mfn
, int index
) {
48 size_t result_in_bytes
= 0;
50 bool res
= (model
->*mfn
)(index
, &result_in_bytes
, &ignored
);
51 return res
? InMBFromB(result_in_bytes
) : 0;
54 class TaskManagerDataDumper
:
55 public base::RefCountedThreadSafe
<TaskManagerDataDumper
> {
57 TaskManagerDataDumper(scoped_refptr
<TaskManagerModel
> model
,
59 : model_(model
), file_(file
.Pass()) {
60 model_
->RegisterOnDataReadyCallback(
61 base::Bind(&TaskManagerDataDumper::OnDataReady
, this));
62 model
->StartListening();
63 // Note that GenerateStateJSON 'new's this object which is reference
69 friend class base::RefCountedThreadSafe
<TaskManagerDataDumper
>;
70 ~TaskManagerDataDumper() {
74 // Some data (for example V8 memory) has not yet arrived, so we wait.
75 // TODO(cpu): Figure out how to make this reliable.
76 static base::TimeDelta delay
= base::TimeDelta::FromMilliseconds(250);
77 base::MessageLoop::current()->PostDelayedTask(
79 base::Bind(&TaskManagerDataDumper::OnDataReadyDelayed
, this),
83 void OnDataReadyDelayed() {
84 model_
->StopListening();
85 // Task manager finally computed (most) values. Lets generate the JSON
86 // data and send it over the pipe.
87 base::DictionaryValue dict
;
88 GatherComputerValues(&dict
);
89 GatherChromeValues(&dict
);
92 auto options
= base::JSONWriter::OPTIONS_PRETTY_PRINT
;
93 if (!base::JSONWriter::WriteWithOptions(&dict
, options
, &json
))
96 file_
.WriteAtCurrentPos(json
.c_str(), json
.size());
98 // this Release() causes our destruction.
103 // TODO(cpu): split the key names below into a separate header that both
104 // caps and chrome can use.
106 void GatherComputerValues(base::DictionaryValue
* dict
) {
108 dict
->SetInteger("system.cpu.type", cpu
.type());
109 dict
->SetInteger("system.cpu.family", cpu
.family());
110 dict
->SetInteger("system.cpu.model", cpu
.model());
111 dict
->SetInteger("system.cpu.stepping", cpu
.stepping());
112 dict
->SetString("system.cpu.brand", cpu
.cpu_brand());
113 dict
->SetInteger("system.cpu.logicalprocessors",
114 base::SysInfo::NumberOfProcessors());
115 dict
->SetInteger("system.cpu.logicalprocessors",
116 base::SysInfo::NumberOfProcessors());
117 int64 memory
= base::SysInfo::AmountOfPhysicalMemory();
118 dict
->SetInteger("system.memory.physical", InMBFromB(memory
));
119 memory
= base::SysInfo::AmountOfAvailablePhysicalMemory();
120 dict
->SetInteger("system.memory.available", InMBFromB(memory
));
121 dict
->SetInteger("system.uptime", base::SysInfo::Uptime() / 1000 );
122 dict
->SetString("os.name", base::SysInfo::OperatingSystemName());
123 #if !defined(OS_LINUX)
124 int32 major
, minor
, bugfix
;
125 base::SysInfo::OperatingSystemVersionNumbers(&major
, &minor
, &bugfix
);
126 dict
->SetInteger("os.version.major", major
);
127 dict
->SetInteger("os.version.minor", minor
);
128 dict
->SetInteger("os.version.bugfix", bugfix
);
129 dict
->SetString("os.arch", base::SysInfo::OperatingSystemArchitecture());
133 void GatherChromeValues(base::DictionaryValue
* dict
) {
134 for (int index
= 0; index
!= model_
->ResourceCount(); ++index
) {
135 auto pid
= model_
->GetProcessId(index
);
136 auto tabs_key
= Key(pid
, "tabs");
137 base::ListValue
* tabs
;
138 if (!dict
->GetList(tabs_key
, &tabs
)) {
139 tabs
= new base::ListValue
;
140 dict
->Set(tabs_key
, tabs
);
141 tabs
->AppendString(model_
->GetResourceTitle(index
));
143 dict
->SetInteger(Key(pid
, "memory.physical"),
144 InMBFromB(model_
.get(),
145 &TaskManagerModel::GetPhysicalMemory
, index
));
146 dict
->SetInteger(Key(pid
, "memory.private"),
147 InMBFromB(model_
.get(),
148 &TaskManagerModel::GetPrivateMemory
, index
));
149 dict
->SetInteger(Key(pid
, "memory.shared"),
150 InMBFromB(model_
.get(),
151 &TaskManagerModel::GetSharedMemory
, index
));
152 dict
->SetInteger(Key(pid
, "memory.video"),
153 InMBFromB(model_
.get(),
154 &TaskManagerModel::GetVideoMemory
, index
));
155 dict
->SetInteger(Key(pid
, "memory.V8.total"),
156 InMBFromB(model_
.get(),
157 &TaskManagerModel::GetV8Memory
, index
));
158 dict
->SetInteger(Key(pid
, "memory.V8.used"),
159 InMBFromB(model_
.get(),
160 &TaskManagerModel::GetV8MemoryUsed
, index
));
161 dict
->SetInteger(Key(pid
, "memory.sqlite"),
162 InMBFromB(model_
.get(),
163 &TaskManagerModel::GetSqliteMemoryUsedBytes
, index
));
164 dict
->SetString(Key(pid
, "uptime"),
165 ProcessUptime(model_
->GetProcess(index
)));
167 // TODO(cpu): Probably best to write the MD5 hash of the title.
168 tabs
->AppendString(model_
->GetResourceTitle(index
));
173 std::string
ProcessUptime(base::ProcessHandle process
) {
175 FILETIME creation_time
;
177 FILETIME kernel_time
;
180 if (!GetProcessTimes(process
, &creation_time
, &exit_time
,
181 &kernel_time
, &user_time
))
182 return std::string("~");
184 auto ct_delta
= base::Time::Now() - base::Time::FromFileTime(creation_time
);
185 return base::StringPrintf("%lld", ct_delta
.InSeconds());
187 return std::string();
191 scoped_refptr
<TaskManagerModel
> model_
;
199 void GenerateStateJSON(
200 scoped_refptr
<TaskManagerModel
> model
, base::File file
) {
201 new TaskManagerDataDumper(model
, file
.Pass());