// Copyright (c) 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/policy/status_uploader.h" #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/location.h" #include "base/sequenced_task_runner.h" #include "chrome/browser/chromeos/policy/device_local_account.h" #include "chrome/browser/chromeos/policy/device_status_collector.h" #include "chromeos/settings/cros_settings_names.h" #include "chromeos/settings/cros_settings_provider.h" #include "components/policy/core/common/cloud/cloud_policy_client.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/media_request_state.h" #include "content/public/common/media_stream_request.h" #include "ui/base/user_activity/user_activity_detector.h" namespace { const int kMinUploadDelayMs = 60 * 1000; // 60 seconds } // namespace namespace policy { const int64 StatusUploader::kDefaultUploadDelayMs = 3 * 60 * 60 * 1000; // 3 hours StatusUploader::StatusUploader( CloudPolicyClient* client, scoped_ptr collector, const scoped_refptr& task_runner) : client_(client), collector_(collector.Pass()), task_runner_(task_runner), upload_frequency_( base::TimeDelta::FromMilliseconds(kDefaultUploadDelayMs)), has_captured_media_(false), weak_factory_(this) { // StatusUploader is currently only created for registered clients, and // it is currently safe to assume that the client will not unregister while // StatusUploader is alive. // // If future changes result in StatusUploader's lifetime extending beyond // unregistration events, then this class should be updated // to skip status uploads for unregistered clients, and to observe the client // and kick off an upload when registration happens. DCHECK(client->is_registered()); // Track whether any media capture devices are in use - this changes what // type of information we are allowed to upload. MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this); // Listen for changes to the upload delay, and start sending updates to the // server. upload_frequency_observer_ = chromeos::CrosSettings::Get()->AddSettingsObserver( chromeos::kReportUploadFrequency, base::Bind(&StatusUploader::RefreshUploadFrequency, base::Unretained(this))); // Update the upload frequency from settings. RefreshUploadFrequency(); // Immediately schedule our next status upload (last_upload_ is set to the // start of the epoch, so this will trigger an update in the immediate // future). ScheduleNextStatusUpload(); } StatusUploader::~StatusUploader() { MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this); } void StatusUploader::ScheduleNextStatusUpload() { // Calculate when to fire off the next update (if it should have already // happened, this yields a TimeDelta of 0). base::TimeDelta delay = std::max( (last_upload_ + upload_frequency_) - base::Time::NowFromSystemTime(), base::TimeDelta()); upload_callback_.Reset(base::Bind(&StatusUploader::UploadStatus, base::Unretained(this))); task_runner_->PostDelayedTask(FROM_HERE, upload_callback_.callback(), delay); } void StatusUploader::RefreshUploadFrequency() { // Attempt to fetch the current value of the reporting settings. // If trusted values are not available, register this function to be called // back when they are available. chromeos::CrosSettings* settings = chromeos::CrosSettings::Get(); if (chromeos::CrosSettingsProvider::TRUSTED != settings->PrepareTrustedValues( base::Bind(&StatusUploader::RefreshUploadFrequency, weak_factory_.GetWeakPtr()))) { return; } // CrosSettings are trusted - update our cached upload_frequency (we cache the // value because CrosSettings can become untrusted at arbitrary times and we // want to use the last trusted value). int frequency; if (settings->GetInteger(chromeos::kReportUploadFrequency, &frequency)) { upload_frequency_ = base::TimeDelta::FromMilliseconds( std::max(kMinUploadDelayMs, frequency)); } // Schedule a new upload with the new frequency - only do this if we've // already performed the initial upload, because we want the initial upload // to happen immediately on startup and not get cancelled by settings changes. if (!last_upload_.is_null()) ScheduleNextStatusUpload(); } bool StatusUploader::IsSessionDataUploadAllowed() { // Check if we're in an auto-launched kiosk session. scoped_ptr account = collector_->GetAutoLaunchedKioskSessionInfo(); if (!account) return false; // Check if there has been any user input. if (!ui::UserActivityDetector::Get()->last_activity_time().is_null()) return false; // Screenshot is allowed as long as we have not captured media. return !has_captured_media_; } void StatusUploader::OnRequestUpdate(int render_process_id, int render_frame_id, content::MediaStreamType stream_type, const content::MediaRequestState state) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // If a video or audio capture stream is opened, set a flag so we disallow // upload of potentially sensitive data. if (state == content::MEDIA_REQUEST_STATE_OPENING && (stream_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || stream_type == content::MEDIA_DEVICE_VIDEO_CAPTURE)) { has_captured_media_ = true; } } void StatusUploader::UploadStatus() { enterprise_management::DeviceStatusReportRequest device_status; bool have_device_status = collector_->GetDeviceStatus(&device_status); enterprise_management::SessionStatusReportRequest session_status; bool have_session_status = collector_->GetDeviceSessionStatus( &session_status); if (!have_device_status && !have_session_status) { // Don't have any status to upload - just set our timer for next time. last_upload_ = base::Time::NowFromSystemTime(); ScheduleNextStatusUpload(); return; } client_->UploadDeviceStatus( have_device_status ? &device_status : nullptr, have_session_status ? &session_status : nullptr, base::Bind(&StatusUploader::OnUploadCompleted, weak_factory_.GetWeakPtr())); } void StatusUploader::OnUploadCompleted(bool success) { // Set the last upload time, regardless of whether the upload was successful // or not (we don't change the time of the next upload based on whether this // upload succeeded or not - if a status upload fails, we just skip it and // wait until it's time to try again. last_upload_ = base::Time::NowFromSystemTime(); // If the upload was successful, tell the collector so it can clear its cache // of pending items. if (success) collector_->OnSubmittedSuccessfully(); ScheduleNextStatusUpload(); } } // namespace policy