Index: ui/events/ozone/evdev/input_device_factory_evdev.cc |
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc |
index f215cd7c67e8dc24e63165ebcad98d103d7e0a7c..7ad1b4a40be0c9f101e278c7b45c2bf1e099206b 100644 |
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc |
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc |
@@ -6,7 +6,12 @@ |
#include <fcntl.h> |
#include <linux/input.h> |
+#include <locale> |
+#include "base/bind.h" |
+#include "base/command_line.h" |
+#include "base/files/file_util.h" |
+#include "base/process/launch.h" |
#include "base/stl_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/thread_task_runner_handle.h" |
@@ -35,6 +40,15 @@ namespace ui { |
namespace { |
+// Binary paths. |
+const char kGzipCommand[] = "/bin/gzip"; |
+const char kDateCommand[] = "/bin/date"; |
+ |
+// Touch event log paths. |
+const char kTouchpadGestureLogPath[] = |
+ "/var/log/xorg/touchpad_activity_log.txt"; |
+const char kTouchpadEvdevLogPath[] = "/var/log/xorg/cmt_input_events.dat"; |
spang
2015/02/02 21:43:16
Are you planning to make a ChromeOS change to crea
Shecky Lin
2015/02/03 08:20:14
Yeah, sorry, this is probably the problem I am run
Shecky Lin
2015/02/03 11:29:22
Just got a second thought on this. Could we instea
spang
2015/02/03 16:31:20
Yep, /tmp would work. If you want to use /var/log
Shecky Lin
2015/02/10 08:21:22
I decided to use /home/chronos/user/log/ directly.
|
+ |
typedef base::Callback<void(scoped_ptr<EventConverterEvdev>)> |
OpenInputDeviceReplyCallback; |
@@ -153,6 +167,115 @@ void DumpTouchDeviceStatus(GesturePropertyProvider* provider, |
} |
} |
} |
+ |
+// Compress dumped event logs in place. |
+void CompressDumpedLog(scoped_ptr<std::vector<std::string>> log_paths) { |
+ for (size_t i = 0; i < log_paths->size(); ++i) { |
+ // Zip the file. |
+ base::CommandLine command = base::CommandLine(base::FilePath(kGzipCommand)); |
+ command.AppendArg("-f"); |
+ command.AppendArg((*log_paths)[i]); |
+ std::string output; |
+ base::GetAppOutput(command, &output); |
+ |
+ // Replace the original file with the zipped one. |
+ base::Move(base::FilePath((*log_paths)[i] + ".gz"), |
+ base::FilePath((*log_paths)[i])); |
+ } |
+} |
+ |
+// Get the current time in a string. |
+// |
+// This is done by calling out to the 'date' binary so that the time format |
+// can be fully compatible with the X11 behavior. |
+std::string GetCurrentTimeForLogging() { |
+ base::CommandLine command = base::CommandLine(base::FilePath(kDateCommand)); |
+ command.AppendArg("+%Y%m%d-%H%M%S"); |
spang
2015/02/02 21:43:16
Does it make sense for this to be in local time wi
Shecky Lin
2015/02/03 08:20:14
I was just trying to do exactly the same thing in
spang
2015/02/03 16:31:20
Ok, "we don't actually care about the exact time"
|
+ std::string output; |
+ base::GetAppOutput(command, &output); |
spang
2015/02/02 21:43:16
Can't you use just "strftime" or similar? Should n
Shecky Lin
2015/02/03 08:20:14
Good idea. Will do. Thanks.
Shecky Lin
2015/02/10 08:21:22
Done.
|
+ return output; |
+} |
+ |
+// Canonize the device name for logging. |
+std::string GetCanonicalDeviceName(const std::string& name) { |
+ std::locale loc; |
+ std::string ret(name); |
+ for (size_t i = 0; i < ret.size(); ++i) |
+ if (!std::isalpha(ret[i], loc)) |
+ ret[i] = '_'; |
+ return ret; |
+} |
+ |
+std::string GenerateEventLogName(GesturePropertyProvider* provider, |
+ const base::FilePath& out_dir, |
+ const std::string& prefix, |
+ const std::string& now, |
+ int id) { |
+ return out_dir.MaybeAsASCII() + "/" + prefix + now + "." + |
+ std::to_string(id) + "." + |
+ GetCanonicalDeviceName(provider->GetDeviceNameById(id)); |
+} |
+ |
+// Dump touch event logs. |
+void DumpTouchEventLog(GesturePropertyProvider* provider, |
spang
2015/02/02 21:43:17
Can you move this function somewhere inside libges
Shecky Lin
2015/02/03 08:20:14
Yeah, make sense, will do.
Shecky Lin
2015/02/10 08:21:22
Done.
|
+ const base::FilePath& out_dir, |
+ scoped_ptr<std::vector<base::FilePath>> log_paths, |
+ const GetTouchEventLogReply& reply) { |
+ // Get device ids. |
+ std::vector<int> ids; |
+ provider->GetDeviceIdsByType(DT_ALL, &ids); |
+ |
+ // Get current time stamp. |
+ std::string now = GetCurrentTimeForLogging(); |
+ |
+ // Dump event logs for gesture devices. |
+ scoped_ptr<std::vector<std::string>> log_paths_to_be_compressed( |
spang
2015/02/02 21:43:17
I don't think you need a new vector here.
You sho
Shecky Lin
2015/02/03 08:20:14
No, this is not for recording the pointer. As said
spang
2015/02/03 16:31:20
Ah, ok.
|
+ new std::vector<std::string>); |
+ for (size_t i = 0; i < ids.size(); ++i) { |
+ // First, see if the device actually uses the gesture library by checking |
+ // if it has any gesture property. |
+ std::vector<std::string> names = provider->GetPropertyNamesById(ids[i]); |
+ if (names.size() == 0) |
+ continue; |
+ |
+ // Set the logging properties to dump event logs. This needs to be done |
+ // synchronously for now or we might have race conditions on the debug |
+ // buffer. If the performance becomes a concern then, we can fork and |
+ // synchronize it. |
+ // |
+ // TODO(sheckylin): Make sure this has no performance impact for user |
+ // feedbacks. |
+ GesturesProp* property = provider->GetProperty(ids[i], "Logging Notify"); |
+ property->SetIntValue(std::vector<int>(1, 1)); |
+ property = provider->GetProperty(ids[i], "Dump Debug Log"); |
+ property->SetBoolValue(std::vector<bool>(1, true)); |
+ |
+ // Rename/move the file to another place since each device's log is |
+ // always dumped using the same name. |
+ std::string gesture_log_filename = GenerateEventLogName( |
+ provider, out_dir, "touchpad_activity_", now, ids[i]); |
+ base::Move(base::FilePath(kTouchpadGestureLogPath), |
+ base::FilePath(gesture_log_filename)); |
+ std::string evdev_log_filename = GenerateEventLogName( |
+ provider, out_dir, "cmt_input_events_", now, ids[i]); |
+ base::Move(base::FilePath(kTouchpadEvdevLogPath), |
+ base::FilePath(evdev_log_filename)); |
+ |
+ // Historically, we compress touchpad/mouse logs with gzip before tarring |
+ // them up. We DONT compress touchscreen logs though. |
+ log_paths_to_be_compressed->push_back(gesture_log_filename); |
+ log_paths->push_back(base::FilePath(gesture_log_filename)); |
+ log_paths_to_be_compressed->push_back(evdev_log_filename); |
+ log_paths->push_back(base::FilePath(evdev_log_filename)); |
+ } |
+ |
+ // Compress touchpad/mouse logs on another thread and return. |
+ base::WorkerPool::PostTaskAndReply( |
+ FROM_HERE, |
+ base::Bind(&CompressDumpedLog, base::Passed(&log_paths_to_be_compressed)), |
+ base::Bind(reply, base::Passed(&log_paths)), true /* task_is_slow */); |
+} |
+ |
#endif |
scoped_ptr<EventConverterEvdev> CreateConverter( |
@@ -414,6 +537,19 @@ void InputDeviceFactoryEvdev::GetTouchDeviceStatus( |
reply.Run(status.Pass()); |
} |
+void InputDeviceFactoryEvdev::GetTouchEventLog( |
+ const base::FilePath& out_dir, |
+ const GetTouchEventLogReply& reply) { |
+ scoped_ptr<std::vector<base::FilePath>> log_paths( |
+ new std::vector<base::FilePath>); |
+#if defined(USE_EVDEV_GESTURES) |
+ DumpTouchEventLog(gesture_property_provider_.get(), out_dir, log_paths.Pass(), |
+ reply); |
+#else |
+ reply.Run(log_paths.Pass()); |
+#endif |
+} |
+ |
base::WeakPtr<InputDeviceFactoryEvdev> InputDeviceFactoryEvdev::GetWeakPtr() { |
return weak_ptr_factory_.GetWeakPtr(); |
} |