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