1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/policy/uploading/status_uploader.h"
#include <algorithm>
#include <string>
#include <utility>
#include "base/check_deref.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/syslog_logging.h"
#include "base/system/sys_info.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "chrome/browser/ash/policy/core/device_local_account.h"
#include "chrome/browser/ash/policy/status_collector/status_collector.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "chromeos/ash/components/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 "third_party/blink/public/common/mediastream/media_stream_request.h"
#include "ui/base/user_activity/user_activity_detector.h"
namespace em = enterprise_management;
namespace {
// Minimum delay between two consecutive uploads
const int kMinUploadDelayMs = 60 * 1000; // 60 seconds
// Minimum delay after scheduling an upload
const int kMinUploadScheduleDelayMs = 60 * 1000; // 60 seconds
// Minimum interval between the last upload and the next immediate upload
constexpr base::TimeDelta kMinImmediateUploadInterval = base::Seconds(10);
// Time after the last user activity after which taking a screenshot is allowed.
constexpr base::TimeDelta kIdlenessCutOffTime = base::Minutes(5);
base::TimeDelta GetDeviceIdleTime() {
base::TimeTicks last_activity =
CHECK_DEREF(ui::UserActivityDetector::Get()).last_activity_time();
if (last_activity.is_null()) {
// No activity since booting.
return base::TimeDelta::Max();
}
return base::TimeTicks::Now() - last_activity;
}
std::string GetLastUserActivityName() {
return CHECK_DEREF(ui::UserActivityDetector::Get()).last_activity_name();
}
} // namespace
namespace policy {
StatusUploader::StatusUploader(
CloudPolicyClient* client,
std::unique_ptr<StatusCollector> collector,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
base::TimeDelta default_upload_frequency)
: client_(client),
collector_(std::move(collector)),
task_runner_(task_runner),
upload_frequency_(default_upload_frequency),
has_captured_media_(false) {
// 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_subscription_ =
ash::CrosSettings::Get()->AddSettingsObserver(
ash::kReportUploadFrequency,
base::BindRepeating(&StatusUploader::RefreshUploadFrequency,
base::Unretained(this)));
// Update the upload frequency from settings.
RefreshUploadFrequency();
// Schedule our next status upload in a minute (last_upload_ is set to the
// start of the epoch, so this will trigger an update in
// kMinUploadScheduleDelayMs from now).
ScheduleNextStatusUpload();
}
StatusUploader::~StatusUploader() {
MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this);
}
bool StatusUploader::ScheduleNextStatusUpload(bool immediately) {
// Don't schedule a new status upload if there's a status upload in progress
// (it will be scheduled once the current one completes).
if (status_upload_in_progress_) {
SYSLOG(INFO) << "In the middle of a status upload, not scheduling the next "
<< "one until this one finishes.";
return false;
}
base::Time now = base::Time::NowFromSystemTime();
// Calculate when to fire off the next update (if it should have already
// happened, this yields a TimeDelta of kMinUploadScheduleDelayMs).
base::TimeDelta delay =
std::max((last_upload_ + upload_frequency_) - now,
base::Milliseconds(kMinUploadScheduleDelayMs));
// The next upload should be scheduled for at least
// kMinImmediateUploadInterval after the last upload if it is immediately.
if (immediately)
delay = std::max((last_upload_ + kMinImmediateUploadInterval) - now,
base::TimeDelta());
upload_callback_.Reset(
base::BindOnce(&StatusUploader::UploadStatus, base::Unretained(this)));
task_runner_->PostDelayedTask(FROM_HERE, upload_callback_.callback(), delay);
return true;
}
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.
ash::CrosSettings* settings = ash::CrosSettings::Get();
if (ash::CrosSettingsProvider::TRUSTED !=
settings->PrepareTrustedValues(
base::BindOnce(&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(ash::kReportUploadFrequency, &frequency)) {
SYSLOG(INFO) << "Changing status upload frequency from "
<< upload_frequency_ << " to "
<< base::Milliseconds(frequency);
upload_frequency_ =
base::Milliseconds(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 in a minute after startup and not get cancelled by settings
// changes.
if (!last_upload_.is_null())
ScheduleNextStatusUpload();
}
bool StatusUploader::IsScreenshotAllowed() {
// Check if we're in an auto-launched kiosk session.
std::unique_ptr<DeviceLocalAccount> account =
collector_->GetAutoLaunchedKioskSessionInfo();
if (!account) {
SYSLOG(WARNING) << "Not a kiosk session, data upload is not allowed.";
return false;
}
// Check if there has been any user input.
if (GetDeviceIdleTime() < kIdlenessCutOffTime) {
SYSLOG(WARNING) << "User input " << GetLastUserActivityName()
<< " detected " << GetDeviceIdleTime()
<< " ago , screenshot upload is not allowed.";
return false;
}
// Screenshot is allowed as long as we have not captured media.
if (has_captured_media_) {
SYSLOG(WARNING) << "Media has been captured, data upload is not allowed.";
return false;
} else {
return true;
}
}
void StatusUploader::OnRequestUpdate(int render_process_id,
int render_frame_id,
blink::mojom::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 == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ||
stream_type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE)) {
has_captured_media_ = true;
}
}
bool StatusUploader::ScheduleNextStatusUploadImmediately() {
return ScheduleNextStatusUpload(true);
}
void StatusUploader::UploadStatus() {
status_upload_in_progress_ = true;
// Gather status in the background.
collector_->GetStatusAsync(base::BindOnce(&StatusUploader::OnStatusReceived,
weak_factory_.GetWeakPtr()));
}
void StatusUploader::OnStatusReceived(StatusCollectorParams callback_params) {
bool has_device_status = callback_params.device_status != nullptr;
bool has_session_status = callback_params.session_status != nullptr;
bool has_child_status = callback_params.child_status != nullptr;
if (!has_device_status && !has_session_status && !has_child_status) {
SYSLOG(INFO) << "Skipping status upload because no data to upload";
// Don't have any status to upload - just set our timer for next time.
last_upload_ = base::Time::NowFromSystemTime();
status_upload_in_progress_ = false;
ScheduleNextStatusUpload();
return;
}
SYSLOG(INFO) << "Starting status upload: has_device_status = "
<< has_device_status;
client_->UploadDeviceStatus(callback_params.device_status.get(),
callback_params.session_status.get(),
callback_params.child_status.get(),
base::BindOnce(&StatusUploader::OnUploadCompleted,
weak_factory_.GetWeakPtr()));
}
void StatusUploader::OnUploadCompleted(CloudPolicyClient::Result result) {
// 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();
status_upload_in_progress_ = false;
if (result.IsClientNotRegisteredError()) {
// This can happen when the DM Token is missing (crbug.com/705607).
VLOG(1) << "Skipping status upload because the client is not registered";
} else if (result.IsSuccess()) {
SYSLOG(INFO) << "Status upload successful";
// Tell the collector so it can clear its cache of pending items.
collector_->OnSubmittedSuccessfully();
} else if (result.IsDMServerError()) {
SYSLOG(ERROR) << "Error uploading status: " << result.GetDMServerError();
} else {
NOTREACHED();
}
ScheduleNextStatusUpload();
}
} // namespace policy
|