OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/metrics/metrics_log_serializer.h" | 5 #include "chrome/browser/metrics/metrics_log_serializer.h" |
6 | 6 |
7 #include <utility> | |
8 | |
7 #include "base/base64.h" | 9 #include "base/base64.h" |
8 #include "base/md5.h" | 10 #include "base/md5.h" |
9 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
10 #include "chrome/browser/browser_process.h" | 12 #include "chrome/browser/browser_process.h" |
11 #include "chrome/browser/prefs/pref_service.h" | 13 #include "chrome/browser/prefs/pref_service.h" |
12 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 14 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
13 #include "chrome/common/pref_names.h" | 15 #include "chrome/common/pref_names.h" |
14 | 16 |
17 namespace { | |
18 | |
15 // The number of "initial" logs we're willing to save, and hope to send during | 19 // The number of "initial" logs we're willing to save, and hope to send during |
16 // a future Chrome session. Initial logs contain crash stats, and are pretty | 20 // a future Chrome session. Initial logs contain crash stats, and are pretty |
17 // small. | 21 // small. |
18 static const size_t kMaxInitialLogsPersisted = 20; | 22 const size_t kMaxInitialLogsPersisted = 20; |
19 | 23 |
20 // The number of ongoing logs we're willing to save persistently, and hope to | 24 // The number of ongoing logs we're willing to save persistently, and hope to |
21 // send during a this or future sessions. Note that each log may be pretty | 25 // send during a this or future sessions. Note that each log may be pretty |
22 // large, as presumably the related "initial" log wasn't sent (probably nothing | 26 // large, as presumably the related "initial" log wasn't sent (probably nothing |
23 // was, as the user was probably off-line). As a result, the log probably kept | 27 // was, as the user was probably off-line). As a result, the log probably kept |
24 // accumulating while the "initial" log was stalled, and couldn't be sent. As a | 28 // accumulating while the "initial" log was stalled, and couldn't be sent. As a |
25 // result, we don't want to save too many of these mega-logs. | 29 // result, we don't want to save too many of these mega-logs. |
26 // A "standard shutdown" will create a small log, including just the data that | 30 // A "standard shutdown" will create a small log, including just the data that |
27 // was not yet been transmitted, and that is normal (to have exactly one | 31 // was not yet been transmitted, and that is normal (to have exactly one |
28 // ongoing_log_ at startup). | 32 // ongoing_log_ at startup). |
29 static const size_t kMaxOngoingLogsPersisted = 8; | 33 const size_t kMaxOngoingLogsPersisted = 8; |
30 | 34 |
31 // We append (2) more elements to persisted lists: the size of the list and a | 35 // We append (2) more elements to persisted lists: the size of the list and a |
32 // checksum of the elements. | 36 // checksum of the elements. |
33 static const size_t kChecksumEntryCount = 2; | 37 const size_t kChecksumEntryCount = 2; |
34 | 38 |
35 namespace { | |
36 // TODO(ziadh): This is here temporarily for a side experiment. Remove later | 39 // TODO(ziadh): This is here temporarily for a side experiment. Remove later |
37 // on. | 40 // on. |
38 enum LogStoreStatus { | 41 enum LogStoreStatus { |
39 STORE_SUCCESS, // Successfully presisted log. | 42 STORE_SUCCESS, // Successfully presisted log. |
40 ENCODE_FAIL, // Failed to encode log. | 43 ENCODE_FAIL, // Failed to encode log. |
41 COMPRESS_FAIL, // Failed to compress log. | 44 COMPRESS_FAIL, // Failed to compress log. |
42 END_STORE_STATUS // Number of bins to use to create the histogram. | 45 END_STORE_STATUS // Number of bins to use to create the histogram. |
43 }; | 46 }; |
44 | 47 |
45 MetricsLogSerializer::LogReadStatus MakeRecallStatusHistogram( | 48 MetricsLogSerializer::LogReadStatus MakeRecallStatusHistogram( |
46 MetricsLogSerializer::LogReadStatus status) { | 49 MetricsLogSerializer::LogReadStatus status) { |
47 UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecall", status, | 50 UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecall", status, |
48 MetricsLogSerializer::END_RECALL_STATUS); | 51 MetricsLogSerializer::END_RECALL_STATUS); |
49 return status; | 52 return status; |
50 } | 53 } |
51 | 54 |
52 // TODO(ziadh): Remove this when done with experiment. | 55 // TODO(ziadh): Remove this when done with experiment. |
53 void MakeStoreStatusHistogram(LogStoreStatus status) { | 56 void MakeStoreStatusHistogram(LogStoreStatus status) { |
54 UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogStore2", status, | 57 UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogStore2", status, |
55 END_STORE_STATUS); | 58 END_STORE_STATUS); |
56 } | 59 } |
60 | |
57 } // namespace | 61 } // namespace |
58 | 62 |
59 | 63 |
60 MetricsLogSerializer::MetricsLogSerializer() {} | 64 MetricsLogSerializer::MetricsLogSerializer() {} |
61 | 65 |
62 MetricsLogSerializer::~MetricsLogSerializer() {} | 66 MetricsLogSerializer::~MetricsLogSerializer() {} |
63 | 67 |
64 void MetricsLogSerializer::SerializeLogs(const std::vector<std::string>& logs, | 68 void MetricsLogSerializer::SerializeLogs( |
65 MetricsLogManager::LogType log_type) { | 69 const std::vector<std::pair<std::string, std::string> >& logs, |
70 MetricsLogManager::LogType log_type) { | |
66 PrefService* local_state = g_browser_process->local_state(); | 71 PrefService* local_state = g_browser_process->local_state(); |
67 DCHECK(local_state); | 72 DCHECK(local_state); |
68 const char* pref = NULL; | 73 const char* pref_xml = NULL; |
74 const char* pref_proto = NULL; | |
69 size_t max_store_count = 0; | 75 size_t max_store_count = 0; |
70 switch (log_type) { | 76 switch (log_type) { |
71 case MetricsLogManager::INITIAL_LOG: | 77 case MetricsLogManager::INITIAL_LOG: |
72 pref = prefs::kMetricsInitialLogs; | 78 pref_xml = prefs::kMetricsInitialLogsXml; |
79 pref_proto = prefs::kMetricsInitialLogsProto; | |
73 max_store_count = kMaxInitialLogsPersisted; | 80 max_store_count = kMaxInitialLogsPersisted; |
74 break; | 81 break; |
75 case MetricsLogManager::ONGOING_LOG: | 82 case MetricsLogManager::ONGOING_LOG: |
76 pref = prefs::kMetricsOngoingLogs; | 83 pref_xml = prefs::kMetricsOngoingLogsXml; |
84 pref_proto = prefs::kMetricsOngoingLogsProto; | |
77 max_store_count = kMaxOngoingLogsPersisted; | 85 max_store_count = kMaxOngoingLogsPersisted; |
78 break; | 86 break; |
79 default: | 87 default: |
80 NOTREACHED(); | 88 NOTREACHED(); |
81 return; | 89 return; |
82 }; | 90 }; |
83 ListPrefUpdate update(local_state, pref); | 91 |
84 ListValue* pref_list = update.Get(); | 92 std::vector<std::string> logs_xml(logs.size()); |
85 WriteLogsToPrefList(logs, max_store_count, pref_list); | 93 std::vector<std::string> logs_proto(logs.size()); |
94 for (size_t i = 0; i < logs.size(); ++i) { | |
95 logs_xml[i] = logs[i].first; | |
96 logs_proto[i] = logs[i].second; | |
97 } | |
98 | |
99 // Write the XML version. | |
100 ListPrefUpdate update_xml(local_state, pref_xml); | |
101 ListValue* pref_list_xml = update_xml.Get(); | |
102 WriteLogsToPrefList(logs_xml, max_store_count, pref_list_xml); | |
103 | |
104 // Write the protobuf version. | |
105 ListPrefUpdate update_proto(local_state, pref_proto); | |
106 ListValue* pref_list_proto = update_proto.Get(); | |
107 WriteLogsToPrefList(logs_proto, max_store_count, pref_list_proto); | |
86 } | 108 } |
87 | 109 |
88 void MetricsLogSerializer::DeserializeLogs(MetricsLogManager::LogType log_type, | 110 void MetricsLogSerializer::DeserializeLogs( |
89 std::vector<std::string>* logs) { | 111 MetricsLogManager::LogType log_type, |
112 std::vector<std::pair<std::string, std::string> >* logs) { | |
90 DCHECK(logs); | 113 DCHECK(logs); |
91 PrefService* local_state = g_browser_process->local_state(); | 114 PrefService* local_state = g_browser_process->local_state(); |
92 DCHECK(local_state); | 115 DCHECK(local_state); |
93 | 116 |
94 const char* pref = (log_type == MetricsLogManager::INITIAL_LOG) ? | 117 const char* pref_xml; |
95 prefs::kMetricsInitialLogs : prefs::kMetricsOngoingLogs; | 118 const char* pref_proto; |
96 const ListValue* unsent_logs = local_state->GetList(pref); | 119 if (log_type == MetricsLogManager::INITIAL_LOG) { |
97 ReadLogsFromPrefList(*unsent_logs, logs); | 120 pref_xml = prefs::kMetricsInitialLogsXml; |
121 pref_proto = prefs::kMetricsInitialLogsProto; | |
122 } else { | |
123 pref_xml = prefs::kMetricsOngoingLogsXml; | |
124 pref_proto = prefs::kMetricsOngoingLogsProto; | |
125 } | |
126 | |
127 const ListValue* unsent_logs_xml = local_state->GetList(pref_xml); | |
128 const ListValue* unsent_logs_proto = local_state->GetList(pref_proto); | |
129 std::vector<std::string> logs_xml; | |
130 std::vector<std::string> logs_proto; | |
131 // TODO(isherman): Error reporting... | |
Ilya Sherman
2012/01/28 08:17:20
(Will address this TODO and the others in this fil
| |
132 ReadLogsFromPrefList(*unsent_logs_xml, &logs_xml); | |
133 ReadLogsFromPrefList(*unsent_logs_proto, &logs_proto); | |
134 | |
135 if (logs_xml.size() != logs_proto.size()) { | |
136 // TODO(isherman): ... | |
137 return; | |
138 } | |
139 | |
140 logs->resize(logs_xml.size()); | |
141 for (size_t i = 0; i < logs->size(); ++i) { | |
142 (*logs)[i] = std::make_pair(logs_xml[i], logs_proto[i]); | |
143 } | |
98 } | 144 } |
99 | 145 |
100 // static | 146 // static |
101 void MetricsLogSerializer::WriteLogsToPrefList( | 147 void MetricsLogSerializer::WriteLogsToPrefList( |
102 const std::vector<std::string>& local_list, | 148 const std::vector<std::string>& local_list, |
103 const size_t kMaxLocalListSize, | 149 const size_t kMaxLocalListSize, |
104 ListValue* list) { | 150 ListValue* list) { |
105 list->Clear(); | 151 list->Clear(); |
106 size_t start = 0; | 152 size_t start = 0; |
107 if (local_list.size() > kMaxLocalListSize) | 153 if (local_list.size() > kMaxLocalListSize) |
108 start = local_list.size() - kMaxLocalListSize; | 154 start = local_list.size() - kMaxLocalListSize; |
109 DCHECK(start <= local_list.size()); | 155 DCHECK_LE(start, local_list.size()); |
110 if (local_list.size() <= start) | 156 if (local_list.size() <= start) |
111 return; | 157 return; |
112 | 158 |
113 // Store size at the beginning of the list. | 159 // Store size at the beginning of the list. |
114 list->Append(Value::CreateIntegerValue(local_list.size() - start)); | 160 list->Append(Value::CreateIntegerValue(local_list.size() - start)); |
115 | 161 |
116 base::MD5Context ctx; | 162 base::MD5Context ctx; |
117 base::MD5Init(&ctx); | 163 base::MD5Init(&ctx); |
118 std::string encoded_log; | 164 std::string encoded_log; |
119 for (std::vector<std::string>::const_iterator it = local_list.begin() + start; | 165 for (std::vector<std::string>::const_iterator it = local_list.begin() + start; |
120 it != local_list.end(); ++it) { | 166 it != local_list.end(); ++it) { |
121 // We encode the compressed log as Value::CreateStringValue() expects to | 167 // We encode the compressed log as Value::CreateStringValue() expects to |
122 // take a valid UTF8 string. | 168 // take a valid UTF8 string. |
123 if (!base::Base64Encode(*it, &encoded_log)) { | 169 if (!base::Base64Encode(*it, &encoded_log)) { |
170 // TODO(isherman): Is it ok for xml and protobuf encoding failures to mix? | |
124 MakeStoreStatusHistogram(ENCODE_FAIL); | 171 MakeStoreStatusHistogram(ENCODE_FAIL); |
125 list->Clear(); | 172 list->Clear(); |
126 return; | 173 return; |
127 } | 174 } |
128 base::MD5Update(&ctx, encoded_log); | 175 base::MD5Update(&ctx, encoded_log); |
129 list->Append(Value::CreateStringValue(encoded_log)); | 176 list->Append(Value::CreateStringValue(encoded_log)); |
130 } | 177 } |
131 | 178 |
132 // Append hash to the end of the list. | 179 // Append hash to the end of the list. |
133 base::MD5Digest digest; | 180 base::MD5Digest digest; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
189 if (!valid) { | 236 if (!valid) { |
190 local_list->clear(); | 237 local_list->clear(); |
191 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); | 238 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); |
192 } | 239 } |
193 if (recovered_md5 != base::MD5DigestToBase16(digest)) { | 240 if (recovered_md5 != base::MD5DigestToBase16(digest)) { |
194 local_list->clear(); | 241 local_list->clear(); |
195 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); | 242 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); |
196 } | 243 } |
197 return MakeRecallStatusHistogram(RECALL_SUCCESS); | 244 return MakeRecallStatusHistogram(RECALL_SUCCESS); |
198 } | 245 } |
OLD | NEW |