OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ui/events/ozone/evdev/libgestures_glue/gesture_feedback.h" |
| 6 |
| 7 #include <time.h> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" |
| 11 #include "base/location.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/process/launch.h" |
| 14 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/string_util.h" |
| 16 #include "base/strings/stringprintf.h" |
| 17 #include "base/threading/worker_pool.h" |
| 18 #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h" |
| 19 |
| 20 namespace ui { |
| 21 |
| 22 namespace { |
| 23 |
| 24 // Binary paths. |
| 25 const char kGzipCommand[] = "/bin/gzip"; |
| 26 const char kDateCommand[] = "/bin/date"; |
| 27 |
| 28 const size_t kTouchLogTimestampMaxSize = 80; |
| 29 |
| 30 // Return the values in an array in one string. Used for touch logging. |
| 31 template <typename T> |
| 32 std::string DumpArrayProperty(const std::vector<T>& value, const char* format) { |
| 33 std::string ret; |
| 34 for (size_t i = 0; i < value.size(); ++i) { |
| 35 if (i > 0) |
| 36 ret.append(", "); |
| 37 ret.append(base::StringPrintf(format, value[i])); |
| 38 } |
| 39 return ret; |
| 40 } |
| 41 |
| 42 // Return the values in a gesture property in one string. Used for touch |
| 43 // logging. |
| 44 std::string DumpGesturePropertyValue(GesturesProp* property) { |
| 45 switch (property->type()) { |
| 46 case GesturePropertyProvider::PT_INT: |
| 47 return DumpArrayProperty(property->GetIntValue(), "%d"); |
| 48 break; |
| 49 case GesturePropertyProvider::PT_SHORT: |
| 50 return DumpArrayProperty(property->GetShortValue(), "%d"); |
| 51 break; |
| 52 case GesturePropertyProvider::PT_BOOL: |
| 53 return DumpArrayProperty(property->GetBoolValue(), "%d"); |
| 54 break; |
| 55 case GesturePropertyProvider::PT_STRING: |
| 56 return "\"" + property->GetStringValue() + "\""; |
| 57 break; |
| 58 case GesturePropertyProvider::PT_REAL: |
| 59 return DumpArrayProperty(property->GetDoubleValue(), "%lf"); |
| 60 break; |
| 61 default: |
| 62 NOTREACHED(); |
| 63 break; |
| 64 } |
| 65 return std::string(); |
| 66 } |
| 67 |
| 68 // Compress dumped event logs in place. |
| 69 void CompressDumpedLog(scoped_ptr<std::vector<std::string>> log_paths) { |
| 70 for (size_t i = 0; i < log_paths->size(); ++i) { |
| 71 // Zip the file. |
| 72 base::CommandLine command = base::CommandLine(base::FilePath(kGzipCommand)); |
| 73 command.AppendArg("-f"); |
| 74 command.AppendArg((*log_paths)[i]); |
| 75 std::string output; |
| 76 base::GetAppOutput(command, &output); |
| 77 |
| 78 // Replace the original file with the zipped one. |
| 79 base::Move(base::FilePath((*log_paths)[i] + ".gz"), |
| 80 base::FilePath((*log_paths)[i])); |
| 81 } |
| 82 } |
| 83 |
| 84 // Get the current time in a string. |
| 85 std::string GetCurrentTimeForLogging() { |
| 86 time_t rawtime; |
| 87 struct tm timeinfo; |
| 88 char buffer[kTouchLogTimestampMaxSize]; |
| 89 |
| 90 time(&rawtime); |
| 91 if (!localtime_r(&rawtime, &timeinfo)) { |
| 92 PLOG(ERROR) << "localtime_r failed"; |
| 93 return ""; |
| 94 } |
| 95 if (!strftime(buffer, kTouchLogTimestampMaxSize, "%Y%m%d-%H%M%S", &timeinfo)) |
| 96 return ""; |
| 97 return std::string(buffer); |
| 98 } |
| 99 |
| 100 // Canonize the device name for logging. |
| 101 std::string GetCanonicalDeviceName(const std::string& name) { |
| 102 std::string ret(name); |
| 103 for (size_t i = 0; i < ret.size(); ++i) |
| 104 if (!IsAsciiAlpha(ret[i])) |
| 105 ret[i] = '_'; |
| 106 return ret; |
| 107 } |
| 108 |
| 109 // Name event logs in a way that is compatible with existing toolchain. |
| 110 std::string GenerateEventLogName(GesturePropertyProvider* provider, |
| 111 const base::FilePath& out_dir, |
| 112 const std::string& prefix, |
| 113 const std::string& now, |
| 114 int id) { |
| 115 return out_dir.value() + "/" + prefix + now + "." + base::IntToString(id) + |
| 116 "." + GetCanonicalDeviceName(provider->GetDeviceNameById(id)); |
| 117 } |
| 118 |
| 119 // Set the logging properties to dump event logs. |
| 120 void StartToDumpEventLog(GesturePropertyProvider* provider, |
| 121 const int device_id) { |
| 122 // Dump gesture log. |
| 123 GesturesProp* property = provider->GetProperty(device_id, "Log Path"); |
| 124 property->SetStringValue(kTouchpadGestureLogPath); |
| 125 property = provider->GetProperty(device_id, "Logging Notify"); |
| 126 property->SetIntValue(std::vector<int>(1, 1)); |
| 127 |
| 128 // Dump evdev log. |
| 129 property = provider->GetProperty(device_id, "Dump Debug Log"); |
| 130 property->SetBoolValue(std::vector<bool>(1, true)); |
| 131 } |
| 132 |
| 133 } // namespace |
| 134 |
| 135 // Dump touch device property values to a string. |
| 136 void DumpTouchDeviceStatus(GesturePropertyProvider* provider, |
| 137 std::string* status) { |
| 138 // We use DT_ALL since we want gesture property values for all devices that |
| 139 // run with the gesture library, not just mice or touchpads. |
| 140 std::vector<int> ids; |
| 141 provider->GetDeviceIdsByType(DT_ALL, &ids); |
| 142 |
| 143 // Dump the property names and values for each device. |
| 144 for (size_t i = 0; i < ids.size(); ++i) { |
| 145 std::vector<std::string> names = provider->GetPropertyNamesById(ids[i]); |
| 146 status->append("\n"); |
| 147 status->append(base::StringPrintf("ID %d:\n", ids[i])); |
| 148 status->append(base::StringPrintf( |
| 149 "Device \'%s\':\n", provider->GetDeviceNameById(ids[i]).c_str())); |
| 150 |
| 151 // Note that, unlike X11, we don't maintain the "atom" concept here. |
| 152 // Therefore, the property name indices we output here shouldn't be treated |
| 153 // as unique identifiers of the properties. |
| 154 std::sort(names.begin(), names.end()); |
| 155 for (size_t j = 0; j < names.size(); ++j) { |
| 156 status->append(base::StringPrintf("\t%s (%zu):", names[j].c_str(), j)); |
| 157 GesturesProp* property = provider->GetProperty(ids[i], names[j]); |
| 158 status->append("\t" + DumpGesturePropertyValue(property) + '\n'); |
| 159 } |
| 160 } |
| 161 } |
| 162 |
| 163 // Dump touch event logs. |
| 164 void DumpTouchEventLog(GesturePropertyProvider* provider, |
| 165 const base::FilePath& out_dir, |
| 166 scoped_ptr<std::vector<base::FilePath>> log_paths, |
| 167 const GetTouchEventLogReply& reply) { |
| 168 // Get device ids. |
| 169 std::vector<int> ids; |
| 170 provider->GetDeviceIdsByType(DT_ALL, &ids); |
| 171 |
| 172 // Get current time stamp. |
| 173 std::string now = GetCurrentTimeForLogging(); |
| 174 |
| 175 // Dump event logs for gesture devices. |
| 176 scoped_ptr<std::vector<std::string>> log_paths_to_be_compressed( |
| 177 new std::vector<std::string>); |
| 178 for (size_t i = 0; i < ids.size(); ++i) { |
| 179 // First, see if the device actually uses the gesture library by checking |
| 180 // if it has any gesture property. |
| 181 std::vector<std::string> names = provider->GetPropertyNamesById(ids[i]); |
| 182 if (names.size() == 0) |
| 183 continue; |
| 184 |
| 185 // Set the logging properties to dump event logs. This needs to be done |
| 186 // synchronously for now or we might have race conditions on the debug |
| 187 // buffer. If the performance becomes a concern then, we can fork and |
| 188 // synchronize it. |
| 189 // |
| 190 // TODO(sheckylin): Make sure this has no performance impact for user |
| 191 // feedbacks. |
| 192 StartToDumpEventLog(provider, ids[i]); |
| 193 |
| 194 // Rename/move the file to another place since each device's log is |
| 195 // always dumped using the same name. |
| 196 std::string gesture_log_filename = GenerateEventLogName( |
| 197 provider, out_dir, "touchpad_activity_", now, ids[i]); |
| 198 base::Move(base::FilePath(kTouchpadGestureLogPath), |
| 199 base::FilePath(gesture_log_filename)); |
| 200 std::string evdev_log_filename = GenerateEventLogName( |
| 201 provider, out_dir, "cmt_input_events_", now, ids[i]); |
| 202 base::Move(base::FilePath(kTouchpadEvdevLogPath), |
| 203 base::FilePath(evdev_log_filename)); |
| 204 |
| 205 // Historically, we compress touchpad/mouse logs with gzip before tarring |
| 206 // them up. We DONT compress touchscreen logs though. |
| 207 log_paths_to_be_compressed->push_back(gesture_log_filename); |
| 208 log_paths->push_back(base::FilePath(gesture_log_filename)); |
| 209 log_paths_to_be_compressed->push_back(evdev_log_filename); |
| 210 log_paths->push_back(base::FilePath(evdev_log_filename)); |
| 211 } |
| 212 |
| 213 // Compress touchpad/mouse logs on another thread and return. |
| 214 base::WorkerPool::PostTaskAndReply( |
| 215 FROM_HERE, |
| 216 base::Bind(&CompressDumpedLog, base::Passed(&log_paths_to_be_compressed)), |
| 217 base::Bind(reply, base::Passed(&log_paths)), true /* task_is_slow */); |
| 218 } |
| 219 |
| 220 } // namespace ui |
OLD | NEW |