Commit 54e6fb88 authored by zelidrag@chromium.org's avatar zelidrag@chromium.org

Removed file access from UI thread for mobile config file loading.

BUG=chromium-os:11535
TEST=make sure no thread trelated assertion are happening during mobile activation now when ScopedAllowIO is removed 
Review URL: http://codereview.chromium.org/8414039

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107970 0039d316-1c4b-4281-b951-d872f2087c98
parent 213f614c
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/string_piece.h" #include "base/string_piece.h"
#include "base/string_util.h" #include "base/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
...@@ -163,25 +162,29 @@ class PortalFrameLoadObserver : public RenderViewHostObserver { ...@@ -163,25 +162,29 @@ class PortalFrameLoadObserver : public RenderViewHostObserver {
DISALLOW_COPY_AND_ASSIGN(PortalFrameLoadObserver); DISALLOW_COPY_AND_ASSIGN(PortalFrameLoadObserver);
}; };
class CellularConfigDocument { class CellularConfigDocument
: public base::RefCountedThreadSafe<CellularConfigDocument> {
public: public:
CellularConfigDocument() {} CellularConfigDocument() {}
// Return error message for a given code. // Return error message for a given code.
std::string GetErrorMessage(const std::string& code); std::string GetErrorMessage(const std::string& code);
void LoadCellularConfigFile();
const std::string& version() { return version_; } const std::string& version() { return version_; }
private:
typedef std::map<std::string, std::string> ErrorMap;
void SetErrorMap(const ErrorMap& map);
bool LoadFromFile(const FilePath& config_path); bool LoadFromFile(const FilePath& config_path);
private:
std::string version_; std::string version_;
std::map<std::string, std::string> error_map_; ErrorMap error_map_;
base::Lock config_lock_;
DISALLOW_COPY_AND_ASSIGN(CellularConfigDocument); DISALLOW_COPY_AND_ASSIGN(CellularConfigDocument);
}; };
static std::map<std::string, std::string> error_messages_;
class MobileSetupUIHTMLSource : public ChromeURLDataManager::DataSource { class MobileSetupUIHTMLSource : public ChromeURLDataManager::DataSource {
public: public:
explicit MobileSetupUIHTMLSource(const std::string& service_path); explicit MobileSetupUIHTMLSource(const std::string& service_path);
...@@ -214,6 +217,7 @@ class MobileSetupHandler ...@@ -214,6 +217,7 @@ class MobileSetupHandler
// Init work after Attach. // Init work after Attach.
void Init(TabContents* contents); void Init(TabContents* contents);
void StartActivationOnUIThread();
// WebUIMessageHandler implementation. // WebUIMessageHandler implementation.
virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE; virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE;
...@@ -244,45 +248,11 @@ class MobileSetupHandler ...@@ -244,45 +248,11 @@ class MobileSetupHandler
PLAN_ACTIVATION_ERROR = 0xFF, PLAN_ACTIVATION_ERROR = 0xFF,
} PlanActivationState; } PlanActivationState;
class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
public:
TaskProxy(const base::WeakPtr<MobileSetupHandler>& handler, int delay)
: handler_(handler), delay_(delay) {
}
TaskProxy(const base::WeakPtr<MobileSetupHandler>& handler,
const std::string& status)
: handler_(handler), status_(status) {
}
void HandleStartActivation() {
if (handler_)
handler_->StartActivation();
}
void HandleSetTransactionStatus() {
if (handler_)
handler_->SetTransactionStatus(status_);
}
void ContinueConnecting() {
if (handler_)
handler_->ContinueConnecting(delay_);
}
void RetryOTASP() {
if (handler_)
handler_->RetryOTASP();
}
private:
base::WeakPtr<MobileSetupHandler> handler_;
std::string status_;
int delay_;
DISALLOW_COPY_AND_ASSIGN(TaskProxy);
};
// Handlers for JS WebUI messages. // Handlers for JS WebUI messages.
void HandleSetTransactionStatus(const ListValue* args); void HandleSetTransactionStatus(const ListValue* args);
void HandleStartActivation(const ListValue* args); void HandleStartActivation(const ListValue* args);
void HandlePaymentPortalLoad(const ListValue* args); void HandlePaymentPortalLoad(const ListValue* args);
void SetTransactionStatus(const std::string& status); void SetTransactionStatus(const std::string& status);
// Schedules activation process via task proxy.
void InitiateActivation();
// Starts activation. // Starts activation.
void StartActivation(); void StartActivation();
// Retried OTASP. // Retried OTASP.
...@@ -333,6 +303,8 @@ class MobileSetupHandler ...@@ -333,6 +303,8 @@ class MobileSetupHandler
// Control routines for handling other types of connections during // Control routines for handling other types of connections during
// cellular activation. // cellular activation.
void ReEnableOtherConnections(); void ReEnableOtherConnections();
// Return error message for a given code.
std::string GetErrorMessage(const std::string& code);
// Converts the currently active CellularNetwork device into a JS object. // Converts the currently active CellularNetwork device into a JS object.
static void GetDeviceInfo(chromeos::CellularNetwork* network, static void GetDeviceInfo(chromeos::CellularNetwork* network,
...@@ -346,16 +318,11 @@ class MobileSetupHandler ...@@ -346,16 +318,11 @@ class MobileSetupHandler
std::string* state, std::string* state,
std::string* error); std::string* error);
// Return error message for a given code.
static std::string GetErrorMessage(const std::string& code);
static void LoadCellularConfig();
// Returns next reconnection state based on the current activation phase. // Returns next reconnection state based on the current activation phase.
static PlanActivationState GetNextReconnectState(PlanActivationState state); static PlanActivationState GetNextReconnectState(PlanActivationState state);
static const char* GetStateDescription(PlanActivationState state); static const char* GetStateDescription(PlanActivationState state);
static scoped_ptr<CellularConfigDocument> cellular_config_; scoped_refptr<CellularConfigDocument> cellular_config_;
TabContents* tab_contents_; TabContents* tab_contents_;
// Internal handler state. // Internal handler state.
PlanActivationState state_; PlanActivationState state_;
...@@ -384,8 +351,6 @@ class MobileSetupHandler ...@@ -384,8 +351,6 @@ class MobileSetupHandler
DISALLOW_COPY_AND_ASSIGN(MobileSetupHandler); DISALLOW_COPY_AND_ASSIGN(MobileSetupHandler);
}; };
scoped_ptr<CellularConfigDocument> MobileSetupHandler::cellular_config_;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// CellularConfigDocument // CellularConfigDocument
...@@ -393,23 +358,32 @@ scoped_ptr<CellularConfigDocument> MobileSetupHandler::cellular_config_; ...@@ -393,23 +358,32 @@ scoped_ptr<CellularConfigDocument> MobileSetupHandler::cellular_config_;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string CellularConfigDocument::GetErrorMessage(const std::string& code) { std::string CellularConfigDocument::GetErrorMessage(const std::string& code) {
std::map<std::string, std::string>::iterator iter = error_map_.find(code); base::AutoLock create(config_lock_);
ErrorMap::iterator iter = error_map_.find(code);
if (iter == error_map_.end()) if (iter == error_map_.end())
return code; return code;
return iter->second; return iter->second;
} }
bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) { void CellularConfigDocument::LoadCellularConfigFile() {
error_map_.clear(); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
// Load partner customization startup manifest if it is available.
FilePath config_path(kCellularConfigPath);
if (!file_util::PathExists(config_path))
return;
std::string config; if (LoadFromFile(config_path)) {
{ DVLOG(1) << "Cellular config file loaded: " << kCellularConfigPath;
// Reading config file causes us to do blocking IO on UI thread. } else {
// Temporarily allow it until we fix http://crosbug.com/11535 LOG(ERROR) << "Error loading cellular config file: " <<
base::ThreadRestrictions::ScopedAllowIO allow_io; kCellularConfigPath;
if (!file_util::ReadFileToString(config_path, &config))
return false;
} }
}
bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) {
std::string config;
if (!file_util::ReadFileToString(config_path, &config))
return false;
scoped_ptr<Value> root(base::JSONReader::Read(config, true)); scoped_ptr<Value> root(base::JSONReader::Read(config, true));
DCHECK(root.get() != NULL); DCHECK(root.get() != NULL);
...@@ -423,6 +397,7 @@ bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) { ...@@ -423,6 +397,7 @@ bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) {
LOG(WARNING) << "Cellular config file missing version"; LOG(WARNING) << "Cellular config file missing version";
return false; return false;
} }
ErrorMap error_map;
DictionaryValue* errors = NULL; DictionaryValue* errors = NULL;
if (!root_dict->GetDictionary(kErrorsField, &errors)) if (!root_dict->GetDictionary(kErrorsField, &errors))
return false; return false;
...@@ -432,15 +407,21 @@ bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) { ...@@ -432,15 +407,21 @@ bool CellularConfigDocument::LoadFromFile(const FilePath& config_path) {
std::string value; std::string value;
if (!errors->GetString(*keys, &value)) { if (!errors->GetString(*keys, &value)) {
LOG(WARNING) << "Bad cellular config error value"; LOG(WARNING) << "Bad cellular config error value";
error_map_.clear();
return false; return false;
} }
error_map.insert(ErrorMap::value_type(*keys, value));
error_map_.insert(std::pair<std::string, std::string>(*keys, value));
} }
SetErrorMap(error_map);
return true; return true;
} }
void CellularConfigDocument::SetErrorMap(
const ErrorMap& map) {
base::AutoLock create(config_lock_);
error_map_.clear();
error_map_.insert(map.begin(), map.end());
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// MobileSetupUIHTMLSource // MobileSetupUIHTMLSource
...@@ -505,7 +486,8 @@ void MobileSetupUIHTMLSource::StartDataRequest(const std::string& path, ...@@ -505,7 +486,8 @@ void MobileSetupUIHTMLSource::StartDataRequest(const std::string& path,
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
MobileSetupHandler::MobileSetupHandler(const std::string& service_path) MobileSetupHandler::MobileSetupHandler(const std::string& service_path)
: tab_contents_(NULL), : cellular_config_(new CellularConfigDocument()),
tab_contents_(NULL),
state_(PLAN_ACTIVATION_PAGE_LOADING), state_(PLAN_ACTIVATION_PAGE_LOADING),
service_path_(service_path), service_path_(service_path),
reenable_wifi_(false), reenable_wifi_(false),
...@@ -536,14 +518,6 @@ WebUIMessageHandler* MobileSetupHandler::Attach(WebUI* web_ui) { ...@@ -536,14 +518,6 @@ WebUIMessageHandler* MobileSetupHandler::Attach(WebUI* web_ui) {
void MobileSetupHandler::Init(TabContents* contents) { void MobileSetupHandler::Init(TabContents* contents) {
tab_contents_ = contents; tab_contents_ = contents;
chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
if (!network || !network->SupportsActivation())
return;
LoadCellularConfig();
if (!chromeos::CrosLibrary::Get()->GetNetworkLibrary()->IsLocked())
SetupActivationProcess(network);
else
already_running_ = true;
} }
void MobileSetupHandler::RegisterMessages() { void MobileSetupHandler::RegisterMessages() {
...@@ -578,8 +552,10 @@ void MobileSetupHandler::OnNetworkChanged(chromeos::NetworkLibrary* cros, ...@@ -578,8 +552,10 @@ void MobileSetupHandler::OnNetworkChanged(chromeos::NetworkLibrary* cros,
} }
void MobileSetupHandler::HandleStartActivation(const ListValue* args) { void MobileSetupHandler::HandleStartActivation(const ListValue* args) {
InitiateActivation(); BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1); base::Bind(&CellularConfigDocument::LoadCellularConfigFile,
cellular_config_.get()),
base::Bind(&MobileSetupHandler::StartActivationOnUIThread, AsWeakPtr()));
} }
void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) { void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) {
...@@ -590,9 +566,9 @@ void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) { ...@@ -590,9 +566,9 @@ void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) {
std::string status; std::string status;
if (!args->GetString(0, &status)) if (!args->GetString(0, &status))
return; return;
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), status);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TaskProxy::HandleSetTransactionStatus, task.get())); base::Bind(&MobileSetupHandler::SetTransactionStatus, AsWeakPtr(),
status));
} }
void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) { void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) {
...@@ -631,14 +607,9 @@ void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) { ...@@ -631,14 +607,9 @@ void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) {
} }
} }
void MobileSetupHandler::InitiateActivation() {
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), 0);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TaskProxy::HandleStartActivation, task.get()));
}
void MobileSetupHandler::StartActivation() { void MobileSetupHandler::StartActivation() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
UMA_HISTOGRAM_COUNTS("Cellular.MobileSetupStart", 1);
chromeos::NetworkLibrary* lib = chromeos::NetworkLibrary* lib =
chromeos::CrosLibrary::Get()->GetNetworkLibrary(); chromeos::CrosLibrary::Get()->GetNetworkLibrary();
chromeos::CellularNetwork* network = GetCellularNetwork(service_path_); chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
...@@ -784,10 +755,9 @@ bool MobileSetupHandler::ConnectToNetwork( ...@@ -784,10 +755,9 @@ bool MobileSetupHandler::ConnectToNetwork(
<< (network ? network->service_path().c_str() : "no service"); << (network ? network->service_path().c_str() : "no service");
// If we coudn't connect during reconnection phase, try to reconnect // If we coudn't connect during reconnection phase, try to reconnect
// with a delay (and try to reconnect if needed). // with a delay (and try to reconnect if needed).
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(),
delay);
BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TaskProxy::ContinueConnecting, task.get()), delay); base::Bind(&MobileSetupHandler::ContinueConnecting, AsWeakPtr(), delay),
delay);
return false; return false;
} }
chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
...@@ -808,10 +778,9 @@ void MobileSetupHandler::ForceReconnect( ...@@ -808,10 +778,9 @@ void MobileSetupHandler::ForceReconnect(
chromeos::CrosLibrary::Get()->GetNetworkLibrary()-> chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
DisconnectFromNetwork(network); DisconnectFromNetwork(network);
// Check the network state 3s after we disconnect to make sure. // Check the network state 3s after we disconnect to make sure.
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(),
delay);
BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TaskProxy::ContinueConnecting, task.get()), delay); base::Bind(&MobileSetupHandler::ContinueConnecting, AsWeakPtr(), delay),
delay);
} }
bool MobileSetupHandler::ConnectionTimeout() { bool MobileSetupHandler::ConnectionTimeout() {
...@@ -1214,9 +1183,9 @@ void MobileSetupHandler::ChangeState(chromeos::CellularNetwork* network, ...@@ -1214,9 +1183,9 @@ void MobileSetupHandler::ChangeState(chromeos::CellularNetwork* network,
break; break;
case PLAN_ACTIVATION_DELAY_OTASP: { case PLAN_ACTIVATION_DELAY_OTASP: {
UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1); UMA_HISTOGRAM_COUNTS("Cellular.RetryOTASP", 1);
scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), 0);
BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TaskProxy::RetryOTASP, task.get()), kOTASPRetryDelay); base::Bind(&MobileSetupHandler::RetryOTASP, AsWeakPtr()),
kOTASPRetryDelay);
break; break;
} }
case PLAN_ACTIVATION_INITIATING_ACTIVATION: case PLAN_ACTIVATION_INITIATING_ACTIVATION:
...@@ -1400,39 +1369,22 @@ void MobileSetupHandler::GetDeviceInfo(chromeos::CellularNetwork* network, ...@@ -1400,39 +1369,22 @@ void MobileSetupHandler::GetDeviceInfo(chromeos::CellularNetwork* network,
} }
std::string MobileSetupHandler::GetErrorMessage(const std::string& code) { std::string MobileSetupHandler::GetErrorMessage(const std::string& code) {
if (!cellular_config_.get())
return "";
return cellular_config_->GetErrorMessage(code); return cellular_config_->GetErrorMessage(code);
} }
void MobileSetupHandler::LoadCellularConfig() { void MobileSetupHandler::StartActivationOnUIThread() {
static bool config_loaded = false; DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (config_loaded) chromeos::CellularNetwork* network = GetCellularNetwork(service_path_);
if (!network || !network->SupportsActivation())
return; return;
config_loaded = true;
// Load partner customization startup manifest if it is available.
FilePath config_path(kCellularConfigPath);
bool config_exists = false;
{
// Reading config file causes us to do blocking IO on UI thread.
// Temporarily allow it until we fix http://crosbug.com/11535
base::ThreadRestrictions::ScopedAllowIO allow_io;
config_exists = file_util::PathExists(config_path);
}
if (config_exists) {
scoped_ptr<CellularConfigDocument> config(new CellularConfigDocument());
bool config_loaded = config->LoadFromFile(config_path);
if (config_loaded) {
LOG(INFO) << "Cellular config file loaded: " << kCellularConfigPath;
// lock
cellular_config_.reset(config.release());
} else {
LOG(ERROR) << "Error loading cellular config file: " <<
kCellularConfigPath;
}
}
}
if (!chromeos::CrosLibrary::Get()->GetNetworkLibrary()->IsLocked())
SetupActivationProcess(network);
else
already_running_ = true;
StartActivation();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment