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