1 // Copyright (c) 2012 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 "chrome/common/child_process_logging.h" 6 7 #import <Foundation/Foundation.h> 8 9 #include "base/command_line.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_split.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/strings/sys_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "chrome/common/metrics/variations/variations_util.h" 17 #include "chrome/installer/util/google_update_settings.h" 18 #include "gpu/config/gpu_info.h" 19 #include "url/gurl.h" 20 21 namespace child_process_logging { 22 23 using base::debug::SetCrashKeyValueFuncT; 24 using base::debug::ClearCrashKeyValueFuncT; 25 using base::debug::SetCrashKeyValue; 26 using base::debug::ClearCrashKey; 27 28 const size_t kMaxNumCrashURLChunks = 8; 29 const size_t kMaxNumURLChunkValueLength = 255; 30 const char* kUrlChunkFormatStr = "url-chunk-%d"; 31 const char* kGuidParamName = "guid"; 32 const char* kGPUVendorIdParamName = "gpu-venid"; 33 const char* kGPUDeviceIdParamName = "gpu-devid"; 34 const char* kGPUDriverVersionParamName = "gpu-driver"; 35 const char* kGPUPixelShaderVersionParamName = "gpu-psver"; 36 const char* kGPUVertexShaderVersionParamName = "gpu-vsver"; 37 const char* kGPUGLVersionParamName = "gpu-glver"; 38 const char* kNumberOfViews = "num-views"; 39 const char* kNumExtensionsName = "num-extensions"; 40 const char* kExtensionNameFormat = "extension-%zu"; 41 const char* kPrinterInfoNameFormat = "prn-info-%zu"; 42 43 // Account for the terminating null character. 44 static const size_t kClientIdSize = 32 + 1; 45 static char g_client_id[kClientIdSize]; 46 47 void SetActiveURLImpl(const GURL& url, 48 SetCrashKeyValueFuncT set_key_func, 49 ClearCrashKeyValueFuncT clear_key_func) { 50 // First remove any old url chunks we might have lying around. 51 for (size_t i = 0; i < kMaxNumCrashURLChunks; i++) { 52 // On Windows the url-chunk items are 1-based, so match that. 53 clear_key_func(base::StringPrintf(kUrlChunkFormatStr, i + 1)); 54 } 55 56 const std::string& raw_url = url.possibly_invalid_spec(); 57 size_t raw_url_length = raw_url.length(); 58 59 // Bail on zero-length URLs. 60 if (raw_url_length == 0) { 61 return; 62 } 63 64 // Parcel the URL up into up to 8, 255 byte segments. 65 size_t offset = 0; 66 for (size_t i = 0; 67 i < kMaxNumCrashURLChunks && offset < raw_url_length; 68 ++i) { 69 70 // On Windows the url-chunk items are 1-based, so match that. 71 std::string key = base::StringPrintf(kUrlChunkFormatStr, i + 1); 72 size_t length = std::min(kMaxNumURLChunkValueLength, 73 raw_url_length - offset); 74 std::string value = raw_url.substr(offset, length); 75 set_key_func(key, value); 76 77 // Next chunk. 78 offset += kMaxNumURLChunkValueLength; 79 } 80 } 81 82 void SetClientIdImpl(const std::string& client_id, 83 SetCrashKeyValueFuncT set_key_func) { 84 set_key_func(kGuidParamName, client_id); 85 } 86 87 void SetActiveURL(const GURL& url) { 88 SetActiveURLImpl(url, SetCrashKeyValue, ClearCrashKey); 89 } 90 91 void SetClientId(const std::string& client_id) { 92 std::string str(client_id); 93 ReplaceSubstringsAfterOffset(&str, 0, "-", ""); 94 95 base::strlcpy(g_client_id, str.c_str(), kClientIdSize); 96 SetClientIdImpl(str, SetCrashKeyValue); 97 98 std::wstring wstr = ASCIIToWide(str); 99 GoogleUpdateSettings::SetMetricsId(wstr); 100 } 101 102 std::string GetClientId() { 103 return std::string(g_client_id); 104 } 105 106 void SetActiveExtensions(const std::set<std::string>& extension_ids) { 107 // Log the count separately to track heavy users. 108 const int count = static_cast<int>(extension_ids.size()); 109 SetCrashKeyValue(kNumExtensionsName, base::IntToString(count)); 110 111 // Record up to |kMaxReportedActiveExtensions| extensions, clearing 112 // keys if there aren't that many. 113 std::set<std::string>::const_iterator iter = extension_ids.begin(); 114 for (size_t i = 0; i < kMaxReportedActiveExtensions; ++i) { 115 std::string key = base::StringPrintf(kExtensionNameFormat, i); 116 if (iter != extension_ids.end()) { 117 SetCrashKeyValue(key, *iter); 118 ++iter; 119 } else { 120 ClearCrashKey(key); 121 } 122 } 123 } 124 125 void SetGpuKeyValue(const char* param_name, const std::string& value_str, 126 SetCrashKeyValueFuncT set_key_func) { 127 set_key_func(param_name, value_str); 128 } 129 130 void SetGpuInfoImpl(const gpu::GPUInfo& gpu_info, 131 SetCrashKeyValueFuncT set_key_func) { 132 SetGpuKeyValue(kGPUVendorIdParamName, 133 base::StringPrintf("0x%04x", gpu_info.gpu.vendor_id), 134 set_key_func); 135 SetGpuKeyValue(kGPUDeviceIdParamName, 136 base::StringPrintf("0x%04x", gpu_info.gpu.device_id), 137 set_key_func); 138 SetGpuKeyValue(kGPUDriverVersionParamName, 139 gpu_info.driver_version, 140 set_key_func); 141 SetGpuKeyValue(kGPUPixelShaderVersionParamName, 142 gpu_info.pixel_shader_version, 143 set_key_func); 144 SetGpuKeyValue(kGPUVertexShaderVersionParamName, 145 gpu_info.vertex_shader_version, 146 set_key_func); 147 SetGpuKeyValue(kGPUGLVersionParamName, 148 gpu_info.gl_version, 149 set_key_func); 150 } 151 152 void SetGpuInfo(const gpu::GPUInfo& gpu_info) { 153 SetGpuInfoImpl(gpu_info, SetCrashKeyValue); 154 } 155 156 void SetPrinterInfo(const char* printer_info) { 157 std::vector<std::string> info; 158 base::SplitString(printer_info, ';', &info); 159 info.resize(kMaxReportedPrinterRecords); 160 for (size_t i = 0; i < info.size(); ++i) { 161 std::string key = base::StringPrintf(kPrinterInfoNameFormat, i); 162 if (!info[i].empty()) { 163 SetCrashKeyValue(key, info[i]); 164 } else { 165 ClearCrashKey(key); 166 } 167 } 168 } 169 170 void SetNumberOfViewsImpl(int number_of_views, 171 SetCrashKeyValueFuncT set_key_func) { 172 std::string value = base::IntToString(number_of_views); 173 set_key_func(kNumberOfViews, value); 174 } 175 176 void SetNumberOfViews(int number_of_views) { 177 SetNumberOfViewsImpl(number_of_views, SetCrashKeyValue); 178 } 179 180 void SetCommandLine(const CommandLine* command_line) { 181 DCHECK(command_line); 182 if (!command_line) 183 return; 184 185 // These should match the corresponding strings in breakpad_win.cc. 186 const char* kNumSwitchesKey = "num-switches"; 187 const char* kSwitchKeyFormat = "switch-%zu"; // 1-based. 188 189 // Note the total number of switches, not including the exec path. 190 const CommandLine::StringVector& argv = command_line->argv(); 191 SetCrashKeyValue(kNumSwitchesKey, 192 base::StringPrintf("%zu", argv.size() - 1)); 193 194 size_t key_i = 0; 195 for (size_t i = 1; i < argv.size() && key_i < kMaxSwitches; ++i, ++key_i) { 196 // TODO(shess): Skip boring switches. 197 std::string key = base::StringPrintf(kSwitchKeyFormat, key_i + 1); 198 SetCrashKeyValue(key, argv[i]); 199 } 200 201 // Clear out any stale keys. 202 for (; key_i < kMaxSwitches; ++key_i) { 203 std::string key = base::StringPrintf(kSwitchKeyFormat, key_i + 1); 204 ClearCrashKey(key); 205 } 206 } 207 208 void SetExperimentList(const std::vector<string16>& experiments) { 209 // These should match the corresponding strings in breakpad_win.cc. 210 const char* kNumExperimentsKey = "num-experiments"; 211 const char* kExperimentChunkFormat = "experiment-chunk-%zu"; // 1-based 212 213 std::vector<string16> chunks; 214 chrome_variations::GenerateVariationChunks(experiments, &chunks); 215 216 // Store up to |kMaxReportedVariationChunks| chunks. 217 for (size_t i = 0; i < kMaxReportedVariationChunks; ++i) { 218 std::string key = base::StringPrintf(kExperimentChunkFormat, i + 1); 219 if (i < chunks.size()) { 220 std::string value = UTF16ToUTF8(chunks[i]); 221 SetCrashKeyValue(key, value); 222 } else { 223 ClearCrashKey(key); 224 } 225 } 226 227 // Make note of the total number of experiments, which may be greater than 228 // what was able to fit in |kMaxReportedVariationChunks|. This is useful when 229 // correlating stability with the number of experiments running 230 // simultaneously. 231 SetCrashKeyValue(kNumExperimentsKey, 232 base::StringPrintf("%zu", experiments.size())); 233 } 234 235 void SetChannel(const std::string& channel) { 236 // This should match the corresponding string in breakpad_win.cc. 237 const std::string kChannelKey = "channel"; 238 SetCrashKeyValue(kChannelKey, channel); 239 } 240 241 } // namespace child_process_logging 242