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

Side by Side Diff: chrome/browser/chromeos/policy/heartbeat_scheduler.cc

Issue 1267983002: Signup for GCM upstream notifications (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gcm-registration
Patch Set: update hearts interval from device policy Created 5 years, 1 month 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) 2015 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 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/chromeos/policy/heartbeat_scheduler.h" 5 #include "chrome/browser/chromeos/policy/heartbeat_scheduler.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/sequenced_task_runner.h" 13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/time/time.h" 15 #include "base/time/time.h"
16 #include "chrome/common/chrome_switches.h" 16 #include "chrome/common/chrome_switches.h"
17 #include "components/gcm_driver/gcm_driver.h" 17 #include "components/gcm_driver/gcm_driver.h"
18 18
19 namespace { 19 namespace {
20 const int kMinHeartbeatIntervalMs = 30 * 1000; // 30 seconds 20 const int kMinHeartbeatIntervalMs = 30 * 1000; // 30 seconds
21 const int kMaxHeartbeatIntervalMs = 24 * 60 * 60 * 1000; // 24 hours 21 const int kMaxHeartbeatIntervalMs = 24 * 60 * 60 * 1000; // 24 hours
22 22
23 // Minimum time between two consecutive upstream notification signs up.
24 const int kMinimumSignupIntervalMs = 3 * 60 * 1000;
25
23 // Our sender ID we send up with all of our GCM messages. 26 // Our sender ID we send up with all of our GCM messages.
24 const char* kHeartbeatGCMAppID = "com.google.chromeos.monitoring"; 27 const char* kHeartbeatGCMAppID = "com.google.chromeos.monitoring";
25 28
26 // The default destination we send our GCM messages to. 29 // The default destination we send our GCM messages to.
27 const char* kHeartbeatGCMDestinationID = "1013309121859"; 30 const char* kHeartbeatGCMDestinationID = "1013309121859";
28 const char* kHeartbeatGCMSenderSuffix = "@google.com"; 31 const char* kHeartbeatGCMSenderSuffix = "@google.com";
29 32
30 const char* kMonitoringMessageTypeKey = "type"; 33 // Destination of upstream notification sign up message.
34 const char* kUpstreamNotificationSignUpDestinationID =
35 "https://gcm.googleapis.com/gcm/gcm.event_tracker";
36
37 // A bit mask, listening events of upstream notification.
38 const char* kUpstreamNotificationSignUpListeningEvents =
39 "3"; // START | DISCONNECTED
40
41 const char* kGcmMessageTypeKey = "type";
31 const char* kHeartbeatTimestampKey = "timestamp"; 42 const char* kHeartbeatTimestampKey = "timestamp";
32 const char* kHeartbeatDomainNameKey = "domain_name"; 43 const char* kHeartbeatDomainNameKey = "domain_name";
33 const char* kHeartbeatDeviceIDKey = "device_id"; 44 const char* kHeartbeatDeviceIDKey = "device_id";
34 const char* kHeartbeatTypeValue = "hb"; 45 const char* kHeartbeatTypeValue = "hb";
46 const char* kUpstreamNotificationNotifyKey = "notify";
35 47
36 // If we get an error registering with GCM, try again in two minutes. 48 // If we get an error registering with GCM, try again in two minutes.
37 const int64 kRegistrationRetryDelayMs = 2 * 60 * 1000; 49 const int64 kRegistrationRetryDelayMs = 2 * 60 * 1000;
38 50
51 const char* kHeartbeatSchedulerScope =
52 "policy.heartbeat_scheduler.upstream_notification";
53
39 // Returns the destination ID for GCM heartbeats. 54 // Returns the destination ID for GCM heartbeats.
40 std::string GetDestinationID() { 55 std::string GetDestinationID() {
41 std::string receiver_id = kHeartbeatGCMDestinationID; 56 std::string receiver_id = kHeartbeatGCMDestinationID;
42 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 57 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
43 switches::kMonitoringDestinationID)) { 58 switches::kMonitoringDestinationID)) {
44 receiver_id = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 59 receiver_id = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
45 switches::kMonitoringDestinationID); 60 switches::kMonitoringDestinationID);
46 } 61 }
47 return receiver_id; 62 return receiver_id;
48 } 63 }
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 if (chromeos::CrosSettingsProvider::TRUSTED != settings->PrepareTrustedValues( 220 if (chromeos::CrosSettingsProvider::TRUSTED != settings->PrepareTrustedValues(
206 base::Bind(&HeartbeatScheduler::RefreshHeartbeatSettings, 221 base::Bind(&HeartbeatScheduler::RefreshHeartbeatSettings,
207 weak_factory_.GetWeakPtr()))) { 222 weak_factory_.GetWeakPtr()))) {
208 return; 223 return;
209 } 224 }
210 225
211 // CrosSettings are trusted - update our cached settings (we cache the 226 // CrosSettings are trusted - update our cached settings (we cache the
212 // value because CrosSettings can become untrusted at arbitrary times and we 227 // value because CrosSettings can become untrusted at arbitrary times and we
213 // want to use the last trusted value). 228 // want to use the last trusted value).
214 int frequency; 229 int frequency;
215 if (settings->GetInteger(chromeos::kHeartbeatFrequency, &frequency)) 230 if (settings->GetInteger(chromeos::kHeartbeatFrequency, &frequency)) {
Andrew T Wilson (Slow) 2015/11/20 16:37:34 So, shouldn't we call AddHeartbeatInterval() even
binjin 2015/11/20 22:56:48 Done.
216 heartbeat_interval_ = EnsureValidHeartbeatInterval( 231 heartbeat_interval_ = EnsureValidHeartbeatInterval(
217 base::TimeDelta::FromMilliseconds(frequency)); 232 base::TimeDelta::FromMilliseconds(frequency));
233 gcm_driver_->AddHeartbeatInterval(kHeartbeatSchedulerScope,
234 heartbeat_interval_.InMilliseconds());
235 }
218 236
219 bool enabled; 237 bool enabled;
220 if (settings->GetBoolean(chromeos::kHeartbeatEnabled, &enabled)) 238 if (settings->GetBoolean(chromeos::kHeartbeatEnabled, &enabled))
221 heartbeat_enabled_ = enabled; 239 heartbeat_enabled_ = enabled;
222 240
223 if (!heartbeat_enabled_) { 241 if (!heartbeat_enabled_) {
224 // Heartbeats are no longer enabled - cancel our callback and any 242 // Heartbeats are no longer enabled - cancel our callback and any
225 // outstanding registration attempts and disconnect from GCM so the 243 // outstanding registration attempts and disconnect from GCM so the
226 // connection can be shut down. If heartbeats are re-enabled later, we 244 // connection can be shut down. If heartbeats are re-enabled later, we
227 // will re-register with GCM. 245 // will re-register with GCM.
228 heartbeat_callback_.Cancel(); 246 heartbeat_callback_.Cancel();
229 ShutdownGCM(); 247 ShutdownGCM();
230 } else { 248 } else {
231 // Schedule a new upload with the new frequency. 249 // Schedule a new upload with the new frequency.
232 ScheduleNextHeartbeat(); 250 ScheduleNextHeartbeat();
233 } 251 }
234 252
235 DVLOG(1) << "heartbeat enabled: " << heartbeat_enabled_; 253 DVLOG(1) << "heartbeat enabled: " << heartbeat_enabled_;
236 DVLOG(1) << "heartbeat frequency: " << heartbeat_interval_; 254 DVLOG(1) << "heartbeat frequency: " << heartbeat_interval_;
237 } 255 }
238 256
239 void HeartbeatScheduler::ShutdownGCM() { 257 void HeartbeatScheduler::ShutdownGCM() {
240 registration_helper_.reset(); 258 registration_helper_.reset();
241 registration_id_.clear(); 259 registration_id_.clear();
242 if (registered_app_handler_) { 260 if (registered_app_handler_) {
243 registered_app_handler_ = false; 261 registered_app_handler_ = false;
262 gcm_driver_->RemoveHeartbeatInterval(kHeartbeatSchedulerScope);
244 gcm_driver_->RemoveAppHandler(kHeartbeatGCMAppID); 263 gcm_driver_->RemoveAppHandler(kHeartbeatGCMAppID);
264 gcm_driver_->RemoveConnectionObserver(this);
245 } 265 }
246 } 266 }
247 267
248 base::TimeDelta HeartbeatScheduler::EnsureValidHeartbeatInterval( 268 base::TimeDelta HeartbeatScheduler::EnsureValidHeartbeatInterval(
249 const base::TimeDelta& interval) { 269 const base::TimeDelta& interval) {
250 const base::TimeDelta min = base::TimeDelta::FromMilliseconds( 270 const base::TimeDelta min = base::TimeDelta::FromMilliseconds(
251 kMinHeartbeatIntervalMs); 271 kMinHeartbeatIntervalMs);
252 const base::TimeDelta max = base::TimeDelta::FromMilliseconds( 272 const base::TimeDelta max = base::TimeDelta::FromMilliseconds(
253 kMaxHeartbeatIntervalMs); 273 kMaxHeartbeatIntervalMs);
254 if (interval < min) { 274 if (interval < min) {
(...skipping 12 matching lines...) Expand all
267 if (!heartbeat_enabled_) 287 if (!heartbeat_enabled_)
268 return; 288 return;
269 289
270 if (registration_id_.empty()) { 290 if (registration_id_.empty()) {
271 // We are not registered with the GCM service yet, so kick off registration. 291 // We are not registered with the GCM service yet, so kick off registration.
272 if (!registration_helper_) { 292 if (!registration_helper_) {
273 // Add ourselves as an AppHandler - this is required in order to setup 293 // Add ourselves as an AppHandler - this is required in order to setup
274 // a GCM connection. 294 // a GCM connection.
275 registered_app_handler_ = true; 295 registered_app_handler_ = true;
276 gcm_driver_->AddAppHandler(kHeartbeatGCMAppID, this); 296 gcm_driver_->AddAppHandler(kHeartbeatGCMAppID, this);
297 gcm_driver_->AddConnectionObserver(this);
277 registration_helper_.reset(new HeartbeatRegistrationHelper( 298 registration_helper_.reset(new HeartbeatRegistrationHelper(
278 gcm_driver_, task_runner_)); 299 gcm_driver_, task_runner_));
279 registration_helper_->Register( 300 registration_helper_->Register(
280 base::Bind(&HeartbeatScheduler::OnRegistrationComplete, 301 base::Bind(&HeartbeatScheduler::OnRegistrationComplete,
281 weak_factory_.GetWeakPtr())); 302 weak_factory_.GetWeakPtr()));
282 } 303 }
283 return; 304 return;
284 } 305 }
285 306
286 // Calculate when to fire off the next update (if it should have already 307 // Calculate when to fire off the next update (if it should have already
(...skipping 14 matching lines...) Expand all
301 registration_helper_.reset(); 322 registration_helper_.reset();
302 registration_id_ = registration_id; 323 registration_id_ = registration_id;
303 324
304 if (cloud_policy_client_) { 325 if (cloud_policy_client_) {
305 // TODO(binjin): Avoid sending the same GCM id to the server. 326 // TODO(binjin): Avoid sending the same GCM id to the server.
306 // See http://crbug.com/516375 327 // See http://crbug.com/516375
307 cloud_policy_client_->UpdateGcmId( 328 cloud_policy_client_->UpdateGcmId(
308 registration_id, 329 registration_id,
309 base::Bind(&HeartbeatScheduler::OnGcmIdUpdateRequestSent, 330 base::Bind(&HeartbeatScheduler::OnGcmIdUpdateRequestSent,
310 weak_factory_.GetWeakPtr())); 331 weak_factory_.GetWeakPtr()));
332 SignUpUpstreamNotification();
311 } 333 }
312 334
313 // Now that GCM registration is complete, start sending heartbeats. 335 // Now that GCM registration is complete, start sending heartbeats.
314 ScheduleNextHeartbeat(); 336 ScheduleNextHeartbeat();
315 } 337 }
316 338
317 void HeartbeatScheduler::SendHeartbeat() { 339 void HeartbeatScheduler::SendHeartbeat() {
318 DCHECK(!registration_id_.empty()); 340 DCHECK(!registration_id_.empty());
319 if (!gcm_driver_ || !heartbeat_enabled_) 341 if (!gcm_driver_ || !heartbeat_enabled_)
320 return; 342 return;
321 343
322 gcm::OutgoingMessage message; 344 gcm::OutgoingMessage message;
323 message.time_to_live = heartbeat_interval_.InSeconds(); 345 message.time_to_live = heartbeat_interval_.InSeconds();
324 // Just use the current timestamp as the message ID - if the user changes the 346 // Just use the current timestamp as the message ID - if the user changes the
325 // time and we send a message with the same ID that we previously used, no 347 // time and we send a message with the same ID that we previously used, no
326 // big deal (the new message will replace the old, which is the behavior we 348 // big deal (the new message will replace the old, which is the behavior we
327 // want anyway, per: 349 // want anyway, per:
328 // https://developer.chrome.com/apps/cloudMessaging#send_messages 350 // https://developer.chrome.com/apps/cloudMessaging#send_messages
329 message.id = base::Int64ToString( 351 message.id = base::Int64ToString(
330 base::Time::NowFromSystemTime().ToInternalValue()); 352 base::Time::NowFromSystemTime().ToInternalValue());
331 message.data[kMonitoringMessageTypeKey] = kHeartbeatTypeValue; 353 message.data[kGcmMessageTypeKey] = kHeartbeatTypeValue;
332 message.data[kHeartbeatTimestampKey] = base::Int64ToString( 354 message.data[kHeartbeatTimestampKey] = base::Int64ToString(
333 base::Time::NowFromSystemTime().ToJavaTime()); 355 base::Time::NowFromSystemTime().ToJavaTime());
334 message.data[kHeartbeatDomainNameKey] = enrollment_domain_; 356 message.data[kHeartbeatDomainNameKey] = enrollment_domain_;
335 message.data[kHeartbeatDeviceIDKey] = device_id_; 357 message.data[kHeartbeatDeviceIDKey] = device_id_;
336 gcm_driver_->Send(kHeartbeatGCMAppID, 358 gcm_driver_->Send(kHeartbeatGCMAppID,
337 GetDestinationID() + kHeartbeatGCMSenderSuffix, 359 GetDestinationID() + kHeartbeatGCMSenderSuffix,
338 message, 360 message,
339 base::Bind(&HeartbeatScheduler::OnHeartbeatSent, 361 base::Bind(&HeartbeatScheduler::OnHeartbeatSent,
340 weak_factory_.GetWeakPtr())); 362 weak_factory_.GetWeakPtr()));
341 } 363 }
342 364
365 void HeartbeatScheduler::SignUpUpstreamNotification() {
366 DCHECK(gcm_driver_);
367
368 if (registration_id_.empty())
369 return;
370
371 base::TimeDelta since_last_sign_up =
Andrew T Wilson (Slow) 2015/11/20 16:37:34 Let's just remove this logic + the member var last
binjin 2015/11/20 22:56:48 Done.
372 base::TimeTicks::Now() - last_upstream_notification_signup_time_;
373
374 if (!last_upstream_notification_signup_time_.is_null() &&
375 since_last_sign_up <
376 base::TimeDelta::FromMilliseconds(kMinimumSignupIntervalMs)) {
377 return;
378 }
379
380 gcm::OutgoingMessage message;
381 message.id =
382 base::Int64ToString(base::Time::NowFromSystemTime().ToInternalValue());
383 message.data[kGcmMessageTypeKey] = kUpstreamNotificationSignUpListeningEvents;
384 message.data[kUpstreamNotificationNotifyKey] =
385 GetDestinationID() + kHeartbeatGCMSenderSuffix;
386 gcm_driver_->Send(kHeartbeatGCMAppID,
387 kUpstreamNotificationSignUpDestinationID, message,
388 base::Bind(&HeartbeatScheduler::OnUpstreamNotificationSent,
389 weak_factory_.GetWeakPtr()));
390 }
391
343 void HeartbeatScheduler::OnHeartbeatSent(const std::string& message_id, 392 void HeartbeatScheduler::OnHeartbeatSent(const std::string& message_id,
344 gcm::GCMClient::Result result) { 393 gcm::GCMClient::Result result) {
345 DVLOG(1) << "Monitoring heartbeat sent - result = " << result; 394 DVLOG(1) << "Monitoring heartbeat sent - result = " << result;
346 // Don't care if the result was successful or not - just schedule the next 395 // Don't care if the result was successful or not - just schedule the next
347 // heartbeat. 396 // heartbeat.
348 DLOG_IF(ERROR, result != gcm::GCMClient::SUCCESS) << 397 DLOG_IF(ERROR, result != gcm::GCMClient::SUCCESS) <<
349 "Error sending monitoring heartbeat: " << result; 398 "Error sending monitoring heartbeat: " << result;
350 last_heartbeat_ = base::Time::NowFromSystemTime(); 399 last_heartbeat_ = base::Time::NowFromSystemTime();
351 ScheduleNextHeartbeat(); 400 ScheduleNextHeartbeat();
352 } 401 }
353 402
403 void HeartbeatScheduler::OnUpstreamNotificationSent(
404 const std::string& message_id,
405 gcm::GCMClient::Result result) {
406 DVLOG(1) << "Upstream notification signup message sent - result = " << result;
407 DLOG_IF(ERROR, result != gcm::GCMClient::SUCCESS)
408 << "Error sending upstream notification signup message: " << result;
409 last_upstream_notification_signup_time_ = base::TimeTicks::Now();
410 }
411
354 HeartbeatScheduler::~HeartbeatScheduler() { 412 HeartbeatScheduler::~HeartbeatScheduler() {
355 ShutdownGCM(); 413 ShutdownGCM();
356 } 414 }
357 415
358 void HeartbeatScheduler::ShutdownHandler() { 416 void HeartbeatScheduler::ShutdownHandler() {
359 // This should never be called, because BrowserProcessImpl::StartTearDown() 417 // This should never be called, because BrowserProcessImpl::StartTearDown()
360 // should shutdown the BrowserPolicyConnector (which destroys this object) 418 // should shutdown the BrowserPolicyConnector (which destroys this object)
361 // before the GCMDriver. Our goal is to make sure that this object is always 419 // before the GCMDriver. Our goal is to make sure that this object is always
362 // shutdown before GCMDriver is shut down, rather than trying to handle the 420 // shutdown before GCMDriver is shut down, rather than trying to handle the
363 // case when GCMDriver goes away. 421 // case when GCMDriver goes away.
(...skipping 14 matching lines...) Expand all
378 const std::string& app_id, 436 const std::string& app_id,
379 const gcm::GCMClient::SendErrorDetails& details) { 437 const gcm::GCMClient::SendErrorDetails& details) {
380 // Ignore send errors - we already are notified above in OnHeartbeatSent(). 438 // Ignore send errors - we already are notified above in OnHeartbeatSent().
381 } 439 }
382 440
383 void HeartbeatScheduler::OnSendAcknowledged(const std::string& app_id, 441 void HeartbeatScheduler::OnSendAcknowledged(const std::string& app_id,
384 const std::string& message_id) { 442 const std::string& message_id) {
385 DVLOG(1) << "Heartbeat sent with message_id: " << message_id; 443 DVLOG(1) << "Heartbeat sent with message_id: " << message_id;
386 } 444 }
387 445
446 void HeartbeatScheduler::OnConnected(const net::IPEndPoint&) {
447 SignUpUpstreamNotification();
448 }
449
388 void HeartbeatScheduler::OnGcmIdUpdateRequestSent(bool success) { 450 void HeartbeatScheduler::OnGcmIdUpdateRequestSent(bool success) {
389 // TODO(binjin): Handle the failure, probably by exponential backoff. 451 // TODO(binjin): Handle the failure, probably by exponential backoff.
390 LOG_IF(WARNING, !success) << "Failed to send GCM id to DM server"; 452 LOG_IF(WARNING, !success) << "Failed to send GCM id to DM server";
391 } 453 }
392 454
393 } // namespace policy 455 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/policy/heartbeat_scheduler.h ('k') | chrome/browser/chromeos/policy/heartbeat_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698