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 for (std::vector<MetricsLogManager::SerializedLog>::const_iterator it = |
| 140 local_list.begin() + start; |
136 it != local_list.end(); ++it) { | 141 it != local_list.end(); ++it) { |
137 // We encode the compressed log as Value::CreateStringValue() expects to | 142 // We encode the compressed log as Value::CreateStringValue() expects to |
138 // take a valid UTF8 string. | 143 // take a valid UTF8 string. |
139 if (!base::Base64Encode(*it, &encoded_log)) { | 144 if (!base::Base64Encode(it->log_text(), &encoded_log)) { |
140 list->Clear(); | 145 list->Clear(); |
141 return; | 146 return; |
142 } | 147 } |
143 base::MD5Update(&ctx, encoded_log); | 148 base::MD5Update(&ctx, encoded_log); |
144 list->Append(Value::CreateStringValue(encoded_log)); | 149 list->Append(Value::CreateStringValue(encoded_log)); |
145 } | 150 } |
146 | 151 |
147 // Append hash to the end of the list. | 152 // Append hash to the end of the list. |
148 base::MD5Digest digest; | 153 base::MD5Digest digest; |
149 base::MD5Final(&digest, &ctx); | 154 base::MD5Final(&digest, &ctx); |
150 list->Append(Value::CreateStringValue(base::MD5DigestToBase16(digest))); | 155 list->Append(Value::CreateStringValue(base::MD5DigestToBase16(digest))); |
151 DCHECK(list->GetSize() >= 3); // Minimum of 3 elements (size, data, hash). | 156 DCHECK(list->GetSize() >= 3); // Minimum of 3 elements (size, data, hash). |
152 } | 157 } |
153 | 158 |
154 // static | 159 // static |
155 MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList( | 160 MetricsLogSerializer::LogReadStatus MetricsLogSerializer::ReadLogsFromPrefList( |
156 const ListValue& list, | 161 const ListValue& list, |
157 std::vector<std::string>* local_list) { | 162 std::vector<MetricsLogManager::SerializedLog>* local_list) { |
158 if (list.GetSize() == 0) | 163 if (list.GetSize() == 0) |
159 return MakeRecallStatusHistogram(LIST_EMPTY); | 164 return MakeRecallStatusHistogram(LIST_EMPTY); |
160 if (list.GetSize() < 3) | 165 if (list.GetSize() < 3) |
161 return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL); | 166 return MakeRecallStatusHistogram(LIST_SIZE_TOO_SMALL); |
162 | 167 |
163 // The size is stored at the beginning of the list. | 168 // The size is stored at the beginning of the list. |
164 int size; | 169 int size; |
165 bool valid = (*list.begin())->GetAsInteger(&size); | 170 bool valid = (*list.begin())->GetAsInteger(&size); |
166 if (!valid) | 171 if (!valid) |
167 return MakeRecallStatusHistogram(LIST_SIZE_MISSING); | 172 return MakeRecallStatusHistogram(LIST_SIZE_MISSING); |
(...skipping 18 matching lines...) Expand all Loading... |
186 it != list.end() - 1; // Last element is the checksum. | 191 it != list.end() - 1; // Last element is the checksum. |
187 ++it, ++local_index) { | 192 ++it, ++local_index) { |
188 bool valid = (*it)->GetAsString(&encoded_log); | 193 bool valid = (*it)->GetAsString(&encoded_log); |
189 if (!valid) { | 194 if (!valid) { |
190 local_list->clear(); | 195 local_list->clear(); |
191 return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION); | 196 return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION); |
192 } | 197 } |
193 | 198 |
194 base::MD5Update(&ctx, encoded_log); | 199 base::MD5Update(&ctx, encoded_log); |
195 | 200 |
196 DCHECK_LT(local_index, local_list->size()); | 201 std::string log_text; |
197 std::string& decoded_log = (*local_list)[local_index]; | 202 if (!base::Base64Decode(encoded_log, &log_text)) { |
198 if (!base::Base64Decode(encoded_log, &decoded_log)) { | |
199 local_list->clear(); | 203 local_list->clear(); |
200 return MakeRecallStatusHistogram(DECODE_FAIL); | 204 return MakeRecallStatusHistogram(DECODE_FAIL); |
201 } | 205 } |
| 206 |
| 207 DCHECK_LT(local_index, local_list->size()); |
| 208 (*local_list)[local_index].SetLogText(log_text); |
202 } | 209 } |
203 | 210 |
204 // Verify checksum. | 211 // Verify checksum. |
205 base::MD5Digest digest; | 212 base::MD5Digest digest; |
206 base::MD5Final(&digest, &ctx); | 213 base::MD5Final(&digest, &ctx); |
207 std::string recovered_md5; | 214 std::string recovered_md5; |
208 // We store the hash at the end of the list. | 215 // We store the hash at the end of the list. |
209 valid = (*(list.end() - 1))->GetAsString(&recovered_md5); | 216 valid = (*(list.end() - 1))->GetAsString(&recovered_md5); |
210 if (!valid) { | 217 if (!valid) { |
211 local_list->clear(); | 218 local_list->clear(); |
212 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); | 219 return MakeRecallStatusHistogram(CHECKSUM_STRING_CORRUPTION); |
213 } | 220 } |
214 if (recovered_md5 != base::MD5DigestToBase16(digest)) { | 221 if (recovered_md5 != base::MD5DigestToBase16(digest)) { |
215 local_list->clear(); | 222 local_list->clear(); |
216 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); | 223 return MakeRecallStatusHistogram(CHECKSUM_CORRUPTION); |
217 } | 224 } |
218 return MakeRecallStatusHistogram(RECALL_SUCCESS); | 225 return MakeRecallStatusHistogram(RECALL_SUCCESS); |
219 } | 226 } |
OLD | NEW |