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