shill: Support Cellular CDMA activation.
Still TODO is communicating the activation error codes to the Cellular service.
... And, of course, asynchronous calls throughout.
BUG=chromium-os:19305
TEST=unit tests
Change-Id: I3e0b4a5a8d3c4c74db35ce7f74b5d958677d8b66
Reviewed-on: http://gerrit.chromium.org/gerrit/6192
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 1430552..989ab75 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -34,6 +34,12 @@
namespace shill {
+const char Cellular::kActivationStateActivated[] = "activated";
+const char Cellular::kActivationStateActivating[] = "activating";
+const char Cellular::kActivationStateNotActivated[] = "not-activated";
+const char Cellular::kActivationStatePartiallyActivated[] =
+ "partially-activated";
+const char Cellular::kActivationStateUnknown[] = "unknown";
const char Cellular::kConnectPropertyPhoneNumber[] = "number";
const char Cellular::kPhoneNumberCDMA[] = "#777";
const char Cellular::kPhoneNumberGSM[] = "*99#";
@@ -176,6 +182,22 @@
return StringPrintf("CellularStateUnknown-%d", state);
}
+// static
+string Cellular::GetCDMAActivationStateString(uint32 state) {
+ switch (state) {
+ case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
+ return kActivationStateActivated;
+ case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
+ return kActivationStateActivating;
+ case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
+ return kActivationStateNotActivated;
+ case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
+ return kActivationStatePartiallyActivated;
+ default:
+ return kActivationStateUnknown;
+ }
+}
+
void Cellular::SetState(State state) {
VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
state_ = state;
@@ -257,11 +279,12 @@
DBusProperties::GetString(
properties, "firmware_revision", &firmware_revision_);
+ // TODO(petkov): Handle "state".
if (type_ == kTypeCDMA) {
- // TODO(petkov): Get activation_state.
+ DBusProperties::GetUint32(
+ properties, "activation_state", &cdma_.activation_state);
DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
-
// TODO(petkov): For now, get the payment and usage URLs from ModemManager
// to match flimflam. In the future, provide a plugin API to get these
// directly from the modem driver.
@@ -338,6 +361,9 @@
void Cellular::HandleNewRegistrationStateTask() {
VLOG(2) << __func__;
if (!IsModemRegistered()) {
+ if (state_ == kStateLinked) {
+ manager_->DeregisterService(service_);
+ }
service_ = NULL;
if (state_ == kStateLinked ||
state_ == kStateConnected ||
@@ -401,11 +427,18 @@
CHECK(!service_.get());
service_ =
new CellularService(control_interface_, dispatcher_, manager_, this);
- if (type_ == kTypeCDMA) {
- service_->set_payment_url(cdma_.payment_url);
- service_->set_usage_url(cdma_.usage_url);
+ switch (type_) {
+ case kTypeGSM:
+ service_->set_activation_state(kActivationStateActivated);
+ break;
+ case kTypeCDMA:
+ service_->set_payment_url(cdma_.payment_url);
+ service_->set_usage_url(cdma_.usage_url);
+ HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
+ break;
+ default:
+ NOTREACHED();
}
- // TODO(petkov): Set activation_state.
// TODO(petkov): Set operator.
}
@@ -476,6 +509,36 @@
}
}
+void Cellular::Activate(const string &carrier) {
+ CHECK_EQ(kTypeCDMA, type_);
+ // Defer connect because we may be in a dbus-c++ callback.
+ dispatcher_->PostTask(
+ task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
+}
+
+void Cellular::ActivateTask(const string &carrier) {
+ VLOG(2) << __func__ << "(" << carrier << ")";
+ if (state_ != kStateEnabled && state_ != kStateRegistered) {
+ LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
+ return;
+ }
+ // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
+ uint32 status = cdma_proxy_->Activate(carrier);
+ if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
+ cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
+ }
+ HandleNewCDMAActivationState(status);
+}
+
+void Cellular::HandleNewCDMAActivationState(uint32 error) {
+ if (!service_.get()) {
+ return;
+ }
+ service_->set_activation_state(
+ GetCDMAActivationStateString(cdma_.activation_state));
+ // TODO(petkov): Handle activation state error codes.
+}
+
void Cellular::OnCDMAActivationStateChanged(
uint32 activation_state,
uint32 activation_error,
@@ -488,7 +551,8 @@
service_.get()) {
service_->set_payment_url(cdma_.payment_url);
}
- // TODO(petkov): Handle activation state updates.
+ cdma_.activation_state = activation_state;
+ HandleNewCDMAActivationState(activation_error);
}
void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
diff --git a/cellular.h b/cellular.h
index 7e3baec..90b915e 100644
--- a/cellular.h
+++ b/cellular.h
@@ -128,6 +128,9 @@
// Asynchronously connects the modem to the network.
void Connect();
+ // Asynchronously activates the modem.
+ void Activate(const std::string &carrier);
+
void set_modem_state(ModemState state) { modem_state_ = state; }
ModemState modem_state() const { return modem_state_; }
@@ -138,7 +141,9 @@
virtual void LinkEvent(unsigned int flags, unsigned int change);
private:
+ FRIEND_TEST(CellularTest, Activate);
FRIEND_TEST(CellularTest, Connect);
+ FRIEND_TEST(CellularTest, GetCDMAActivationStateString);
FRIEND_TEST(CellularTest, GetCDMARegistrationState);
FRIEND_TEST(CellularTest, GetCDMASignalQuality);
FRIEND_TEST(CellularTest, GetModemInfo);
@@ -152,12 +157,18 @@
FRIEND_TEST(CellularTest, StartLinked);
FRIEND_TEST(CellularTest, StartRegister);
+ static const char kActivationStateActivated[];
+ static const char kActivationStateActivating[];
+ static const char kActivationStateNotActivated[];
+ static const char kActivationStatePartiallyActivated[];
+ static const char kActivationStateUnknown[];
static const char kPhoneNumberCDMA[];
static const char kPhoneNumberGSM[];
void SetState(State state);
void ConnectTask(const DBusPropertiesMap &properties);
+ void ActivateTask(const std::string &carrier);
// Invoked when the modem is connected to the cellular network to transition
// to the network-connected state and bring the network interface up.
@@ -177,6 +188,8 @@
std::string GetTypeString() const;
static std::string GetStateString(State state);
+ static std::string GetCDMAActivationStateString(uint32 state);
+
void EnableModem();
void GetModemStatus();
void GetGSMProperties();
@@ -206,6 +219,8 @@
void HandleNewSignalQuality(uint32 strength);
+ void HandleNewCDMAActivationState(uint32 error);
+
// Returns true if the modem is registered. Note that this method looks at the
// latest CDMA/GSM registration info obtained from the modem rather than the
// device |state_|.
diff --git a/cellular_service.cc b/cellular_service.cc
index 654c5b4..f0cb2ab 100644
--- a/cellular_service.cc
+++ b/cellular_service.cc
@@ -51,7 +51,11 @@
void CellularService::Disconnect() { }
-std::string CellularService::GetDeviceRpcId() {
+void CellularService::ActivateCellularModem(const string &carrier) {
+ cellular_->Activate(carrier);
+}
+
+string CellularService::GetDeviceRpcId() {
return cellular_->GetRpcIdentifier();
}
diff --git a/cellular_service.h b/cellular_service.h
index 1c75358..a16b1bb 100644
--- a/cellular_service.h
+++ b/cellular_service.h
@@ -27,8 +27,15 @@
const CellularRefPtr &device);
virtual ~CellularService();
+ // Inherited from Service.
virtual void Connect();
virtual void Disconnect();
+ virtual void ActivateCellularModem(const std::string &carrier);
+
+ const std::string &activation_state() const { return activation_state_; }
+ void set_activation_state(const std::string &state) {
+ activation_state_ = state;
+ }
uint8 strength() const { return strength_; }
void set_strength(uint8 strength) { strength_ = strength; }
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 8d551a7..4fb5a2b 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -229,6 +229,22 @@
device_->GetStateString(Cellular::kStateLinked));
}
+TEST_F(CellularTest, GetCDMAActivationStateString) {
+ EXPECT_EQ("activated",
+ device_->GetCDMAActivationStateString(
+ MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED));
+ EXPECT_EQ("activating",
+ device_->GetCDMAActivationStateString(
+ MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING));
+ EXPECT_EQ("not-activated",
+ device_->GetCDMAActivationStateString(
+ MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED));
+ EXPECT_EQ("partially-activated",
+ device_->GetCDMAActivationStateString(
+ MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED));
+ EXPECT_EQ("unknown", device_->GetCDMAActivationStateString(123));
+}
+
TEST_F(CellularTest, Start) {
EXPECT_CALL(*proxy_, Enable(true)).Times(1);
EXPECT_CALL(*simple_proxy_, GetStatus())
@@ -409,4 +425,17 @@
dispatcher_.DispatchPendingEvents();
}
+TEST_F(CellularTest, Activate) {
+ static const char kCarrier[] = "The Cellular Carrier";
+ device_->type_ = Cellular::kTypeCDMA;
+ EXPECT_CALL(*cdma_proxy_, Activate(kCarrier))
+ .WillOnce(Return(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR));
+ device_->Activate(kCarrier);
+ device_->cdma_proxy_.reset(cdma_proxy_.release());
+ device_->state_ = Cellular::kStateEnabled;
+ dispatcher_.DispatchPendingEvents();
+ EXPECT_EQ(MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING,
+ device_->cdma_.activation_state);
+}
+
} // namespace shill
diff --git a/mock_modem_cdma_proxy.h b/mock_modem_cdma_proxy.h
index fdd9d93..59b1a4c 100644
--- a/mock_modem_cdma_proxy.h
+++ b/mock_modem_cdma_proxy.h
@@ -13,6 +13,7 @@
class MockModemCDMAProxy : public ModemCDMAProxyInterface {
public:
+ MOCK_METHOD1(Activate, uint32(const std::string &carrier));
MOCK_METHOD2(GetRegistrationState, void(uint32 *cdma_1x_state,
uint32 *evdo_state));
MOCK_METHOD0(GetSignalQuality, uint32());
diff --git a/modem_cdma_proxy.cc b/modem_cdma_proxy.cc
index 4628fb8..4a92f88 100644
--- a/modem_cdma_proxy.cc
+++ b/modem_cdma_proxy.cc
@@ -18,6 +18,10 @@
ModemCDMAProxy::~ModemCDMAProxy() {}
+uint32 ModemCDMAProxy::Activate(const string &carrier) {
+ return proxy_.Activate(carrier);
+}
+
void ModemCDMAProxy::GetRegistrationState(uint32 *cdma_1x_state,
uint32 *evdo_state) {
proxy_.GetRegistrationState(*cdma_1x_state, *evdo_state);
diff --git a/modem_cdma_proxy.h b/modem_cdma_proxy.h
index 33d021f..a116d9d 100644
--- a/modem_cdma_proxy.h
+++ b/modem_cdma_proxy.h
@@ -22,6 +22,7 @@
virtual ~ModemCDMAProxy();
// Inherited from ModemCDMAProxyInterface.
+ virtual uint32 Activate(const std::string &carrier);
virtual void GetRegistrationState(uint32 *cdma_1x_state, uint32 *evdo_state);
virtual uint32 GetSignalQuality();
diff --git a/modem_cdma_proxy_interface.h b/modem_cdma_proxy_interface.h
index 9a91f3e..7a333a9 100644
--- a/modem_cdma_proxy_interface.h
+++ b/modem_cdma_proxy_interface.h
@@ -5,6 +5,8 @@
#ifndef SHILL_MODEM_CDMA_PROXY_INTERFACE_
#define SHILL_MODEM_CDMA_PROXY_INTERFACE_
+#include <string>
+
#include <base/basictypes.h>
namespace shill {
@@ -15,9 +17,9 @@
public:
virtual ~ModemCDMAProxyInterface() {}
+ virtual uint32 Activate(const std::string &carrier) = 0;
virtual void GetRegistrationState(uint32 *cdma_1x_state,
uint32 *evdo_state) = 0;
-
virtual uint32 GetSignalQuality() = 0;
};
diff --git a/service.cc b/service.cc
index e0c8916..373e9b3 100644
--- a/service.cc
+++ b/service.cc
@@ -148,6 +148,10 @@
Service::~Service() {}
+void Service::ActivateCellularModem(const std::string &carrier) {
+ NOTREACHED() << "Attempt to activate a non-cellular service?";
+}
+
string Service::GetRpcIdentifier() const {
return adaptor_->GetRpcIdentifier();
}
diff --git a/service.h b/service.h
index 16bade6..be7fc0a 100644
--- a/service.h
+++ b/service.h
@@ -90,6 +90,9 @@
virtual void Connect() = 0;
virtual void Disconnect() = 0;
+ // The default implementation asserts.
+ virtual void ActivateCellularModem(const std::string &carrier);
+
virtual bool IsActive() { return false; }
// Returns a string that is guaranteed to uniquely identify this Service
diff --git a/service_dbus_adaptor.cc b/service_dbus_adaptor.cc
index d6ab4fb..1b3f644 100644
--- a/service_dbus_adaptor.cc
+++ b/service_dbus_adaptor.cc
@@ -85,8 +85,9 @@
::DBus::Error &error) {
}
-void ServiceDBusAdaptor::ActivateCellularModem(const string& ,
+void ServiceDBusAdaptor::ActivateCellularModem(const string &carrier,
::DBus::Error &error) {
+ service_->ActivateCellularModem(carrier);
}
} // namespace shill
diff --git a/service_dbus_adaptor.h b/service_dbus_adaptor.h
index a637112..51b9a31 100644
--- a/service_dbus_adaptor.h
+++ b/service_dbus_adaptor.h
@@ -52,10 +52,11 @@
void Remove(::DBus::Error &error);
void MoveBefore(const ::DBus::Path& , ::DBus::Error &error);
void MoveAfter(const ::DBus::Path& , ::DBus::Error &error);
- void ActivateCellularModem(const std::string& , ::DBus::Error &error);
+ void ActivateCellularModem(const std::string &carrier, ::DBus::Error &error);
private:
Service *service_;
+
DISALLOW_COPY_AND_ASSIGN(ServiceDBusAdaptor);
};