- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / pending_extension_manager.cc
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/pending_extension_manager.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/version.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "url/gurl.h"
14
15 using content::BrowserThread;
16
17 namespace {
18
19 // Install predicate used by AddFromExternalUpdateUrl().
20 bool AlwaysInstall(const extensions::Extension* extension) {
21   return true;
22 }
23
24 std::string GetVersionString(const Version& version) {
25   return version.IsValid() ? version.GetString() : "invalid";
26 }
27
28 }  // namespace
29
30 namespace extensions {
31
32 PendingExtensionManager::PendingExtensionManager(
33     const ExtensionServiceInterface& service)
34     : service_(service) {
35 }
36
37 PendingExtensionManager::~PendingExtensionManager() {}
38
39 const PendingExtensionInfo* PendingExtensionManager::GetById(
40     const std::string& id) const {
41   PendingExtensionList::const_iterator iter;
42   for (iter = pending_extension_list_.begin();
43        iter != pending_extension_list_.end();
44        ++iter) {
45     if (id == iter->id())
46       return &(*iter);
47   }
48
49   return NULL;
50 }
51
52 bool PendingExtensionManager::Remove(const std::string& id) {
53   PendingExtensionList::iterator iter;
54   for (iter = pending_extension_list_.begin();
55        iter != pending_extension_list_.end();
56        ++iter) {
57     if (id == iter->id()) {
58       pending_extension_list_.erase(iter);
59       return true;
60     }
61   }
62
63   return false;
64 }
65
66 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
67   PendingExtensionList::const_iterator iter;
68   for (iter = pending_extension_list_.begin();
69        iter != pending_extension_list_.end();
70        ++iter) {
71     if (id == iter->id())
72       return true;
73   }
74
75   return false;
76 }
77
78 bool PendingExtensionManager::HasPendingExtensions() const {
79   return !pending_extension_list_.empty();
80 }
81
82 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
83   PendingExtensionList::const_iterator iter;
84   for (iter = pending_extension_list_.begin();
85        iter != pending_extension_list_.end();
86        ++iter) {
87     if (iter->is_from_sync())
88       return true;
89   }
90
91   return false;
92 }
93
94 bool PendingExtensionManager::AddFromSync(
95     const std::string& id,
96     const GURL& update_url,
97     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
98     bool install_silently) {
99   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
100
101   if (service_.GetInstalledExtension(id)) {
102     LOG(ERROR) << "Trying to add pending extension " << id
103                << " which already exists";
104     return false;
105   }
106
107   // Make sure we don't ever try to install the CWS app, because even though
108   // it is listed as a syncable app (because its values need to be synced) it
109   // should already be installed on every instance.
110   if (id == extension_misc::kWebStoreAppId) {
111     NOTREACHED();
112     return false;
113   }
114
115   const bool kIsFromSync = true;
116   const Manifest::Location kSyncLocation = Manifest::INTERNAL;
117   const bool kMarkAcknowledged = false;
118
119   return AddExtensionImpl(id, update_url, Version(), should_allow_install,
120                           kIsFromSync, install_silently, kSyncLocation,
121                           Extension::NO_FLAGS, kMarkAcknowledged);
122 }
123
124 bool PendingExtensionManager::AddFromExtensionImport(
125     const std::string& id,
126     const GURL& update_url,
127     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
128   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
129
130   if (service_.GetInstalledExtension(id)) {
131     LOG(ERROR) << "Trying to add pending extension " << id
132                << " which already exists";
133     return false;
134   }
135
136   const bool kIsFromSync = false;
137   const bool kInstallSilently = true;
138   const Manifest::Location kManifestLocation = Manifest::INTERNAL;
139   const bool kMarkAcknowledged = false;
140
141   return AddExtensionImpl(id, update_url, Version(), should_allow_install,
142                           kIsFromSync, kInstallSilently, kManifestLocation,
143                           Extension::NO_FLAGS, kMarkAcknowledged);
144 }
145
146 bool PendingExtensionManager::AddFromExternalUpdateUrl(
147     const std::string& id,
148     const GURL& update_url,
149     Manifest::Location location,
150     int creation_flags,
151     bool mark_acknowledged) {
152   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153
154   const bool kIsFromSync = false;
155   const bool kInstallSilently = true;
156
157   const Extension* extension = service_.GetInstalledExtension(id);
158   if (extension &&
159       location == Manifest::GetHigherPriorityLocation(location,
160                                                        extension->location())) {
161     // If the new location has higher priority than the location of an existing
162     // extension, let the update process overwrite the existing extension.
163   } else {
164     if (service_.IsExternalExtensionUninstalled(id))
165       return false;
166
167     if (extension) {
168       LOG(DFATAL) << "Trying to add extension " << id
169                   << " by external update, but it is already installed.";
170       return false;
171     }
172   }
173
174   return AddExtensionImpl(id, update_url, Version(), &AlwaysInstall,
175                           kIsFromSync, kInstallSilently,
176                           location, creation_flags, mark_acknowledged);
177 }
178
179
180 bool PendingExtensionManager::AddFromExternalFile(
181     const std::string& id,
182     Manifest::Location install_source,
183     const Version& version,
184     int creation_flags,
185     bool mark_acknowledged) {
186   // TODO(skerner): AddFromSync() checks to see if the extension is
187   // installed, but this method assumes that the caller already
188   // made sure it is not installed.  Make all AddFrom*() methods
189   // consistent.
190   GURL kUpdateUrl = GURL();
191   bool kIsFromSync = false;
192   bool kInstallSilently = true;
193
194   return AddExtensionImpl(
195       id,
196       kUpdateUrl,
197       version,
198       &AlwaysInstall,
199       kIsFromSync,
200       kInstallSilently,
201       install_source,
202       creation_flags,
203       mark_acknowledged);
204 }
205
206 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
207     std::list<std::string>* out_ids_for_update_check) const {
208   PendingExtensionList::const_iterator iter;
209   for (iter = pending_extension_list_.begin();
210        iter != pending_extension_list_.end();
211        ++iter) {
212     Manifest::Location install_source = iter->install_source();
213
214     // Some install sources read a CRX from the filesystem.  They can
215     // not be fetched from an update URL, so don't include them in the
216     // set of ids.
217     if (install_source == Manifest::EXTERNAL_PREF ||
218         install_source == Manifest::EXTERNAL_REGISTRY)
219       continue;
220
221     out_ids_for_update_check->push_back(iter->id());
222   }
223 }
224
225 bool PendingExtensionManager::AddExtensionImpl(
226     const std::string& id,
227     const GURL& update_url,
228     const Version& version,
229     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
230     bool is_from_sync,
231     bool install_silently,
232     Manifest::Location install_source,
233     int creation_flags,
234     bool mark_acknowledged) {
235   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236
237   PendingExtensionInfo info(id,
238                             update_url,
239                             version,
240                             should_allow_install,
241                             is_from_sync,
242                             install_silently,
243                             install_source,
244                             creation_flags,
245                             mark_acknowledged);
246
247   if (const PendingExtensionInfo* pending = GetById(id)) {
248     // Bugs in this code will manifest as sporadic incorrect extension
249     // locations in situations where multiple install sources run at the
250     // same time. For example, on first login to a chrome os machine, an
251     // extension may be requested by sync and the default extension set.
252     // The following logging will help diagnose such issues.
253     VLOG(1) << "Extension id " << id
254             << " was entered for update more than once."
255             << "  old location: " << pending->install_source()
256             << "  new location: " << install_source
257             << "  old version: " << GetVersionString(pending->version())
258             << "  new version: " << GetVersionString(version);
259
260     // Never override an existing extension with an older version. Only
261     // extensions from local CRX files have a known version; extensions from an
262     // update URL will get the latest version.
263
264     // If |pending| has the same or higher precedence than |info| then don't
265     // install |info| over |pending|.
266     if (pending->CompareTo(info) >= 0)
267       return false;
268
269     VLOG(1) << "Overwrite existing record.";
270
271     std::replace(pending_extension_list_.begin(),
272                  pending_extension_list_.end(),
273                  *pending,
274                  info);
275   } else {
276     pending_extension_list_.push_back(info);
277   }
278
279   return true;
280 }
281
282 void PendingExtensionManager::AddForTesting(
283     const PendingExtensionInfo& pending_extension_info) {
284   pending_extension_list_.push_back(pending_extension_info);
285 }
286
287 }  // namespace extensions