• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetExtensionUpdater(Profile * profile)96 ExtensionUpdater* GetExtensionUpdater(Profile* profile) {
97     return profile->GetExtensionService()->updater();
98 }
99 
GetImageURLFromData(const std::string & contents)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 
GetDefaultImageURL(developer_private::ItemType type)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.
ToDataURL(const base::FilePath & path,developer_private::ItemType type)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 
GetExtensionID(const RenderViewHost * render_view_host)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 
BroadcastItemStateChanged(content::BrowserContext * browser_context,developer::EventType event_type,const std::string & item_id)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>*
GetFactoryInstance()175 DeveloperPrivateAPI::GetFactoryInstance() {
176   return g_factory.Pointer();
177 }
178 
179 // static
Get(content::BrowserContext * context)180 DeveloperPrivateAPI* DeveloperPrivateAPI::Get(
181     content::BrowserContext* context) {
182   return GetFactoryInstance()->Get(context);
183 }
184 
DeveloperPrivateAPI(content::BrowserContext * context)185 DeveloperPrivateAPI::DeveloperPrivateAPI(content::BrowserContext* context)
186     : profile_(Profile::FromBrowserContext(context)) {
187   RegisterNotifications();
188 }
189 
DeveloperPrivateEventRouter(Profile * profile)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 
~DeveloperPrivateEventRouter()205 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
206   ErrorConsole::Get(profile_)->RemoveObserver(this);
207 }
208 
AddExtensionId(const std::string & extension_id)209 void DeveloperPrivateEventRouter::AddExtensionId(
210     const std::string& extension_id) {
211   extension_ids_.insert(extension_id);
212 }
213 
RemoveExtensionId(const std::string & extension_id)214 void DeveloperPrivateEventRouter::RemoveExtensionId(
215     const std::string& extension_id) {
216   extension_ids_.erase(extension_id);
217 }
218 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)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 
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)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 
OnExtensionWillBeInstalled(content::BrowserContext * browser_context,const Extension * extension,bool is_update,bool from_ephemeral,const std::string & old_name)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 
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension)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 
OnErrorAdded(const ExtensionError * error)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 
SetLastUnpackedDirectory(const base::FilePath & path)296 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
297   last_unpacked_directory_ = path;
298 }
299 
RegisterNotifications()300 void DeveloperPrivateAPI::RegisterNotifications() {
301   EventRouter::Get(profile_)->RegisterObserver(
302       this, developer_private::OnItemStateChanged::kEventName);
303 }
304 
~DeveloperPrivateAPI()305 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
306 
Shutdown()307 void DeveloperPrivateAPI::Shutdown() {}
308 
OnListenerAdded(const EventListenerInfo & details)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 
OnListenerRemoved(const EventListenerInfo & details)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 
RunSync()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 
~DeveloperPrivateAutoUpdateFunction()339 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
340 
341 scoped_ptr<developer::ItemInfo>
CreateItemInfo(const Extension & item,bool item_is_enabled)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 
GetIconsOnFileThread(ItemInfoList item_list,const std::map<std::string,ExtensionResource> idToIcon)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::
GetInspectablePagesForExtensionProcess(const Extension * extension,const std::set<content::RenderViewHost * > & views,ItemInspectViewList * result)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 
GetAppWindowPagesForExtensionProfile(const Extension * extension,ItemInspectViewList * result)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::
constructInspectView(const GURL & url,int render_process_id,int render_view_id,bool incognito,bool generated_background_page)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::
GetInspectablePagesForExtension(const Extension * extension,bool extension_is_enabled)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 
RunAsync()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 
~DeveloperPrivateGetItemsInfoFunction()668 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
669 
RunSync()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::
~DeveloperPrivateAllowFileAccessFunction()700     ~DeveloperPrivateAllowFileAccessFunction() {}
701 
RunSync()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::
~DeveloperPrivateAllowIncognitoFunction()721     ~DeveloperPrivateAllowIncognitoFunction() {}
722 
RunSync()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 
RunSync()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 
~DeveloperPrivateReloadFunction()764 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
765 
766 // This is called when the user clicks "Revoke File Access."
InstallUIProceed()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 
InstallUIAbort(bool user_initiated)778 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
779     bool user_initiated) {
780   SendResponse(true);
781   Release();
782 }
783 
784 DeveloperPrivateShowPermissionsDialogFunction::
DeveloperPrivateShowPermissionsDialogFunction()785     DeveloperPrivateShowPermissionsDialogFunction() {}
786 
787 DeveloperPrivateShowPermissionsDialogFunction::
~DeveloperPrivateShowPermissionsDialogFunction()788     ~DeveloperPrivateShowPermissionsDialogFunction() {}
789 
DeveloperPrivateEnableFunction()790 DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {}
791 
RunSync()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 
OnRequirementsChecked(const std::string & extension_id,std::vector<std::string> requirements_errors)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 
~DeveloperPrivateEnableFunction()870 DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {}
871 
RunSync()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 
~DeveloperPrivateInspectFunction()910 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
911 
RunAsync()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 
FileSelected(const base::FilePath & path)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 
FileSelectionCanceled()936 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
937   SendResponse(false);
938   Release();
939 }
940 
ShowPicker(ui::SelectFileDialog::Type picker_type,const base::FilePath & last_directory,const base::string16 & select_title,const ui::SelectFileDialog::FileTypeInfo & info,int file_type_index)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 
RunAsync()969 bool DeveloperPrivateChooseEntryFunction::RunAsync() {
970   return false;
971 }
972 
~DeveloperPrivateChooseEntryFunction()973 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
974 
OnPackSuccess(const base::FilePath & crx_file,const base::FilePath & pem_file)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 
OnPackFailure(const std::string & error,ExtensionCreator::ErrorType error_type)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 
RunAsync()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 
DeveloperPrivatePackDirectoryFunction()1051 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction()
1052 {}
1053 
~DeveloperPrivatePackDirectoryFunction()1054 DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction()
1055 {}
1056 
~DeveloperPrivateLoadUnpackedFunction()1057 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
1058 
RunAsync()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 
Load()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 
ClearExistingDirectoryContent(const base::FilePath & project_path)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 
ReadSyncFileSystemDirectory(const base::FilePath & project_path,const base::FilePath & destination_path)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 
ReadSyncFileSystemDirectoryCb(const base::FilePath & project_path,const base::FilePath & destination_path,base::File::Error status,const fileapi::FileSystemOperation::FileEntryList & file_list,bool has_more)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 
SnapshotFileCallback(const base::FilePath & target_path,base::File::Error result,const base::File::Info & file_info,const base::FilePath & src_path,const scoped_refptr<webkit_blob::ShareableFileReference> & file_ref)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 
CopyFile(const base::FilePath & src_path,const base::FilePath & target_path)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 
DeveloperPrivateLoadDirectoryFunction()1260 DeveloperPrivateLoadDirectoryFunction::DeveloperPrivateLoadDirectoryFunction()
1261     : pending_copy_operations_count_(0), success_(true) {}
1262 
~DeveloperPrivateLoadDirectoryFunction()1263 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction()
1264     {}
1265 
RunAsync()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 
FileSelected(const base::FilePath & path)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 
FileSelectionCanceled()1313 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1314   SendResponse(false);
1315   Release();
1316 }
1317 
~DeveloperPrivateChoosePathFunction()1318 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1319 
RunSync()1320 bool DeveloperPrivateIsProfileManagedFunction::RunSync() {
1321   SetResult(new base::FundamentalValue(GetProfile()->IsSupervised()));
1322   return true;
1323 }
1324 
1325 DeveloperPrivateIsProfileManagedFunction::
~DeveloperPrivateIsProfileManagedFunction()1326     ~DeveloperPrivateIsProfileManagedFunction() {
1327 }
1328 
1329 DeveloperPrivateRequestFileSourceFunction::
DeveloperPrivateRequestFileSourceFunction()1330     DeveloperPrivateRequestFileSourceFunction() {}
1331 
1332 DeveloperPrivateRequestFileSourceFunction::
~DeveloperPrivateRequestFileSourceFunction()1333     ~DeveloperPrivateRequestFileSourceFunction() {}
1334 
RunAsync()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 
LaunchCallback(const base::DictionaryValue & results)1355 void DeveloperPrivateRequestFileSourceFunction::LaunchCallback(
1356     const base::DictionaryValue& results) {
1357   SetResult(results.DeepCopy());
1358   SendResponse(true);
1359   Release();  // Balanced in RunAsync().
1360 }
1361 
DeveloperPrivateOpenDevToolsFunction()1362 DeveloperPrivateOpenDevToolsFunction::DeveloperPrivateOpenDevToolsFunction() {}
~DeveloperPrivateOpenDevToolsFunction()1363 DeveloperPrivateOpenDevToolsFunction::~DeveloperPrivateOpenDevToolsFunction() {}
1364 
RunAsync()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