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