OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <string> | |
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 "base/prefs/pref_service.h" | 12 #include "base/prefs/pref_service.h" |
11 #include "chrome/browser/browser_process.h" | 13 #include "chrome/browser/browser_process.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 |
15 namespace { | 17 namespace { |
16 | 18 |
(...skipping 28 matching lines...) Expand all Loading... | |
45 return status; | 47 return status; |
46 } | 48 } |
47 | 49 |
48 } // namespace | 50 } // namespace |
49 | 51 |
50 | 52 |
51 MetricsLogSerializer::MetricsLogSerializer() {} | 53 MetricsLogSerializer::MetricsLogSerializer() {} |
52 | 54 |
53 MetricsLogSerializer::~MetricsLogSerializer() {} | 55 MetricsLogSerializer::~MetricsLogSerializer() {} |
54 | 56 |
55 void MetricsLogSerializer::SerializeLogs(const std::vector<std::string>& logs, | 57 void MetricsLogSerializer::SerializeLogs( |
56 MetricsLogManager::LogType log_type) { | 58 const std::vector<MetricsLogManager::SerializedLog>& logs, |
59 MetricsLogManager::LogType log_type) { | |
57 PrefService* local_state = g_browser_process->local_state(); | 60 PrefService* local_state = g_browser_process->local_state(); |
58 DCHECK(local_state); | 61 DCHECK(local_state); |
59 const char* pref = NULL; | 62 const char* pref = NULL; |
60 size_t store_length_limit = 0; | 63 size_t store_length_limit = 0; |
61 switch (log_type) { | 64 switch (log_type) { |
62 case MetricsLogManager::INITIAL_LOG: | 65 case MetricsLogManager::INITIAL_LOG: |
63 pref = prefs::kMetricsInitialLogs; | 66 pref = prefs::kMetricsInitialLogs; |
64 store_length_limit = kInitialLogsPersistLimit; | 67 store_length_limit = kInitialLogsPersistLimit; |
65 break; | 68 break; |
66 case MetricsLogManager::ONGOING_LOG: | 69 case MetricsLogManager::ONGOING_LOG: |
67 pref = prefs::kMetricsOngoingLogs; | 70 pref = prefs::kMetricsOngoingLogs; |
68 store_length_limit = kOngoingLogsPersistLimit; | 71 store_length_limit = kOngoingLogsPersistLimit; |
69 break; | 72 break; |
70 case MetricsLogManager::NO_LOG: | 73 case MetricsLogManager::NO_LOG: |
71 NOTREACHED(); | 74 NOTREACHED(); |
72 return; | 75 return; |
73 }; | 76 }; |
74 | 77 |
75 ListPrefUpdate update(local_state, pref); | 78 ListPrefUpdate update(local_state, pref); |
76 WriteLogsToPrefList(logs, store_length_limit, kStorageByteLimitPerLogType, | 79 WriteLogsToPrefList(logs, store_length_limit, kStorageByteLimitPerLogType, |
77 update.Get()); | 80 update.Get()); |
78 } | 81 } |
79 | 82 |
80 void MetricsLogSerializer::DeserializeLogs(MetricsLogManager::LogType log_type, | 83 void MetricsLogSerializer::DeserializeLogs( |
81 std::vector<std::string>* logs) { | 84 MetricsLogManager::LogType log_type, |
85 std::vector<MetricsLogManager::SerializedLog>* logs) { | |
82 DCHECK(logs); | 86 DCHECK(logs); |
83 PrefService* local_state = g_browser_process->local_state(); | 87 PrefService* local_state = g_browser_process->local_state(); |
84 DCHECK(local_state); | 88 DCHECK(local_state); |
85 | 89 |
86 const char* pref; | 90 const char* pref; |
87 if (log_type == MetricsLogManager::INITIAL_LOG) | 91 if (log_type == MetricsLogManager::INITIAL_LOG) |
88 pref = prefs::kMetricsInitialLogs; | 92 pref = prefs::kMetricsInitialLogs; |
89 else | 93 else |
90 pref = prefs::kMetricsOngoingLogs; | 94 pref = prefs::kMetricsOngoingLogs; |
91 | 95 |
92 const ListValue* unsent_logs = local_state->GetList(pref); | 96 const ListValue* unsent_logs = local_state->GetList(pref); |
93 ReadLogsFromPrefList(*unsent_logs, logs); | 97 ReadLogsFromPrefList(*unsent_logs, logs); |
94 } | 98 } |
95 | 99 |
96 // static | 100 // static |
97 void MetricsLogSerializer::WriteLogsToPrefList( | 101 void MetricsLogSerializer::WriteLogsToPrefList( |
98 const std::vector<std::string>& local_list, | 102 const std::vector<MetricsLogManager::SerializedLog>& local_list, |
99 size_t list_length_limit, | 103 size_t list_length_limit, |
100 size_t byte_limit, | 104 size_t byte_limit, |
101 base::ListValue* list) { | 105 base::ListValue* list) { |
102 // One of the limit arguments must be non-zero. | 106 // One of the limit arguments must be non-zero. |
103 DCHECK(list_length_limit > 0 || byte_limit > 0); | 107 DCHECK(list_length_limit > 0 || byte_limit > 0); |
104 | 108 |
105 list->Clear(); | 109 list->Clear(); |
106 if (local_list.size() == 0) | 110 if (local_list.size() == 0) |
107 return; | 111 return; |
108 | 112 |
109 size_t start = 0; | 113 size_t start = 0; |
110 // If there are too many logs, keep the most recent logs up to the length | 114 // If there are too many logs, keep the most recent logs up to the length |
111 // limit, and at least to the minimum number of bytes. | 115 // limit, and at least to the minimum number of bytes. |
112 if (local_list.size() > list_length_limit) { | 116 if (local_list.size() > list_length_limit) { |
113 start = local_list.size(); | 117 start = local_list.size(); |
114 size_t bytes_used = 0; | 118 size_t bytes_used = 0; |
115 for (std::vector<std::string>::const_reverse_iterator | 119 for (std::vector<MetricsLogManager::SerializedLog>::const_reverse_iterator |
116 it = local_list.rbegin(); it != local_list.rend(); ++it) { | 120 it = local_list.rbegin(); it != local_list.rend(); ++it) { |
117 size_t log_size = it->length(); | 121 size_t log_size = it->log_text.length(); |
118 if (bytes_used >= byte_limit && | 122 if (bytes_used >= byte_limit && |
119 (local_list.size() - start) >= list_length_limit) | 123 (local_list.size() - start) >= list_length_limit) |
120 break; | 124 break; |
121 bytes_used += log_size; | 125 bytes_used += log_size; |
122 --start; | 126 --start; |
123 } | 127 } |
124 } | 128 } |
125 DCHECK_LT(start, local_list.size()); | 129 DCHECK_LT(start, local_list.size()); |
126 if (start >= local_list.size()) | 130 if (start >= local_list.size()) |
127 return; | 131 return; |
128 | 132 |
129 // Store size at the beginning of the list. | 133 // Store size at the beginning of the list. |
130 list->Append(Value::CreateIntegerValue(local_list.size() - start)); | 134 list->Append(Value::CreateIntegerValue(local_list.size() - start)); |
131 | 135 |
132 base::MD5Context ctx; | 136 base::MD5Context ctx; |
133 base::MD5Init(&ctx); | 137 base::MD5Init(&ctx); |
134 std::string encoded_log; | 138 std::string encoded_log; |
135 for (std::vector<std::string>::const_iterator it = local_list.begin() + start; | 139 std::vector<MetricsLogManager::SerializedLog>::const_iterator it; |
Ilya Sherman
2013/10/16 18:26:14
nit: Please keep this scoped within the for loop.
Alexei Svitkine (slow)
2013/10/16 19:31:46
Done.
| |
136 it != local_list.end(); ++it) { | 140 for (it = local_list.begin() + start; it != local_list.end(); ++it) { |
137 // We encode the compressed log as Value::CreateStringValue() expects to | 141 // We encode the compressed log as Value::CreateStringValue() expects to |
138 // take a valid UTF8 string. | 142 // take a valid UTF8 string. |
139 if (!base::Base64Encode(*it, &encoded_log)) { | 143 if (!base::Base64Encode(it->log_text, &encoded_log)) { |
140 list->Clear(); | 144 list->Clear(); |
141 return; | 145 return; |
142 } | 146 } |
143 base::MD5Update(&ctx, encoded_log); | 147 base::MD5Update(&ctx, encoded_log); |
144 list->Append(Value::CreateStringValue(encoded_log)); | 148 list->Append(Value::CreateStringValue(encoded_log)); |
145 } | 149 } |
146 | 150 |
147 // Append hash to the end of the list. | 151 // Append hash to the end of the list. |
148 base::MD5Digest digest; | 152 base::MD5Digest digest; |
149 base::MD5Final(&digest, &ctx); | 153 base::MD5Final(&digest, &ctx); |
150 list->Append(Value::CreateStringValue(base::MD5DigestToBase16(digest))); | 154 list->Append(Value::CreateStringValue(base::MD5DigestToBase16(digest))); |
151 DCHECK(list->GetSize() >= 3); // Minimum of 3 elements (size, data, hash). | 155 DCHECK(list->GetSize() >= 3); // Minimum of 3 elements (size, data, hash). |
152 } | 156 } |
153 | 157 |
154 // static | 158 // static |
155 MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList( | 159 MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList( |
156 const ListValue& list, | 160 const ListValue& list, |
157 std::vector<std::string>* local_list) { | 161 std::vector<MetricsLogManager::SerializedLog>* local_list) { |
158 if (list.GetSize() == 0) | 162 if (list.GetSize() == 0) |
159 return MakeRecallStatusHistogram(LIST_EMPTY); | 163 return MakeRecallStatusHistogram(LIST_EMPTY); |
160 if (list.GetSize() < 3) | 164 if (list.GetSize() < 3) |
161 return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL); | 165 return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL); |
162 | 166 |
163 // The size is stored at the beginning of the list. | 167 // The size is stored at the beginning of the list. |
164 int size; | 168 int size; |
165 bool valid = (*list.begin())->GetAsInteger(&size); | 169 bool valid = (*list.begin())->GetAsInteger(&size); |
166 if (!valid) | 170 if (!valid) |
167 return MakeRecallStatusHistogram(LIST_SIZE_MISSING); | 171 return MakeRecallStatusHistogram(LIST_SIZE_MISSING); |
(...skipping 19 matching lines...) Expand all Loading... | |
187 ++it, ++local_index) { | 191 ++it, ++local_index) { |
188 bool valid = (*it)->GetAsString(&encoded_log); | 192 bool valid = (*it)->GetAsString(&encoded_log); |
189 if (!valid) { | 193 if (!valid) { |
190 local_list->clear(); | 194 local_list->clear(); |
191 return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION); | 195 return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION); |
192 } | 196 } |
193 | 197 |
194 base::MD5Update(&ctx, encoded_log); | 198 base::MD5Update(&ctx, encoded_log); |
195 | 199 |
196 DCHECK_LT(local_index, local_list->size()); | 200 DCHECK_LT(local_index, local_list->size()); |
197 std::string& decoded_log = (*local_list)[local_index]; | 201 MetricsLogManager::SerializedLog* decoded_log = &(*local_list)[local_index]; |
198 if (!base::Base64Decode(encoded_log, &decoded_log)) { | 202 if (!base::Base64Decode(encoded_log, &decoded_log->log_text)) { |
199 local_list->clear(); | 203 local_list->clear(); |
200 return MakeRecallStatusHistogram(DECODE_FAIL); | 204 return MakeRecallStatusHistogram(DECODE_FAIL); |
201 } | 205 } |
206 decoded_log->UpdateHash(); | |
202 } | 207 } |
203 | 208 |
204 // Verify checksum. | 209 // Verify checksum. |
205 base::MD5Digest digest; | 210 base::MD5Digest digest; |
206 base::MD5Final(&digest, &ctx); | 211 base::MD5Final(&digest, &ctx); |
207 std::string recovered_md5; | 212 std::string recovered_md5; |
208 // We store the hash at the end of the list. | 213 // We store the hash at the end of the list. |
209 valid = (*(list.end() - 1))->GetAsString(&recovered_md5); | 214 valid = (*(list.end() - 1))->GetAsString(&recovered_md5); |
210 if (!valid) { | 215 if (!valid) { |
211 local_list->clear(); | 216 local_list->clear(); |
212 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); | 217 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); |
213 } | 218 } |
214 if (recovered_md5 != base::MD5DigestToBase16(digest)) { | 219 if (recovered_md5 != base::MD5DigestToBase16(digest)) { |
215 local_list->clear(); | 220 local_list->clear(); |
216 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); | 221 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); |
217 } | 222 } |
218 return MakeRecallStatusHistogram(RECALL_SUCCESS); | 223 return MakeRecallStatusHistogram(RECALL_SUCCESS); |
219 } | 224 } |
OLD | NEW |