[email protected] | 6014d67 | 2008-12-05 00:38:25 | [diff] [blame^] | 1 | // Copyright (c) 2006-2008 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/extensions_service.h" |
| 6 | |
| 7 | #include "base/file_util.h" |
| 8 | #include "base/values.h" |
| 9 | #include "base/string_util.h" |
| 10 | #include "base/thread.h" |
| 11 | #include "chrome/browser/browser_process.h" |
| 12 | #include "chrome/common/json_value_serializer.h" |
| 13 | |
| 14 | // ExtensionsService |
| 15 | |
| 16 | const FilePath::CharType* ExtensionsService::kInstallDirectoryName = |
| 17 | FILE_PATH_LITERAL("Extensions"); |
| 18 | |
| 19 | ExtensionsService::ExtensionsService(const FilePath& profile_directory) |
| 20 | : message_loop_(MessageLoop::current()), |
| 21 | backend_(new ExtensionsServiceBackend), |
| 22 | install_directory_(profile_directory.Append(kInstallDirectoryName)) { |
| 23 | } |
| 24 | |
| 25 | ExtensionsService::~ExtensionsService() { |
| 26 | for (ExtensionList::iterator iter = extensions_.begin(); |
| 27 | iter != extensions_.end(); ++iter) { |
| 28 | delete *iter; |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | bool ExtensionsService::Init() { |
| 33 | // TODO(aa): This message loop should probably come from a backend |
| 34 | // interface, similar to how the message loop for the frontend comes |
| 35 | // from the frontend interface. |
| 36 | g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
| 37 | NewRunnableMethod(backend_.get(), |
| 38 | &ExtensionsServiceBackend::LoadExtensionsFromDirectory, |
| 39 | install_directory_, |
| 40 | scoped_refptr<ExtensionsServiceFrontendInterface>(this))); |
| 41 | // TODO(aa): Load extensions from other registered directories. |
| 42 | |
| 43 | return true; |
| 44 | } |
| 45 | |
| 46 | MessageLoop* ExtensionsService::GetMessageLoop() { |
| 47 | return message_loop_; |
| 48 | } |
| 49 | |
| 50 | void ExtensionsService::OnExtensionsLoadedFromDirectory( |
| 51 | ExtensionList* extensions) { |
| 52 | extensions_.assign(extensions->begin(), extensions->end()); |
| 53 | delete extensions; |
| 54 | |
| 55 | // TODO(aa): Notify extensions are loaded. |
| 56 | } |
| 57 | |
| 58 | void ExtensionsService::OnExtensionLoadError(const std::wstring& error) { |
| 59 | // TODO(aa): Print the error message out somewhere better. Ideally we would |
| 60 | // use the JavaScript console I think, but that is complicated since these |
| 61 | // errors are not related to any particular page. |
| 62 | LOG(WARNING) << "Error loading extension: " << error; |
| 63 | } |
| 64 | |
| 65 | |
| 66 | // ExtensionsServicesBackend |
| 67 | |
| 68 | bool ExtensionsServiceBackend::LoadExtensionsFromDirectory( |
| 69 | const FilePath& path, |
| 70 | scoped_refptr<ExtensionsServiceFrontendInterface> frontend) { |
| 71 | // Find all child directories in the install directory and load their |
| 72 | // manifests. Post errors and results to the frontend. |
| 73 | scoped_ptr<ExtensionList> extensions(new ExtensionList); |
| 74 | file_util::FileEnumerator enumerator(path.ToWStringHack(), |
| 75 | false, // not recursive |
| 76 | file_util::FileEnumerator::DIRECTORIES); |
| 77 | for (std::wstring child_path = enumerator.Next(); !child_path.empty(); |
| 78 | child_path = enumerator.Next()) { |
| 79 | FilePath manifest_path = FilePath::FromWStringHack(child_path).Append( |
| 80 | Extension::kManifestFilename); |
| 81 | if (!file_util::PathExists(manifest_path)) { |
| 82 | ReportExtensionLoadError(frontend.get(), |
| 83 | Extension::kInvalidManifestError); |
| 84 | continue; |
| 85 | } |
| 86 | |
| 87 | JSONFileValueSerializer serializer(manifest_path.ToWStringHack()); |
| 88 | Value* root = NULL; |
| 89 | if (!serializer.Deserialize(&root)) { |
| 90 | ReportExtensionLoadError(frontend.get(), |
| 91 | Extension::kInvalidManifestError); |
| 92 | continue; |
| 93 | } |
| 94 | |
| 95 | if (!root->IsType(Value::TYPE_DICTIONARY)) { |
| 96 | ReportExtensionLoadError(frontend.get(), |
| 97 | Extension::kInvalidManifestError); |
| 98 | continue; |
| 99 | } |
| 100 | |
| 101 | scoped_ptr<Extension> extension(new Extension()); |
| 102 | std::wstring error; |
| 103 | if (!extension->InitFromValue(*static_cast<DictionaryValue*>(root), |
| 104 | &error)) { |
| 105 | ReportExtensionLoadError(frontend.get(), |
| 106 | Extension::kInvalidManifestError); |
| 107 | continue; |
| 108 | } |
| 109 | |
| 110 | extensions->push_back(extension.release()); |
| 111 | } |
| 112 | |
| 113 | ReportExtensionsLoaded(frontend.get(), extensions.release()); |
| 114 | return true; |
| 115 | } |
| 116 | |
| 117 | void ExtensionsServiceBackend::ReportExtensionLoadError( |
| 118 | ExtensionsServiceFrontendInterface *frontend, const std::wstring &error) { |
| 119 | frontend->GetMessageLoop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 120 | frontend, &ExtensionsServiceFrontendInterface::OnExtensionLoadError, |
| 121 | error)); |
| 122 | } |
| 123 | |
| 124 | void ExtensionsServiceBackend::ReportExtensionsLoaded( |
| 125 | ExtensionsServiceFrontendInterface *frontend, ExtensionList* extensions) { |
| 126 | frontend->GetMessageLoop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 127 | frontend, |
| 128 | &ExtensionsServiceFrontendInterface::OnExtensionsLoadedFromDirectory, |
| 129 | extensions)); |
| 130 | } |