This source file includes following definitions.
- GetErrorMessage
- LoadCellularConfigFile
- SetErrorMap
- LoadFromFile
- weak_ptr_factory_
- GetInstance
- TerminateActivation
- DefaultNetworkChanged
- NetworkPropertiesUpdated
- AddObserver
- RemoveObserver
- InitiateActivation
- ContinueActivation
- GetPropertiesAndContinueActivation
- GetPropertiesFailure
- OnSetTransactionStatus
- HandleSetTransactionStatus
- OnPortalLoaded
- HandlePortalLoaded
- StartOTASPTimer
- StartActivation
- RetryOTASP
- StartOTASP
- HandleOTASPTimeout
- ForceReconnect
- ReconnectTimedOut
- ContinueConnecting
- RefreshCellularNetworks
- GetNetworkState
- EvaluateCellularNetwork
- PickNextState
- PickNextOfflineState
- PickNextOnlineState
- GetStateDescription
- CompleteActivation
- RunningActivation
- HandleActivationFailure
- RequestCellularActivation
- ChangeState
- ReEnableCertRevocationChecking
- DisableCertRevocationChecking
- GotActivationError
- GetErrorMessage
- SignalCellularPlanPayment
- HasRecentCellularPlanPayment
#include "chrome/browser/chromeos/mobile/mobile_activator.h"
#include <algorithm>
#include <map>
#include <string>
#include "ash/system/chromeos/network/network_connect.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/observer_list_threadsafe.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/pref_names.h"
#include "chromeos/network/device_state.h"
#include "chromeos/network/network_activation_handler.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_connection_handler.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/network_handler_callbacks.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/shill_property_util.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using content::BrowserThread;
namespace {
const char kCellularConfigPath[] =
"/usr/share/chromeos-assets/mobile/mobile_config.json";
const char kVersionField[] = "version";
const char kErrorsField[] = "errors";
const int kMaxOTASPTries = 3;
const int kMaxPortalReconnectCount = 2;
const int kReconnectDelayMS = 3000;
const int kOTASPRetryDelay = 40000;
const int kMaxReconnectTime = 30000;
const char kErrorDefault[] = "default";
const char kErrorBadConnectionPartial[] = "bad_connection_partial";
const char kErrorBadConnectionActivated[] = "bad_connection_activated";
const char kErrorRoamingOnConnection[] = "roaming_connection";
const char kErrorNoEVDO[] = "no_evdo";
const char kErrorRoamingActivation[] = "roaming_activation";
const char kErrorRoamingPartiallyActivated[] = "roaming_partially_activated";
const char kErrorNoService[] = "no_service";
const char kErrorDisabled[] = "disabled";
const char kErrorNoDevice[] = "no_device";
const char kFailedPaymentError[] = "failed_payment";
const char kFailedConnectivity[] = "connectivity";
}
namespace chromeos {
CellularConfigDocument::CellularConfigDocument() {}
std::string CellularConfigDocument::GetErrorMessage(const std::string& code) {
base::AutoLock create(config_lock_);
ErrorMap::iterator iter = error_map_.find(code);
if (iter == error_map_.end())
return code;
return iter->second;
}
void CellularConfigDocument::LoadCellularConfigFile() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath config_path(kCellularConfigPath);
if (!base::PathExists(config_path))
return;
if (LoadFromFile(config_path))
DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath;
else
LOG(ERROR) << "Error loading cellular config file: " << kCellularConfigPath;
}
CellularConfigDocument::~CellularConfigDocument() {}
void CellularConfigDocument::SetErrorMap(
const ErrorMap& map) {
base::AutoLock create(config_lock_);
error_map_.clear();
error_map_.insert(map.begin(), map.end());
}
bool CellularConfigDocument::LoadFromFile(const base::FilePath& config_path) {
std::string config;
if (!base::ReadFileToString(config_path, &config))
return false;
scoped_ptr<base::Value> root(
base::JSONReader::Read(config, base::JSON_ALLOW_TRAILING_COMMAS));
DCHECK(root.get() != NULL);
if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) {
LOG(WARNING) << "Bad cellular config file";
return false;
}
base::DictionaryValue* root_dict =
static_cast<base::DictionaryValue*>(root.get());
if (!root_dict->GetString(kVersionField, &version_)) {
LOG(WARNING) << "Cellular config file missing version";
return false;
}
ErrorMap error_map;
base::DictionaryValue* errors = NULL;
if (!root_dict->GetDictionary(kErrorsField, &errors))
return false;
for (base::DictionaryValue::Iterator it(*errors);
!it.IsAtEnd(); it.Advance()) {
std::string value;
if (!it.value().GetAsString(&value)) {
LOG(WARNING) << "Bad cellular config error value";
return false;
}
error_map.insert(ErrorMap::value_type(it.key(), value));
}
SetErrorMap(error_map);
return true;
}
MobileActivator::MobileActivator()
: cellular_config_(new CellularConfigDocument()),
state_(PLAN_ACTIVATION_PAGE_LOADING),
reenable_cert_check_(false),
terminated_(true),
pending_activation_request_(false),
connection_retry_count_(0),
initial_OTASP_attempts_(0),
trying_OTASP_attempts_(0),
final_OTASP_attempts_(0),
payment_reconnect_count_(0),
weak_ptr_factory_(this) {
}
MobileActivator::~MobileActivator() {
TerminateActivation();
}
MobileActivator* MobileActivator::GetInstance() {
return Singleton<MobileActivator>::get();
}
void MobileActivator::TerminateActivation() {
state_duration_timer_.Stop();
continue_reconnect_timer_.Stop();
reconnect_timeout_timer_.Stop();
if (NetworkHandler::IsInitialized())
NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
FROM_HERE);
ReEnableCertRevocationChecking();
meid_.clear();
iccid_.clear();
service_path_.clear();
device_path_.clear();
state_ = PLAN_ACTIVATION_PAGE_LOADING;
reenable_cert_check_ = false;
terminated_ = true;
cellular_config_ = new CellularConfigDocument();
}
void MobileActivator::DefaultNetworkChanged(const NetworkState* network) {
RefreshCellularNetworks();
}
void MobileActivator::NetworkPropertiesUpdated(const NetworkState* network) {
if (state_ == PLAN_ACTIVATION_PAGE_LOADING)
return;
if (!network || network->type() != shill::kTypeCellular)
return;
const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
GetDeviceState(network->device_path());
if (!device) {
LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
return;
}
if (network->device_path() != device_path_) {
LOG(WARNING) << "Ignoring property update for cellular service "
<< network->path()
<< " on unknown device " << network->device_path()
<< " (Stored device path = " << device_path_ << ")";
return;
}
service_path_ = network->path();
EvaluateCellularNetwork(network);
}
void MobileActivator::AddObserver(MobileActivator::Observer* observer) {
DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.AddObserver(observer);
}
void MobileActivator::RemoveObserver(MobileActivator::Observer* observer) {
DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.RemoveObserver(observer);
}
void MobileActivator::InitiateActivation(const std::string& service_path) {
DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::UI));
const NetworkState* network = GetNetworkState(service_path);
if (!network) {
LOG(ERROR) << "Cellular service can't be found: " << service_path;
return;
}
const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
GetDeviceState(network->device_path());
if (!device) {
LOG(ERROR) << "Cellular device can't be found: " << network->device_path();
return;
}
terminated_ = false;
meid_ = device->meid();
iccid_ = device->iccid();
service_path_ = service_path;
device_path_ = network->device_path();
ChangeState(network, PLAN_ACTIVATION_PAGE_LOADING, "");
BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
base::Bind(&CellularConfigDocument::LoadCellularConfigFile,
cellular_config_.get()),
base::Bind(&MobileActivator::ContinueActivation, AsWeakPtr()));
}
void MobileActivator::ContinueActivation() {
NetworkHandler::Get()->network_configuration_handler()->GetProperties(
service_path_,
base::Bind(&MobileActivator::GetPropertiesAndContinueActivation,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&MobileActivator::GetPropertiesFailure,
weak_ptr_factory_.GetWeakPtr()));
}
void MobileActivator::GetPropertiesAndContinueActivation(
const std::string& service_path,
const base::DictionaryValue& properties) {
if (service_path != service_path_) {
NET_LOG_EVENT("MobileActivator::GetProperties received for stale network",
service_path);
return;
}
const base::DictionaryValue* payment_dict;
std::string usage_url, payment_url;
if (!properties.GetStringWithoutPathExpansion(
shill::kUsageURLProperty, &usage_url) ||
!properties.GetDictionaryWithoutPathExpansion(
shill::kPaymentPortalProperty, &payment_dict) ||
!payment_dict->GetStringWithoutPathExpansion(
shill::kPaymentPortalURL, &payment_url)) {
NET_LOG_ERROR("MobileActivator missing properties", service_path_);
return;
}
if (payment_url.empty() && usage_url.empty())
return;
DisableCertRevocationChecking();
base::DictionaryValue auto_connect_property;
auto_connect_property.SetBoolean(shill::kAutoConnectProperty, true);
NetworkHandler::Get()->network_configuration_handler()->SetProperties(
service_path_,
auto_connect_property,
base::Bind(&base::DoNothing),
network_handler::ErrorCallback());
StartActivation();
}
void MobileActivator::GetPropertiesFailure(
const std::string& error_name,
scoped_ptr<base::DictionaryValue> error_data) {
NET_LOG_ERROR("MobileActivator GetProperties Failed: " + error_name,
service_path_);
}
void MobileActivator::OnSetTransactionStatus(bool success) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&MobileActivator::HandleSetTransactionStatus,
AsWeakPtr(), success));
}
void MobileActivator::HandleSetTransactionStatus(bool success) {
if (success && state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) {
SignalCellularPlanPayment();
UMA_HISTOGRAM_COUNTS("Cellular.PaymentReceived", 1);
const NetworkState* network = GetNetworkState(service_path_);
if (network && network->activate_over_non_cellular_networks()) {
state_ = PLAN_ACTIVATION_DONE;
NetworkHandler::Get()->network_activation_handler()->
CompleteActivation(network->path(),
base::Bind(&base::DoNothing),
network_handler::ErrorCallback());
} else {
StartOTASP();
}
} else {
UMA_HISTOGRAM_COUNTS("Cellular.PaymentFailed", 1);
}
}
void MobileActivator::OnPortalLoaded(bool success) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&MobileActivator::HandlePortalLoaded,
AsWeakPtr(), success));
}
void MobileActivator::HandlePortalLoaded(bool success) {
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
ChangeState(NULL, PLAN_ACTIVATION_ERROR,
GetErrorMessage(kErrorNoService));
return;
}
if (state_ == PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING ||
state_ == PLAN_ACTIVATION_SHOWING_PAYMENT) {
if (success) {
payment_reconnect_count_ = 0;
ChangeState(network, PLAN_ACTIVATION_SHOWING_PAYMENT, std::string());
} else {
if (network->activate_over_non_cellular_networks())
return;
payment_reconnect_count_++;
if (payment_reconnect_count_ > kMaxPortalReconnectCount) {
ChangeState(NULL, PLAN_ACTIVATION_ERROR,
GetErrorMessage(kErrorNoService));
return;
}
ChangeState(network,
PLAN_ACTIVATION_RECONNECTING,
GetErrorMessage(kFailedPaymentError));
}
} else {
NOTREACHED() << "Called paymentPortalLoad while in unexpected state: "
<< GetStateDescription(state_);
}
}
void MobileActivator::StartOTASPTimer() {
pending_activation_request_ = false;
state_duration_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kOTASPRetryDelay),
this, &MobileActivator::HandleOTASPTimeout);
}
void MobileActivator::StartActivation() {
UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1);
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
NetworkStateHandler::TechnologyState technology_state =
NetworkHandler::Get()->network_state_handler()->GetTechnologyState(
NetworkTypePattern::Cellular());
std::string error;
if (technology_state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) {
error = kErrorNoDevice;
} else if (technology_state != NetworkStateHandler::TECHNOLOGY_ENABLED) {
error = kErrorDisabled;
} else {
error = kErrorNoService;
}
ChangeState(NULL, PLAN_ACTIVATION_ERROR, GetErrorMessage(error));
return;
}
NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
if (network->activate_over_non_cellular_networks()) {
ChangeState(
network,
(network->activation_state() == shill::kActivationStateActivated) ?
PLAN_ACTIVATION_DONE :
PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
"");
RefreshCellularNetworks();
return;
}
if (HasRecentCellularPlanPayment() &&
(network->activation_state() ==
shill::kActivationStatePartiallyActivated)) {
state_ = PLAN_ACTIVATION_START_OTASP;
} else {
state_ = PLAN_ACTIVATION_START;
}
EvaluateCellularNetwork(network);
}
void MobileActivator::RetryOTASP() {
DCHECK(state_ == PLAN_ACTIVATION_DELAY_OTASP);
StartOTASP();
}
void MobileActivator::StartOTASP() {
const NetworkState* network = GetNetworkState(service_path_);
ChangeState(network, PLAN_ACTIVATION_START_OTASP, std::string());
EvaluateCellularNetwork(network);
}
void MobileActivator::HandleOTASPTimeout() {
LOG(WARNING) << "OTASP seems to be taking too long.";
const NetworkState* network = GetNetworkState(service_path_);
if (state_ == PLAN_ACTIVATION_INITIATING_ACTIVATION) {
++initial_OTASP_attempts_;
if (initial_OTASP_attempts_ <= kMaxOTASPTries) {
ChangeState(network,
PLAN_ACTIVATION_RECONNECTING,
GetErrorMessage(kErrorDefault));
return;
}
} else if (state_ == PLAN_ACTIVATION_TRYING_OTASP) {
++trying_OTASP_attempts_;
if (trying_OTASP_attempts_ <= kMaxOTASPTries) {
ChangeState(network,
PLAN_ACTIVATION_RECONNECTING,
GetErrorMessage(kErrorDefault));
return;
}
} else if (state_ == PLAN_ACTIVATION_OTASP) {
++final_OTASP_attempts_;
if (final_OTASP_attempts_ <= kMaxOTASPTries) {
ChangeState(network,
PLAN_ACTIVATION_DELAY_OTASP,
GetErrorMessage(kErrorDefault));
return;
}
} else {
LOG(ERROR) << "OTASP timed out from a non-OTASP wait state?";
}
LOG(ERROR) << "OTASP failed too many times; aborting.";
ChangeState(network,
PLAN_ACTIVATION_ERROR,
GetErrorMessage(kErrorDefault));
}
void MobileActivator::ForceReconnect(const NetworkState* network,
PlanActivationState next_state) {
DCHECK(network);
post_reconnect_state_ = next_state;
UMA_HISTOGRAM_COUNTS("Cellular.ActivationRetry", 1);
VLOG(1) << "Disconnecting from " << network->path();
NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
network->path(),
base::Bind(&base::DoNothing),
network_handler::ErrorCallback());
continue_reconnect_timer_.Stop();
continue_reconnect_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kReconnectDelayMS),
this, &MobileActivator::ContinueConnecting);
reconnect_timeout_timer_.Stop();
reconnect_timeout_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kMaxReconnectTime),
this, &MobileActivator::ReconnectTimedOut);
}
void MobileActivator::ReconnectTimedOut() {
LOG(ERROR) << "Ending activation attempt after failing to reconnect.";
const NetworkState* network = GetNetworkState(service_path_);
ChangeState(network,
PLAN_ACTIVATION_ERROR,
GetErrorMessage(kFailedConnectivity));
}
void MobileActivator::ContinueConnecting() {
const NetworkState* network = GetNetworkState(service_path_);
if (network && network->IsConnectedState()) {
if (network->connection_state() == shill::kStatePortal &&
network->error() == shill::kErrorDNSLookupFailed) {
NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
network->path(),
base::Bind(&base::DoNothing),
network_handler::ErrorCallback());
return;
}
continue_reconnect_timer_.Stop();
EvaluateCellularNetwork(network);
} else {
LOG(WARNING) << "Connect failed, will try again in a little bit.";
if (network) {
VLOG(1) << "Connecting to: " << network->path();
ash::network_connect::ConnectToNetwork(
network->path(), NULL );
}
}
}
void MobileActivator::RefreshCellularNetworks() {
if (state_ == PLAN_ACTIVATION_PAGE_LOADING ||
state_ == PLAN_ACTIVATION_DONE ||
state_ == PLAN_ACTIVATION_ERROR) {
return;
}
NetworkStateHandler* nsh = NetworkHandler::Get()->network_state_handler();
const NetworkState* network = GetNetworkState(service_path_);
if (network && network->activate_over_non_cellular_networks()) {
bool waiting = (state_ == PLAN_ACTIVATION_WAITING_FOR_CONNECTION);
bool is_online = nsh->DefaultNetwork() &&
nsh->DefaultNetwork()->connection_state() == shill::kStateOnline;
if (waiting && is_online) {
ChangeState(network, post_reconnect_state_, "");
} else if (!waiting && !is_online) {
ChangeState(network, PLAN_ACTIVATION_WAITING_FOR_CONNECTION, "");
}
}
EvaluateCellularNetwork(network);
}
const NetworkState* MobileActivator::GetNetworkState(
const std::string& service_path) {
return NetworkHandler::Get()->network_state_handler()->GetNetworkState(
service_path);
}
void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) {
if (terminated_) {
LOG(ERROR) << "Tried to run MobileActivator state machine while "
<< "terminated.";
return;
}
if (!network) {
LOG(WARNING) << "Cellular service lost";
return;
}
LOG(WARNING) << "Cellular:\n service state=" << network->connection_state()
<< "\n ui=" << GetStateDescription(state_)
<< "\n activation=" << network->activation_state()
<< "\n error=" << network->error()
<< "\n setvice_path=" << network->path()
<< "\n connected=" << network->IsConnectedState();
if (network->activate_over_non_cellular_networks())
return;
std::string error_description;
PlanActivationState new_state = PickNextState(network, &error_description);
ChangeState(network, new_state, error_description);
}
MobileActivator::PlanActivationState MobileActivator::PickNextState(
const NetworkState* network, std::string* error_description) const {
PlanActivationState new_state = state_;
if (!network->IsConnectedState())
new_state = PickNextOfflineState(network);
else
new_state = PickNextOnlineState(network);
if (new_state != PLAN_ACTIVATION_ERROR &&
GotActivationError(network, error_description)) {
const std::string& activation = network->activation_state();
if ((activation == shill::kActivationStatePartiallyActivated ||
activation == shill::kActivationStateActivating) &&
(network->error().empty() ||
network->error() == shill::kErrorOtaspFailed) &&
network->connection_state() == shill::kStateActivationFailure) {
NET_LOG_EVENT("Activation failure detected ", network->path());
switch (state_) {
case PLAN_ACTIVATION_OTASP:
new_state = PLAN_ACTIVATION_DELAY_OTASP;
break;
case PLAN_ACTIVATION_INITIATING_ACTIVATION:
case PLAN_ACTIVATION_TRYING_OTASP:
new_state = PLAN_ACTIVATION_START;
break;
case PLAN_ACTIVATION_START:
new_state = PLAN_ACTIVATION_TRYING_OTASP;
break;
case PLAN_ACTIVATION_DELAY_OTASP:
new_state = state_;
break;
default:
new_state = PLAN_ACTIVATION_ERROR;
break;
}
} else {
LOG(WARNING) << "Unexpected activation failure for " << network->path();
new_state = PLAN_ACTIVATION_ERROR;
}
}
if (new_state == PLAN_ACTIVATION_ERROR && !error_description->length())
*error_description = GetErrorMessage(kErrorDefault);
return new_state;
}
MobileActivator::PlanActivationState MobileActivator::PickNextOfflineState(
const NetworkState* network) const {
PlanActivationState new_state = state_;
const std::string& activation = network->activation_state();
switch (state_) {
case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
case PLAN_ACTIVATION_SHOWING_PAYMENT:
if (!network->activate_over_non_cellular_networks())
new_state = PLAN_ACTIVATION_RECONNECTING;
break;
case PLAN_ACTIVATION_START:
if (activation == shill::kActivationStateActivated) {
if (network->connection_state() == shill::kStatePortal)
new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
else
new_state = PLAN_ACTIVATION_DONE;
} else if (activation == shill::kActivationStatePartiallyActivated) {
new_state = PLAN_ACTIVATION_TRYING_OTASP;
} else {
new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
}
break;
default:
VLOG(1) << "Waiting for cellular service to connect.";
break;
}
return new_state;
}
MobileActivator::PlanActivationState MobileActivator::PickNextOnlineState(
const NetworkState* network) const {
PlanActivationState new_state = state_;
const std::string& activation = network->activation_state();
switch (state_) {
case PLAN_ACTIVATION_START:
if (activation == shill::kActivationStateActivated) {
if (network->connection_state() == shill::kStatePortal)
new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
else
new_state = PLAN_ACTIVATION_DONE;
} else if (activation == shill::kActivationStatePartiallyActivated) {
new_state = PLAN_ACTIVATION_TRYING_OTASP;
} else {
new_state = PLAN_ACTIVATION_INITIATING_ACTIVATION;
}
break;
case PLAN_ACTIVATION_START_OTASP: {
if (activation == shill::kActivationStatePartiallyActivated) {
new_state = PLAN_ACTIVATION_OTASP;
} else if (activation == shill::kActivationStateActivated) {
new_state = PLAN_ACTIVATION_RECONNECTING;
} else {
LOG(WARNING) << "Unexpected activation state for device "
<< network->path();
}
break;
}
case PLAN_ACTIVATION_DELAY_OTASP:
break;
case PLAN_ACTIVATION_INITIATING_ACTIVATION: {
if (pending_activation_request_) {
VLOG(1) << "Waiting for pending activation attempt to finish";
} else if (activation == shill::kActivationStateActivated ||
activation == shill::kActivationStatePartiallyActivated) {
new_state = PLAN_ACTIVATION_START;
} else if (activation == shill::kActivationStateNotActivated ||
activation == shill::kActivationStateActivating) {
} else {
LOG(WARNING) << "Unknown transition";
}
break;
}
case PLAN_ACTIVATION_OTASP:
case PLAN_ACTIVATION_TRYING_OTASP:
if (pending_activation_request_) {
VLOG(1) << "Waiting for pending activation attempt to finish";
} else if (activation == shill::kActivationStateNotActivated ||
activation == shill::kActivationStateActivating) {
VLOG(1) << "Waiting for the OTASP to finish and the service to "
<< "come back online";
} else if (activation == shill::kActivationStateActivated) {
new_state = PLAN_ACTIVATION_DONE;
} else {
new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
}
break;
case PLAN_ACTIVATION_RECONNECTING_PAYMENT:
if (network->connection_state() != shill::kStatePortal &&
activation == shill::kActivationStateActivated)
new_state = PLAN_ACTIVATION_DONE;
else
new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
break;
case PLAN_ACTIVATION_PAGE_LOADING:
break;
case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
case PLAN_ACTIVATION_SHOWING_PAYMENT:
case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
break;
case PLAN_ACTIVATION_RECONNECTING:
new_state = post_reconnect_state_;
break;
case PLAN_ACTIVATION_DONE:
case PLAN_ACTIVATION_ERROR:
break;
}
return new_state;
}
const char* MobileActivator::GetStateDescription(PlanActivationState state) {
switch (state) {
case PLAN_ACTIVATION_PAGE_LOADING:
return "PAGE_LOADING";
case PLAN_ACTIVATION_START:
return "ACTIVATION_START";
case PLAN_ACTIVATION_INITIATING_ACTIVATION:
return "INITIATING_ACTIVATION";
case PLAN_ACTIVATION_TRYING_OTASP:
return "TRYING_OTASP";
case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
return "PAYMENT_PORTAL_LOADING";
case PLAN_ACTIVATION_SHOWING_PAYMENT:
return "SHOWING_PAYMENT";
case PLAN_ACTIVATION_RECONNECTING_PAYMENT:
return "RECONNECTING_PAYMENT";
case PLAN_ACTIVATION_DELAY_OTASP:
return "DELAY_OTASP";
case PLAN_ACTIVATION_START_OTASP:
return "START_OTASP";
case PLAN_ACTIVATION_OTASP:
return "OTASP";
case PLAN_ACTIVATION_DONE:
return "DONE";
case PLAN_ACTIVATION_ERROR:
return "ERROR";
case PLAN_ACTIVATION_RECONNECTING:
return "RECONNECTING";
case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
return "WAITING FOR CONNECTION";
}
return "UNKNOWN";
}
void MobileActivator::CompleteActivation() {
NetworkHandler::Get()->network_state_handler()->RemoveObserver(
this, FROM_HERE);
ReEnableCertRevocationChecking();
}
bool MobileActivator::RunningActivation() const {
return !(state_ == PLAN_ACTIVATION_DONE ||
state_ == PLAN_ACTIVATION_ERROR ||
state_ == PLAN_ACTIVATION_PAGE_LOADING);
}
void MobileActivator::HandleActivationFailure(
const std::string& service_path,
PlanActivationState new_state,
const std::string& error_name,
scoped_ptr<base::DictionaryValue> error_data) {
pending_activation_request_ = false;
const NetworkState* network = GetNetworkState(service_path);
if (!network) {
NET_LOG_ERROR("Cellular service no longer exists", service_path);
return;
}
UMA_HISTOGRAM_COUNTS("Cellular.ActivationFailure", 1);
NET_LOG_ERROR("Failed to call Activate() on service", service_path);
if (new_state == PLAN_ACTIVATION_OTASP) {
ChangeState(network, PLAN_ACTIVATION_DELAY_OTASP, std::string());
} else {
ChangeState(network,
PLAN_ACTIVATION_ERROR,
GetErrorMessage(kFailedConnectivity));
}
}
void MobileActivator::RequestCellularActivation(
const NetworkState* network,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback) {
DCHECK(network);
NET_LOG_EVENT("Activating cellular service", network->path());
UMA_HISTOGRAM_COUNTS("Cellular.ActivationTry", 1);
pending_activation_request_ = true;
NetworkHandler::Get()->network_activation_handler()->
Activate(network->path(),
"",
success_callback,
error_callback);
}
void MobileActivator::ChangeState(const NetworkState* network,
PlanActivationState new_state,
std::string error_description) {
if (!network) {
switch (new_state) {
case PLAN_ACTIVATION_INITIATING_ACTIVATION:
case PLAN_ACTIVATION_TRYING_OTASP:
case PLAN_ACTIVATION_OTASP:
case PLAN_ACTIVATION_DONE:
new_state = PLAN_ACTIVATION_ERROR;
error_description = GetErrorMessage(kErrorNoService);
default:
break;
}
}
static bool first_time = true;
VLOG(1) << "Activation state flip old = "
<< GetStateDescription(state_)
<< ", new = " << GetStateDescription(new_state);
if (state_ == new_state && !first_time)
return;
first_time = false;
VLOG(1) << "Transitioning...";
state_duration_timer_.Stop();
continue_reconnect_timer_.Stop();
reconnect_timeout_timer_.Stop();
const PlanActivationState old_state = state_;
state_ = new_state;
FOR_EACH_OBSERVER(Observer, observers_,
OnActivationStateChanged(network, state_, error_description));
switch (new_state) {
case PLAN_ACTIVATION_START:
break;
case PLAN_ACTIVATION_DELAY_OTASP: {
UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1);
BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
base::Bind(&MobileActivator::RetryOTASP, AsWeakPtr()),
base::TimeDelta::FromMilliseconds(kOTASPRetryDelay));
break;
}
case PLAN_ACTIVATION_START_OTASP:
break;
case PLAN_ACTIVATION_INITIATING_ACTIVATION:
case PLAN_ACTIVATION_TRYING_OTASP:
case PLAN_ACTIVATION_OTASP: {
DCHECK(network);
network_handler::ErrorCallback on_activation_error =
base::Bind(&MobileActivator::HandleActivationFailure, AsWeakPtr(),
network->path(),
new_state);
RequestCellularActivation(
network,
base::Bind(&MobileActivator::StartOTASPTimer, AsWeakPtr()),
on_activation_error);
}
break;
case PLAN_ACTIVATION_PAGE_LOADING:
return;
case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
case PLAN_ACTIVATION_SHOWING_PAYMENT:
case PLAN_ACTIVATION_RECONNECTING_PAYMENT:
break;
case PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
post_reconnect_state_ = old_state;
break;
case PLAN_ACTIVATION_RECONNECTING: {
PlanActivationState next_state = old_state;
switch (old_state) {
case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
case PLAN_ACTIVATION_SHOWING_PAYMENT:
next_state = PLAN_ACTIVATION_RECONNECTING_PAYMENT;
break;
case PLAN_ACTIVATION_INITIATING_ACTIVATION:
case PLAN_ACTIVATION_TRYING_OTASP:
next_state = PLAN_ACTIVATION_START;
break;
case PLAN_ACTIVATION_START_OTASP:
case PLAN_ACTIVATION_OTASP:
if (!network || !network->IsConnectedState()) {
next_state = PLAN_ACTIVATION_START_OTASP;
} else {
next_state = PLAN_ACTIVATION_DONE;
}
break;
default:
LOG(ERROR) << "Transitioned to RECONNECTING from an unexpected "
<< "state.";
break;
}
if (network)
ForceReconnect(network, next_state);
break;
}
case PLAN_ACTIVATION_DONE:
DCHECK(network);
CompleteActivation();
UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupSucceeded", 1);
break;
case PLAN_ACTIVATION_ERROR:
CompleteActivation();
UMA_HISTOGRAM_COUNTS("Cellular.PlanFailed", 1);
break;
default:
break;
}
}
void MobileActivator::ReEnableCertRevocationChecking() {
if (!g_browser_process)
return;
PrefService* prefs = g_browser_process->local_state();
if (!prefs)
return;
if (reenable_cert_check_) {
prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled,
true);
reenable_cert_check_ = false;
}
}
void MobileActivator::DisableCertRevocationChecking() {
PrefService* prefs = g_browser_process->local_state();
if (!reenable_cert_check_ &&
prefs->GetBoolean(
prefs::kCertRevocationCheckingEnabled)) {
reenable_cert_check_ = true;
prefs->SetBoolean(prefs::kCertRevocationCheckingEnabled, false);
}
}
bool MobileActivator::GotActivationError(
const NetworkState* network, std::string* error) const {
DCHECK(network);
bool got_error = false;
const char* error_code = kErrorDefault;
const std::string& activation = network->activation_state();
if (network->connection_state() == shill::kStateFailure &&
network->error() == shill::kErrorAaaFailed) {
if (activation == shill::kActivationStatePartiallyActivated) {
error_code = kErrorBadConnectionPartial;
} else if (activation == shill::kActivationStateActivated) {
if (network->roaming() == shill::kRoamingStateHome)
error_code = kErrorBadConnectionActivated;
else if (network->roaming() == shill::kRoamingStateRoaming)
error_code = kErrorRoamingOnConnection;
}
got_error = true;
} else if (network->connection_state() == shill::kStateActivationFailure) {
if (network->error() == shill::kErrorNeedEvdo) {
if (activation == shill::kActivationStatePartiallyActivated)
error_code = kErrorNoEVDO;
} else if (network->error() == shill::kErrorNeedHomeNetwork) {
if (activation == shill::kActivationStateNotActivated) {
error_code = kErrorRoamingActivation;
} else if (activation == shill::kActivationStatePartiallyActivated) {
error_code = kErrorRoamingPartiallyActivated;
}
}
got_error = true;
}
if (got_error)
*error = GetErrorMessage(error_code);
return got_error;
}
std::string MobileActivator::GetErrorMessage(const std::string& code) const {
return cellular_config_->GetErrorMessage(code);
}
void MobileActivator::SignalCellularPlanPayment() {
DCHECK(!HasRecentCellularPlanPayment());
cellular_plan_payment_time_ = base::Time::Now();
}
bool MobileActivator::HasRecentCellularPlanPayment() const {
const int kRecentPlanPaymentHours = 6;
return (base::Time::Now() -
cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours;
}
}