blob: 39c7c724e336ed0e15af9d2291ff0dace15d8185 [file] [log] [blame]
// 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 <algorithm>
#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<DeviceStatusCollector> collector,
const scoped_refptr<base::SequencedTaskRunner>& 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<DeviceLocalAccount> 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