blob: 0b740a4f0294863ba051d66370917fb6289cd228 [file] [log] [blame]
// Copyright (c) 2012 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/upgrade_detector_chromeos.h"
#include <stdint.h>
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/update_engine_client.h"
using chromeos::DBusThreadManager;
using chromeos::UpdateEngineClient;
namespace {
// How long to wait (each cycle) before checking which severity level we should
// be at. Once we reach the highest severity, the timer will stop.
const int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes.
} // namespace
class UpgradeDetectorChromeos::ChannelsRequester {
public:
typedef base::Callback<void(const std::string&, const std::string&)>
OnChannelsReceivedCallback;
ChannelsRequester() : weak_factory_(this) {}
void RequestChannels(const OnChannelsReceivedCallback& callback) {
UpdateEngineClient* client =
DBusThreadManager::Get()->GetUpdateEngineClient();
callback_ = callback;
client->GetChannel(true /* get_current_channel */,
base::Bind(&ChannelsRequester::SetCurrentChannel,
weak_factory_.GetWeakPtr()));
client->GetChannel(false /* get_current_channel */,
base::Bind(&ChannelsRequester::SetTargetChannel,
weak_factory_.GetWeakPtr()));
}
private:
void SetCurrentChannel(const std::string& current_channel) {
DCHECK(!current_channel.empty());
current_channel_ = current_channel;
TriggerCallbackIfReady();
}
void SetTargetChannel(const std::string& target_channel) {
DCHECK(!target_channel.empty());
target_channel_ = target_channel;
TriggerCallbackIfReady();
}
void TriggerCallbackIfReady() {
if (current_channel_.empty() || target_channel_.empty())
return;
if (!callback_.is_null())
callback_.Run(current_channel_, target_channel_);
}
std::string current_channel_;
std::string target_channel_;
OnChannelsReceivedCallback callback_;
base::WeakPtrFactory<ChannelsRequester> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChannelsRequester);
};
UpgradeDetectorChromeos::UpgradeDetectorChromeos()
: initialized_(false), weak_factory_(this) {
}
UpgradeDetectorChromeos::~UpgradeDetectorChromeos() {
}
void UpgradeDetectorChromeos::Init() {
DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
initialized_ = true;
}
void UpgradeDetectorChromeos::Shutdown() {
// Init() may not be called from tests.
if (!initialized_)
return;
DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
}
void UpgradeDetectorChromeos::UpdateStatusChanged(
const UpdateEngineClient::Status& status) {
if (status.status == UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
upgrade_detected_time_ = base::Time::Now();
channels_requester_.reset(new UpgradeDetectorChromeos::ChannelsRequester());
channels_requester_->RequestChannels(
base::Bind(&UpgradeDetectorChromeos::OnChannelsReceived,
weak_factory_.GetWeakPtr()));
} else if (status.status ==
UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE) {
// Update engine broadcasts this state only when update is available but
// downloading over cellular connection requires user's agreement.
NotifyUpdateOverCellularAvailable();
}
}
void UpgradeDetectorChromeos::OnUpdateOverCellularOneTimePermissionGranted() {
NotifyUpdateOverCellularOneTimePermissionGranted();
}
void UpgradeDetectorChromeos::NotifyOnUpgrade() {
base::TimeDelta delta = base::Time::Now() - upgrade_detected_time_;
int64_t time_passed = delta.InDays();
const int kSevereThreshold = 7;
const int kHighThreshold = 4;
const int kElevatedThreshold = 2;
const int kLowThreshold = 0;
// These if statements must be sorted (highest interval first).
if (time_passed >= kSevereThreshold) {
set_upgrade_notification_stage(UPGRADE_ANNOYANCE_SEVERE);
// We can't get any higher, baby.
upgrade_notification_timer_.Stop();
} else if (time_passed >= kHighThreshold) {
set_upgrade_notification_stage(UPGRADE_ANNOYANCE_HIGH);
} else if (time_passed >= kElevatedThreshold) {
set_upgrade_notification_stage(UPGRADE_ANNOYANCE_ELEVATED);
} else if (time_passed >= kLowThreshold) {
set_upgrade_notification_stage(UPGRADE_ANNOYANCE_LOW);
} else {
return; // Not ready to recommend upgrade.
}
NotifyUpgrade();
}
void UpgradeDetectorChromeos::OnChannelsReceived(
const std::string& current_channel,
const std::string& target_channel) {
// As current update engine status is UPDATE_STATUS_UPDATED_NEED_REBOOT
// and target channel is more stable than current channel, powerwash
// will be performed after reboot.
set_is_factory_reset_required(UpdateEngineClient::IsTargetChannelMoreStable(
current_channel, target_channel));
// ChromeOS shows upgrade arrow once the upgrade becomes available.
NotifyOnUpgrade();
// Setup timer to to move along the upgrade advisory system.
upgrade_notification_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kNotifyCycleTimeMs),
this,
&UpgradeDetectorChromeos::NotifyOnUpgrade);
}
// static
UpgradeDetectorChromeos* UpgradeDetectorChromeos::GetInstance() {
return base::Singleton<UpgradeDetectorChromeos>::get();
}
// static
UpgradeDetector* UpgradeDetector::GetInstance() {
return UpgradeDetectorChromeos::GetInstance();
}