1 // Copyright (c) 2011 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 "base/logging.h"
6 #include "base/stl_util-inl.h"
7 #include "chrome/browser/extensions/extension_service.h"
8 #include "chrome/browser/extensions/pending_extension_manager.h"
9 #include "chrome/common/extensions/extension.h"
10 #include "content/browser/browser_thread.h"
11
12 namespace {
13
14 // Install predicate used by AddFromDefaultAppList().
IsApp(const Extension & extension)15 bool IsApp(const Extension& extension) {
16 return extension.is_app();
17 }
18
19 // Install predicate used by AddFromExternalUpdateUrl().
AlwaysInstall(const Extension & extension)20 bool AlwaysInstall(const Extension& extension) {
21 return true;
22 }
23
24 } // namespace
25
PendingExtensionManager(const ExtensionServiceInterface & service)26 PendingExtensionManager::PendingExtensionManager(
27 const ExtensionServiceInterface& service)
28 : service_(service) {
29 }
30
~PendingExtensionManager()31 PendingExtensionManager::~PendingExtensionManager() {}
32
GetById(const std::string & id,PendingExtensionInfo * out_pending_extension_info) const33 bool PendingExtensionManager::GetById(
34 const std::string& id,
35 PendingExtensionInfo* out_pending_extension_info) const {
36
37 PendingExtensionMap::const_iterator it = pending_extension_map_.find(id);
38 if (it != pending_extension_map_.end()) {
39 *out_pending_extension_info = it->second;
40 return true;
41 }
42
43 return false;
44 }
45
Remove(const std::string & id)46 void PendingExtensionManager::Remove(const std::string& id) {
47 pending_extension_map_.erase(id);
48 }
49
IsIdPending(const std::string & id) const50 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
51 return ContainsKey(pending_extension_map_, id);
52 }
53
AddFromSync(const std::string & id,const GURL & update_url,PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,bool install_silently,bool enable_on_install,bool enable_incognito_on_install)54 bool PendingExtensionManager::AddFromSync(
55 const std::string& id,
56 const GURL& update_url,
57 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
58 bool install_silently,
59 bool enable_on_install,
60 bool enable_incognito_on_install) {
61 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
62
63 if (service_.GetExtensionById(id, true)) {
64 LOG(ERROR) << "Trying to add pending extension " << id
65 << " which already exists";
66 return false;
67 }
68
69 const bool kIsFromSync = true;
70 const Extension::Location kSyncLocation = Extension::INTERNAL;
71
72 return AddExtensionImpl(id, update_url, should_allow_install,
73 kIsFromSync, install_silently,
74 enable_on_install,
75 enable_incognito_on_install,
76 kSyncLocation);
77 }
78
AddFromExternalUpdateUrl(const std::string & id,const GURL & update_url,Extension::Location location)79 void PendingExtensionManager::AddFromExternalUpdateUrl(
80 const std::string& id, const GURL& update_url,
81 Extension::Location location) {
82 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83
84 const bool kIsFromSync = false;
85 const bool kInstallSilently = true;
86 const bool kEnableOnInstall = true;
87 const bool kEnableIncognitoOnInstall = false;
88
89 if (service_.IsExternalExtensionUninstalled(id))
90 return;
91
92 if (service_.GetExtensionById(id, true)) {
93 LOG(DFATAL) << "Trying to add extension " << id
94 << " by external update, but it is already installed.";
95 return;
96 }
97
98 AddExtensionImpl(id, update_url, &AlwaysInstall,
99 kIsFromSync, kInstallSilently,
100 kEnableOnInstall, kEnableIncognitoOnInstall,
101 location);
102 }
103
104
105 // TODO(akalin): Change DefaultAppList to DefaultExtensionList and
106 // remove the IsApp() check.
AddFromDefaultAppList(const std::string & id)107 void PendingExtensionManager::AddFromDefaultAppList(
108 const std::string& id) {
109 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110
111 const bool kIsFromSync = false;
112 const bool kInstallSilently = true;
113 const bool kEnableOnInstall = true;
114 const bool kEnableIncognitoOnInstall = true;
115
116 // This can legitimately happen if the user manually installed one of the
117 // default apps before this code ran.
118 if (service_.GetExtensionById(id, true))
119 return;
120
121 AddExtensionImpl(id, GURL(), &IsApp,
122 kIsFromSync, kInstallSilently,
123 kEnableOnInstall, kEnableIncognitoOnInstall,
124 Extension::INTERNAL);
125 }
126
AddFromExternalFile(const std::string & id,Extension::Location location)127 void PendingExtensionManager::AddFromExternalFile(
128 const std::string& id,
129 Extension::Location location) {
130
131 GURL kUpdateUrl = GURL();
132 bool kIsFromSync = false;
133 bool kInstallSilently = true;
134 bool kEnableOnInstall = true;
135 bool kEnableIncognitoOnInstall = false;
136
137 pending_extension_map_[id] =
138 PendingExtensionInfo(kUpdateUrl,
139 &AlwaysInstall,
140 kIsFromSync,
141 kInstallSilently,
142 kEnableOnInstall,
143 kEnableIncognitoOnInstall,
144 location);
145 }
146
AddExtensionImpl(const std::string & id,const GURL & update_url,PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,bool is_from_sync,bool install_silently,bool enable_on_install,bool enable_incognito_on_install,Extension::Location install_source)147 bool PendingExtensionManager::AddExtensionImpl(
148 const std::string& id, const GURL& update_url,
149 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
150 bool is_from_sync, bool install_silently,
151 bool enable_on_install, bool enable_incognito_on_install,
152 Extension::Location install_source) {
153 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
154
155 // Will add a pending extension record unless this variable is set to false.
156 bool should_add_pending_record = true;
157
158 if (ContainsKey(pending_extension_map_, id)) {
159 // Bugs in this code will manifest as sporadic incorrect extension
160 // locations in situations where multiple install sources run at the
161 // same time. For example, on first login to a chrome os machine, an
162 // extension may be requested by sync sync and the default extension set.
163 // The following logging will help diagnose such issues.
164 VLOG(1) << "Extension id " << id
165 << " was entered for update more than once."
166 << " old location: " << pending_extension_map_[id].install_source()
167 << " new location: " << install_source;
168
169 Extension::Location higher_priority_location =
170 Extension::GetHigherPriorityLocation(
171 install_source, pending_extension_map_[id].install_source());
172
173 if (higher_priority_location == install_source) {
174 VLOG(1) << "Overwrite existing record.";
175
176 } else {
177 VLOG(1) << "Keep existing record.";
178 should_add_pending_record = false;
179 }
180 }
181
182 if (should_add_pending_record) {
183 pending_extension_map_[id] = PendingExtensionInfo(
184 update_url,
185 should_allow_install,
186 is_from_sync,
187 install_silently,
188 enable_on_install,
189 enable_incognito_on_install,
190 install_source);
191 return true;
192 }
193 return false;
194 }
195
AddForTesting(const std::string & id,const PendingExtensionInfo & pending_extension_info)196 void PendingExtensionManager::AddForTesting(
197 const std::string& id,
198 const PendingExtensionInfo& pending_extension_info) {
199 pending_extension_map_[id] = pending_extension_info;
200 }
201