Home | History | Annotate | Download | only in automation
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/automation/automation_provider.h"
      6 
      7 #include <set>
      8 
      9 #include "base/callback.h"
     10 #include "base/debug/trace_event.h"
     11 #include "base/file_path.h"
     12 #include "base/json/json_reader.h"
     13 #include "base/json/json_writer.h"
     14 #include "base/json/string_escape.h"
     15 #include "base/message_loop.h"
     16 #include "base/path_service.h"
     17 #include "base/process_util.h"
     18 #include "base/stl_util-inl.h"
     19 #include "base/string_number_conversions.h"
     20 #include "base/string_util.h"
     21 #include "base/synchronization/waitable_event.h"
     22 #include "base/task.h"
     23 #include "base/threading/thread.h"
     24 #include "base/utf_string_conversions.h"
     25 #include "base/values.h"
     26 #include "chrome/app/chrome_command_ids.h"
     27 #include "chrome/browser/autocomplete/autocomplete_edit.h"
     28 #include "chrome/browser/autofill/autofill_manager.h"
     29 #include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
     30 #include "chrome/browser/automation/automation_browser_tracker.h"
     31 #include "chrome/browser/automation/automation_extension_tracker.h"
     32 #include "chrome/browser/automation/automation_provider_list.h"
     33 #include "chrome/browser/automation/automation_provider_observers.h"
     34 #include "chrome/browser/automation/automation_resource_message_filter.h"
     35 #include "chrome/browser/automation/automation_tab_tracker.h"
     36 #include "chrome/browser/automation/automation_window_tracker.h"
     37 #include "chrome/browser/automation/ui_controls.h"
     38 #include "chrome/browser/blocked_content_container.h"
     39 #include "chrome/browser/bookmarks/bookmark_model.h"
     40 #include "chrome/browser/bookmarks/bookmark_storage.h"
     41 #include "chrome/browser/browser_process.h"
     42 #include "chrome/browser/browsing_data_remover.h"
     43 #include "chrome/browser/character_encoding.h"
     44 #include "chrome/browser/content_settings/host_content_settings_map.h"
     45 #include "chrome/browser/debugger/devtools_manager.h"
     46 #include "chrome/browser/dom_operation_notification_details.h"
     47 #include "chrome/browser/download/download_item.h"
     48 #include "chrome/browser/download/download_shelf.h"
     49 #include "chrome/browser/download/save_package.h"
     50 #include "chrome/browser/extensions/crx_installer.h"
     51 #include "chrome/browser/extensions/extension_browser_event_router.h"
     52 #include "chrome/browser/extensions/extension_host.h"
     53 #include "chrome/browser/extensions/extension_install_ui.h"
     54 #include "chrome/browser/extensions/extension_message_service.h"
     55 #include "chrome/browser/extensions/extension_service.h"
     56 #include "chrome/browser/extensions/extension_tabs_module.h"
     57 #include "chrome/browser/extensions/extension_toolbar_model.h"
     58 #include "chrome/browser/extensions/user_script_master.h"
     59 #include "chrome/browser/io_thread.h"
     60 #include "chrome/browser/net/url_request_mock_util.h"
     61 #include "chrome/browser/platform_util.h"
     62 #include "chrome/browser/prefs/pref_service.h"
     63 #include "chrome/browser/printing/print_job.h"
     64 #include "chrome/browser/profiles/profile_manager.h"
     65 #include "chrome/browser/ssl/ssl_blocking_page.h"
     66 #include "chrome/browser/ssl/ssl_manager.h"
     67 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
     68 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
     69 #include "chrome/browser/ui/browser_list.h"
     70 #include "chrome/browser/ui/browser_window.h"
     71 #include "chrome/browser/ui/download/download_tab_helper.h"
     72 #include "chrome/browser/ui/find_bar/find_bar.h"
     73 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
     74 #include "chrome/browser/ui/find_bar/find_notification_details.h"
     75 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
     76 #include "chrome/browser/ui/login/login_prompt.h"
     77 #include "chrome/browser/ui/omnibox/location_bar.h"
     78 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     79 #include "chrome/common/automation_constants.h"
     80 #include "chrome/common/automation_messages.h"
     81 #include "chrome/common/chrome_constants.h"
     82 #include "chrome/common/chrome_paths.h"
     83 #include "chrome/common/chrome_switches.h"
     84 #include "chrome/common/chrome_version_info.h"
     85 #include "chrome/common/extensions/extension.h"
     86 #include "chrome/common/pref_names.h"
     87 #include "chrome/common/url_constants.h"
     88 #include "chrome/test/automation/tab_proxy.h"
     89 #include "content/browser/browser_thread.h"
     90 #include "content/browser/renderer_host/render_process_host.h"
     91 #include "content/browser/renderer_host/render_view_host.h"
     92 #include "content/browser/tab_contents/navigation_entry.h"
     93 #include "content/browser/tab_contents/tab_contents.h"
     94 #include "content/browser/tab_contents/tab_contents_view.h"
     95 #include "content/common/json_value_serializer.h"
     96 #include "net/proxy/proxy_config_service_fixed.h"
     97 #include "net/proxy/proxy_service.h"
     98 #include "net/url_request/url_request_context.h"
     99 #include "net/url_request/url_request_context_getter.h"
    100 #include "webkit/glue/password_form.h"
    101 
    102 #if defined(OS_WIN)
    103 #include "chrome/browser/external_tab_container_win.h"
    104 #endif  // defined(OS_WIN)
    105 
    106 using base::Time;
    107 
    108 AutomationProvider::AutomationProvider(Profile* profile)
    109     : profile_(profile),
    110       reply_message_(NULL),
    111       reinitialize_on_channel_error_(false),
    112       is_connected_(false),
    113       initial_tab_loads_complete_(false),
    114       network_library_initialized_(true) {
    115   TRACE_EVENT_BEGIN("AutomationProvider::AutomationProvider", 0, "");
    116 
    117   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    118 
    119   browser_tracker_.reset(new AutomationBrowserTracker(this));
    120   extension_tracker_.reset(new AutomationExtensionTracker(this));
    121   tab_tracker_.reset(new AutomationTabTracker(this));
    122   window_tracker_.reset(new AutomationWindowTracker(this));
    123   autocomplete_edit_tracker_.reset(
    124       new AutomationAutocompleteEditTracker(this));
    125   new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this));
    126   metric_event_duration_observer_.reset(new MetricEventDurationObserver());
    127   extension_test_result_observer_.reset(
    128       new ExtensionTestResultNotificationObserver(this));
    129   g_browser_process->AddRefModule();
    130 
    131   TRACE_EVENT_END("AutomationProvider::AutomationProvider", 0, "");
    132 }
    133 
    134 AutomationProvider::~AutomationProvider() {
    135   if (channel_.get())
    136     channel_->Close();
    137 
    138   g_browser_process->ReleaseModule();
    139 }
    140 
    141 bool AutomationProvider::InitializeChannel(const std::string& channel_id) {
    142   TRACE_EVENT_BEGIN("AutomationProvider::InitializeChannel", 0, "");
    143 
    144   channel_id_ = channel_id;
    145   std::string effective_channel_id = channel_id;
    146 
    147   // If the channel_id starts with kNamedInterfacePrefix, create a named IPC
    148   // server and listen on it, else connect as client to an existing IPC server
    149   bool use_named_interface =
    150       channel_id.find(automation::kNamedInterfacePrefix) == 0;
    151   if (use_named_interface) {
    152     effective_channel_id = channel_id.substr(
    153         strlen(automation::kNamedInterfacePrefix));
    154     if (effective_channel_id.length() <= 0)
    155       return false;
    156 
    157     reinitialize_on_channel_error_ = true;
    158   }
    159 
    160   if (!automation_resource_message_filter_.get()) {
    161     automation_resource_message_filter_ = new AutomationResourceMessageFilter;
    162   }
    163 
    164   channel_.reset(new IPC::SyncChannel(
    165       effective_channel_id,
    166       use_named_interface ? IPC::Channel::MODE_NAMED_SERVER
    167                           : IPC::Channel::MODE_CLIENT,
    168       this,
    169       g_browser_process->io_thread()->message_loop(),
    170       true, g_browser_process->shutdown_event()));
    171   channel_->AddFilter(automation_resource_message_filter_);
    172 
    173 #if defined(OS_CHROMEOS)
    174   // Wait for the network manager to initialize.
    175   // The observer will delete itself when done.
    176   network_library_initialized_ = false;
    177   NetworkManagerInitObserver* observer = new NetworkManagerInitObserver(this);
    178   if (!observer->Init())
    179     delete observer;
    180 #endif
    181 
    182   TRACE_EVENT_END("AutomationProvider::InitializeChannel", 0, "");
    183 
    184   return true;
    185 }
    186 
    187 std::string AutomationProvider::GetProtocolVersion() {
    188   chrome::VersionInfo version_info;
    189   return version_info.Version().c_str();
    190 }
    191 
    192 void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
    193   if (expected_tabs == 0)
    194     OnInitialTabLoadsComplete();
    195   else
    196     initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
    197 }
    198 
    199 void AutomationProvider::OnInitialTabLoadsComplete() {
    200   initial_tab_loads_complete_ = true;
    201   if (is_connected_ && network_library_initialized_)
    202     Send(new AutomationMsg_InitialLoadsComplete());
    203 }
    204 
    205 void AutomationProvider::OnNetworkLibraryInit() {
    206   network_library_initialized_ = true;
    207   if (is_connected_ && initial_tab_loads_complete_)
    208     Send(new AutomationMsg_InitialLoadsComplete());
    209 }
    210 
    211 void AutomationProvider::AddLoginHandler(NavigationController* tab,
    212                                          LoginHandler* handler) {
    213   login_handler_map_[tab] = handler;
    214 }
    215 
    216 void AutomationProvider::RemoveLoginHandler(NavigationController* tab) {
    217   DCHECK(login_handler_map_[tab]);
    218   login_handler_map_.erase(tab);
    219 }
    220 
    221 int AutomationProvider::GetIndexForNavigationController(
    222     const NavigationController* controller, const Browser* parent) const {
    223   DCHECK(parent);
    224   return parent->GetIndexOfController(controller);
    225 }
    226 
    227 int AutomationProvider::AddExtension(const Extension* extension) {
    228   DCHECK(extension);
    229   return extension_tracker_->Add(extension);
    230 }
    231 
    232 // TODO(phajdan.jr): move to TestingAutomationProvider.
    233 DictionaryValue* AutomationProvider::GetDictionaryFromDownloadItem(
    234     const DownloadItem* download) {
    235   std::map<DownloadItem::DownloadState, std::string> state_to_string;
    236   state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS");
    237   state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED");
    238   state_to_string[DownloadItem::REMOVING] = std::string("REMOVING");
    239   state_to_string[DownloadItem::INTERRUPTED] = std::string("INTERRUPTED");
    240   state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE");
    241 
    242   std::map<DownloadItem::SafetyState, std::string> safety_state_to_string;
    243   safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE");
    244   safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS");
    245   safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] =
    246       std::string("DANGEROUS_BUT_VALIDATED");
    247 
    248   DictionaryValue* dl_item_value = new DictionaryValue;
    249   dl_item_value->SetInteger("id", static_cast<int>(download->id()));
    250   dl_item_value->SetString("url", download->url().spec());
    251   dl_item_value->SetString("referrer_url", download->referrer_url().spec());
    252   dl_item_value->SetString("file_name",
    253                            download->GetFileNameToReportUser().value());
    254   dl_item_value->SetString("full_path",
    255                            download->GetTargetFilePath().value());
    256   dl_item_value->SetBoolean("is_paused", download->is_paused());
    257   dl_item_value->SetBoolean("open_when_complete",
    258                             download->open_when_complete());
    259   dl_item_value->SetBoolean("is_extension_install",
    260                             download->is_extension_install());
    261   dl_item_value->SetBoolean("is_temporary", download->is_temporary());
    262   dl_item_value->SetBoolean("is_otr", download->is_otr());  // incognito
    263   dl_item_value->SetString("state", state_to_string[download->state()]);
    264   dl_item_value->SetString("safety_state",
    265                            safety_state_to_string[download->safety_state()]);
    266   dl_item_value->SetInteger("PercentComplete", download->PercentComplete());
    267 
    268   return dl_item_value;
    269 }
    270 
    271 const Extension* AutomationProvider::GetExtension(int extension_handle) {
    272   return extension_tracker_->GetResource(extension_handle);
    273 }
    274 
    275 const Extension* AutomationProvider::GetEnabledExtension(int extension_handle) {
    276   const Extension* extension =
    277       extension_tracker_->GetResource(extension_handle);
    278   ExtensionService* service = profile_->GetExtensionService();
    279   if (extension && service &&
    280       service->GetExtensionById(extension->id(), false))
    281     return extension;
    282   return NULL;
    283 }
    284 
    285 const Extension* AutomationProvider::GetDisabledExtension(
    286     int extension_handle) {
    287   const Extension* extension =
    288       extension_tracker_->GetResource(extension_handle);
    289   ExtensionService* service = profile_->GetExtensionService();
    290   if (extension && service &&
    291       service->GetExtensionById(extension->id(), true) &&
    292       !service->GetExtensionById(extension->id(), false))
    293     return extension;
    294   return NULL;
    295 }
    296 
    297 void AutomationProvider::OnChannelConnected(int pid) {
    298   is_connected_ = true;
    299   LOG(INFO) << "Testing channel connected, sending hello message";
    300 
    301   // Send a hello message with our current automation protocol version.
    302   channel_->Send(new AutomationMsg_Hello(GetProtocolVersion()));
    303   if (initial_tab_loads_complete_ && network_library_initialized_)
    304     Send(new AutomationMsg_InitialLoadsComplete());
    305 }
    306 
    307 bool AutomationProvider::OnMessageReceived(const IPC::Message& message) {
    308   bool handled = true;
    309   bool deserialize_success = true;
    310   IPC_BEGIN_MESSAGE_MAP_EX(AutomationProvider, message, deserialize_success)
    311 #if !defined(OS_MACOSX)
    312     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag,
    313                                     WindowSimulateDrag)
    314 #endif  // !defined(OS_MACOSX)
    315     IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
    316     IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig)
    317     IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync)
    318     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
    319     IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
    320     IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll)
    321     IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut)
    322     IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy)
    323     IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste)
    324     IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync)
    325     IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync)
    326     IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize)
    327     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InstallExtension,
    328                                     InstallExtension)
    329     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForExtensionTestResult,
    330                                     WaitForExtensionTestResult)
    331     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    332         AutomationMsg_InstallExtensionAndGetHandle,
    333         InstallExtensionAndGetHandle)
    334     IPC_MESSAGE_HANDLER(AutomationMsg_UninstallExtension,
    335                         UninstallExtension)
    336     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EnableExtension,
    337                                     EnableExtension)
    338     IPC_MESSAGE_HANDLER(AutomationMsg_DisableExtension,
    339                         DisableExtension)
    340     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    341         AutomationMsg_ExecuteExtensionActionInActiveTabAsync,
    342         ExecuteExtensionActionInActiveTabAsync)
    343     IPC_MESSAGE_HANDLER(AutomationMsg_MoveExtensionBrowserAction,
    344                         MoveExtensionBrowserAction)
    345     IPC_MESSAGE_HANDLER(AutomationMsg_GetExtensionProperty,
    346                         GetExtensionProperty)
    347     IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync)
    348     IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData)
    349     IPC_MESSAGE_HANDLER(AutomationMsg_JavaScriptStressTestControl,
    350                         JavaScriptStressTestControl)
    351 #if defined(OS_WIN)
    352     // These are for use with external tabs.
    353     IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
    354     IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
    355                         ProcessUnhandledAccelerator)
    356     IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus)
    357     IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition)
    358     IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome,
    359                         OnForwardContextMenuCommandToChrome)
    360     IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab,
    361                         NavigateInExternalTab)
    362     IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex,
    363                         NavigateExternalTabAtIndex)
    364     IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab)
    365     IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
    366                         OnMessageFromExternalHost)
    367     IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved)
    368     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers,
    369                                     OnRunUnloadHandlers)
    370     IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel)
    371 #endif  // defined(OS_WIN)
    372     IPC_MESSAGE_UNHANDLED(handled = false; OnUnhandledMessage())
    373   IPC_END_MESSAGE_MAP_EX()
    374   if (!deserialize_success)
    375     OnMessageDeserializationFailure();
    376   return handled;
    377 }
    378 
    379 void AutomationProvider::OnUnhandledMessage() {
    380   // We should not hang here. Print a message to indicate what's going on,
    381   // and disconnect the channel to notify the caller about the error
    382   // in a way it can't ignore, and make any further attempts to send
    383   // messages fail fast.
    384   LOG(ERROR) << "AutomationProvider received a message it can't handle. "
    385              << "Please make sure that you use switches::kTestingChannelID "
    386              << "for test code (TestingAutomationProvider), and "
    387              << "switches::kAutomationClientChannelID for everything else "
    388              << "(like ChromeFrame). Closing the automation channel.";
    389   channel_->Close();
    390 }
    391 
    392 void AutomationProvider::OnMessageDeserializationFailure() {
    393   LOG(ERROR) << "Failed to deserialize IPC message. "
    394              << "Closing the automation channel.";
    395   channel_->Close();
    396 }
    397 
    398 // This task just adds another task to the event queue.  This is useful if
    399 // you want to ensure that any tasks added to the event queue after this one
    400 // have already been processed by the time |task| is run.
    401 class InvokeTaskLaterTask : public Task {
    402  public:
    403   explicit InvokeTaskLaterTask(Task* task) : task_(task) {}
    404   virtual ~InvokeTaskLaterTask() {}
    405 
    406   virtual void Run() {
    407     MessageLoop::current()->PostTask(FROM_HERE, task_);
    408   }
    409 
    410  private:
    411   Task* task_;
    412 
    413   DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask);
    414 };
    415 
    416 void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
    417   if (window_tracker_->ContainsHandle(handle)) {
    418     window_tracker_->Remove(window_tracker_->GetResource(handle));
    419   }
    420 }
    421 
    422 bool AutomationProvider::ReinitializeChannel() {
    423   base::ThreadRestrictions::ScopedAllowIO allow_io;
    424 
    425   // Make sure any old channels are cleaned up before starting up a new one.
    426   channel_.reset();
    427   return InitializeChannel(channel_id_);
    428 }
    429 
    430 void AutomationProvider::OnChannelError() {
    431   if (reinitialize_on_channel_error_) {
    432     VLOG(1) << "AutomationProxy disconnected, resetting AutomationProvider.";
    433     if (ReinitializeChannel())
    434       return;
    435     VLOG(1) << "Error reinitializing AutomationProvider channel.";
    436   }
    437   VLOG(1) << "AutomationProxy went away, shutting down app.";
    438   AutomationProviderList::GetInstance()->RemoveProvider(this);
    439 }
    440 
    441 bool AutomationProvider::Send(IPC::Message* msg) {
    442   DCHECK(channel_.get());
    443   return channel_->Send(msg);
    444 }
    445 
    446 Browser* AutomationProvider::FindAndActivateTab(
    447     NavigationController* controller) {
    448   int tab_index;
    449   Browser* browser = Browser::GetBrowserForController(controller, &tab_index);
    450   if (browser)
    451     browser->ActivateTabAt(tab_index, true);
    452 
    453   return browser;
    454 }
    455 
    456 void AutomationProvider::HandleFindRequest(
    457     int handle,
    458     const AutomationMsg_Find_Params& params,
    459     IPC::Message* reply_message) {
    460   if (!tab_tracker_->ContainsHandle(handle)) {
    461     AutomationMsg_Find::WriteReplyParams(reply_message, -1, -1);
    462     Send(reply_message);
    463     return;
    464   }
    465 
    466   NavigationController* nav = tab_tracker_->GetResource(handle);
    467   TabContents* tab_contents = nav->tab_contents();
    468 
    469   SendFindRequest(tab_contents,
    470                   false,
    471                   params.search_string,
    472                   params.forward,
    473                   params.match_case,
    474                   params.find_next,
    475                   reply_message);
    476 }
    477 
    478 void AutomationProvider::SendFindRequest(
    479     TabContents* tab_contents,
    480     bool with_json,
    481     const string16& search_string,
    482     bool forward,
    483     bool match_case,
    484     bool find_next,
    485     IPC::Message* reply_message) {
    486   int request_id = FindInPageNotificationObserver::kFindInPageRequestId;
    487   FindInPageNotificationObserver* observer =
    488       new FindInPageNotificationObserver(this,
    489                                          tab_contents,
    490                                          with_json,
    491                                          reply_message);
    492   if (!with_json) {
    493     find_in_page_observer_.reset(observer);
    494   }
    495   TabContentsWrapper* wrapper =
    496       TabContentsWrapper::GetCurrentWrapperForContents(tab_contents);
    497   if (wrapper)
    498     wrapper->find_tab_helper()->set_current_find_request_id(request_id);
    499 
    500   tab_contents->render_view_host()->StartFinding(
    501       FindInPageNotificationObserver::kFindInPageRequestId,
    502       search_string,
    503       forward,
    504       match_case,
    505       find_next);
    506 }
    507 
    508 class SetProxyConfigTask : public Task {
    509  public:
    510   SetProxyConfigTask(net::URLRequestContextGetter* request_context_getter,
    511                      const std::string& new_proxy_config)
    512       : request_context_getter_(request_context_getter),
    513         proxy_config_(new_proxy_config) {}
    514   virtual void Run() {
    515     // First, deserialize the JSON string. If this fails, log and bail.
    516     JSONStringValueSerializer deserializer(proxy_config_);
    517     std::string error_msg;
    518     scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg));
    519     if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) {
    520       DLOG(WARNING) << "Received bad JSON string for ProxyConfig: "
    521                     << error_msg;
    522       return;
    523     }
    524 
    525     scoped_ptr<DictionaryValue> dict(
    526         static_cast<DictionaryValue*>(root.release()));
    527     // Now put together a proxy configuration from the deserialized string.
    528     net::ProxyConfig pc;
    529     PopulateProxyConfig(*dict.get(), &pc);
    530 
    531     net::ProxyService* proxy_service =
    532         request_context_getter_->GetURLRequestContext()->proxy_service();
    533     DCHECK(proxy_service);
    534     scoped_ptr<net::ProxyConfigService> proxy_config_service(
    535         new net::ProxyConfigServiceFixed(pc));
    536     proxy_service->ResetConfigService(proxy_config_service.release());
    537   }
    538 
    539   void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) {
    540     DCHECK(pc);
    541     bool no_proxy = false;
    542     if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) {
    543       // Make no changes to the ProxyConfig.
    544       return;
    545     }
    546     bool auto_config;
    547     if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) {
    548       pc->set_auto_detect(true);
    549     }
    550     std::string pac_url;
    551     if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) {
    552       pc->set_pac_url(GURL(pac_url));
    553     }
    554     std::string proxy_bypass_list;
    555     if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) {
    556       pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list);
    557     }
    558     std::string proxy_server;
    559     if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) {
    560       pc->proxy_rules().ParseFromString(proxy_server);
    561     }
    562   }
    563 
    564  private:
    565   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
    566   std::string proxy_config_;
    567 };
    568 
    569 
    570 void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) {
    571   net::URLRequestContextGetter* context_getter =
    572       Profile::GetDefaultRequestContext();
    573   if (!context_getter) {
    574     FilePath user_data_dir;
    575     PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
    576     ProfileManager* profile_manager = g_browser_process->profile_manager();
    577     DCHECK(profile_manager);
    578     Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
    579     DCHECK(profile);
    580     context_getter = profile->GetRequestContext();
    581   }
    582   DCHECK(context_getter);
    583 
    584   BrowserThread::PostTask(
    585       BrowserThread::IO, FROM_HERE,
    586       new SetProxyConfigTask(context_getter, new_proxy_config));
    587 }
    588 
    589 TabContents* AutomationProvider::GetTabContentsForHandle(
    590     int handle, NavigationController** tab) {
    591   if (tab_tracker_->ContainsHandle(handle)) {
    592     NavigationController* nav_controller = tab_tracker_->GetResource(handle);
    593     if (tab)
    594       *tab = nav_controller;
    595     return nav_controller->tab_contents();
    596   }
    597   return NULL;
    598 }
    599 
    600 // Gets the current used encoding name of the page in the specified tab.
    601 void AutomationProvider::OverrideEncoding(int tab_handle,
    602                                           const std::string& encoding_name,
    603                                           bool* success) {
    604   *success = false;
    605   if (tab_tracker_->ContainsHandle(tab_handle)) {
    606     NavigationController* nav = tab_tracker_->GetResource(tab_handle);
    607     if (!nav)
    608       return;
    609     Browser* browser = FindAndActivateTab(nav);
    610 
    611     // If the browser has UI, simulate what a user would do.
    612     // Activate the tab and then click the encoding menu.
    613     if (browser &&
    614         browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) {
    615       int selected_encoding_id =
    616           CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name);
    617       if (selected_encoding_id) {
    618         browser->OverrideEncoding(selected_encoding_id);
    619         *success = true;
    620       }
    621     } else {
    622       // There is no UI, Chrome probably runs as Chrome-Frame mode.
    623       // Try to get TabContents and call its override_encoding method.
    624       TabContents* contents = nav->tab_contents();
    625       if (!contents)
    626         return;
    627       const std::string selected_encoding =
    628           CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name);
    629       if (selected_encoding.empty())
    630         return;
    631       contents->SetOverrideEncoding(selected_encoding);
    632     }
    633   }
    634 }
    635 
    636 void AutomationProvider::SelectAll(int tab_handle) {
    637   RenderViewHost* view = GetViewForTab(tab_handle);
    638   if (!view) {
    639     NOTREACHED();
    640     return;
    641   }
    642 
    643   view->SelectAll();
    644 }
    645 
    646 void AutomationProvider::Cut(int tab_handle) {
    647   RenderViewHost* view = GetViewForTab(tab_handle);
    648   if (!view) {
    649     NOTREACHED();
    650     return;
    651   }
    652 
    653   view->Cut();
    654 }
    655 
    656 void AutomationProvider::Copy(int tab_handle) {
    657   RenderViewHost* view = GetViewForTab(tab_handle);
    658   if (!view) {
    659     NOTREACHED();
    660     return;
    661   }
    662 
    663   view->Copy();
    664 }
    665 
    666 void AutomationProvider::Paste(int tab_handle) {
    667   RenderViewHost* view = GetViewForTab(tab_handle);
    668   if (!view) {
    669     NOTREACHED();
    670     return;
    671   }
    672 
    673   view->Paste();
    674 }
    675 
    676 void AutomationProvider::ReloadAsync(int tab_handle) {
    677   if (tab_tracker_->ContainsHandle(tab_handle)) {
    678     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    679     if (!tab) {
    680       NOTREACHED();
    681       return;
    682     }
    683 
    684     const bool check_for_repost = true;
    685     tab->Reload(check_for_repost);
    686   }
    687 }
    688 
    689 void AutomationProvider::StopAsync(int tab_handle) {
    690   RenderViewHost* view = GetViewForTab(tab_handle);
    691   if (!view) {
    692     // We tolerate StopAsync being called even before a view has been created.
    693     // So just log a warning instead of a NOTREACHED().
    694     DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle;
    695     return;
    696   }
    697 
    698   view->Stop();
    699 }
    700 
    701 void AutomationProvider::OnSetPageFontSize(int tab_handle,
    702                                            int font_size) {
    703   AutomationPageFontSize automation_font_size =
    704       static_cast<AutomationPageFontSize>(font_size);
    705 
    706   if (automation_font_size < SMALLEST_FONT ||
    707       automation_font_size > LARGEST_FONT) {
    708       DLOG(ERROR) << "Invalid font size specified : "
    709                   << font_size;
    710       return;
    711   }
    712 
    713   if (tab_tracker_->ContainsHandle(tab_handle)) {
    714     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    715     DCHECK(tab != NULL);
    716     if (tab && tab->tab_contents()) {
    717       DCHECK(tab->tab_contents()->profile() != NULL);
    718       tab->tab_contents()->profile()->GetPrefs()->SetInteger(
    719           prefs::kWebKitDefaultFontSize, font_size);
    720     }
    721   }
    722 }
    723 
    724 void AutomationProvider::RemoveBrowsingData(int remove_mask) {
    725   BrowsingDataRemover* remover;
    726   remover = new BrowsingDataRemover(profile(),
    727       BrowsingDataRemover::EVERYTHING,  // All time periods.
    728       base::Time());
    729   remover->Remove(remove_mask);
    730   // BrowsingDataRemover deletes itself.
    731 }
    732 
    733 void AutomationProvider::JavaScriptStressTestControl(int tab_handle,
    734                                                      int cmd,
    735                                                      int param) {
    736   RenderViewHost* view = GetViewForTab(tab_handle);
    737   if (!view) {
    738     NOTREACHED();
    739     return;
    740   }
    741 
    742   view->JavaScriptStressTestControl(cmd, param);
    743 }
    744 
    745 RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
    746   if (tab_tracker_->ContainsHandle(tab_handle)) {
    747     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    748     if (!tab) {
    749       NOTREACHED();
    750       return NULL;
    751     }
    752 
    753     TabContents* tab_contents = tab->tab_contents();
    754     if (!tab_contents) {
    755       NOTREACHED();
    756       return NULL;
    757     }
    758 
    759     RenderViewHost* view_host = tab_contents->render_view_host();
    760     return view_host;
    761   }
    762 
    763   return NULL;
    764 }
    765 
    766 void AutomationProvider::InstallExtension(const FilePath& crx_path,
    767                                           IPC::Message* reply_message) {
    768   ExtensionService* service = profile_->GetExtensionService();
    769   if (service) {
    770     // The observer will delete itself when done.
    771     new ExtensionInstallNotificationObserver(this,
    772                                              AutomationMsg_InstallExtension::ID,
    773                                              reply_message);
    774 
    775     scoped_refptr<CrxInstaller> installer(
    776         new CrxInstaller(service, NULL));  // silent install, no UI
    777     installer->InstallCrx(crx_path);
    778   } else {
    779     AutomationMsg_InstallExtension::WriteReplyParams(
    780         reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
    781     Send(reply_message);
    782   }
    783 }
    784 
    785 void AutomationProvider::WaitForExtensionTestResult(
    786     IPC::Message* reply_message) {
    787   DCHECK(!reply_message_);
    788   reply_message_ = reply_message;
    789   // Call MaybeSendResult, because the result might have come in before
    790   // we were waiting on it.
    791   extension_test_result_observer_->MaybeSendResult();
    792 }
    793 
    794 void AutomationProvider::InstallExtensionAndGetHandle(
    795     const FilePath& crx_path, bool with_ui, IPC::Message* reply_message) {
    796   ExtensionService* service = profile_->GetExtensionService();
    797   ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
    798   if (service && manager) {
    799     // The observer will delete itself when done.
    800     new ExtensionReadyNotificationObserver(
    801         manager,
    802         this,
    803         AutomationMsg_InstallExtensionAndGetHandle::ID,
    804         reply_message);
    805 
    806     ExtensionInstallUI* client =
    807         (with_ui ? new ExtensionInstallUI(profile_) : NULL);
    808     scoped_refptr<CrxInstaller> installer(new CrxInstaller(service, client));
    809     installer->InstallCrx(crx_path);
    810   } else {
    811     AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams(
    812         reply_message, 0);
    813     Send(reply_message);
    814   }
    815 }
    816 
    817 void AutomationProvider::UninstallExtension(int extension_handle,
    818                                             bool* success) {
    819   *success = false;
    820   const Extension* extension = GetExtension(extension_handle);
    821   ExtensionService* service = profile_->GetExtensionService();
    822   if (extension && service) {
    823     ExtensionUnloadNotificationObserver observer;
    824     service->UninstallExtension(extension->id(), false, NULL);
    825     // The extension unload notification should have been sent synchronously
    826     // with the uninstall. Just to be safe, check that it was received.
    827     *success = observer.did_receive_unload_notification();
    828   }
    829 }
    830 
    831 void AutomationProvider::EnableExtension(int extension_handle,
    832                                          IPC::Message* reply_message) {
    833   const Extension* extension = GetDisabledExtension(extension_handle);
    834   ExtensionService* service = profile_->GetExtensionService();
    835   ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
    836   // Only enable if this extension is disabled.
    837   if (extension && service && manager) {
    838     // The observer will delete itself when done.
    839     new ExtensionReadyNotificationObserver(
    840         manager,
    841         this,
    842         AutomationMsg_EnableExtension::ID,
    843         reply_message);
    844     service->EnableExtension(extension->id());
    845   } else {
    846     AutomationMsg_EnableExtension::WriteReplyParams(reply_message, false);
    847     Send(reply_message);
    848   }
    849 }
    850 
    851 void AutomationProvider::DisableExtension(int extension_handle,
    852                                           bool* success) {
    853   *success = false;
    854   const Extension* extension = GetEnabledExtension(extension_handle);
    855   ExtensionService* service = profile_->GetExtensionService();
    856   if (extension && service) {
    857     ExtensionUnloadNotificationObserver observer;
    858     service->DisableExtension(extension->id());
    859     // The extension unload notification should have been sent synchronously
    860     // with the disable. Just to be safe, check that it was received.
    861     *success = observer.did_receive_unload_notification();
    862   }
    863 }
    864 
    865 void AutomationProvider::ExecuteExtensionActionInActiveTabAsync(
    866     int extension_handle, int browser_handle,
    867     IPC::Message* reply_message) {
    868   bool success = false;
    869   const Extension* extension = GetEnabledExtension(extension_handle);
    870   ExtensionService* service = profile_->GetExtensionService();
    871   ExtensionMessageService* message_service =
    872       profile_->GetExtensionMessageService();
    873   Browser* browser = browser_tracker_->GetResource(browser_handle);
    874   if (extension && service && message_service && browser) {
    875     int tab_id = ExtensionTabUtil::GetTabId(browser->GetSelectedTabContents());
    876     if (extension->page_action()) {
    877       service->browser_event_router()->PageActionExecuted(
    878           browser->profile(), extension->id(), "action", tab_id, "", 1);
    879       success = true;
    880     } else if (extension->browser_action()) {
    881       service->browser_event_router()->BrowserActionExecuted(
    882           browser->profile(), extension->id(), browser);
    883       success = true;
    884     }
    885   }
    886   AutomationMsg_ExecuteExtensionActionInActiveTabAsync::WriteReplyParams(
    887       reply_message, success);
    888   Send(reply_message);
    889 }
    890 
    891 void AutomationProvider::MoveExtensionBrowserAction(
    892     int extension_handle, int index, bool* success) {
    893   *success = false;
    894   const Extension* extension = GetEnabledExtension(extension_handle);
    895   ExtensionService* service = profile_->GetExtensionService();
    896   if (extension && service) {
    897     ExtensionToolbarModel* toolbar = service->toolbar_model();
    898     if (toolbar) {
    899       if (index >= 0 && index < static_cast<int>(toolbar->size())) {
    900         toolbar->MoveBrowserAction(extension, index);
    901         *success = true;
    902       } else {
    903         DLOG(WARNING) << "Attempted to move browser action to invalid index.";
    904       }
    905     }
    906   }
    907 }
    908 
    909 void AutomationProvider::GetExtensionProperty(
    910     int extension_handle,
    911     AutomationMsg_ExtensionProperty type,
    912     bool* success,
    913     std::string* value) {
    914   *success = false;
    915   const Extension* extension = GetExtension(extension_handle);
    916   ExtensionService* service = profile_->GetExtensionService();
    917   if (extension && service) {
    918     ExtensionToolbarModel* toolbar = service->toolbar_model();
    919     int found_index = -1;
    920     int index = 0;
    921     switch (type) {
    922       case AUTOMATION_MSG_EXTENSION_ID:
    923         *value = extension->id();
    924         *success = true;
    925         break;
    926       case AUTOMATION_MSG_EXTENSION_NAME:
    927         *value = extension->name();
    928         *success = true;
    929         break;
    930       case AUTOMATION_MSG_EXTENSION_VERSION:
    931         *value = extension->VersionString();
    932         *success = true;
    933         break;
    934       case AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX:
    935         if (toolbar) {
    936           for (ExtensionList::const_iterator iter = toolbar->begin();
    937                iter != toolbar->end(); iter++) {
    938             // Skip this extension if we are in incognito mode
    939             // and it is not incognito-enabled.
    940             if (profile_->IsOffTheRecord() &&
    941                 !service->IsIncognitoEnabled((*iter)->id()))
    942               continue;
    943             if (*iter == extension) {
    944               found_index = index;
    945               break;
    946             }
    947             index++;
    948           }
    949           *value = base::IntToString(found_index);
    950           *success = true;
    951         }
    952         break;
    953       default:
    954         LOG(WARNING) << "Trying to get undefined extension property";
    955         break;
    956     }
    957   }
    958 }
    959 
    960 void AutomationProvider::SaveAsAsync(int tab_handle) {
    961   NavigationController* tab = NULL;
    962   TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab);
    963   if (tab_contents) {
    964     TabContentsWrapper* wrapper =
    965         TabContentsWrapper::GetCurrentWrapperForContents(tab_contents);
    966     wrapper->download_tab_helper()->OnSavePage();
    967   }
    968 }
    969