| 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].SwapLogText(&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 |