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