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