Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: components/policy/core/common/cloud/cloud_policy_client.cc

Issue 885653007: Modify CloudPolicyClient to support multiple concurrent requests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More review feedback Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "components/policy/core/common/cloud/cloud_policy_client.h" 5 #include "components/policy/core/common/cloud/cloud_policy_client.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/guid.h" 8 #include "base/guid.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 } 72 }
73 73
74 void CloudPolicyClient::SetupRegistration(const std::string& dm_token, 74 void CloudPolicyClient::SetupRegistration(const std::string& dm_token,
75 const std::string& client_id) { 75 const std::string& client_id) {
76 DCHECK(!dm_token.empty()); 76 DCHECK(!dm_token.empty());
77 DCHECK(!client_id.empty()); 77 DCHECK(!client_id.empty());
78 DCHECK(!is_registered()); 78 DCHECK(!is_registered());
79 79
80 dm_token_ = dm_token; 80 dm_token_ = dm_token;
81 client_id_ = client_id; 81 client_id_ = client_id;
82 request_job_.reset(); 82 request_jobs_.clear();
83 policy_fetch_request_job_.reset();
83 STLDeleteValues(&responses_); 84 STLDeleteValues(&responses_);
84 85
85 NotifyRegistrationStateChanged(); 86 NotifyRegistrationStateChanged();
86 } 87 }
87 88
88 void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type, 89 void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type,
89 em::DeviceRegisterRequest::Flavor flavor, 90 em::DeviceRegisterRequest::Flavor flavor,
90 const std::string& auth_token, 91 const std::string& auth_token,
91 const std::string& client_id, 92 const std::string& client_id,
92 const std::string& requisition, 93 const std::string& requisition,
93 const std::string& current_state_key) { 94 const std::string& current_state_key) {
94 DCHECK(service_); 95 DCHECK(service_);
95 DCHECK(!auth_token.empty()); 96 DCHECK(!auth_token.empty());
96 DCHECK(!is_registered()); 97 DCHECK(!is_registered());
97 98
98 if (client_id.empty()) { 99 if (client_id.empty()) {
99 // Generate a new client ID. This is intentionally done on each new 100 // Generate a new client ID. This is intentionally done on each new
100 // registration request in order to preserve privacy. Reusing IDs would mean 101 // registration request in order to preserve privacy. Reusing IDs would mean
101 // the server could track clients by their registration attempts. 102 // the server could track clients by their registration attempts.
102 client_id_ = base::GenerateGUID(); 103 client_id_ = base::GenerateGUID();
103 } else { 104 } else {
104 client_id_ = client_id; 105 client_id_ = client_id;
105 } 106 }
106 107
107 request_job_.reset( 108 policy_fetch_request_job_.reset(
108 service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION, 109 service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION,
109 GetRequestContext())); 110 GetRequestContext()));
110 request_job_->SetOAuthToken(auth_token); 111 policy_fetch_request_job_->SetOAuthToken(auth_token);
111 request_job_->SetClientID(client_id_); 112 policy_fetch_request_job_->SetClientID(client_id_);
112 113
113 em::DeviceRegisterRequest* request = 114 em::DeviceRegisterRequest* request =
114 request_job_->GetRequest()->mutable_register_request(); 115 policy_fetch_request_job_->GetRequest()->mutable_register_request();
115 if (!client_id.empty()) 116 if (!client_id.empty())
116 request->set_reregister(true); 117 request->set_reregister(true);
117 request->set_type(type); 118 request->set_type(type);
118 if (!machine_id_.empty()) 119 if (!machine_id_.empty())
119 request->set_machine_id(machine_id_); 120 request->set_machine_id(machine_id_);
120 if (!machine_model_.empty()) 121 if (!machine_model_.empty())
121 request->set_machine_model(machine_model_); 122 request->set_machine_model(machine_model_);
122 if (!requisition.empty()) 123 if (!requisition.empty())
123 request->set_requisition(requisition); 124 request->set_requisition(requisition);
124 if (!current_state_key.empty()) 125 if (!current_state_key.empty())
125 request->set_server_backed_state_key(current_state_key); 126 request->set_server_backed_state_key(current_state_key);
126 request->set_flavor(flavor); 127 request->set_flavor(flavor);
127 128
128 request_job_->SetRetryCallback( 129 policy_fetch_request_job_->SetRetryCallback(
129 base::Bind(&CloudPolicyClient::OnRetryRegister, base::Unretained(this))); 130 base::Bind(&CloudPolicyClient::OnRetryRegister, base::Unretained(this)));
130 131
131 request_job_->Start(base::Bind(&CloudPolicyClient::OnRegisterCompleted, 132 policy_fetch_request_job_->Start(
132 base::Unretained(this))); 133 base::Bind(&CloudPolicyClient::OnRegisterCompleted,
134 base::Unretained(this)));
133 } 135 }
134 136
135 void CloudPolicyClient::SetInvalidationInfo( 137 void CloudPolicyClient::SetInvalidationInfo(
136 int64 version, 138 int64 version,
137 const std::string& payload) { 139 const std::string& payload) {
138 invalidation_version_ = version; 140 invalidation_version_ = version;
139 invalidation_payload_ = payload; 141 invalidation_payload_ = payload;
140 } 142 }
141 143
142 void CloudPolicyClient::FetchPolicy() { 144 void CloudPolicyClient::FetchPolicy() {
143 CHECK(is_registered()); 145 CHECK(is_registered());
144 CHECK(!types_to_fetch_.empty()); 146 CHECK(!types_to_fetch_.empty());
145 147
146 request_job_.reset( 148 policy_fetch_request_job_.reset(
147 service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH, 149 service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH,
148 GetRequestContext())); 150 GetRequestContext()));
149 request_job_->SetDMToken(dm_token_); 151 policy_fetch_request_job_->SetDMToken(dm_token_);
150 request_job_->SetClientID(client_id_); 152 policy_fetch_request_job_->SetClientID(client_id_);
151 request_job_->SetUserAffiliation(user_affiliation_); 153 policy_fetch_request_job_->SetUserAffiliation(user_affiliation_);
152 154
153 em::DeviceManagementRequest* request = request_job_->GetRequest(); 155 em::DeviceManagementRequest* request =
156 policy_fetch_request_job_->GetRequest();
154 157
155 // Build policy fetch requests. 158 // Build policy fetch requests.
156 em::DevicePolicyRequest* policy_request = request->mutable_policy_request(); 159 em::DevicePolicyRequest* policy_request = request->mutable_policy_request();
157 for (const auto& type_to_fetch : types_to_fetch_) { 160 for (const auto& type_to_fetch : types_to_fetch_) {
158 em::PolicyFetchRequest* fetch_request = policy_request->add_request(); 161 em::PolicyFetchRequest* fetch_request = policy_request->add_request();
159 fetch_request->set_policy_type(type_to_fetch.first); 162 fetch_request->set_policy_type(type_to_fetch.first);
160 if (!type_to_fetch.second.empty()) 163 if (!type_to_fetch.second.empty())
161 fetch_request->set_settings_entity_id(type_to_fetch.second); 164 fetch_request->set_settings_entity_id(type_to_fetch.second);
162 165
163 // Request signed policy blobs to help prevent tampering on the client. 166 // Request signed policy blobs to help prevent tampering on the client.
(...skipping 30 matching lines...) Expand all
194 ++key) { 197 ++key) {
195 key_update_request->add_server_backed_state_key(*key); 198 key_update_request->add_server_backed_state_key(*key);
196 } 199 }
197 } 200 }
198 201
199 // Set the fetched invalidation version to the latest invalidation version 202 // Set the fetched invalidation version to the latest invalidation version
200 // since it is now the invalidation version used for the latest fetch. 203 // since it is now the invalidation version used for the latest fetch.
201 fetched_invalidation_version_ = invalidation_version_; 204 fetched_invalidation_version_ = invalidation_version_;
202 205
203 // Fire the job. 206 // Fire the job.
204 request_job_->Start(base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted, 207 policy_fetch_request_job_->Start(
205 base::Unretained(this))); 208 base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted,
209 base::Unretained(this)));
206 } 210 }
207 211
208 void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) { 212 void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) {
209 CHECK(is_registered()); 213 CHECK(is_registered());
210 DCHECK(!auth_token.empty()); 214 DCHECK(!auth_token.empty());
211 215
212 request_job_.reset(service_->CreateJob( 216 policy_fetch_request_job_.reset(service_->CreateJob(
213 DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH, 217 DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH,
214 GetRequestContext())); 218 GetRequestContext()));
215 // The credentials of a domain user are needed in order to mint a new OAuth2 219 // The credentials of a domain user are needed in order to mint a new OAuth2
216 // authorization token for the robot account. 220 // authorization token for the robot account.
217 request_job_->SetOAuthToken(auth_token); 221 policy_fetch_request_job_->SetOAuthToken(auth_token);
218 request_job_->SetDMToken(dm_token_); 222 policy_fetch_request_job_->SetDMToken(dm_token_);
219 request_job_->SetClientID(client_id_); 223 policy_fetch_request_job_->SetClientID(client_id_);
220 224
221 em::DeviceServiceApiAccessRequest* request = 225 em::DeviceServiceApiAccessRequest* request =
222 request_job_->GetRequest()->mutable_service_api_access_request(); 226 policy_fetch_request_job_->GetRequest()->
227 mutable_service_api_access_request();
223 request->set_oauth2_client_id( 228 request->set_oauth2_client_id(
224 GaiaUrls::GetInstance()->oauth2_chrome_client_id()); 229 GaiaUrls::GetInstance()->oauth2_chrome_client_id());
225 request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope); 230 request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope);
226 231
227 request_job_->Start( 232 policy_fetch_request_job_->Start(
228 base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted, 233 base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
229 base::Unretained(this))); 234 base::Unretained(this)));
230 } 235 }
231 236
232 void CloudPolicyClient::Unregister() { 237 void CloudPolicyClient::Unregister() {
233 DCHECK(service_); 238 DCHECK(service_);
234 request_job_.reset( 239 policy_fetch_request_job_.reset(
235 service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION, 240 service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION,
236 GetRequestContext())); 241 GetRequestContext()));
237 request_job_->SetDMToken(dm_token_); 242 policy_fetch_request_job_->SetDMToken(dm_token_);
238 request_job_->SetClientID(client_id_); 243 policy_fetch_request_job_->SetClientID(client_id_);
239 request_job_->GetRequest()->mutable_unregister_request(); 244 policy_fetch_request_job_->GetRequest()->mutable_unregister_request();
240 request_job_->Start(base::Bind(&CloudPolicyClient::OnUnregisterCompleted, 245 policy_fetch_request_job_->Start(
241 base::Unretained(this))); 246 base::Bind(&CloudPolicyClient::OnUnregisterCompleted,
247 base::Unretained(this)));
242 } 248 }
243 249
244 void CloudPolicyClient::UploadCertificate( 250 void CloudPolicyClient::UploadCertificate(
245 const std::string& certificate_data, 251 const std::string& certificate_data,
246 const CloudPolicyClient::StatusCallback& callback) { 252 const CloudPolicyClient::StatusCallback& callback) {
247 CHECK(is_registered()); 253 CHECK(is_registered());
248 request_job_.reset( 254 scoped_ptr<DeviceManagementRequestJob> request_job(
249 service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE, 255 service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE,
250 GetRequestContext())); 256 GetRequestContext()));
251 request_job_->SetDMToken(dm_token_); 257 request_job->SetDMToken(dm_token_);
252 request_job_->SetClientID(client_id_); 258 request_job->SetClientID(client_id_);
253 259
254 em::DeviceManagementRequest* request = request_job_->GetRequest(); 260 em::DeviceManagementRequest* request = request_job->GetRequest();
255 request->mutable_cert_upload_request()->set_device_certificate( 261 request->mutable_cert_upload_request()->set_device_certificate(
256 certificate_data); 262 certificate_data);
257 263
258 DeviceManagementRequestJob::Callback job_callback = base::Bind( 264 DeviceManagementRequestJob::Callback job_callback = base::Bind(
259 &CloudPolicyClient::OnCertificateUploadCompleted, 265 &CloudPolicyClient::OnCertificateUploadCompleted,
260 base::Unretained(this), 266 base::Unretained(this),
267 request_job.get(),
261 callback); 268 callback);
262 request_job_->Start(job_callback); 269 request_jobs_.push_back(request_job.Pass());
270 request_jobs_.back()->Start(job_callback);
263 } 271 }
264 272
265 void CloudPolicyClient::UploadDeviceStatus( 273 void CloudPolicyClient::UploadDeviceStatus(
266 const em::DeviceStatusReportRequest* device_status, 274 const em::DeviceStatusReportRequest* device_status,
267 const em::SessionStatusReportRequest* session_status, 275 const em::SessionStatusReportRequest* session_status,
268 const CloudPolicyClient::StatusCallback& callback) { 276 const CloudPolicyClient::StatusCallback& callback) {
269 CHECK(is_registered()); 277 CHECK(is_registered());
270 // Should pass in at least one type of status. 278 // Should pass in at least one type of status.
271 DCHECK(device_status || session_status); 279 DCHECK(device_status || session_status);
272 request_job_.reset( 280 scoped_ptr<DeviceManagementRequestJob> request_job(
273 service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_STATUS, 281 service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_STATUS,
274 GetRequestContext())); 282 GetRequestContext()));
275 request_job_->SetDMToken(dm_token_); 283 request_job->SetDMToken(dm_token_);
276 request_job_->SetClientID(client_id_); 284 request_job->SetClientID(client_id_);
277 285
278 em::DeviceManagementRequest* request = request_job_->GetRequest(); 286 em::DeviceManagementRequest* request = request_job->GetRequest();
279 if (device_status) 287 if (device_status)
280 *request->mutable_device_status_report_request() = *device_status; 288 *request->mutable_device_status_report_request() = *device_status;
281 if (session_status) 289 if (session_status)
282 *request->mutable_session_status_report_request() = *session_status; 290 *request->mutable_session_status_report_request() = *session_status;
283 291
284 DeviceManagementRequestJob::Callback job_callback = base::Bind( 292 DeviceManagementRequestJob::Callback job_callback = base::Bind(
285 &CloudPolicyClient::OnStatusUploadCompleted, 293 &CloudPolicyClient::OnStatusUploadCompleted,
286 base::Unretained(this), 294 base::Unretained(this),
295 request_job.get(),
287 callback); 296 callback);
288 297
289 // TODO(atwilson): Change CloudPolicyClient to support multiple requests in 298 request_jobs_.push_back(request_job.Pass());
290 // parallel, so status upload requests don't get cancelled by things like 299 request_jobs_.back()->Start(job_callback);
291 // policy fetches (http://crbug.com/452563).
292 request_job_->Start(job_callback);
293 } 300 }
294 301
295 void CloudPolicyClient::AddObserver(Observer* observer) { 302 void CloudPolicyClient::AddObserver(Observer* observer) {
296 observers_.AddObserver(observer); 303 observers_.AddObserver(observer);
297 } 304 }
298 305
299 void CloudPolicyClient::RemoveObserver(Observer* observer) { 306 void CloudPolicyClient::RemoveObserver(Observer* observer) {
300 observers_.RemoveObserver(observer); 307 observers_.RemoveObserver(observer);
301 } 308 }
302 309
(...skipping 20 matching lines...) Expand all
323 ResponseMap::const_iterator it = 330 ResponseMap::const_iterator it =
324 responses_.find(std::make_pair(policy_type, settings_entity_id)); 331 responses_.find(std::make_pair(policy_type, settings_entity_id));
325 return it == responses_.end() ? nullptr : it->second; 332 return it == responses_.end() ? nullptr : it->second;
326 } 333 }
327 334
328 scoped_refptr<net::URLRequestContextGetter> 335 scoped_refptr<net::URLRequestContextGetter>
329 CloudPolicyClient::GetRequestContext() { 336 CloudPolicyClient::GetRequestContext() {
330 return request_context_; 337 return request_context_;
331 } 338 }
332 339
340 int CloudPolicyClient::GetActiveRequestCountForTest() const {
341 return request_jobs_.size();
342 }
343
333 void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob* job) { 344 void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob* job) {
334 DCHECK_EQ(request_job_.get(), job); 345 DCHECK_EQ(policy_fetch_request_job_.get(), job);
335 // If the initial request managed to get to the server but the response didn't 346 // If the initial request managed to get to the server but the response didn't
336 // arrive at the client then retrying with the same client ID will fail. 347 // arrive at the client then retrying with the same client ID will fail.
337 // Set the re-registration flag so that the server accepts it. 348 // Set the re-registration flag so that the server accepts it.
338 // If the server hasn't seen the client ID before then it will also accept 349 // If the server hasn't seen the client ID before then it will also accept
339 // the re-registration. 350 // the re-registration.
340 job->GetRequest()->mutable_register_request()->set_reregister(true); 351 job->GetRequest()->mutable_register_request()->set_reregister(true);
341 } 352 }
342 353
343 void CloudPolicyClient::OnRegisterCompleted( 354 void CloudPolicyClient::OnRegisterCompleted(
344 DeviceManagementStatus status, 355 DeviceManagementStatus status,
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 int net_error, 454 int net_error,
444 const em::DeviceManagementResponse& response) { 455 const em::DeviceManagementResponse& response) {
445 if (status == DM_STATUS_SUCCESS && !response.has_unregister_response()) { 456 if (status == DM_STATUS_SUCCESS && !response.has_unregister_response()) {
446 // Assume unregistration has succeeded either way. 457 // Assume unregistration has succeeded either way.
447 LOG(WARNING) << "Empty unregistration response."; 458 LOG(WARNING) << "Empty unregistration response.";
448 } 459 }
449 460
450 status_ = status; 461 status_ = status;
451 if (status == DM_STATUS_SUCCESS) { 462 if (status == DM_STATUS_SUCCESS) {
452 dm_token_.clear(); 463 dm_token_.clear();
464 // Cancel all outstanding jobs.
465 request_jobs_.clear();
453 NotifyRegistrationStateChanged(); 466 NotifyRegistrationStateChanged();
454 } else { 467 } else {
455 NotifyClientError(); 468 NotifyClientError();
456 } 469 }
457 } 470 }
458 471
459 void CloudPolicyClient::OnCertificateUploadCompleted( 472 void CloudPolicyClient::OnCertificateUploadCompleted(
473 const DeviceManagementRequestJob* job,
460 const CloudPolicyClient::StatusCallback& callback, 474 const CloudPolicyClient::StatusCallback& callback,
461 DeviceManagementStatus status, 475 DeviceManagementStatus status,
462 int net_error, 476 int net_error,
463 const enterprise_management::DeviceManagementResponse& response) { 477 const enterprise_management::DeviceManagementResponse& response) {
464 if (status == DM_STATUS_SUCCESS && !response.has_cert_upload_response()) { 478 bool success = true;
465 LOG(WARNING) << "Empty upload certificate response.";
466 callback.Run(false);
467 return;
468 }
469
470 status_ = status; 479 status_ = status;
471 if (status != DM_STATUS_SUCCESS) { 480 if (status != DM_STATUS_SUCCESS) {
481 success = false;
472 NotifyClientError(); 482 NotifyClientError();
473 callback.Run(false); 483 } else if (!response.has_cert_upload_response()) {
474 return; 484 LOG(WARNING) << "Empty upload certificate response.";
485 success = false;
475 } 486 }
476 callback.Run(true); 487 callback.Run(success);
488 // Must call RemoveJob() last, because it frees |callback|.
489 RemoveJob(job);
490 }
491
492 void CloudPolicyClient::RemoveJob(const DeviceManagementRequestJob* job) {
493 for (auto it = request_jobs_.begin(); it != request_jobs_.end(); ++it) {
494 if (*it == job) {
495 request_jobs_.erase(it);
496 return;
497 }
498 }
499 // This job was already deleted from our list, somehow. This shouldn't
500 // happen since deleting the job should cancel the callback.
501 NOTREACHED();
477 } 502 }
478 503
479 void CloudPolicyClient::OnStatusUploadCompleted( 504 void CloudPolicyClient::OnStatusUploadCompleted(
505 const DeviceManagementRequestJob* job,
480 const CloudPolicyClient::StatusCallback& callback, 506 const CloudPolicyClient::StatusCallback& callback,
481 DeviceManagementStatus status, 507 DeviceManagementStatus status,
482 int net_error, 508 int net_error,
483 const enterprise_management::DeviceManagementResponse& response) { 509 const enterprise_management::DeviceManagementResponse& response) {
484 status_ = status; 510 status_ = status;
485 if (status != DM_STATUS_SUCCESS) 511 if (status != DM_STATUS_SUCCESS)
486 NotifyClientError(); 512 NotifyClientError();
487 513
488 callback.Run(status == DM_STATUS_SUCCESS); 514 callback.Run(status == DM_STATUS_SUCCESS);
515 // Must call RemoveJob() last, because it frees |callback|.
516 RemoveJob(job);
489 } 517 }
490 518
491 void CloudPolicyClient::NotifyPolicyFetched() { 519 void CloudPolicyClient::NotifyPolicyFetched() {
492 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this)); 520 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this));
493 } 521 }
494 522
495 void CloudPolicyClient::NotifyRegistrationStateChanged() { 523 void CloudPolicyClient::NotifyRegistrationStateChanged() {
496 FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this)); 524 FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this));
497 } 525 }
498 526
499 void CloudPolicyClient::NotifyRobotAuthCodesFetched() { 527 void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
500 FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this)); 528 FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this));
501 } 529 }
502 530
503 void CloudPolicyClient::NotifyClientError() { 531 void CloudPolicyClient::NotifyClientError() {
504 FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this)); 532 FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this));
505 } 533 }
506 534
507 } // namespace policy 535 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698