OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "google_apis/gcm/engine/gservices_settings.h" | 5 #include "google_apis/gcm/engine/gservices_settings.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/sha1.h" | |
8 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
10 | 11 |
11 namespace { | 12 namespace { |
12 // The expected time in seconds between periodic checkins. | 13 // The expected time in seconds between periodic checkins. |
13 const char kCheckinIntervalKey[] = "checkin_interval"; | 14 const char kCheckinIntervalKey[] = "checkin_interval"; |
14 // The override URL to the checkin server. | 15 // The override URL to the checkin server. |
15 const char kCheckinURLKey[] = "checkin_url"; | 16 const char kCheckinURLKey[] = "checkin_url"; |
16 // The MCS machine name to connect to. | 17 // The MCS machine name to connect to. |
17 const char kMCSHostnameKey[] = "gcm_hostname"; | 18 const char kMCSHostnameKey[] = "gcm_hostname"; |
18 // The MCS port to connect to. | 19 // The MCS port to connect to. |
19 const char kMCSSecurePortKey[] = "gcm_secure_port"; | 20 const char kMCSSecurePortKey[] = "gcm_secure_port"; |
20 // The URL to get MCS registration IDs. | 21 // The URL to get MCS registration IDs. |
21 const char kRegistrationURLKey[] = "gcm_registration_url"; | 22 const char kRegistrationURLKey[] = "gcm_registration_url"; |
22 | 23 |
23 const int64 kDefaultCheckinInterval = 2 * 24 * 60 * 60; // seconds = 2 days. | 24 const int64 kDefaultCheckinInterval = 2 * 24 * 60 * 60; // seconds = 2 days. |
24 const int64 kMinimumCheckinInterval = 12 * 60 * 60; // seconds = 12 hours. | 25 const int64 kMinimumCheckinInterval = 12 * 60 * 60; // seconds = 12 hours. |
25 const char kDefaultCheckinURL[] = "https://android.clients.google.com/checkin"; | 26 const char kDefaultCheckinURL[] = "https://android.clients.google.com/checkin"; |
26 const char kDefaultMCSHostname[] = "mtalk.google.com"; | 27 const char kDefaultMCSHostname[] = "mtalk.google.com"; |
27 const int kDefaultMCSMainSecurePort = 5228; | 28 const int kDefaultMCSMainSecurePort = 5228; |
28 const int kDefaultMCSFallbackSecurePort = 443; | 29 const int kDefaultMCSFallbackSecurePort = 443; |
29 const char kDefaultRegistrationURL[] = | 30 const char kDefaultRegistrationURL[] = |
30 "https://android.clients.google.com/c2dm/register3"; | 31 "https://android.clients.google.com/c2dm/register3"; |
32 const char kDeleteSettingPrefix[] = "delete_"; | |
33 const char kDigestVersionPrefix[] = "1-"; | |
31 const char kMCSEnpointTemplate[] = "https://%s:%d"; | 34 const char kMCSEnpointTemplate[] = "https://%s:%d"; |
32 | 35 |
33 std::string MakeMCSEndpoint(const std::string& mcs_hostname, int port) { | 36 std::string MakeMCSEndpoint(const std::string& mcs_hostname, int port) { |
34 return base::StringPrintf(kMCSEnpointTemplate, mcs_hostname.c_str(), port); | 37 return base::StringPrintf(kMCSEnpointTemplate, mcs_hostname.c_str(), port); |
35 } | 38 } |
36 | 39 |
40 GURL DefaultMainMCSEndpoint() { | |
41 return GURL(MakeMCSEndpoint(kDefaultMCSHostname, kDefaultMCSMainSecurePort)); | |
42 } | |
43 | |
44 GURL DefaultFallbackMCSEndpoint() { | |
45 return GURL( | |
46 MakeMCSEndpoint(kDefaultMCSHostname, kDefaultMCSFallbackSecurePort)); | |
47 } | |
48 | |
37 } // namespace | 49 } // namespace |
38 | 50 |
39 namespace gcm { | 51 namespace gcm { |
40 | 52 |
41 // static | 53 // static |
42 const base::TimeDelta GServicesSettings::MinimumCheckinInterval() { | 54 const base::TimeDelta GServicesSettings::MinimumCheckinInterval() { |
43 return base::TimeDelta::FromSeconds(kMinimumCheckinInterval); | 55 return base::TimeDelta::FromSeconds(kMinimumCheckinInterval); |
44 } | 56 } |
45 | 57 |
46 // static | 58 // static |
47 const GURL GServicesSettings::DefaultCheckinURL() { | 59 const GURL GServicesSettings::DefaultCheckinURL() { |
48 return GURL(kDefaultCheckinURL); | 60 return GURL(kDefaultCheckinURL); |
49 } | 61 } |
50 | 62 |
51 GServicesSettings::GServicesSettings() | 63 // static |
52 : checkin_interval_(base::TimeDelta::FromSeconds(kDefaultCheckinInterval)), | 64 std::string GServicesSettings::CalculateDigest(const SettingsMap& settings) { |
53 checkin_url_(kDefaultCheckinURL), | 65 char hash[base::kSHA1Length]; |
jianli
2014/05/13 21:41:52
Why not defining this as unsigned char array?
fgorski
2014/05/13 23:53:28
Done.
| |
54 mcs_main_endpoint_(MakeMCSEndpoint(kDefaultMCSHostname, | 66 std::vector<char> data; |
jianli
2014/05/13 21:41:52
It seems to be easier to use std::string, like:
fgorski
2014/05/13 23:53:28
Done.
| |
55 kDefaultMCSMainSecurePort)), | 67 for (SettingsMap::const_iterator iter = settings.begin(); |
56 mcs_fallback_endpoint_(MakeMCSEndpoint(kDefaultMCSHostname, | 68 iter != settings.end(); |
57 kDefaultMCSFallbackSecurePort)), | 69 ++iter) { |
58 registration_url_(kDefaultRegistrationURL), | 70 data.insert(data.end(), iter->first.begin(), iter->first.end()); |
59 weak_ptr_factory_(this) { | 71 data.push_back((char)0); |
jianli
2014/05/13 21:41:52
nit: '\0' to replace c type conversion
fgorski
2014/05/13 23:53:28
Done.
| |
72 data.insert(data.end(), iter->second.begin(), iter->second.end()); | |
73 data.push_back((char)0); | |
74 } | |
75 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(&data[0]), | |
76 data.size(), | |
77 reinterpret_cast<unsigned char*>(hash)); | |
78 return kDigestVersionPrefix + base::HexEncode(hash, base::kSHA1Length); | |
jianli
2014/05/13 21:41:52
Just to confirm that this is not base64 encoded, r
fgorski
2014/05/13 23:53:28
HEX is expected.
| |
79 } | |
80 | |
81 GServicesSettings::GServicesSettings() : weak_ptr_factory_(this) { | |
82 settings_[kCheckinIntervalKey] = base::Int64ToString(kDefaultCheckinInterval); | |
83 settings_[kCheckinURLKey] = kDefaultCheckinURL; | |
84 settings_[kMCSHostnameKey] = kDefaultMCSHostname; | |
85 settings_[kMCSSecurePortKey] = base::IntToString(kDefaultMCSMainSecurePort); | |
86 settings_[kRegistrationURLKey] = kDefaultRegistrationURL; | |
87 digest_ = CalculateDigest(settings_); | |
60 } | 88 } |
61 | 89 |
62 GServicesSettings::~GServicesSettings() {} | 90 GServicesSettings::~GServicesSettings() {} |
63 | 91 |
64 bool GServicesSettings::UpdateFromCheckinResponse( | 92 bool GServicesSettings::UpdateFromCheckinResponse( |
65 const checkin_proto::AndroidCheckinResponse& checkin_response) { | 93 const checkin_proto::AndroidCheckinResponse& checkin_response) { |
66 if (!checkin_response.has_digest() || | 94 if (!checkin_response.has_settings_diff()) { |
67 checkin_response.digest() == digest_) { | 95 LOG(ERROR) << "Field settings_diff not set in response."; |
68 // There are no changes as digest is the same or no settings provided. | 96 return false; |
69 return false; | 97 } |
70 } | 98 |
71 | 99 if (!checkin_response.has_digest()) { |
72 std::map<std::string, std::string> settings; | 100 LOG(ERROR) << "Field digest not set in response."; |
101 return false; | |
102 } | |
103 | |
104 bool settings_diff = checkin_response.settings_diff(); | |
105 SettingsMap new_settings; | |
106 // Only reuse the existing settings, if we are given a settings difference. | |
107 if (settings_diff) | |
108 new_settings = GetSettingsMap(); | |
109 | |
73 for (int i = 0; i < checkin_response.setting_size(); ++i) { | 110 for (int i = 0; i < checkin_response.setting_size(); ++i) { |
74 std::string name = checkin_response.setting(i).name(); | 111 std::string name = checkin_response.setting(i).name(); |
75 std::string value = checkin_response.setting(i).value(); | 112 std::string value = checkin_response.setting(i).value(); |
76 settings[name] = value; | 113 if (settings_diff && name.find(kDeleteSettingPrefix) == 0) { |
jianli
2014/05/13 21:41:52
Consider adding the check for empty name.
fgorski
2014/05/13 23:53:28
Done.
| |
77 } | 114 std::string setting_to_delete = |
78 | 115 name.substr(arraysize(kDeleteSettingPrefix)); |
79 // Only update the settings in store and digest, if the settings actually | 116 new_settings.erase(setting_to_delete); |
80 // passed the verificaiton in update settings. | 117 } else { |
81 if (UpdateSettings(settings)) { | 118 new_settings[name] = value; |
82 digest_ = checkin_response.digest(); | 119 } |
83 return true; | 120 } |
84 } | 121 |
85 | 122 if (!VerifySettings(new_settings)) |
86 return false; | 123 return false; |
124 | |
125 std::string digest = CalculateDigest(new_settings); | |
126 if (digest != checkin_response.digest()) { | |
127 LOG(ERROR) << "Calculated digest does not match the original digest."; | |
jianli
2014/05/13 21:41:52
nit: combine all 3 logs into one, like:
LOG(ERRO
fgorski
2014/05/13 23:53:28
Done.
| |
128 LOG(ERROR) << "Expected G-Services settings digest: " | |
129 << checkin_response.digest(); | |
130 LOG(ERROR) << "Calculated G-services settings digest: " << digest; | |
131 return false; | |
132 } | |
133 | |
134 if (digest == digest_) | |
135 return false; | |
136 | |
137 settings_ = new_settings; | |
jianli
2014/05/13 21:41:52
nit: use swap for efficiency
fgorski
2014/05/13 23:53:28
Done.
| |
138 digest_ = digest; | |
139 return true; | |
87 } | 140 } |
88 | 141 |
89 void GServicesSettings::UpdateFromLoadResult( | 142 void GServicesSettings::UpdateFromLoadResult( |
90 const GCMStore::LoadResult& load_result) { | 143 const GCMStore::LoadResult& load_result) { |
91 if (UpdateSettings(load_result.gservices_settings)) | 144 if (VerifySettings(load_result.gservices_settings) && |
145 VerifyDigest(load_result.gservices_settings, | |
146 load_result.gservices_digest)) { | |
147 settings_ = load_result.gservices_settings; | |
92 digest_ = load_result.gservices_digest; | 148 digest_ = load_result.gservices_digest; |
93 } | 149 } |
94 | 150 } |
95 std::map<std::string, std::string> GServicesSettings::GetSettingsMap() const { | 151 |
96 std::map<std::string, std::string> settings; | 152 GServicesSettings::SettingsMap GServicesSettings::GetSettingsMap() const { |
jianli
2014/05/13 21:41:52
This can be defined as getter now.
fgorski
2014/05/13 23:53:28
Done.
| |
97 settings[kCheckinIntervalKey] = | 153 return settings_; |
98 base::Int64ToString(checkin_interval_.InSeconds()); | 154 } |
99 settings[kCheckinURLKey] = checkin_url_.spec(); | 155 |
100 settings[kMCSHostnameKey] = mcs_main_endpoint_.host(); | 156 base::TimeDelta GServicesSettings::checkin_interval() const { |
101 settings[kMCSSecurePortKey] = mcs_main_endpoint_.port(); | 157 int64 checkin_interval = kMinimumCheckinInterval; |
102 settings[kRegistrationURLKey] = registration_url_.spec(); | 158 SettingsMap::const_iterator iter = settings_.find(kCheckinIntervalKey); |
103 return settings; | 159 if (iter == settings_.end() || |
104 } | 160 !base::StringToInt64(iter->second, &checkin_interval)) { |
105 | 161 checkin_interval = kDefaultCheckinInterval; |
106 bool GServicesSettings::UpdateSettings( | 162 } |
107 const std::map<std::string, std::string>& settings) { | 163 |
108 int64 new_checkin_interval = kMinimumCheckinInterval; | 164 if (checkin_interval < kMinimumCheckinInterval) |
109 std::map<std::string, std::string>::const_iterator iter = | 165 checkin_interval = kMinimumCheckinInterval; |
110 settings.find(kCheckinIntervalKey); | 166 |
167 return base::TimeDelta::FromSeconds(checkin_interval); | |
168 } | |
169 | |
170 GURL GServicesSettings::checkin_url() const { | |
171 SettingsMap::const_iterator iter = settings_.find(kCheckinURLKey); | |
172 if (iter == settings_.end() || iter->second.empty()) | |
173 return GURL(kDefaultCheckinURL); | |
174 return GURL(iter->second); | |
175 } | |
176 | |
177 GURL GServicesSettings::mcs_main_endpoint() const { | |
178 SettingsMap::const_iterator iter = settings_.find(kMCSHostnameKey); | |
179 if (iter == settings_.end() || iter->second.empty()) | |
180 return DefaultMainMCSEndpoint(); | |
181 | |
182 std::string mcs_hostname = iter->second; | |
183 | |
184 iter = settings_.find(kMCSSecurePortKey); | |
185 int mcs_secure_port = kDefaultMCSMainSecurePort; | |
186 if (iter == settings_.end() || iter->second.empty() || | |
187 !base::StringToInt(iter->second, &mcs_secure_port)) | |
188 return DefaultMainMCSEndpoint(); | |
189 | |
190 GURL mcs_endpoint(MakeMCSEndpoint(mcs_hostname, mcs_secure_port)); | |
191 | |
192 if (!mcs_endpoint.is_valid()) | |
193 return DefaultMainMCSEndpoint(); | |
194 | |
195 return mcs_endpoint; | |
196 } | |
197 | |
198 GURL GServicesSettings::mcs_fallback_endpoint() const { | |
199 SettingsMap::const_iterator iter = settings_.find(kMCSHostnameKey); | |
200 if (iter == settings_.end() || iter->second.empty()) | |
201 return DefaultFallbackMCSEndpoint(); | |
202 | |
203 GURL mcs_endpoint( | |
204 MakeMCSEndpoint(iter->second, kDefaultMCSFallbackSecurePort)); | |
205 | |
206 if (!mcs_endpoint.is_valid()) | |
207 return DefaultFallbackMCSEndpoint(); | |
208 | |
209 return mcs_endpoint; | |
210 } | |
211 | |
212 GURL GServicesSettings::registration_url() const { | |
213 SettingsMap::const_iterator iter = settings_.find(kRegistrationURLKey); | |
214 if (iter == settings_.end() || iter->second.empty()) | |
215 return GURL(kDefaultRegistrationURL); | |
216 return GURL(iter->second); | |
217 } | |
218 | |
219 bool GServicesSettings::VerifyCheckinInterval( | |
220 const SettingsMap& settings) const { | |
221 SettingsMap::const_iterator iter = settings.find(kCheckinIntervalKey); | |
111 if (iter == settings.end()) { | 222 if (iter == settings.end()) { |
112 LOG(ERROR) << "Setting not found: " << kCheckinIntervalKey; | 223 LOG(ERROR) << "Setting not found: " << kCheckinIntervalKey; |
113 return false; | 224 return false; |
114 } | 225 } |
115 if (!base::StringToInt64(iter->second, &new_checkin_interval)) { | 226 int64 checkin_interval = kMinimumCheckinInterval; |
227 if (!base::StringToInt64(iter->second, &checkin_interval)) { | |
116 LOG(ERROR) << "Failed to parse checkin interval: " << iter->second; | 228 LOG(ERROR) << "Failed to parse checkin interval: " << iter->second; |
117 return false; | 229 return false; |
118 } | 230 } |
119 if (new_checkin_interval < kMinimumCheckinInterval) { | 231 if (checkin_interval == std::numeric_limits<int64>::max()) { |
120 LOG(ERROR) << "Checkin interval: " << new_checkin_interval | 232 LOG(ERROR) << "Checkin interval is too big: " << checkin_interval; |
233 return false; | |
234 } | |
235 if (checkin_interval < kMinimumCheckinInterval) { | |
236 // This is emited as an error, but is not mean to fail verification. | |
237 LOG(ERROR) << "Checkin interval: " << checkin_interval | |
121 << " is less than allowed minimum: " << kMinimumCheckinInterval; | 238 << " is less than allowed minimum: " << kMinimumCheckinInterval; |
122 new_checkin_interval = kMinimumCheckinInterval; | 239 } |
123 } | 240 |
124 if (new_checkin_interval == std::numeric_limits<int64>::max()) { | 241 return true; |
125 LOG(ERROR) << "Checkin interval is too big: " << new_checkin_interval; | 242 } |
126 return false; | 243 |
127 } | 244 bool GServicesSettings::VerifyMCSEndpoint(const SettingsMap& settings) const { |
128 | 245 SettingsMap::const_iterator iter = settings.find(kMCSHostnameKey); |
129 std::string new_mcs_hostname; | 246 std::string mcs_hostname; |
130 iter = settings.find(kMCSHostnameKey); | |
131 if (iter == settings.end()) { | 247 if (iter == settings.end()) { |
132 LOG(ERROR) << "Setting not found: " << kMCSHostnameKey; | 248 LOG(ERROR) << "Setting not found: " << kMCSHostnameKey; |
133 return false; | 249 return false; |
134 } | 250 } |
135 new_mcs_hostname = iter->second; | 251 mcs_hostname = iter->second; |
136 if (new_mcs_hostname.empty()) { | 252 if (iter->second.empty()) { |
137 LOG(ERROR) << "Empty MCS hostname provided."; | 253 LOG(ERROR) << "Empty MCS hostname provided."; |
138 return false; | 254 return false; |
139 } | 255 } |
140 | 256 |
141 int new_mcs_secure_port = -1; | 257 int mcs_secure_port = -1; |
142 iter = settings.find(kMCSSecurePortKey); | 258 iter = settings.find(kMCSSecurePortKey); |
143 if (iter == settings.end()) { | 259 if (iter == settings.end()) { |
144 LOG(ERROR) << "Setting not found: " << kMCSSecurePortKey; | 260 LOG(ERROR) << "Setting not found: " << kMCSSecurePortKey; |
145 return false; | 261 return false; |
146 } | 262 } |
147 if (!base::StringToInt(iter->second, &new_mcs_secure_port)) { | 263 if (!base::StringToInt(iter->second, &mcs_secure_port)) { |
148 LOG(ERROR) << "Failed to parse MCS secure port: " << iter->second; | 264 LOG(ERROR) << "Failed to parse MCS secure port: " << iter->second; |
149 return false; | 265 return false; |
150 } | 266 } |
151 if (new_mcs_secure_port < 0 || 65535 < new_mcs_secure_port) { | 267 if (mcs_secure_port < 0 || 65535 < mcs_secure_port) { |
152 LOG(ERROR) << "Incorrect port value: " << new_mcs_secure_port; | 268 LOG(ERROR) << "Incorrect port value: " << mcs_secure_port; |
153 return false; | 269 return false; |
154 } | 270 } |
155 | 271 |
156 GURL new_mcs_main_endpoint = | 272 GURL mcs_main_endpoint(MakeMCSEndpoint(mcs_hostname, mcs_secure_port)); |
157 GURL(MakeMCSEndpoint(new_mcs_hostname, new_mcs_secure_port)); | 273 if (!mcs_main_endpoint.is_valid()) { |
158 GURL new_mcs_fallback_endpoint = | 274 LOG(ERROR) << "Invalid main MCS endpoint: " |
159 GURL(MakeMCSEndpoint(new_mcs_hostname, kDefaultMCSFallbackSecurePort)); | 275 << mcs_main_endpoint.possibly_invalid_spec(); |
160 if (!new_mcs_main_endpoint.is_valid() || | 276 return false; |
161 !new_mcs_fallback_endpoint.is_valid()) | 277 } |
162 return false; | 278 GURL mcs_fallback_endpoint( |
163 | 279 MakeMCSEndpoint(mcs_hostname, kDefaultMCSFallbackSecurePort)); |
164 GURL new_checkin_url; | 280 if (!mcs_fallback_endpoint.is_valid()) { |
165 iter = settings.find(kCheckinURLKey); | 281 LOG(ERROR) << "Invalid fallback MCS endpoint: " |
282 << mcs_fallback_endpoint.possibly_invalid_spec(); | |
283 return false; | |
284 } | |
285 | |
286 return true; | |
287 } | |
288 | |
289 bool GServicesSettings::VerifyCheckinURL(const SettingsMap& settings) const { | |
jianli
2014/05/13 21:41:52
It seems that this could be defined as static meth
fgorski
2014/05/13 23:53:28
Done.
| |
290 SettingsMap::const_iterator iter = settings.find(kCheckinURLKey); | |
166 if (iter == settings.end()) { | 291 if (iter == settings.end()) { |
167 LOG(ERROR) << "Setting not found: " << kCheckinURLKey; | 292 LOG(ERROR) << "Setting not found: " << kCheckinURLKey; |
168 return false; | 293 return false; |
169 } | 294 } |
170 new_checkin_url = GURL(iter->second); | 295 GURL checkin_url(iter->second); |
171 if (!new_checkin_url.is_valid()) { | 296 if (!checkin_url.is_valid()) { |
172 LOG(ERROR) << "Invalid checkin URL provided: " | 297 LOG(ERROR) << "Invalid checkin URL provided: " |
173 << new_checkin_url.possibly_invalid_spec(); | 298 << checkin_url.possibly_invalid_spec(); |
174 return false; | 299 return false; |
175 } | 300 } |
176 | 301 |
177 GURL new_registration_url; | 302 return true; |
178 iter = settings.find(kRegistrationURLKey); | 303 } |
304 | |
305 bool GServicesSettings::VerifyRegistrationURL( | |
306 const SettingsMap& settings) const { | |
307 SettingsMap::const_iterator iter = settings.find(kRegistrationURLKey); | |
179 if (iter == settings.end()) { | 308 if (iter == settings.end()) { |
180 LOG(ERROR) << "Setting not found: " << kRegistrationURLKey; | 309 LOG(ERROR) << "Setting not found: " << kRegistrationURLKey; |
181 return false; | 310 return false; |
182 } | 311 } |
183 new_registration_url = GURL(iter->second); | 312 GURL registration_url(iter->second); |
184 if (!new_registration_url.is_valid()) { | 313 if (!registration_url.is_valid()) { |
185 LOG(ERROR) << "Invalid registration URL provided: " | 314 LOG(ERROR) << "Invalid registration URL provided: " |
186 << new_registration_url.possibly_invalid_spec(); | 315 << registration_url.possibly_invalid_spec(); |
187 return false; | 316 return false; |
188 } | 317 } |
189 | 318 |
190 // We only update the settings once all of them are correct. | 319 return true; |
191 checkin_interval_ = base::TimeDelta::FromSeconds(new_checkin_interval); | 320 } |
192 mcs_main_endpoint_ = new_mcs_main_endpoint; | 321 |
193 mcs_fallback_endpoint_ = new_mcs_fallback_endpoint; | 322 bool GServicesSettings::VerifySettings(const SettingsMap& settings) const { |
194 checkin_url_ = new_checkin_url; | 323 return VerifyCheckinInterval(settings) && VerifyMCSEndpoint(settings) && |
195 registration_url_ = new_registration_url; | 324 VerifyCheckinURL(settings) && VerifyRegistrationURL(settings); |
196 return true; | 325 } |
197 } | 326 |
198 | 327 bool GServicesSettings::VerifyDigest(const SettingsMap& settings, |
328 const std::string& expected_digest) const { | |
329 std::string calculated_digest = CalculateDigest(settings); | |
330 if (calculated_digest != expected_digest) { | |
331 LOG(ERROR) << "Calculated digest does not match the original digest."; | |
332 LOG(ERROR) << "Expected G-Services settings digest: " << expected_digest; | |
333 LOG(ERROR) << "Calculated G-services settings digest: " | |
334 << calculated_digest; | |
335 return false; | |
336 } | |
337 | |
338 return true; | |
339 } | |
340 | |
199 } // namespace gcm | 341 } // namespace gcm |
OLD | NEW |