1 // Copyright (c) 2012 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/importer/external_process_importer_client.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/importer/external_process_importer_host.h" 11 #include "chrome/browser/importer/in_process_importer_bridge.h" 12 #include "chrome/common/importer/firefox_importer_utils.h" 13 #include "chrome/common/importer/imported_bookmark_entry.h" 14 #include "chrome/common/importer/profile_import_process_messages.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/utility_process_host.h" 17 #include "grit/components_strings.h" 18 #include "grit/generated_resources.h" 19 #include "ui/base/l10n/l10n_util.h" 20 21 using content::BrowserThread; 22 using content::UtilityProcessHost; 23 24 ExternalProcessImporterClient::ExternalProcessImporterClient( 25 base::WeakPtr<ExternalProcessImporterHost> importer_host, 26 const importer::SourceProfile& source_profile, 27 uint16 items, 28 InProcessImporterBridge* bridge) 29 : total_bookmarks_count_(0), 30 total_history_rows_count_(0), 31 total_favicons_count_(0), 32 process_importer_host_(importer_host), 33 source_profile_(source_profile), 34 items_(items), 35 bridge_(bridge), 36 cancelled_(false) { 37 process_importer_host_->NotifyImportStarted(); 38 } 39 40 void ExternalProcessImporterClient::Start() { 41 AddRef(); // balanced in Cleanup. 42 BrowserThread::ID thread_id; 43 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id)); 44 BrowserThread::PostTask( 45 BrowserThread::IO, FROM_HERE, 46 base::Bind(&ExternalProcessImporterClient::StartProcessOnIOThread, 47 this, 48 thread_id)); 49 } 50 51 void ExternalProcessImporterClient::Cancel() { 52 if (cancelled_) 53 return; 54 55 cancelled_ = true; 56 BrowserThread::PostTask( 57 BrowserThread::IO, FROM_HERE, 58 base::Bind( 59 &ExternalProcessImporterClient::CancelImportProcessOnIOThread, 60 this)); 61 Release(); 62 } 63 64 void ExternalProcessImporterClient::OnProcessCrashed(int exit_code) { 65 DLOG(ERROR) << __FUNCTION__; 66 if (cancelled_) 67 return; 68 69 // If the host is still around, cancel the import; otherwise it means the 70 // import was already cancelled or completed and this message can be dropped. 71 if (process_importer_host_.get()) 72 process_importer_host_->Cancel(); 73 } 74 75 bool ExternalProcessImporterClient::OnMessageReceived( 76 const IPC::Message& message) { 77 bool handled = true; 78 IPC_BEGIN_MESSAGE_MAP(ExternalProcessImporterClient, message) 79 // Notification messages about the state of the import process. 80 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Started, 81 OnImportStart) 82 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Finished, 83 OnImportFinished) 84 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_ImportItem_Started, 85 OnImportItemStart) 86 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_ImportItem_Finished, 87 OnImportItemFinished) 88 // Data messages containing items to be written to the user profile. 89 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHistoryImportStart, 90 OnHistoryImportStart) 91 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHistoryImportGroup, 92 OnHistoryImportGroup) 93 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHomePageImportReady, 94 OnHomePageImportReady) 95 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyBookmarksImportStart, 96 OnBookmarksImportStart) 97 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup, 98 OnBookmarksImportGroup) 99 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFaviconsImportStart, 100 OnFaviconsImportStart) 101 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFaviconsImportGroup, 102 OnFaviconsImportGroup) 103 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyPasswordFormReady, 104 OnPasswordFormImportReady) 105 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyKeywordsReady, 106 OnKeywordsImportReady) 107 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFirefoxSearchEngData, 108 OnFirefoxSearchEngineDataReceived) 109 #if defined(OS_WIN) 110 IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyIE7PasswordInfo, 111 OnIE7PasswordReceived) 112 #endif 113 IPC_MESSAGE_UNHANDLED(handled = false) 114 IPC_END_MESSAGE_MAP() 115 return handled; 116 } 117 118 void ExternalProcessImporterClient::OnImportStart() { 119 if (cancelled_) 120 return; 121 122 bridge_->NotifyStarted(); 123 } 124 125 void ExternalProcessImporterClient::OnImportFinished( 126 bool succeeded, const std::string& error_msg) { 127 if (cancelled_) 128 return; 129 130 if (!succeeded) 131 LOG(WARNING) << "Import failed. Error: " << error_msg; 132 Cleanup(); 133 } 134 135 void ExternalProcessImporterClient::OnImportItemStart(int item_data) { 136 if (cancelled_) 137 return; 138 139 bridge_->NotifyItemStarted(static_cast<importer::ImportItem>(item_data)); 140 } 141 142 void ExternalProcessImporterClient::OnImportItemFinished(int item_data) { 143 if (cancelled_) 144 return; 145 146 importer::ImportItem import_item = 147 static_cast<importer::ImportItem>(item_data); 148 bridge_->NotifyItemEnded(import_item); 149 BrowserThread::PostTask( 150 BrowserThread::IO, FROM_HERE, 151 base::Bind(&ExternalProcessImporterClient::NotifyItemFinishedOnIOThread, 152 this, 153 import_item)); 154 } 155 156 void ExternalProcessImporterClient::OnHistoryImportStart( 157 size_t total_history_rows_count) { 158 if (cancelled_) 159 return; 160 161 total_history_rows_count_ = total_history_rows_count; 162 history_rows_.reserve(total_history_rows_count); 163 } 164 165 void ExternalProcessImporterClient::OnHistoryImportGroup( 166 const std::vector<ImporterURLRow>& history_rows_group, 167 int visit_source) { 168 if (cancelled_) 169 return; 170 171 history_rows_.insert(history_rows_.end(), history_rows_group.begin(), 172 history_rows_group.end()); 173 if (history_rows_.size() == total_history_rows_count_) 174 bridge_->SetHistoryItems(history_rows_, 175 static_cast<importer::VisitSource>(visit_source)); 176 } 177 178 void ExternalProcessImporterClient::OnHomePageImportReady( 179 const GURL& home_page) { 180 if (cancelled_) 181 return; 182 183 bridge_->AddHomePage(home_page); 184 } 185 186 void ExternalProcessImporterClient::OnBookmarksImportStart( 187 const base::string16& first_folder_name, 188 size_t total_bookmarks_count) { 189 if (cancelled_) 190 return; 191 192 bookmarks_first_folder_name_ = first_folder_name; 193 total_bookmarks_count_ = total_bookmarks_count; 194 bookmarks_.reserve(total_bookmarks_count); 195 } 196 197 void ExternalProcessImporterClient::OnBookmarksImportGroup( 198 const std::vector<ImportedBookmarkEntry>& bookmarks_group) { 199 if (cancelled_) 200 return; 201 202 // Collect sets of bookmarks from importer process until we have reached 203 // total_bookmarks_count_: 204 bookmarks_.insert(bookmarks_.end(), bookmarks_group.begin(), 205 bookmarks_group.end()); 206 if (bookmarks_.size() == total_bookmarks_count_) 207 bridge_->AddBookmarks(bookmarks_, bookmarks_first_folder_name_); 208 } 209 210 void ExternalProcessImporterClient::OnFaviconsImportStart( 211 size_t total_favicons_count) { 212 if (cancelled_) 213 return; 214 215 total_favicons_count_ = total_favicons_count; 216 favicons_.reserve(total_favicons_count); 217 } 218 219 void ExternalProcessImporterClient::OnFaviconsImportGroup( 220 const std::vector<ImportedFaviconUsage>& favicons_group) { 221 if (cancelled_) 222 return; 223 224 favicons_.insert(favicons_.end(), favicons_group.begin(), 225 favicons_group.end()); 226 if (favicons_.size() == total_favicons_count_) 227 bridge_->SetFavicons(favicons_); 228 } 229 230 void ExternalProcessImporterClient::OnPasswordFormImportReady( 231 const autofill::PasswordForm& form) { 232 if (cancelled_) 233 return; 234 235 bridge_->SetPasswordForm(form); 236 } 237 238 void ExternalProcessImporterClient::OnKeywordsImportReady( 239 const std::vector<importer::URLKeywordInfo>& url_keywords, 240 bool unique_on_host_and_path) { 241 if (cancelled_) 242 return; 243 bridge_->SetKeywords(url_keywords, unique_on_host_and_path); 244 } 245 246 void ExternalProcessImporterClient::OnFirefoxSearchEngineDataReceived( 247 const std::vector<std::string> search_engine_data) { 248 if (cancelled_) 249 return; 250 bridge_->SetFirefoxSearchEnginesXMLData(search_engine_data); 251 } 252 253 #if defined(OS_WIN) 254 void ExternalProcessImporterClient::OnIE7PasswordReceived( 255 const importer::ImporterIE7PasswordInfo& importer_password_info) { 256 if (cancelled_) 257 return; 258 bridge_->AddIE7PasswordInfo(importer_password_info); 259 } 260 #endif 261 262 ExternalProcessImporterClient::~ExternalProcessImporterClient() {} 263 264 void ExternalProcessImporterClient::Cleanup() { 265 if (cancelled_) 266 return; 267 268 if (process_importer_host_.get()) 269 process_importer_host_->NotifyImportEnded(); 270 Release(); 271 } 272 273 void ExternalProcessImporterClient::CancelImportProcessOnIOThread() { 274 if (utility_process_host_.get()) 275 utility_process_host_->Send(new ProfileImportProcessMsg_CancelImport()); 276 } 277 278 void ExternalProcessImporterClient::NotifyItemFinishedOnIOThread( 279 importer::ImportItem import_item) { 280 utility_process_host_->Send( 281 new ProfileImportProcessMsg_ReportImportItemFinished(import_item)); 282 } 283 284 void ExternalProcessImporterClient::StartProcessOnIOThread( 285 BrowserThread::ID thread_id) { 286 utility_process_host_ = UtilityProcessHost::Create( 287 this, BrowserThread::GetMessageLoopProxyForThread(thread_id).get()) 288 ->AsWeakPtr(); 289 utility_process_host_->DisableSandbox(); 290 291 #if defined(OS_MACOSX) 292 base::EnvironmentMap env; 293 std::string dylib_path = GetFirefoxDylibPath().value(); 294 if (!dylib_path.empty()) 295 env["DYLD_FALLBACK_LIBRARY_PATH"] = dylib_path; 296 utility_process_host_->SetEnv(env); 297 #endif 298 299 // Dictionary of all localized strings that could be needed by the importer 300 // in the external process. 301 base::DictionaryValue localized_strings; 302 localized_strings.SetString( 303 base::IntToString(IDS_BOOKMARK_GROUP), 304 l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP)); 305 localized_strings.SetString( 306 base::IntToString(IDS_BOOKMARK_GROUP_FROM_FIREFOX), 307 l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_FIREFOX)); 308 localized_strings.SetString( 309 base::IntToString(IDS_BOOKMARK_GROUP_FROM_SAFARI), 310 l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_SAFARI)); 311 localized_strings.SetString( 312 base::IntToString(IDS_IMPORT_FROM_FIREFOX), 313 l10n_util::GetStringUTF8(IDS_IMPORT_FROM_FIREFOX)); 314 localized_strings.SetString( 315 base::IntToString(IDS_IMPORT_FROM_ICEWEASEL), 316 l10n_util::GetStringUTF8(IDS_IMPORT_FROM_ICEWEASEL)); 317 localized_strings.SetString( 318 base::IntToString(IDS_IMPORT_FROM_SAFARI), 319 l10n_util::GetStringUTF8(IDS_IMPORT_FROM_SAFARI)); 320 localized_strings.SetString( 321 base::IntToString(IDS_BOOKMARK_BAR_FOLDER_NAME), 322 l10n_util::GetStringUTF8(IDS_BOOKMARK_BAR_FOLDER_NAME)); 323 324 utility_process_host_->Send(new ProfileImportProcessMsg_StartImport( 325 source_profile_, items_, localized_strings)); 326 } 327