1 // Copyright (c) 2013 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/chromeos/system_logs/touch_log_source.h"
7 #include "ash/touch/touch_hud_debug.h"
9 #include "base/bind_helpers.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_string_value_serializer.h"
15 #include "base/logging.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/process/launch.h"
18 #include "components/feedback/feedback_util.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "ui/ozone/public/input_controller.h"
21 #include "ui/ozone/public/ozone_platform.h"
23 using content::BrowserThread
;
27 const char kHUDLogDataKey
[] = "hud_log";
29 // The prefix "hack-33025" was historically chosen in http://crbug.com/139715.
30 // We continue to go with it in order to be compatible with the existing touch
31 // log processing toolchain.
32 const char kDeviceStatusLogDataKey
[] = "hack-33025-touchpad";
33 const char kTouchpadEventLogDataKey
[] = "hack-33025-touchpad_activity";
35 // Directory for temp touch event logs.
36 const char kTouchEventLogDir
[] = "/home/chronos/user/log";
38 // Prefixes of touch event logs.
39 const char kTouchpadGestureLogPrefix
[] = "touchpad_activity_";
40 const char kTouchpadEvdevLogPrefix
[] = "cmt_input_events_";
43 const char kShellCommand
[] = "/bin/sh";
44 const char kTarCommand
[] = "/bin/tar cf -";
45 const char kUuencodeCommand
[] = "/usr/bin/uuencode";
47 const int kMaxDeviceTouchEventLogs
= 7;
49 // Clean up intermediate log files dumped during feedback creation.
50 void CleanupEventLog(scoped_ptr
<std::vector
<base::FilePath
>> log_paths
) {
51 for (size_t i
= 0; i
< log_paths
->size(); ++i
)
52 base::DeleteFile((*log_paths
)[i
], false);
55 // Check for all known log paths and find the ones whose filenames match a
56 // prefix. Concatenate their filenames into one string. |max_log_count| is
57 // the maximum number of logs that we will collect.
59 // This is used to distinguish touchpad/mice logs from touchscreen logs.
60 std::string
GetEventLogListOfOnePrefix(
61 const std::vector
<base::FilePath
>& log_paths
,
62 const std::string
& prefix
,
63 const int max_log_count
) {
66 for (size_t i
= 0; i
< log_paths
.size(); ++i
) {
67 const std::string basename
= log_paths
[i
].BaseName().value();
68 if (StartsWithASCII(basename
, prefix
, true)) {
69 log_list
.append(" " + log_paths
[i
].value());
71 // Limit the max number of collected logs to shorten the log collection
73 if (++collected
>= max_log_count
)
81 // Pack the collected event logs in a way that is compatible with the log
83 void PackEventLog(system_logs::SystemLogsResponse
* response
,
84 scoped_ptr
<std::vector
<base::FilePath
>> log_paths
) {
85 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
87 // Combine logs with a command line call that tars them up and uuencode the
88 // result in one string. This is to be compatible with the X11 behavior.
89 std::vector
<std::pair
<std::string
, base::CommandLine
>> commands
;
90 base::CommandLine command
= base::CommandLine(base::FilePath(kShellCommand
));
91 command
.AppendArg("-c");
93 // Make a list that contains touchpad (and mouse) event logs only.
94 const std::string touchpad_log_list
=
95 GetEventLogListOfOnePrefix(*log_paths
, kTouchpadGestureLogPrefix
,
96 kMaxDeviceTouchEventLogs
) +
97 GetEventLogListOfOnePrefix(*log_paths
, kTouchpadEvdevLogPrefix
,
98 kMaxDeviceTouchEventLogs
);
99 command
.AppendArg(std::string(kTarCommand
) + touchpad_log_list
+
100 " 2>/dev/null | " + kUuencodeCommand
+
101 " -m touchpad_activity_log.tar");
102 commands
.push_back(std::make_pair(kTouchpadEventLogDataKey
, command
));
104 // For now only touchpad (and mouse) logs are actually collected.
105 for (size_t i
= 0; i
< commands
.size(); ++i
) {
107 base::GetAppOutput(commands
[i
].second
, &output
);
108 (*response
)[commands
[i
].first
] = output
;
111 // Cleanup these temporary log files.
112 BrowserThread::PostBlockingPoolTask(
113 FROM_HERE
, base::Bind(CleanupEventLog
, base::Passed(&log_paths
)));
116 // Callback for handing the outcome of GetTouchEventLog().
118 // This is the end of the whole touch log collection process.
119 void OnEventLogCollected(scoped_ptr
<system_logs::SystemLogsResponse
> response
,
120 const system_logs::SysLogsSourceCallback
& callback
,
121 scoped_ptr
<std::vector
<base::FilePath
>> log_paths
) {
122 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
124 // We cannot eliminate these temporaries and inline these closures because the
125 // compiler may call release() before get().
126 const base::Closure pack_closure
=
127 base::Bind(&PackEventLog
, base::Unretained(response
.get()),
128 base::Passed(&log_paths
));
129 const base::Closure callback_closure
=
130 base::Bind(callback
, base::Owned(response
.release()));
131 BrowserThread::PostBlockingPoolTaskAndReply(FROM_HERE
, pack_closure
,
135 // Callback for handing the outcome of GetTouchDeviceStatus().
137 // Appends the collected log to the SystemLogsResponse map. Also goes on to
138 // collect touch event logs.
139 void OnStatusLogCollected(scoped_ptr
<system_logs::SystemLogsResponse
> response
,
140 const system_logs::SysLogsSourceCallback
& callback
,
141 scoped_ptr
<std::string
> log
) {
142 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
143 (*response
)[kDeviceStatusLogDataKey
] = *log
;
145 // Collect touch event logs.
146 const base::FilePath
kBaseLogPath(kTouchEventLogDir
);
147 ui::OzonePlatform::GetInstance()->GetInputController()->GetTouchEventLog(
149 base::Bind(&OnEventLogCollected
, base::Passed(&response
), callback
));
152 // Collect touch HUD debug logs. This needs to be done on the UI thread.
153 void CollectTouchHudDebugLog(system_logs::SystemLogsResponse
* response
) {
154 scoped_ptr
<base::DictionaryValue
> dictionary
=
155 ash::TouchHudDebug::GetAllAsDictionary();
156 if (!dictionary
->empty()) {
157 std::string touch_log
;
158 JSONStringValueSerializer
json(&touch_log
);
159 json
.set_pretty_print(true);
160 if (json
.Serialize(*dictionary
) && !touch_log
.empty())
161 (*response
)[kHUDLogDataKey
] = touch_log
;
167 namespace system_logs
{
169 void TouchLogSource::Fetch(const SysLogsSourceCallback
& callback
) {
170 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
171 DCHECK(!callback
.is_null());
173 scoped_ptr
<SystemLogsResponse
> response(new SystemLogsResponse
);
174 CollectTouchHudDebugLog(response
.get());
176 // Collect touch device status logs.
177 ui::OzonePlatform::GetInstance()->GetInputController()->GetTouchDeviceStatus(
178 base::Bind(&OnStatusLogCollected
, base::Passed(&response
), callback
));
181 } // namespace system_logs