| OLD | NEW |
| (Empty) |
| 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/component_updater/flash_component_installer.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/base_paths.h" | |
| 10 #include "base/bind.h" | |
| 11 #include "base/compiler_specific.h" | |
| 12 #include "base/file_path.h" | |
| 13 #include "base/file_util.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/path_service.h" | |
| 16 #include "base/string_util.h" | |
| 17 #include "base/values.h" | |
| 18 #include "chrome/browser/component_updater/component_updater_service.h" | |
| 19 #include "chrome/browser/plugins/plugin_prefs.h" | |
| 20 #include "chrome/common/chrome_paths.h" | |
| 21 #include "content/public/browser/browser_thread.h" | |
| 22 #include "content/public/browser/plugin_service.h" | |
| 23 #include "webkit/plugins/webplugininfo.h" | |
| 24 | |
| 25 using content::BrowserThread; | |
| 26 using content::PluginService; | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 // CRX hash. The extension id is: immdilkhigodmjbnngapbehchmihabbg. | |
| 31 const uint8 sha2_hash[] = {0x8c, 0xc3, 0x8b, 0xa7, 0x86, 0xe3, 0xc9, 0x1d, | |
| 32 0xd6, 0x0f, 0x14, 0x72, 0x7c, 0x87, 0x01, 0x16, | |
| 33 0xe2, 0x00, 0x6c, 0x98, 0xbc, 0xfb, 0x14, 0x1b, | |
| 34 0x5c, 0xcd, 0xff, 0x3d, 0xa3, 0x2e, 0x2c, 0x49}; | |
| 35 | |
| 36 // File name of the internal Flash plugin on different platforms. | |
| 37 const FilePath::CharType kFlashPluginFileName[] = | |
| 38 #if defined(OS_MACOSX) | |
| 39 FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin"); | |
| 40 #elif defined(OS_WIN) | |
| 41 FILE_PATH_LITERAL("gcswf32.dll"); | |
| 42 #else // OS_LINUX, etc. | |
| 43 FILE_PATH_LITERAL("libgcflashplayer.so"); | |
| 44 #endif | |
| 45 | |
| 46 const char kNPAPIFlashManifestName[] = "NPAPIFlash"; | |
| 47 | |
| 48 // The NPAPI flash plugins are in a directory with this name. | |
| 49 const FilePath::CharType kNPAPIFlashBaseDirectory[] = | |
| 50 FILE_PATH_LITERAL("NPAPIFlash"); | |
| 51 | |
| 52 // The base directory on windows looks like: | |
| 53 // <profile>\AppData\Local\Google\Chrome\User Data\NPAPIFlash\. | |
| 54 FilePath GetNPAPIFlashBaseDirectory() { | |
| 55 FilePath result; | |
| 56 PathService::Get(chrome::DIR_USER_DATA, &result); | |
| 57 return result.Append(kNPAPIFlashBaseDirectory); | |
| 58 } | |
| 59 | |
| 60 std::string NormalizeVersion(const string16& version) { | |
| 61 std::string ascii_ver = UTF16ToASCII(version); | |
| 62 std::replace(ascii_ver.begin(), ascii_ver.end(), ',', '.'); | |
| 63 return ascii_ver; | |
| 64 } | |
| 65 | |
| 66 } // namespace | |
| 67 | |
| 68 class NPAPIFlashComponentInstaller : public ComponentInstaller { | |
| 69 public: | |
| 70 explicit NPAPIFlashComponentInstaller(const Version& version); | |
| 71 | |
| 72 virtual ~NPAPIFlashComponentInstaller() {} | |
| 73 | |
| 74 virtual void OnUpdateError(int error) OVERRIDE; | |
| 75 | |
| 76 virtual bool Install(base::DictionaryValue* manifest, | |
| 77 const FilePath& unpack_path) OVERRIDE; | |
| 78 | |
| 79 private: | |
| 80 Version current_version_; | |
| 81 }; | |
| 82 | |
| 83 NPAPIFlashComponentInstaller::NPAPIFlashComponentInstaller( | |
| 84 const Version& version) : current_version_(version) { | |
| 85 DCHECK(version.IsValid()); | |
| 86 } | |
| 87 | |
| 88 void NPAPIFlashComponentInstaller::OnUpdateError(int error) { | |
| 89 NOTREACHED() << "NPAPI flash update error: " << error; | |
| 90 } | |
| 91 | |
| 92 bool NPAPIFlashComponentInstaller::Install(base::DictionaryValue* manifest, | |
| 93 const FilePath& unpack_path) { | |
| 94 std::string name; | |
| 95 manifest->GetStringASCII("name", &name); | |
| 96 if (name != kNPAPIFlashManifestName) | |
| 97 return false; | |
| 98 std::string proposed_version; | |
| 99 manifest->GetStringASCII("version", &proposed_version); | |
| 100 Version version(proposed_version.c_str()); | |
| 101 if (!version.IsValid()) | |
| 102 return false; | |
| 103 if (current_version_.CompareTo(version) >= 0) | |
| 104 return false; | |
| 105 if (!file_util::PathExists(unpack_path.Append(kFlashPluginFileName))) | |
| 106 return false; | |
| 107 // Passed the basic tests. Time to install it. | |
| 108 if (!file_util::Move(unpack_path, GetNPAPIFlashBaseDirectory())) | |
| 109 return false; | |
| 110 // Installation is done. Now tell the rest of chrome. | |
| 111 current_version_ = version; | |
| 112 PluginService::GetInstance()->RefreshPlugins(); | |
| 113 return true; | |
| 114 } | |
| 115 | |
| 116 void FinishFlashUpdateRegistration(ComponentUpdateService* cus, | |
| 117 const webkit::WebPluginInfo& info) { | |
| 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 119 | |
| 120 // todo(cpu): Add PluginPrefs code here to determine if what we update | |
| 121 // is actually going to be used. | |
| 122 | |
| 123 Version version(NormalizeVersion(info.version)); | |
| 124 if (!version.IsValid()) { | |
| 125 NOTREACHED(); | |
| 126 return; | |
| 127 } | |
| 128 | |
| 129 CrxComponent flash; | |
| 130 flash.name = "npapi_flash"; | |
| 131 flash.installer = new NPAPIFlashComponentInstaller(version); | |
| 132 flash.version = version; | |
| 133 flash.pk_hash.assign(sha2_hash, &sha2_hash[sizeof(sha2_hash)]); | |
| 134 if (cus->RegisterComponent(flash) != ComponentUpdateService::kOk) { | |
| 135 NOTREACHED() << "Flash component registration fail"; | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 // The code in this function is only concerned about learning what flash plugin | |
| 140 // chrome is using and what is its version. This will determine if we register | |
| 141 // for component update or not. Read the comments on RegisterNPAPIFlashComponent | |
| 142 // for more background. | |
| 143 void StartFlashUpdateRegistration(ComponentUpdateService* cus, | |
| 144 const std::vector<webkit::WebPluginInfo>&) { | |
| 145 FilePath builtin_plugin_path; | |
| 146 if (!PathService::Get(chrome::FILE_FLASH_PLUGIN_EXISTING, | |
| 147 &builtin_plugin_path)) | |
| 148 return; | |
| 149 | |
| 150 FilePath updated_plugin_path = | |
| 151 GetNPAPIFlashBaseDirectory().Append(kFlashPluginFileName); | |
| 152 | |
| 153 PluginService* plugins = PluginService::GetInstance(); | |
| 154 webkit::WebPluginInfo plugin_info; | |
| 155 | |
| 156 if (plugins->GetPluginInfoByPath(updated_plugin_path, &plugin_info)) { | |
| 157 // The updated plugin is newer. Since flash is used by pretty much every | |
| 158 // webpage out there, odds are it is going to be loaded, which means | |
| 159 // receiving an update is pointless since we can't swap them. You might | |
| 160 // find this pessimistic. The way we get out of this situation is when | |
| 161 // we update the whole product. | |
| 162 DLOG(INFO) << "updated plugin overriding built-in flash"; | |
| 163 return; | |
| 164 } else if (plugins->GetPluginInfoByPath(builtin_plugin_path, &plugin_info)) { | |
| 165 // The built plugin is newer. Delete the updated plugin and register for | |
| 166 // updates. This should be the normal case. | |
| 167 file_util::Delete(GetNPAPIFlashBaseDirectory(), true); | |
| 168 } else { | |
| 169 // Strange installation. Log and abort registration. | |
| 170 DLOG(WARNING) << "Strange flash npapi configuration"; | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 175 base::Bind(&FinishFlashUpdateRegistration, cus, plugin_info)); | |
| 176 } | |
| 177 | |
| 178 // Here is the general plan of action: we are going to update flash and we have | |
| 179 // the following cases: | |
| 180 // 1- The active flash is not the built-in flash (user override). | |
| 181 // 2- The active flash is the built-in flash. | |
| 182 // 3- The active flash is the one from the component updater. | |
| 183 // In case 1 we do nothing. In cases 2 and 3 we need to compare versions | |
| 184 // and if the higher version is: | |
| 185 // case 2: remove the component update flash, register with component updater. | |
| 186 // case 3: register with component updater. | |
| 187 // | |
| 188 // In practice, it's complicated. First off, to learn the version of the plugin | |
| 189 // we have to do file IO, which PluginList will do for us but we have to be | |
| 190 // careful not to trigger this on the UI thread: AddExtraPluginPath and | |
| 191 // RefreshPlugins don't trigger file IO, but most of the others calls do. | |
| 192 // | |
| 193 // Secondly, we can do this in a delayed task. Right now we just need to | |
| 194 // register the right plugin before chrome loads the first flash-ladden page. | |
| 195 // | |
| 196 // Interestingly, if PluginList finds two plugins with the same filename and | |
| 197 // same mimetypes, it will only keep the one with the higher version. This is | |
| 198 // our case in the sense that a component updated flash is very much the same | |
| 199 // thing as built-in flash: sometimes newer or sometimes older. That is why | |
| 200 // you don't see version comparison in this code. | |
| 201 // | |
| 202 // So to kick off the magic we add the updated flash path here, even though | |
| 203 // there might not be a flash player in that location. If there is and it is | |
| 204 // newer, it will take its place then we fire StartFlashUpdateRegistration | |
| 205 // on the IO thread to learn which one won. Since we do it in a delayed task | |
| 206 // probably somebody (unknowingly) will pay for the file IO, so usually get | |
| 207 // the information for free. | |
| 208 void RegisterNPAPIFlashComponent(ComponentUpdateService* cus) { | |
| 209 #if !defined(OS_CHROMEOS) | |
| 210 FilePath path = GetNPAPIFlashBaseDirectory().Append(kFlashPluginFileName); | |
| 211 PluginService::GetInstance()->AddExtraPluginPath(path); | |
| 212 PluginService::GetInstance()->RefreshPlugins(); | |
| 213 | |
| 214 // Post the task to the FILE thread because IO may be done once the plugins | |
| 215 // are loaded. | |
| 216 BrowserThread::PostDelayedTask( | |
| 217 BrowserThread::FILE, | |
| 218 FROM_HERE, | |
| 219 base::Bind(&PluginService::GetPlugins, | |
| 220 base::Unretained(PluginService::GetInstance()), | |
| 221 base::Bind(&StartFlashUpdateRegistration, cus)), | |
| 222 base::TimeDelta::FromSeconds(8)); | |
| 223 #endif | |
| 224 } | |
| OLD | NEW |