1 // Copyright 2013 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.
5 #include "chrome/browser/extensions/extension_util.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/values.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_sync_service.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
16 #include "chrome/common/extensions/sync_helper.h"
17 #include "content/public/browser/site_instance.h"
18 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_icon_set.h"
23 #include "extensions/common/manifest.h"
24 #include "extensions/common/manifest_handlers/incognito_info.h"
25 #include "grit/theme_resources.h"
26 #include "ui/base/resource/resource_bundle.h"
28 namespace extensions {
31 bool IsIncognitoEnabled(const std::string& extension_id,
32 content::BrowserContext* context) {
33 const Extension* extension = ExtensionRegistry::Get(context)->
34 GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
36 if (!extension->can_be_incognito_enabled())
38 // If this is an existing component extension we always allow it to
39 // work in incognito mode.
40 if (extension->location() == Manifest::COMPONENT)
44 return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
47 void SetIsIncognitoEnabled(const std::string& extension_id,
48 content::BrowserContext* context,
50 ExtensionService* service =
51 ExtensionSystem::Get(context)->extension_service();
53 const Extension* extension = service->GetInstalledExtension(extension_id);
56 if (!extension->can_be_incognito_enabled())
59 if (extension->location() == Manifest::COMPONENT) {
60 // This shouldn't be called for component extensions unless it is called
61 // by sync, for syncable component extensions.
62 // See http://crbug.com/112290 and associated CLs for the sordid history.
63 DCHECK(sync_helper::IsSyncable(extension));
65 // If we are here, make sure the we aren't trying to change the value.
66 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, service->profile()));
71 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(service->profile());
72 // Broadcast unloaded and loaded events to update browser state. Only bother
73 // if the value changed and the extension is actually enabled, since there is
75 bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
76 if (enabled == old_enabled)
79 extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
81 bool extension_is_enabled = service->extensions()->Contains(extension_id);
83 // When we reload the extension the ID may be invalidated if we've passed it
84 // by const ref everywhere. Make a copy to be safe.
85 std::string id = extension_id;
86 if (extension_is_enabled)
87 service->ReloadExtension(id);
89 // Reloading the extension invalidates the |extension| pointer.
90 extension = service->GetInstalledExtension(id);
92 ExtensionSyncService::Get(service->profile())->
93 SyncExtensionChangeIfNeeded(*extension);
97 bool CanCrossIncognito(const Extension* extension,
98 content::BrowserContext* context) {
99 // We allow the extension to see events and data from another profile iff it
100 // uses "spanning" behavior and it has incognito access. "split" mode
101 // extensions only see events for a matching profile.
103 return IsIncognitoEnabled(extension->id(), context) &&
104 !IncognitoInfo::IsSplitMode(extension);
107 bool CanLoadInIncognito(const Extension* extension,
108 content::BrowserContext* context) {
110 if (extension->is_hosted_app())
112 // Packaged apps and regular extensions need to be enabled specifically for
113 // incognito (and split mode should be set).
114 return IncognitoInfo::IsSplitMode(extension) &&
115 IsIncognitoEnabled(extension->id(), context);
118 bool AllowFileAccess(const std::string& extension_id,
119 content::BrowserContext* context) {
120 return CommandLine::ForCurrentProcess()->HasSwitch(
121 switches::kDisableExtensionsFileAccessCheck) ||
122 ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
125 void SetAllowFileAccess(const std::string& extension_id,
126 content::BrowserContext* context,
128 ExtensionService* service =
129 ExtensionSystem::Get(context)->extension_service();
132 // Reload to update browser state. Only bother if the value changed and the
133 // extension is actually enabled, since there is no UI otherwise.
134 if (allow == AllowFileAccess(extension_id, context))
137 ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
139 bool extension_is_enabled = service->extensions()->Contains(extension_id);
140 if (extension_is_enabled)
141 service->ReloadExtension(extension_id);
144 bool IsAppLaunchable(const std::string& extension_id,
145 content::BrowserContext* context) {
146 return !(ExtensionPrefs::Get(context)->GetDisableReasons(extension_id) &
147 Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
150 bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
151 content::BrowserContext* context) {
152 return ExtensionRegistry::Get(context)->GetExtensionById(
153 extension_id, ExtensionRegistry::ENABLED) != NULL;
156 bool IsExtensionIdle(const std::string& extension_id,
157 content::BrowserContext* context) {
158 ProcessManager* process_manager =
159 ExtensionSystem::Get(context)->process_manager();
160 DCHECK(process_manager);
161 ExtensionHost* host =
162 process_manager->GetBackgroundHostForExtension(extension_id);
166 content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL(
167 Extension::GetBaseURLFromExtensionId(extension_id));
168 if (site_instance && site_instance->HasProcess())
171 return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
174 bool IsExtensionInstalledPermanently(const std::string& extension_id,
175 content::BrowserContext* context) {
176 const Extension* extension = ExtensionRegistry::Get(context)->
177 GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
178 return extension && !extension->is_ephemeral();
181 GURL GetSiteForExtensionId(const std::string& extension_id,
182 content::BrowserContext* context) {
183 return content::SiteInstance::GetSiteForURL(
184 context, Extension::GetBaseURLFromExtensionId(extension_id));
187 scoped_ptr<base::DictionaryValue> GetExtensionInfo(const Extension* extension) {
189 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
191 dict->SetString("id", extension->id());
192 dict->SetString("name", extension->name());
194 GURL icon = extensions::ExtensionIconSource::GetIconURL(
196 extension_misc::EXTENSION_ICON_SMALLISH,
197 ExtensionIconSet::MATCH_BIGGER,
198 false, // Not grayscale.
199 NULL); // Don't set bool if exists.
200 dict->SetString("icon", icon.spec());
205 bool HasIsolatedStorage(const ExtensionInfo& info) {
206 if (!info.extension_manifest.get())
210 scoped_refptr<const Extension> extension(Extension::Create(
212 info.extension_location,
213 *info.extension_manifest,
217 if (!extension.get())
220 return AppIsolationInfo::HasIsolatedStorage(extension.get());
223 bool SiteHasIsolatedStorage(const GURL& extension_site_url,
224 content::BrowserContext* context) {
225 const Extension* extension = ExtensionRegistry::Get(context)->
226 enabled_extensions().GetExtensionOrAppByURL(extension_site_url);
228 return AppIsolationInfo::HasIsolatedStorage(extension);
230 if (extension_site_url.SchemeIs(kExtensionScheme)) {
231 // The site URL may also be from an evicted ephemeral app. We do not
232 // immediately delete their data when they are removed from extension
234 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
236 scoped_ptr<ExtensionInfo> info = prefs->GetEvictedEphemeralAppInfo(
237 extension_site_url.host());
239 return HasIsolatedStorage(*info);
245 const gfx::ImageSkia& GetDefaultAppIcon() {
246 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
247 IDR_APP_DEFAULT_ICON);
250 const gfx::ImageSkia& GetDefaultExtensionIcon() {
251 return *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
252 IDR_EXTENSION_DEFAULT_ICON);
256 } // namespace extensions