extension_util.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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.
4
5#include "chrome/browser/extensions/extension_util.h"
6
7#include "base/command_line.h"
8#include "chrome/browser/extensions/extension_service.h"
9#include "chrome/browser/extensions/extension_sync_service.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/common/chrome_switches.h"
12#include "chrome/common/extensions/sync_helper.h"
13#include "content/public/browser/site_instance.h"
14#include "extensions/browser/extension_prefs.h"
15#include "extensions/browser/extension_registry.h"
16#include "extensions/browser/extension_system.h"
17#include "extensions/common/extension.h"
18#include "extensions/common/manifest.h"
19#include "extensions/common/manifest_handlers/incognito_info.h"
20
21namespace extensions {
22namespace util {
23
24bool IsIncognitoEnabled(const std::string& extension_id,
25                        content::BrowserContext* context) {
26  const Extension* extension = ExtensionRegistry::Get(context)->
27      GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
28  if (extension) {
29    if (!extension->can_be_incognito_enabled())
30      return false;
31    // If this is an existing component extension we always allow it to
32    // work in incognito mode.
33    if (extension->location() == Manifest::COMPONENT)
34      return true;
35  }
36
37  return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id);
38}
39
40void SetIsIncognitoEnabled(const std::string& extension_id,
41                           content::BrowserContext* context,
42                           bool enabled) {
43  ExtensionService* service =
44      ExtensionSystem::Get(context)->extension_service();
45  CHECK(service);
46  const Extension* extension = service->GetInstalledExtension(extension_id);
47
48  if (extension) {
49    if (!extension->can_be_incognito_enabled())
50      return;
51
52    if (extension->location() == Manifest::COMPONENT) {
53      // This shouldn't be called for component extensions unless it is called
54      // by sync, for syncable component extensions.
55      // See http://crbug.com/112290 and associated CLs for the sordid history.
56      DCHECK(sync_helper::IsSyncable(extension));
57
58      // If we are here, make sure the we aren't trying to change the value.
59      DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id, service->profile()));
60      return;
61    }
62  }
63
64  ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(service->profile());
65  // Broadcast unloaded and loaded events to update browser state. Only bother
66  // if the value changed and the extension is actually enabled, since there is
67  // no UI otherwise.
68  bool old_enabled = extension_prefs->IsIncognitoEnabled(extension_id);
69  if (enabled == old_enabled)
70    return;
71
72  extension_prefs->SetIsIncognitoEnabled(extension_id, enabled);
73
74  bool extension_is_enabled = service->extensions()->Contains(extension_id);
75
76  // When we reload the extension the ID may be invalidated if we've passed it
77  // by const ref everywhere. Make a copy to be safe.
78  std::string id = extension_id;
79  if (extension_is_enabled)
80    service->ReloadExtension(id);
81
82  // Reloading the extension invalidates the |extension| pointer.
83  extension = service->GetInstalledExtension(id);
84  if (extension) {
85    ExtensionSyncService::Get(service->profile())->
86        SyncExtensionChangeIfNeeded(*extension);
87  }
88}
89
90bool CanCrossIncognito(const Extension* extension,
91                       content::BrowserContext* context) {
92  // We allow the extension to see events and data from another profile iff it
93  // uses "spanning" behavior and it has incognito access. "split" mode
94  // extensions only see events for a matching profile.
95  CHECK(extension);
96  return IsIncognitoEnabled(extension->id(), context) &&
97         !IncognitoInfo::IsSplitMode(extension);
98}
99
100bool CanLoadInIncognito(const Extension* extension,
101                        content::BrowserContext* context) {
102  CHECK(extension);
103  if (extension->is_hosted_app())
104    return true;
105  // Packaged apps and regular extensions need to be enabled specifically for
106  // incognito (and split mode should be set).
107  return IncognitoInfo::IsSplitMode(extension) &&
108         IsIncognitoEnabled(extension->id(), context);
109}
110
111bool AllowFileAccess(const std::string& extension_id,
112                     content::BrowserContext* context) {
113  return CommandLine::ForCurrentProcess()->HasSwitch(
114             switches::kDisableExtensionsFileAccessCheck) ||
115         ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
116}
117
118void SetAllowFileAccess(const std::string& extension_id,
119                        content::BrowserContext* context,
120                        bool allow) {
121  ExtensionService* service =
122      ExtensionSystem::Get(context)->extension_service();
123  CHECK(service);
124
125  // Reload to update browser state. Only bother if the value changed and the
126  // extension is actually enabled, since there is no UI otherwise.
127  if (allow == AllowFileAccess(extension_id, context))
128    return;
129
130  ExtensionPrefs::Get(context)->SetAllowFileAccess(extension_id, allow);
131
132  bool extension_is_enabled = service->extensions()->Contains(extension_id);
133  if (extension_is_enabled)
134    service->ReloadExtension(extension_id);
135}
136
137bool IsAppLaunchable(const std::string& extension_id,
138                     content::BrowserContext* context) {
139  return !(ExtensionPrefs::Get(context)->GetDisableReasons(extension_id) &
140           Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
141}
142
143bool IsAppLaunchableWithoutEnabling(const std::string& extension_id,
144                                    content::BrowserContext* context) {
145  return ExtensionRegistry::Get(context)->GetExtensionById(
146      extension_id, ExtensionRegistry::ENABLED) != NULL;
147}
148
149bool IsExtensionIdle(const std::string& extension_id,
150                     content::BrowserContext* context) {
151  ProcessManager* process_manager =
152      ExtensionSystem::Get(context)->process_manager();
153  DCHECK(process_manager);
154  ExtensionHost* host =
155      process_manager->GetBackgroundHostForExtension(extension_id);
156  if (host)
157    return false;
158
159  content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL(
160      Extension::GetBaseURLFromExtensionId(extension_id));
161  if (site_instance && site_instance->HasProcess())
162    return false;
163
164  return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
165}
166
167bool IsExtensionInstalledPermanently(const std::string& extension_id,
168                                     content::BrowserContext* context) {
169  const Extension* extension = ExtensionRegistry::Get(context)->
170      GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
171  return extension && !extension->is_ephemeral();
172}
173
174GURL GetSiteForExtensionId(const std::string& extension_id,
175                           content::BrowserContext* context) {
176  return content::SiteInstance::GetSiteForURL(
177      context, Extension::GetBaseURLFromExtensionId(extension_id));
178}
179
180}  // namespace util
181}  // namespace extensions
182