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/extensions/api/developer_private/developer_private_api.h" 6 7 #include "apps/app_load_service.h" 8 #include "apps/app_restore_service.h" 9 #include "apps/app_window.h" 10 #include "apps/app_window_registry.h" 11 #include "apps/saved_files_service.h" 12 #include "base/base64.h" 13 #include "base/bind.h" 14 #include "base/command_line.h" 15 #include "base/file_util.h" 16 #include "base/files/file_enumerator.h" 17 #include "base/i18n/file_util_icu.h" 18 #include "base/lazy_instance.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "base/values.h" 22 #include "chrome/browser/chrome_notification_types.h" 23 #include "chrome/browser/devtools/devtools_window.h" 24 #include "chrome/browser/extensions/api/developer_private/entry_picker.h" 25 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 26 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" 27 #include "chrome/browser/extensions/devtools_util.h" 28 #include "chrome/browser/extensions/extension_disabled_ui.h" 29 #include "chrome/browser/extensions/extension_error_reporter.h" 30 #include "chrome/browser/extensions/extension_service.h" 31 #include "chrome/browser/extensions/extension_ui_util.h" 32 #include "chrome/browser/extensions/extension_util.h" 33 #include "chrome/browser/extensions/unpacked_installer.h" 34 #include "chrome/browser/extensions/updater/extension_updater.h" 35 #include "chrome/browser/platform_util.h" 36 #include "chrome/browser/profiles/profile.h" 37 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h" 38 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 39 #include "chrome/browser/ui/chrome_select_file_policy.h" 40 #include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h" 41 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 42 #include "chrome/common/extensions/api/developer_private.h" 43 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 44 #include "chrome/common/extensions/manifest_url_handler.h" 45 #include "chrome/common/url_constants.h" 46 #include "content/public/browser/browser_thread.h" 47 #include "content/public/browser/notification_service.h" 48 #include "content/public/browser/render_process_host.h" 49 #include "content/public/browser/render_view_host.h" 50 #include "content/public/browser/site_instance.h" 51 #include "content/public/browser/storage_partition.h" 52 #include "content/public/browser/web_contents.h" 53 #include "extensions/browser/extension_error.h" 54 #include "extensions/browser/extension_prefs.h" 55 #include "extensions/browser/extension_registry.h" 56 #include "extensions/browser/extension_system.h" 57 #include "extensions/browser/management_policy.h" 58 #include "extensions/browser/view_type_utils.h" 59 #include "extensions/common/constants.h" 60 #include "extensions/common/extension_resource.h" 61 #include "extensions/common/extension_set.h" 62 #include "extensions/common/install_warning.h" 63 #include "extensions/common/manifest.h" 64 #include "extensions/common/manifest_handlers/background_info.h" 65 #include "extensions/common/manifest_handlers/icons_handler.h" 66 #include "extensions/common/manifest_handlers/incognito_info.h" 67 #include "extensions/common/manifest_handlers/offline_enabled_info.h" 68 #include "extensions/common/permissions/permissions_data.h" 69 #include "extensions/common/switches.h" 70 #include "grit/chromium_strings.h" 71 #include "grit/generated_resources.h" 72 #include "grit/theme_resources.h" 73 #include "net/base/net_util.h" 74 #include "ui/base/l10n/l10n_util.h" 75 #include "ui/base/resource/resource_bundle.h" 76 #include "ui/base/webui/web_ui_util.h" 77 #include "webkit/browser/fileapi/external_mount_points.h" 78 #include "webkit/browser/fileapi/file_system_context.h" 79 #include "webkit/browser/fileapi/file_system_operation.h" 80 #include "webkit/browser/fileapi/file_system_operation_runner.h" 81 #include "webkit/common/blob/shareable_file_reference.h" 82 83 using apps::AppWindow; 84 using apps::AppWindowRegistry; 85 using content::RenderViewHost; 86 87 namespace extensions { 88 89 namespace developer_private = api::developer_private; 90 91 namespace { 92 93 const base::FilePath::CharType kUnpackedAppsFolder[] 94 = FILE_PATH_LITERAL("apps_target"); 95 96 ExtensionUpdater* GetExtensionUpdater(Profile* profile) { 97 return profile->GetExtensionService()->updater(); 98 } 99 100 GURL GetImageURLFromData(const std::string& contents) { 101 std::string contents_base64; 102 base::Base64Encode(contents, &contents_base64); 103 104 // TODO(dvh): make use of content::kDataScheme. Filed as crbug/297301. 105 const char kDataURLPrefix[] = "data:;base64,"; 106 return GURL(kDataURLPrefix + contents_base64); 107 } 108 109 GURL GetDefaultImageURL(developer_private::ItemType type) { 110 int icon_resource_id; 111 switch (type) { 112 case developer::ITEM_TYPE_LEGACY_PACKAGED_APP: 113 case developer::ITEM_TYPE_HOSTED_APP: 114 case developer::ITEM_TYPE_PACKAGED_APP: 115 icon_resource_id = IDR_APP_DEFAULT_ICON; 116 break; 117 default: 118 icon_resource_id = IDR_EXTENSION_DEFAULT_ICON; 119 break; 120 } 121 122 return GetImageURLFromData( 123 ResourceBundle::GetSharedInstance().GetRawDataResourceForScale( 124 icon_resource_id, ui::SCALE_FACTOR_100P).as_string()); 125 } 126 127 // TODO(dvh): This code should be refactored and moved to 128 // extensions::ImageLoader. Also a resize should be performed to avoid 129 // potential huge URLs: crbug/297298. 130 GURL ToDataURL(const base::FilePath& path, developer_private::ItemType type) { 131 std::string contents; 132 if (path.empty() || !base::ReadFileToString(path, &contents)) 133 return GetDefaultImageURL(type); 134 135 return GetImageURLFromData(contents); 136 } 137 138 std::string GetExtensionID(const RenderViewHost* render_view_host) { 139 if (!render_view_host->GetSiteInstance()) 140 return std::string(); 141 142 return render_view_host->GetSiteInstance()->GetSiteURL().host(); 143 } 144 145 void BroadcastItemStateChanged(content::BrowserContext* browser_context, 146 developer::EventType event_type, 147 const std::string& item_id) { 148 developer::EventData event_data; 149 event_data.event_type = event_type; 150 event_data.item_id = item_id; 151 152 scoped_ptr<base::ListValue> args(new base::ListValue()); 153 args->Append(event_data.ToValue().release()); 154 scoped_ptr<Event> event(new Event( 155 developer_private::OnItemStateChanged::kEventName, args.Pass())); 156 EventRouter::Get(browser_context)->BroadcastEvent(event.Pass()); 157 } 158 159 } // namespace 160 161 namespace AllowFileAccess = api::developer_private::AllowFileAccess; 162 namespace AllowIncognito = api::developer_private::AllowIncognito; 163 namespace ChoosePath = api::developer_private::ChoosePath; 164 namespace Enable = api::developer_private::Enable; 165 namespace GetItemsInfo = api::developer_private::GetItemsInfo; 166 namespace Inspect = api::developer_private::Inspect; 167 namespace PackDirectory = api::developer_private::PackDirectory; 168 namespace Reload = api::developer_private::Reload; 169 170 static base::LazyInstance<BrowserContextKeyedAPIFactory<DeveloperPrivateAPI> > 171 g_factory = LAZY_INSTANCE_INITIALIZER; 172 173 // static 174 BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>* 175 DeveloperPrivateAPI::GetFactoryInstance() { 176 return g_factory.Pointer(); 177 } 178 179 // static 180 DeveloperPrivateAPI* DeveloperPrivateAPI::Get( 181 content::BrowserContext* context) { 182 return GetFactoryInstance()->Get(context); 183 } 184 185 DeveloperPrivateAPI::DeveloperPrivateAPI(content::BrowserContext* context) 186 : profile_(Profile::FromBrowserContext(context)) { 187 RegisterNotifications(); 188 } 189 190 DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile) 191 : extension_registry_observer_(this), profile_(profile) { 192 registrar_.Add(this, 193 chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, 194 content::Source<Profile>(profile_)); 195 registrar_.Add(this, 196 chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, 197 content::Source<Profile>(profile_)); 198 199 // TODO(limasdf): Use scoped_observer instead. 200 ErrorConsole::Get(profile)->AddObserver(this); 201 202 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 203 } 204 205 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() { 206 ErrorConsole::Get(profile_)->RemoveObserver(this); 207 } 208 209 void DeveloperPrivateEventRouter::AddExtensionId( 210 const std::string& extension_id) { 211 extension_ids_.insert(extension_id); 212 } 213 214 void DeveloperPrivateEventRouter::RemoveExtensionId( 215 const std::string& extension_id) { 216 extension_ids_.erase(extension_id); 217 } 218 219 void DeveloperPrivateEventRouter::Observe( 220 int type, 221 const content::NotificationSource& source, 222 const content::NotificationDetails& details) { 223 Profile* profile = content::Source<Profile>(source).ptr(); 224 CHECK(profile); 225 CHECK(profile_->IsSameProfile(profile)); 226 developer::EventData event_data; 227 228 switch (type) { 229 case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED: { 230 event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED; 231 event_data.item_id = GetExtensionID( 232 content::Details<const RenderViewHost>(details).ptr()); 233 break; 234 } 235 case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED: { 236 event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED; 237 event_data.item_id = GetExtensionID( 238 content::Details<const RenderViewHost>(details).ptr()); 239 break; 240 } 241 default: 242 NOTREACHED(); 243 return; 244 } 245 246 BroadcastItemStateChanged(profile, event_data.event_type, event_data.item_id); 247 } 248 249 void DeveloperPrivateEventRouter::OnExtensionLoaded( 250 content::BrowserContext* browser_context, 251 const Extension* extension) { 252 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context))); 253 BroadcastItemStateChanged( 254 browser_context, developer::EVENT_TYPE_LOADED, extension->id()); 255 } 256 257 void DeveloperPrivateEventRouter::OnExtensionUnloaded( 258 content::BrowserContext* browser_context, 259 const Extension* extension, 260 UnloadedExtensionInfo::Reason reason) { 261 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context))); 262 BroadcastItemStateChanged( 263 browser_context, developer::EVENT_TYPE_UNLOADED, extension->id()); 264 } 265 266 void DeveloperPrivateEventRouter::OnExtensionWillBeInstalled( 267 content::BrowserContext* browser_context, 268 const Extension* extension, 269 bool is_update, 270 bool from_ephemeral, 271 const std::string& old_name) { 272 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context))); 273 BroadcastItemStateChanged( 274 browser_context, developer::EVENT_TYPE_INSTALLED, extension->id()); 275 } 276 277 void DeveloperPrivateEventRouter::OnExtensionUninstalled( 278 content::BrowserContext* browser_context, 279 const Extension* extension) { 280 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context))); 281 BroadcastItemStateChanged( 282 browser_context, developer::EVENT_TYPE_UNINSTALLED, extension->id()); 283 } 284 285 void DeveloperPrivateEventRouter::OnErrorAdded(const ExtensionError* error) { 286 // We don't want to handle errors thrown by extensions subscribed to these 287 // events (currently only the Apps Developer Tool), because doing so risks 288 // entering a loop. 289 if (extension_ids_.find(error->extension_id()) != extension_ids_.end()) 290 return; 291 292 BroadcastItemStateChanged( 293 profile_, developer::EVENT_TYPE_ERROR_ADDED, error->extension_id()); 294 } 295 296 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) { 297 last_unpacked_directory_ = path; 298 } 299 300 void DeveloperPrivateAPI::RegisterNotifications() { 301 EventRouter::Get(profile_)->RegisterObserver( 302 this, developer_private::OnItemStateChanged::kEventName); 303 } 304 305 DeveloperPrivateAPI::~DeveloperPrivateAPI() {} 306 307 void DeveloperPrivateAPI::Shutdown() {} 308 309 void DeveloperPrivateAPI::OnListenerAdded( 310 const EventListenerInfo& details) { 311 if (!developer_private_event_router_) { 312 developer_private_event_router_.reset( 313 new DeveloperPrivateEventRouter(profile_)); 314 } 315 316 developer_private_event_router_->AddExtensionId(details.extension_id); 317 } 318 319 void DeveloperPrivateAPI::OnListenerRemoved( 320 const EventListenerInfo& details) { 321 if (!EventRouter::Get(profile_)->HasEventListener( 322 developer_private::OnItemStateChanged::kEventName)) { 323 developer_private_event_router_.reset(NULL); 324 } else { 325 developer_private_event_router_->RemoveExtensionId(details.extension_id); 326 } 327 } 328 329 namespace api { 330 331 bool DeveloperPrivateAutoUpdateFunction::RunSync() { 332 ExtensionUpdater* updater = GetExtensionUpdater(GetProfile()); 333 if (updater) 334 updater->CheckNow(ExtensionUpdater::CheckParams()); 335 SetResult(new base::FundamentalValue(true)); 336 return true; 337 } 338 339 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {} 340 341 scoped_ptr<developer::ItemInfo> 342 DeveloperPrivateGetItemsInfoFunction::CreateItemInfo(const Extension& item, 343 bool item_is_enabled) { 344 scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo()); 345 346 ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); 347 ExtensionService* service = system->extension_service(); 348 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile()); 349 350 info->id = item.id(); 351 info->name = item.name(); 352 info->enabled = service->IsExtensionEnabled(info->id); 353 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item); 354 info->version = item.VersionString(); 355 info->description = item.description(); 356 357 if (item.is_app()) { 358 if (item.is_legacy_packaged_app()) 359 info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP; 360 else if (item.is_hosted_app()) 361 info->type = developer::ITEM_TYPE_HOSTED_APP; 362 else if (item.is_platform_app()) 363 info->type = developer::ITEM_TYPE_PACKAGED_APP; 364 else 365 NOTREACHED(); 366 } else if (item.is_theme()) { 367 info->type = developer::ITEM_TYPE_THEME; 368 } else if (item.is_extension()) { 369 info->type = developer::ITEM_TYPE_EXTENSION; 370 } else { 371 NOTREACHED(); 372 } 373 374 if (Manifest::IsUnpackedLocation(item.location())) { 375 info->path.reset( 376 new std::string(base::UTF16ToUTF8(item.path().LossyDisplayName()))); 377 // If the ErrorConsole is enabled and the extension is unpacked, use the 378 // more detailed errors from the ErrorConsole. Otherwise, use the install 379 // warnings (using both is redundant). 380 ErrorConsole* error_console = ErrorConsole::Get(GetProfile()); 381 if (error_console->IsEnabledForAppsDeveloperTools() && 382 item.location() == Manifest::UNPACKED) { 383 const ErrorList& errors = error_console->GetErrorsForExtension(item.id()); 384 if (!errors.empty()) { 385 for (ErrorList::const_iterator iter = errors.begin(); 386 iter != errors.end(); 387 ++iter) { 388 switch ((*iter)->type()) { 389 case ExtensionError::MANIFEST_ERROR: 390 info->manifest_errors.push_back( 391 make_linked_ptr((*iter)->ToValue().release())); 392 break; 393 case ExtensionError::RUNTIME_ERROR: { 394 const RuntimeError* error = 395 static_cast<const RuntimeError*>(*iter); 396 scoped_ptr<base::DictionaryValue> value = error->ToValue(); 397 bool can_inspect = content::RenderViewHost::FromID( 398 error->render_process_id(), 399 error->render_view_id()) != NULL; 400 value->SetBoolean("canInspect", can_inspect); 401 info->runtime_errors.push_back(make_linked_ptr(value.release())); 402 break; 403 } 404 case ExtensionError::NUM_ERROR_TYPES: 405 NOTREACHED(); 406 break; 407 } 408 } 409 } 410 } else { 411 for (std::vector<InstallWarning>::const_iterator it = 412 item.install_warnings().begin(); 413 it != item.install_warnings().end(); 414 ++it) { 415 scoped_ptr<developer::InstallWarning> warning( 416 new developer::InstallWarning); 417 warning->message = it->message; 418 info->install_warnings.push_back(make_linked_ptr(warning.release())); 419 } 420 } 421 } 422 423 info->incognito_enabled = util::IsIncognitoEnabled(item.id(), GetProfile()); 424 info->wants_file_access = item.wants_file_access(); 425 info->allow_file_access = util::AllowFileAccess(item.id(), GetProfile()); 426 info->allow_reload = Manifest::IsUnpackedLocation(item.location()); 427 info->is_unpacked = Manifest::IsUnpackedLocation(item.location()); 428 info->terminated = registry->terminated_extensions().Contains(item.id()); 429 info->allow_incognito = item.can_be_incognito_enabled(); 430 431 info->homepage_url.reset(new std::string( 432 ManifestURL::GetHomepageURL(&item).spec())); 433 if (!ManifestURL::GetOptionsPage(&item).is_empty()) { 434 info->options_url.reset( 435 new std::string(ManifestURL::GetOptionsPage(&item).spec())); 436 } 437 438 if (!ManifestURL::GetUpdateURL(&item).is_empty()) { 439 info->update_url.reset( 440 new std::string(ManifestURL::GetUpdateURL(&item).spec())); 441 } 442 443 if (item.is_app()) { 444 info->app_launch_url.reset( 445 new std::string(AppLaunchInfo::GetFullLaunchURL(&item).spec())); 446 } 447 448 info->may_disable = system->management_policy()-> 449 UserMayModifySettings(&item, NULL); 450 info->is_app = item.is_app(); 451 info->views = GetInspectablePagesForExtension(&item, item_is_enabled); 452 453 return info.Pass(); 454 } 455 456 void DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread( 457 ItemInfoList item_list, 458 const std::map<std::string, ExtensionResource> idToIcon) { 459 for (ItemInfoList::iterator iter = item_list.begin(); 460 iter != item_list.end(); ++iter) { 461 developer_private::ItemInfo* info = iter->get(); 462 std::map<std::string, ExtensionResource>::const_iterator resource_ptr 463 = idToIcon.find(info->id); 464 if (resource_ptr != idToIcon.end()) { 465 info->icon_url = 466 ToDataURL(resource_ptr->second.GetFilePath(), info->type).spec(); 467 } 468 } 469 470 results_ = developer::GetItemsInfo::Results::Create(item_list); 471 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 472 base::Bind(&DeveloperPrivateGetItemsInfoFunction::SendResponse, 473 this, 474 true)); 475 } 476 477 void DeveloperPrivateGetItemsInfoFunction:: 478 GetInspectablePagesForExtensionProcess( 479 const Extension* extension, 480 const std::set<content::RenderViewHost*>& views, 481 ItemInspectViewList* result) { 482 bool has_generated_background_page = 483 BackgroundInfo::HasGeneratedBackgroundPage(extension); 484 for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin(); 485 iter != views.end(); ++iter) { 486 content::RenderViewHost* host = *iter; 487 content::WebContents* web_contents = 488 content::WebContents::FromRenderViewHost(host); 489 ViewType host_type = GetViewType(web_contents); 490 if (VIEW_TYPE_EXTENSION_POPUP == host_type || 491 VIEW_TYPE_EXTENSION_DIALOG == host_type) 492 continue; 493 494 content::RenderProcessHost* process = host->GetProcess(); 495 bool is_background_page = 496 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension)); 497 result->push_back(constructInspectView( 498 web_contents->GetURL(), 499 process->GetID(), 500 host->GetRoutingID(), 501 process->GetBrowserContext()->IsOffTheRecord(), 502 is_background_page && has_generated_background_page)); 503 } 504 } 505 506 void DeveloperPrivateGetItemsInfoFunction::GetAppWindowPagesForExtensionProfile( 507 const Extension* extension, 508 ItemInspectViewList* result) { 509 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile()); 510 if (!registry) return; 511 512 const AppWindowRegistry::AppWindowList windows = 513 registry->GetAppWindowsForApp(extension->id()); 514 515 bool has_generated_background_page = 516 BackgroundInfo::HasGeneratedBackgroundPage(extension); 517 for (AppWindowRegistry::const_iterator it = windows.begin(); 518 it != windows.end(); 519 ++it) { 520 content::WebContents* web_contents = (*it)->web_contents(); 521 RenderViewHost* host = web_contents->GetRenderViewHost(); 522 content::RenderProcessHost* process = host->GetProcess(); 523 bool is_background_page = 524 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension)); 525 result->push_back(constructInspectView( 526 web_contents->GetURL(), 527 process->GetID(), 528 host->GetRoutingID(), 529 process->GetBrowserContext()->IsOffTheRecord(), 530 is_background_page && has_generated_background_page)); 531 } 532 } 533 534 linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction:: 535 constructInspectView( 536 const GURL& url, 537 int render_process_id, 538 int render_view_id, 539 bool incognito, 540 bool generated_background_page) { 541 linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView()); 542 543 if (url.scheme() == kExtensionScheme) { 544 // No leading slash. 545 view->path = url.path().substr(1); 546 } else { 547 // For live pages, use the full URL. 548 view->path = url.spec(); 549 } 550 551 view->render_process_id = render_process_id; 552 view->render_view_id = render_view_id; 553 view->incognito = incognito; 554 view->generated_background_page = generated_background_page; 555 return view; 556 } 557 558 ItemInspectViewList DeveloperPrivateGetItemsInfoFunction:: 559 GetInspectablePagesForExtension( 560 const Extension* extension, 561 bool extension_is_enabled) { 562 ItemInspectViewList result; 563 // Get the extension process's active views. 564 ProcessManager* process_manager = 565 ExtensionSystem::Get(GetProfile())->process_manager(); 566 GetInspectablePagesForExtensionProcess( 567 extension, 568 process_manager->GetRenderViewHostsForExtension(extension->id()), 569 &result); 570 571 // Get app window views. 572 GetAppWindowPagesForExtensionProfile(extension, &result); 573 574 // Include a link to start the lazy background page, if applicable. 575 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 576 extension_is_enabled && 577 !process_manager->GetBackgroundHostForExtension(extension->id())) { 578 result.push_back(constructInspectView( 579 BackgroundInfo::GetBackgroundURL(extension), 580 -1, 581 -1, 582 false, 583 BackgroundInfo::HasGeneratedBackgroundPage(extension))); 584 } 585 586 ExtensionService* service = GetProfile()->GetExtensionService(); 587 // Repeat for the incognito process, if applicable. Don't try to get 588 // app windows for incognito process. 589 if (service->profile()->HasOffTheRecordProfile() && 590 IncognitoInfo::IsSplitMode(extension)) { 591 process_manager = ExtensionSystem::Get( 592 service->profile()->GetOffTheRecordProfile())->process_manager(); 593 GetInspectablePagesForExtensionProcess( 594 extension, 595 process_manager->GetRenderViewHostsForExtension(extension->id()), 596 &result); 597 598 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 599 extension_is_enabled && 600 !process_manager->GetBackgroundHostForExtension(extension->id())) { 601 result.push_back(constructInspectView( 602 BackgroundInfo::GetBackgroundURL(extension), 603 -1, 604 -1, 605 false, 606 BackgroundInfo::HasGeneratedBackgroundPage(extension))); 607 } 608 } 609 610 return result; 611 } 612 613 bool DeveloperPrivateGetItemsInfoFunction::RunAsync() { 614 scoped_ptr<developer::GetItemsInfo::Params> params( 615 developer::GetItemsInfo::Params::Create(*args_)); 616 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 617 618 bool include_disabled = params->include_disabled; 619 bool include_terminated = params->include_terminated; 620 621 ExtensionSet items; 622 623 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile()); 624 625 items.InsertAll(registry->enabled_extensions()); 626 627 if (include_disabled) { 628 items.InsertAll(registry->disabled_extensions()); 629 } 630 631 if (include_terminated) { 632 items.InsertAll(registry->terminated_extensions()); 633 } 634 635 ExtensionService* service = 636 ExtensionSystem::Get(GetProfile())->extension_service(); 637 std::map<std::string, ExtensionResource> id_to_icon; 638 ItemInfoList item_list; 639 640 for (ExtensionSet::const_iterator iter = items.begin(); iter != items.end(); 641 ++iter) { 642 const Extension& item = *iter->get(); 643 644 ExtensionResource item_resource = 645 IconsInfo::GetIconResource(&item, 646 extension_misc::EXTENSION_ICON_MEDIUM, 647 ExtensionIconSet::MATCH_BIGGER); 648 id_to_icon[item.id()] = item_resource; 649 650 // Don't show component extensions and invisible apps. 651 if (ui_util::ShouldNotBeVisible(&item, GetProfile())) 652 continue; 653 654 item_list.push_back(make_linked_ptr<developer::ItemInfo>( 655 CreateItemInfo( 656 item, service->IsExtensionEnabled(item.id())).release())); 657 } 658 659 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 660 base::Bind(&DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread, 661 this, 662 item_list, 663 id_to_icon)); 664 665 return true; 666 } 667 668 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {} 669 670 bool DeveloperPrivateAllowFileAccessFunction::RunSync() { 671 scoped_ptr<AllowFileAccess::Params> params( 672 AllowFileAccess::Params::Create(*args_)); 673 EXTENSION_FUNCTION_VALIDATE(params.get()); 674 675 EXTENSION_FUNCTION_VALIDATE(user_gesture_); 676 677 ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); 678 ManagementPolicy* management_policy = system->management_policy(); 679 const Extension* extension = 680 ExtensionRegistry::Get(GetProfile()) 681 ->GetExtensionById(params->item_id, ExtensionRegistry::EVERYTHING); 682 bool result = true; 683 684 if (!extension) { 685 result = false; 686 } else if (!management_policy->UserMayModifySettings(extension, NULL)) { 687 LOG(ERROR) << "Attempt to change allow file access of an extension that " 688 << "non-usermanagable was made. Extension id : " 689 << extension->id(); 690 result = false; 691 } else { 692 util::SetAllowFileAccess(extension->id(), GetProfile(), params->allow); 693 result = true; 694 } 695 696 return result; 697 } 698 699 DeveloperPrivateAllowFileAccessFunction:: 700 ~DeveloperPrivateAllowFileAccessFunction() {} 701 702 bool DeveloperPrivateAllowIncognitoFunction::RunSync() { 703 scoped_ptr<AllowIncognito::Params> params( 704 AllowIncognito::Params::Create(*args_)); 705 EXTENSION_FUNCTION_VALIDATE(params.get()); 706 707 const Extension* extension = 708 ExtensionRegistry::Get(GetProfile()) 709 ->GetExtensionById(params->item_id, ExtensionRegistry::EVERYTHING); 710 bool result = true; 711 712 if (!extension) 713 result = false; 714 else 715 util::SetIsIncognitoEnabled(extension->id(), GetProfile(), params->allow); 716 717 return result; 718 } 719 720 DeveloperPrivateAllowIncognitoFunction:: 721 ~DeveloperPrivateAllowIncognitoFunction() {} 722 723 bool DeveloperPrivateReloadFunction::RunSync() { 724 scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_)); 725 EXTENSION_FUNCTION_VALIDATE(params.get()); 726 727 ExtensionService* service = GetProfile()->GetExtensionService(); 728 CHECK(!params->item_id.empty()); 729 service->ReloadExtension(params->item_id); 730 return true; 731 } 732 733 bool DeveloperPrivateShowPermissionsDialogFunction::RunSync() { 734 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_)); 735 CHECK(!extension_id_.empty()); 736 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile()); 737 DCHECK(registry); 738 AppWindow* app_window = 739 registry->GetAppWindowForRenderViewHost(render_view_host()); 740 prompt_.reset(new ExtensionInstallPrompt(app_window->web_contents())); 741 const Extension* extension = 742 ExtensionRegistry::Get(GetProfile()) 743 ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING); 744 745 if (!extension) 746 return false; 747 748 // Released by InstallUIAbort or InstallUIProceed. 749 AddRef(); 750 std::vector<base::FilePath> retained_file_paths; 751 if (extension->permissions_data()->HasAPIPermission( 752 APIPermission::kFileSystem)) { 753 std::vector<apps::SavedFileEntry> retained_file_entries = 754 apps::SavedFilesService::Get(GetProfile()) 755 ->GetAllFileEntries(extension_id_); 756 for (size_t i = 0; i < retained_file_entries.size(); i++) { 757 retained_file_paths.push_back(retained_file_entries[i].path); 758 } 759 } 760 prompt_->ReviewPermissions(this, extension, retained_file_paths); 761 return true; 762 } 763 764 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {} 765 766 // This is called when the user clicks "Revoke File Access." 767 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() { 768 apps::SavedFilesService::Get(GetProfile()) 769 ->ClearQueue(GetProfile()->GetExtensionService()->GetExtensionById( 770 extension_id_, true)); 771 if (apps::AppRestoreService::Get(GetProfile()) 772 ->IsAppRestorable(extension_id_)) 773 apps::AppLoadService::Get(GetProfile())->RestartApplication(extension_id_); 774 SendResponse(true); 775 Release(); 776 } 777 778 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort( 779 bool user_initiated) { 780 SendResponse(true); 781 Release(); 782 } 783 784 DeveloperPrivateShowPermissionsDialogFunction:: 785 DeveloperPrivateShowPermissionsDialogFunction() {} 786 787 DeveloperPrivateShowPermissionsDialogFunction:: 788 ~DeveloperPrivateShowPermissionsDialogFunction() {} 789 790 DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {} 791 792 bool DeveloperPrivateEnableFunction::RunSync() { 793 scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_)); 794 EXTENSION_FUNCTION_VALIDATE(params.get()); 795 796 std::string extension_id = params->item_id; 797 798 const Extension* extension = 799 ExtensionRegistry::Get(GetProfile()) 800 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 801 if (!extension) { 802 LOG(ERROR) << "Did not find extension with id " << extension_id; 803 return false; 804 } 805 ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); 806 ManagementPolicy* policy = system->management_policy(); 807 bool enable = params->enable; 808 if (!policy->UserMayModifySettings(extension, NULL) || 809 (!enable && policy->MustRemainEnabled(extension, NULL)) || 810 (enable && policy->MustRemainDisabled(extension, NULL, NULL))) { 811 LOG(ERROR) << "Attempt to change enable state denied by management policy. " 812 << "Extension id: " << extension_id.c_str(); 813 return false; 814 } 815 816 ExtensionService* service = system->extension_service(); 817 if (enable) { 818 ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile()); 819 if (prefs->DidExtensionEscalatePermissions(extension_id)) { 820 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile()); 821 CHECK(registry); 822 AppWindow* app_window = 823 registry->GetAppWindowForRenderViewHost(render_view_host()); 824 if (!app_window) { 825 return false; 826 } 827 828 ShowExtensionDisabledDialog( 829 service, app_window->web_contents(), extension); 830 } else if ((prefs->GetDisableReasons(extension_id) & 831 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) && 832 !requirements_checker_.get()) { 833 // Recheck the requirements. 834 scoped_refptr<const Extension> extension = 835 service->GetExtensionById(extension_id, true); 836 requirements_checker_.reset(new RequirementsChecker); 837 // Released by OnRequirementsChecked. 838 AddRef(); 839 requirements_checker_->Check( 840 extension, 841 base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked, 842 this, extension_id)); 843 } else { 844 service->EnableExtension(extension_id); 845 846 // Make sure any browser action contained within it is not hidden. 847 ExtensionActionAPI::SetBrowserActionVisibility( 848 prefs, extension->id(), true); 849 } 850 } else { 851 service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION); 852 } 853 return true; 854 } 855 856 void DeveloperPrivateEnableFunction::OnRequirementsChecked( 857 const std::string& extension_id, 858 std::vector<std::string> requirements_errors) { 859 if (requirements_errors.empty()) { 860 ExtensionService* service = GetProfile()->GetExtensionService(); 861 service->EnableExtension(extension_id); 862 } else { 863 ExtensionErrorReporter::GetInstance()->ReportError( 864 base::UTF8ToUTF16(JoinString(requirements_errors, ' ')), 865 true); // Be noisy. 866 } 867 Release(); 868 } 869 870 DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {} 871 872 bool DeveloperPrivateInspectFunction::RunSync() { 873 scoped_ptr<developer::Inspect::Params> params( 874 developer::Inspect::Params::Create(*args_)); 875 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 876 const developer::InspectOptions& options = params->options; 877 878 int render_process_id; 879 base::StringToInt(options.render_process_id, &render_process_id); 880 881 if (render_process_id == -1) { 882 // This is a lazy background page. Identify if it is a normal 883 // or incognito background page. 884 ExtensionService* service = GetProfile()->GetExtensionService(); 885 if (options.incognito) 886 service = ExtensionSystem::Get( 887 service->profile()->GetOffTheRecordProfile())->extension_service(); 888 const Extension* extension = service->extensions()->GetByID( 889 options.extension_id); 890 DCHECK(extension); 891 // Wakes up the background page and opens the inspect window. 892 devtools_util::InspectBackgroundPage(extension, GetProfile()); 893 return false; 894 } 895 896 int render_view_id; 897 base::StringToInt(options.render_view_id, &render_view_id); 898 content::RenderViewHost* host = content::RenderViewHost::FromID( 899 render_process_id, render_view_id); 900 901 if (!host) { 902 // This can happen if the host has gone away since the page was displayed. 903 return false; 904 } 905 906 DevToolsWindow::OpenDevToolsWindow(host); 907 return true; 908 } 909 910 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {} 911 912 bool DeveloperPrivateLoadUnpackedFunction::RunAsync() { 913 base::string16 select_title = 914 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 915 916 // Balanced in FileSelected / FileSelectionCanceled. 917 AddRef(); 918 bool result = ShowPicker( 919 ui::SelectFileDialog::SELECT_FOLDER, 920 DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(), 921 select_title, 922 ui::SelectFileDialog::FileTypeInfo(), 923 0); 924 return result; 925 } 926 927 void DeveloperPrivateLoadUnpackedFunction::FileSelected( 928 const base::FilePath& path) { 929 ExtensionService* service = GetProfile()->GetExtensionService(); 930 UnpackedInstaller::Create(service)->Load(path); 931 DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path); 932 SendResponse(true); 933 Release(); 934 } 935 936 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() { 937 SendResponse(false); 938 Release(); 939 } 940 941 bool DeveloperPrivateChooseEntryFunction::ShowPicker( 942 ui::SelectFileDialog::Type picker_type, 943 const base::FilePath& last_directory, 944 const base::string16& select_title, 945 const ui::SelectFileDialog::FileTypeInfo& info, 946 int file_type_index) { 947 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile()); 948 DCHECK(registry); 949 AppWindow* app_window = 950 registry->GetAppWindowForRenderViewHost(render_view_host()); 951 if (!app_window) { 952 return false; 953 } 954 955 // The entry picker will hold a reference to this function instance, 956 // and subsequent sending of the function response) until the user has 957 // selected a file or cancelled the picker. At that point, the picker will 958 // delete itself. 959 new EntryPicker(this, 960 app_window->web_contents(), 961 picker_type, 962 last_directory, 963 select_title, 964 info, 965 file_type_index); 966 return true; 967 } 968 969 bool DeveloperPrivateChooseEntryFunction::RunAsync() { 970 return false; 971 } 972 973 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {} 974 975 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess( 976 const base::FilePath& crx_file, 977 const base::FilePath& pem_file) { 978 developer::PackDirectoryResponse response; 979 response.message = base::UTF16ToUTF8( 980 PackExtensionJob::StandardSuccessMessage(crx_file, pem_file)); 981 response.status = developer::PACK_STATUS_SUCCESS; 982 results_ = developer::PackDirectory::Results::Create(response); 983 SendResponse(true); 984 Release(); 985 } 986 987 void DeveloperPrivatePackDirectoryFunction::OnPackFailure( 988 const std::string& error, 989 ExtensionCreator::ErrorType error_type) { 990 developer::PackDirectoryResponse response; 991 response.message = error; 992 if (error_type == ExtensionCreator::kCRXExists) { 993 response.item_path = item_path_str_; 994 response.pem_path = key_path_str_; 995 response.override_flags = ExtensionCreator::kOverwriteCRX; 996 response.status = developer::PACK_STATUS_WARNING; 997 } else { 998 response.status = developer::PACK_STATUS_ERROR; 999 } 1000 results_ = developer::PackDirectory::Results::Create(response); 1001 SendResponse(true); 1002 Release(); 1003 } 1004 1005 bool DeveloperPrivatePackDirectoryFunction::RunAsync() { 1006 scoped_ptr<PackDirectory::Params> params( 1007 PackDirectory::Params::Create(*args_)); 1008 EXTENSION_FUNCTION_VALIDATE(params.get()); 1009 1010 int flags = params->flags; 1011 item_path_str_ = params->path; 1012 key_path_str_ = params->private_key_path; 1013 1014 base::FilePath root_directory = 1015 base::FilePath::FromUTF8Unsafe(item_path_str_); 1016 1017 base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_); 1018 1019 developer::PackDirectoryResponse response; 1020 if (root_directory.empty()) { 1021 if (item_path_str_.empty()) 1022 response.message = l10n_util::GetStringUTF8( 1023 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED); 1024 else 1025 response.message = l10n_util::GetStringUTF8( 1026 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID); 1027 1028 response.status = developer::PACK_STATUS_ERROR; 1029 results_ = developer::PackDirectory::Results::Create(response); 1030 SendResponse(true); 1031 return true; 1032 } 1033 1034 if (!key_path_str_.empty() && key_file.empty()) { 1035 response.message = l10n_util::GetStringUTF8( 1036 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID); 1037 response.status = developer::PACK_STATUS_ERROR; 1038 results_ = developer::PackDirectory::Results::Create(response); 1039 SendResponse(true); 1040 return true; 1041 } 1042 1043 // Balanced in OnPackSuccess / OnPackFailure. 1044 AddRef(); 1045 1046 pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags); 1047 pack_job_->Start(); 1048 return true; 1049 } 1050 1051 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() 1052 {} 1053 1054 DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction() 1055 {} 1056 1057 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {} 1058 1059 bool DeveloperPrivateLoadDirectoryFunction::RunAsync() { 1060 // TODO(grv) : add unittests. 1061 std::string directory_url_str; 1062 std::string filesystem_name; 1063 std::string filesystem_path; 1064 1065 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); 1066 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); 1067 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &directory_url_str)); 1068 1069 // Directory url is non empty only for syncfilesystem. 1070 if (directory_url_str != "") { 1071 context_ = content::BrowserContext::GetStoragePartition( 1072 GetProfile(), render_view_host()->GetSiteInstance()) 1073 ->GetFileSystemContext(); 1074 1075 fileapi::FileSystemURL directory_url = 1076 context_->CrackURL(GURL(directory_url_str)); 1077 1078 if (!directory_url.is_valid() && directory_url.type() == 1079 fileapi::kFileSystemTypeSyncable) { 1080 SetError("DirectoryEntry of unsupported filesystem."); 1081 return false; 1082 } 1083 1084 size_t pos = 0; 1085 // Parse the project directory name from the project url. The project url is 1086 // expected to have project name as the suffix. 1087 if ((pos = directory_url_str.rfind("/")) == std::string::npos) { 1088 SetError("Invalid Directory entry."); 1089 return false; 1090 } 1091 1092 std::string project_name; 1093 project_name = directory_url_str.substr(pos + 1); 1094 project_base_url_ = directory_url_str.substr(0, pos + 1); 1095 1096 base::FilePath project_path(GetProfile()->GetPath()); 1097 project_path = project_path.Append(kUnpackedAppsFolder); 1098 project_path = project_path.Append( 1099 base::FilePath::FromUTF8Unsafe(project_name)); 1100 1101 project_base_path_ = project_path; 1102 1103 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 1104 base::Bind(&DeveloperPrivateLoadDirectoryFunction:: 1105 ClearExistingDirectoryContent, 1106 this, 1107 project_base_path_)); 1108 } else { 1109 // Check if the DirecotryEntry is the instance of chrome filesystem. 1110 if (!app_file_handler_util::ValidateFileEntryAndGetPath(filesystem_name, 1111 filesystem_path, 1112 render_view_host_, 1113 &project_base_path_, 1114 &error_)) 1115 return false; 1116 1117 Load(); 1118 } 1119 1120 return true; 1121 } 1122 1123 void DeveloperPrivateLoadDirectoryFunction::Load() { 1124 ExtensionService* service = GetProfile()->GetExtensionService(); 1125 UnpackedInstaller::Create(service)->Load(project_base_path_); 1126 1127 // TODO(grv) : The unpacked installer should fire an event when complete 1128 // and return the extension_id. 1129 SetResult(new base::StringValue("-1")); 1130 SendResponse(true); 1131 } 1132 1133 void DeveloperPrivateLoadDirectoryFunction::ClearExistingDirectoryContent( 1134 const base::FilePath& project_path) { 1135 1136 // Clear the project directory before copying new files. 1137 base::DeleteFile(project_path, true/*recursive*/); 1138 1139 pending_copy_operations_count_ = 1; 1140 1141 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 1142 base::Bind(&DeveloperPrivateLoadDirectoryFunction:: 1143 ReadSyncFileSystemDirectory, 1144 this, project_path, project_path.BaseName())); 1145 } 1146 1147 void DeveloperPrivateLoadDirectoryFunction::ReadSyncFileSystemDirectory( 1148 const base::FilePath& project_path, 1149 const base::FilePath& destination_path) { 1150 1151 current_path_ = context_->CrackURL(GURL(project_base_url_)).path(); 1152 1153 GURL project_url = GURL(project_base_url_ + destination_path.MaybeAsASCII()); 1154 1155 fileapi::FileSystemURL url = context_->CrackURL(project_url); 1156 1157 context_->operation_runner()->ReadDirectory( 1158 url, base::Bind(&DeveloperPrivateLoadDirectoryFunction:: 1159 ReadSyncFileSystemDirectoryCb, 1160 this, project_path, destination_path)); 1161 } 1162 1163 void DeveloperPrivateLoadDirectoryFunction::ReadSyncFileSystemDirectoryCb( 1164 const base::FilePath& project_path, 1165 const base::FilePath& destination_path, 1166 base::File::Error status, 1167 const fileapi::FileSystemOperation::FileEntryList& file_list, 1168 bool has_more) { 1169 1170 if (status != base::File::FILE_OK) { 1171 DLOG(ERROR) << "Error in copying files from sync filesystem."; 1172 return; 1173 } 1174 1175 // We add 1 to the pending copy operations for both files and directories. We 1176 // release the directory copy operation once all the files under the directory 1177 // are added for copying. We do that to ensure that pendingCopyOperationsCount 1178 // does not become zero before all copy operations are finished. 1179 // In case the directory happens to be executing the last copy operation it 1180 // will call SendResponse to send the response to the API. The pending copy 1181 // operations of files are released by the CopyFile function. 1182 pending_copy_operations_count_ += file_list.size(); 1183 1184 for (size_t i = 0; i < file_list.size(); ++i) { 1185 if (file_list[i].is_directory) { 1186 ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name), 1187 destination_path.Append(file_list[i].name)); 1188 continue; 1189 } 1190 1191 std::string origin_url( 1192 Extension::GetBaseURLFromExtensionId(extension_id()).spec()); 1193 fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL( 1194 GURL(origin_url), 1195 current_path_.Append(destination_path.Append(file_list[i].name)))); 1196 base::FilePath target_path = project_path; 1197 target_path = target_path.Append(file_list[i].name); 1198 1199 context_->operation_runner()->CreateSnapshotFile( 1200 url, 1201 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback, 1202 this, 1203 target_path)); 1204 } 1205 1206 if (!has_more) { 1207 // Directory copy operation released here. 1208 pending_copy_operations_count_--; 1209 1210 if (!pending_copy_operations_count_) { 1211 content::BrowserThread::PostTask( 1212 content::BrowserThread::UI, FROM_HERE, 1213 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SendResponse, 1214 this, 1215 success_)); 1216 } 1217 } 1218 } 1219 1220 void DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback( 1221 const base::FilePath& target_path, 1222 base::File::Error result, 1223 const base::File::Info& file_info, 1224 const base::FilePath& src_path, 1225 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { 1226 if (result != base::File::FILE_OK) { 1227 SetError("Error in copying files from sync filesystem."); 1228 success_ = false; 1229 return; 1230 } 1231 1232 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 1233 base::Bind(&DeveloperPrivateLoadDirectoryFunction::CopyFile, 1234 this, 1235 src_path, 1236 target_path)); 1237 } 1238 1239 void DeveloperPrivateLoadDirectoryFunction::CopyFile( 1240 const base::FilePath& src_path, 1241 const base::FilePath& target_path) { 1242 if (!base::CreateDirectory(target_path.DirName())) { 1243 SetError("Error in copying files from sync filesystem."); 1244 success_ = false; 1245 } 1246 1247 if (success_) 1248 base::CopyFile(src_path, target_path); 1249 1250 CHECK(pending_copy_operations_count_ > 0); 1251 pending_copy_operations_count_--; 1252 1253 if (!pending_copy_operations_count_) { 1254 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1255 base::Bind(&DeveloperPrivateLoadDirectoryFunction::Load, 1256 this)); 1257 } 1258 } 1259 1260 DeveloperPrivateLoadDirectoryFunction::DeveloperPrivateLoadDirectoryFunction() 1261 : pending_copy_operations_count_(0), success_(true) {} 1262 1263 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction() 1264 {} 1265 1266 bool DeveloperPrivateChoosePathFunction::RunAsync() { 1267 scoped_ptr<developer::ChoosePath::Params> params( 1268 developer::ChoosePath::Params::Create(*args_)); 1269 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 1270 1271 ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER; 1272 ui::SelectFileDialog::FileTypeInfo info; 1273 if (params->select_type == developer::SELECT_TYPE_FILE) { 1274 type = ui::SelectFileDialog::SELECT_OPEN_FILE; 1275 } 1276 base::string16 select_title; 1277 1278 int file_type_index = 0; 1279 if (params->file_type == developer::FILE_TYPE_LOAD) { 1280 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 1281 } else if (params->file_type == developer::FILE_TYPE_PEM) { 1282 select_title = l10n_util::GetStringUTF16( 1283 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); 1284 info.extensions.push_back(std::vector<base::FilePath::StringType>()); 1285 info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); 1286 info.extension_description_overrides.push_back( 1287 l10n_util::GetStringUTF16( 1288 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); 1289 info.include_all_files = true; 1290 file_type_index = 1; 1291 } else { 1292 NOTREACHED(); 1293 } 1294 1295 // Balanced by FileSelected / FileSelectionCanceled. 1296 AddRef(); 1297 bool result = ShowPicker( 1298 type, 1299 DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(), 1300 select_title, 1301 info, 1302 file_type_index); 1303 return result; 1304 } 1305 1306 void DeveloperPrivateChoosePathFunction::FileSelected( 1307 const base::FilePath& path) { 1308 SetResult(new base::StringValue(base::UTF16ToUTF8(path.LossyDisplayName()))); 1309 SendResponse(true); 1310 Release(); 1311 } 1312 1313 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() { 1314 SendResponse(false); 1315 Release(); 1316 } 1317 1318 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {} 1319 1320 bool DeveloperPrivateIsProfileManagedFunction::RunSync() { 1321 SetResult(new base::FundamentalValue(GetProfile()->IsSupervised())); 1322 return true; 1323 } 1324 1325 DeveloperPrivateIsProfileManagedFunction:: 1326 ~DeveloperPrivateIsProfileManagedFunction() { 1327 } 1328 1329 DeveloperPrivateRequestFileSourceFunction:: 1330 DeveloperPrivateRequestFileSourceFunction() {} 1331 1332 DeveloperPrivateRequestFileSourceFunction:: 1333 ~DeveloperPrivateRequestFileSourceFunction() {} 1334 1335 bool DeveloperPrivateRequestFileSourceFunction::RunAsync() { 1336 scoped_ptr<developer::RequestFileSource::Params> params( 1337 developer::RequestFileSource::Params::Create(*args_)); 1338 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 1339 1340 base::DictionaryValue* dict = NULL; 1341 if (!params->dict->GetAsDictionary(&dict)) { 1342 NOTREACHED(); 1343 return false; 1344 } 1345 1346 AddRef(); // Balanced in LaunchCallback(). 1347 error_ui_util::HandleRequestFileSource( 1348 dict, 1349 GetProfile(), 1350 base::Bind(&DeveloperPrivateRequestFileSourceFunction::LaunchCallback, 1351 base::Unretained(this))); 1352 return true; 1353 } 1354 1355 void DeveloperPrivateRequestFileSourceFunction::LaunchCallback( 1356 const base::DictionaryValue& results) { 1357 SetResult(results.DeepCopy()); 1358 SendResponse(true); 1359 Release(); // Balanced in RunAsync(). 1360 } 1361 1362 DeveloperPrivateOpenDevToolsFunction::DeveloperPrivateOpenDevToolsFunction() {} 1363 DeveloperPrivateOpenDevToolsFunction::~DeveloperPrivateOpenDevToolsFunction() {} 1364 1365 bool DeveloperPrivateOpenDevToolsFunction::RunAsync() { 1366 scoped_ptr<developer::OpenDevTools::Params> params( 1367 developer::OpenDevTools::Params::Create(*args_)); 1368 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 1369 1370 base::DictionaryValue* dict = NULL; 1371 if (!params->dict->GetAsDictionary(&dict)) { 1372 NOTREACHED(); 1373 return false; 1374 } 1375 1376 error_ui_util::HandleOpenDevTools(dict); 1377 1378 return true; 1379 } 1380 1381 } // namespace api 1382 1383 } // namespace extensions 1384