Skip to content

Commit

Permalink
Enable Verizon OTA activation.
Browse files Browse the repository at this point in the history
    
Enables OTA activation using the old Wifi flow except it connects to the cellular network instead of requiring a Wifi connection.
    
BUG=chromium:384185
TEST=Unit tests, manually activate SIM on CDMA and LTE

Review URL: https://codereview.chromium.org/406473002

Cr-Commit-Position: refs/heads/master@{#288854}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288854 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
thieule@chromium.org committed Aug 12, 2014
1 parent 43ebf82 commit 8bb063b
Show file tree
Hide file tree
Showing 17 changed files with 335 additions and 138 deletions.
19 changes: 12 additions & 7 deletions ash/system/chromeos/network/network_connect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,17 @@ void ConnectToNetwork(const std::string& service_path,
gfx::NativeWindow parent_window) {
NET_LOG_USER("ConnectToNetwork", service_path);
const NetworkState* network = GetNetworkState(service_path);
if (network && !network->error().empty() && !network->security().empty()) {
NET_LOG_USER("Configure: " + network->error(), service_path);
// If the network is in an error state, show the configuration UI directly
// to avoid a spurious notification.
HandleUnconfiguredNetwork(service_path, parent_window);
return;
if (network) {
if (!network->error().empty() && !network->security().empty()) {
NET_LOG_USER("Configure: " + network->error(), service_path);
// If the network is in an error state, show the configuration UI directly
// to avoid a spurious notification.
HandleUnconfiguredNetwork(service_path, parent_window);
return;
} else if (network->RequiresActivation()) {
ActivateCellular(service_path);
return;
}
}
const bool check_error_state = true;
CallConnectToNetwork(service_path, check_error_state, parent_window);
Expand Down Expand Up @@ -442,7 +447,7 @@ void ShowMobileSetup(const std::string& service_path) {
return;
}
if (cellular->activation_state() != shill::kActivationStateActivated &&
cellular->activate_over_non_cellular_networks() &&
cellular->activation_type() == shill::kActivationTypeNonCellular &&
!handler->DefaultNetwork()) {
message_center::MessageCenter::Get()->AddNotification(
message_center::Notification::CreateSystemNotification(
Expand Down
152 changes: 118 additions & 34 deletions chrome/browser/chromeos/mobile/mobile_activator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ const char kErrorNoDevice[] = "no_device";
const char kFailedPaymentError[] = "failed_payment";
const char kFailedConnectivity[] = "connectivity";

// Returns true if the device follows the simple activation flow.
bool IsSimpleActivationFlow(const chromeos::NetworkState* network) {
return (network->activation_type() == shill::kActivationTypeNonCellular ||
network->activation_type() == shill::kActivationTypeOTA);
}

} // namespace

namespace chromeos {
Expand Down Expand Up @@ -184,9 +190,10 @@ void MobileActivator::TerminateActivation() {
continue_reconnect_timer_.Stop();
reconnect_timeout_timer_.Stop();

if (NetworkHandler::IsInitialized())
NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
FROM_HERE);
if (NetworkHandler::IsInitialized()) {
NetworkHandler::Get()->network_state_handler()->
RemoveObserver(this, FROM_HERE);
}
ReEnableCertRevocationChecking();
meid_.clear();
iccid_.clear();
Expand Down Expand Up @@ -245,10 +252,9 @@ 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;
LOG(WARNING) << "Cellular service can't be found: " << service_path;
return;
}

const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
GetDeviceState(network->device_path());
if (!device) {
Expand Down Expand Up @@ -335,7 +341,7 @@ void MobileActivator::HandleSetTransactionStatus(bool success) {
SignalCellularPlanPayment();
UMA_HISTOGRAM_COUNTS("Cellular.PaymentReceived", 1);
const NetworkState* network = GetNetworkState(service_path_);
if (network && network->activate_over_non_cellular_networks()) {
if (network && IsSimpleActivationFlow(network)) {
state_ = PLAN_ACTIVATION_DONE;
NetworkHandler::Get()->network_activation_handler()->
CompleteActivation(network->path(),
Expand Down Expand Up @@ -370,7 +376,7 @@ void MobileActivator::HandlePortalLoaded(bool success) {
} else {
// There is no point in forcing reconnecting the cellular network if the
// activation should not be done over it.
if (network->activate_over_non_cellular_networks())
if (network->activation_type() == shill::kActivationTypeNonCellular)
return;

payment_reconnect_count_++;
Expand Down Expand Up @@ -421,18 +427,57 @@ void MobileActivator::StartActivation() {

// Start monitoring network property changes.
NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
if (network->activate_over_non_cellular_networks()) {
// Fast forward to payment portal loading if the activation is performed
// over a non-cellular network.
ChangeState(
network,
(network->activation_state() == shill::kActivationStateActivated) ?
PLAN_ACTIVATION_DONE :
PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
"");
// Verify that there is no need to wait for the connection. This will also
// evaluate the network.
RefreshCellularNetworks();

if (network->activation_type() == shill::kActivationTypeNonCellular)
StartActivationOverNonCellularNetwork();
else if (network->activation_type() == shill::kActivationTypeOTA)
StartActivationOTA();
else if (network->activation_type() == shill::kActivationTypeOTASP)
StartActivationOTASP();
}

void MobileActivator::StartActivationOverNonCellularNetwork() {
// Fast forward to payment portal loading.
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

ChangeState(
network,
(network->activation_state() == shill::kActivationStateActivated) ?
PLAN_ACTIVATION_DONE :
PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
"" /* error_description */);

RefreshCellularNetworks();
}

void MobileActivator::StartActivationOTA() {
// Connect to the network if we don't currently have access.
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

const NetworkState* default_network = GetDefaultNetwork();
bool is_online_or_portal = default_network &&
(default_network->connection_state() == shill::kStateOnline ||
default_network->connection_state() == shill::kStatePortal);
if (!is_online_or_portal)
ConnectNetwork(network);

ChangeState(network, PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
"" /* error_description */);
RefreshCellularNetworks();
}

void MobileActivator::StartActivationOTASP() {
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

Expand All @@ -455,13 +500,23 @@ void MobileActivator::RetryOTASP() {

void MobileActivator::StartOTASP() {
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

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 (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

// We're here because one of OTASP steps is taking too long to complete.
// Usually, this means something bad has happened below us.
if (state_ == PLAN_ACTIVATION_INITIATING_ACTIVATION) {
Expand Down Expand Up @@ -498,6 +553,14 @@ void MobileActivator::HandleOTASPTimeout() {
GetErrorMessage(kErrorDefault));
}

void MobileActivator::ConnectNetwork(const NetworkState* network) {
NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
network->path(),
base::Bind(&base::DoNothing),
network_handler::ErrorCallback(),
false /* check_error_state */);
}

void MobileActivator::ForceReconnect(const NetworkState* network,
PlanActivationState next_state) {
DCHECK(network);
Expand Down Expand Up @@ -530,6 +593,11 @@ void MobileActivator::ForceReconnect(const NetworkState* network,
void MobileActivator::ReconnectTimedOut() {
LOG(ERROR) << "Ending activation attempt after failing to reconnect.";
const NetworkState* network = GetNetworkState(service_path_);
if (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

ChangeState(network,
PLAN_ACTIVATION_ERROR,
GetErrorMessage(kFailedConnectivity));
Expand Down Expand Up @@ -569,15 +637,27 @@ void MobileActivator::RefreshCellularNetworks() {
return;
}

NetworkStateHandler* nsh = NetworkHandler::Get()->network_state_handler();
const NetworkState* network = GetNetworkState(service_path_);
if (network && network->activate_over_non_cellular_networks()) {
if (!network) {
LOG(WARNING) << "Cellular service can't be found: " << service_path_;
return;
}

if (IsSimpleActivationFlow(network)) {
bool waiting = (state_ == PLAN_ACTIVATION_WAITING_FOR_CONNECTION);
bool is_online = nsh->DefaultNetwork() &&
nsh->DefaultNetwork()->connection_state() == shill::kStateOnline;
if (waiting && is_online) {
// We're only interested in whether or not we have access to the payment
// portal (regardless of which network we use to access it), so check
// the default network connection state. The default network is the network
// used to route default traffic. Also, note that we can access the
// payment portal over a cellular network in the portalled state.
const NetworkState* default_network = GetDefaultNetwork();
bool is_online_or_portal = default_network &&
(default_network->connection_state() == shill::kStateOnline ||
(default_network->type() == shill::kTypeCellular &&
default_network->connection_state() == shill::kStatePortal));
if (waiting && is_online_or_portal) {
ChangeState(network, post_reconnect_state_, "");
} else if (!waiting && !is_online) {
} else if (!waiting && !is_online_or_portal) {
ChangeState(network, PLAN_ACTIVATION_WAITING_FOR_CONNECTION, "");
}
}
Expand All @@ -591,6 +671,10 @@ const NetworkState* MobileActivator::GetNetworkState(
service_path);
}

const NetworkState* MobileActivator::GetDefaultNetwork() {
return NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
}

void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) {
if (terminated_) {
LOG(ERROR) << "Tried to run MobileActivator state machine while "
Expand All @@ -610,9 +694,9 @@ void MobileActivator::EvaluateCellularNetwork(const NetworkState* network) {
<< "\n setvice_path=" << network->path()
<< "\n connected=" << network->IsConnectedState();

// If the network is activated over non cellular network, the activator state
// does not depend on the network's own state.
if (network->activate_over_non_cellular_networks())
// If the network is activated over non cellular network or OTA, the
// activator state does not depend on the network's own state.
if (IsSimpleActivationFlow(network))
return;

std::string error_description;
Expand Down Expand Up @@ -678,7 +762,7 @@ MobileActivator::PlanActivationState MobileActivator::PickNextOfflineState(
switch (state_) {
case PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING:
case PLAN_ACTIVATION_SHOWING_PAYMENT:
if (!network->activate_over_non_cellular_networks())
if (!IsSimpleActivationFlow(network))
new_state = PLAN_ACTIVATION_RECONNECTING;
break;
case PLAN_ACTIVATION_START:
Expand Down Expand Up @@ -707,10 +791,10 @@ MobileActivator::PlanActivationState MobileActivator::PickNextOnlineState(
switch (state_) {
case PLAN_ACTIVATION_START:
if (activation == shill::kActivationStateActivated) {
if (network->connection_state() == shill::kStatePortal)
new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
else
if (network->connection_state() == shill::kStateOnline)
new_state = PLAN_ACTIVATION_DONE;
else
new_state = PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING;
} else if (activation == shill::kActivationStatePartiallyActivated) {
new_state = PLAN_ACTIVATION_TRYING_OTASP;
} else {
Expand Down Expand Up @@ -826,8 +910,8 @@ const char* MobileActivator::GetStateDescription(PlanActivationState state) {

void MobileActivator::CompleteActivation() {
// Remove observers, we are done with this page.
NetworkHandler::Get()->network_state_handler()->RemoveObserver(
this, FROM_HERE);
NetworkHandler::Get()->network_state_handler()->
RemoveObserver(this, FROM_HERE);

// Reactivate other types of connections if we have
// shut them down previously.
Expand Down
46 changes: 36 additions & 10 deletions chrome/browser/chromeos/mobile/mobile_activator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class DictionaryValue;

namespace chromeos {

class NetworkConnectionHandler;
class NetworkState;
class NetworkStateHandler;
class TestMobileActivator;

// Cellular plan config document.
Expand Down Expand Up @@ -55,6 +57,24 @@ class CellularConfigDocument
};

// This class performs mobile plan activation process.
//
// There are two types of activation flow:
//
// 1. Over-the-air Service Provision (OTASP) activation
// a. Call shill Activate() to partially activate modem so it can
// connect to the network.
// b. Enable auto-connect on the modem so it will connect to the network
// in the next step.
// c. Call shill Activate() again which resets the modem, when the modem
// comes back, it will auto-connect to the network.
// d. Navigate to the payment portal.
// e. Activate the modem using OTASP via shill Activate().
//
// 2. Simple activation - used by non-cellular activation and over-the-air
// (OTA) activation.
// a. Ensure there's a network connection.
// a. Navigate to payment portal.
// b. Activate the modem via shill CompletetActivation().
class MobileActivator
: public base::SupportsWeakPtr<MobileActivator>,
public NetworkStateHandlerObserver {
Expand Down Expand Up @@ -126,15 +146,17 @@ class MobileActivator
// Process payment transaction status.
void OnSetTransactionStatus(bool success);

protected:
// For unit tests.
void set_state_for_test(PlanActivationState state) {
state_ = state;
}
virtual const NetworkState* GetNetworkState(const std::string& service_path);
virtual const NetworkState* GetDefaultNetwork();

private:
friend struct DefaultSingletonTraits<MobileActivator>;
friend class TestMobileActivator;
FRIEND_TEST_ALL_PREFIXES(MobileActivatorTest, BasicFlowForNewDevices);
FRIEND_TEST_ALL_PREFIXES(MobileActivatorTest, OTASPScheduling);
FRIEND_TEST_ALL_PREFIXES(MobileActivatorTest,
ReconnectOnDisconnectFromPaymentPortal);
FRIEND_TEST_ALL_PREFIXES(MobileActivatorTest, StartAtStart);
// We reach directly into the activator for testing purposes.
friend class MobileActivatorTest;

MobileActivator();
Expand All @@ -158,6 +180,12 @@ class MobileActivator
void HandleSetTransactionStatus(bool success);
// Starts activation.
void StartActivation();
// Starts activation over non-cellular network.
void StartActivationOverNonCellularNetwork();
// Starts OTA activation.
void StartActivationOTA();
// Starts OTASP activation.
void StartActivationOTASP();
// Called after we delay our OTASP (after payment).
void RetryOTASP();
// Continues activation process. This method is called after we disconnect
Expand All @@ -171,6 +199,8 @@ class MobileActivator
void StartOTASP();
// Called when an OTASP attempt times out.
void HandleOTASPTimeout();
// Connect to network.
virtual void ConnectNetwork(const NetworkState* network);
// Forces disconnect / reconnect when we detect portal connectivity issues.
void ForceReconnect(const NetworkState* network,
PlanActivationState next_state);
Expand All @@ -181,10 +211,6 @@ class MobileActivator
// state.
void RefreshCellularNetworks();

// Helper to get network state corresponding to service path. Provided
// for easy mocking in unit tests.
virtual const NetworkState* GetNetworkState(const std::string& service_path);

// Verify the state of cellular network and modify internal state.
virtual void EvaluateCellularNetwork(const NetworkState* network);
// PickNextState selects the desired state based on the current state of the
Expand Down
Loading

0 comments on commit 8bb063b

Please sign in to comment.