swiftshader_component_installer.cc revision 010d83a9304c5a91596085d917d248abff47903a
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/swiftshader_component_installer.h" 6 7#include <string> 8#include <vector> 9 10#include "base/base_paths.h" 11#include "base/bind.h" 12#include "base/compiler_specific.h" 13#include "base/cpu.h" 14#include "base/file_util.h" 15#include "base/files/file_enumerator.h" 16#include "base/files/file_path.h" 17#include "base/logging.h" 18#include "base/path_service.h" 19#include "base/strings/string_util.h" 20#include "base/values.h" 21#include "chrome/browser/component_updater/component_updater_service.h" 22#include "chrome/common/chrome_paths.h" 23#include "content/public/browser/browser_thread.h" 24#include "content/public/browser/gpu_data_manager.h" 25#include "content/public/browser/gpu_data_manager_observer.h" 26#include "gpu/config/gpu_feature_type.h" 27 28using content::BrowserThread; 29using content::GpuDataManager; 30 31namespace component_updater { 32 33namespace { 34 35// CRX hash. The extension id is: nhfgdggnnopgbfdlpeoalgcjdgfafocg. 36const uint8 kSha2Hash[] = {0xd7, 0x56, 0x36, 0x6d, 0xde, 0xf6, 0x15, 0x3b, 37 0xf4, 0xe0, 0xb6, 0x29, 0x36, 0x50, 0x5e, 0x26, 38 0xbd, 0x77, 0x8b, 0x8e, 0x35, 0xc2, 0x7e, 0x43, 39 0x52, 0x47, 0x62, 0xed, 0x12, 0xca, 0xcc, 0x6a}; 40 41// File name of the internal SwiftShader plugin on different platforms. 42const base::FilePath::CharType kSwiftShaderEglName[] = 43 FILE_PATH_LITERAL("libegl.dll"); 44const base::FilePath::CharType kSwiftShaderGlesName[] = 45 FILE_PATH_LITERAL("libglesv2.dll"); 46 47const char kSwiftShaderManifestName[] = "SwiftShader"; 48 49const base::FilePath::CharType kSwiftShaderBaseDirectory[] = 50 FILE_PATH_LITERAL("SwiftShader"); 51 52// If we don't have a SwiftShader component, this is the version we claim. 53const char kNullVersion[] = "0.0.0.0"; 54 55// The base directory on windows looks like: 56// <profile>\AppData\Local\Google\Chrome\User Data\SwiftShader\. 57base::FilePath GetSwiftShaderBaseDirectory() { 58 base::FilePath result; 59 PathService::Get(chrome::DIR_USER_DATA, &result); 60 return result.Append(kSwiftShaderBaseDirectory); 61} 62 63// SwiftShader has version encoded in the path itself 64// so we need to enumerate the directories to find the full path. 65// On success it returns something like: 66// <profile>\AppData\Local\Google\Chrome\User Data\SwiftShader\10.3.44.555\. 67bool GetLatestSwiftShaderDirectory(base::FilePath* result, 68 Version* latest, 69 std::vector<base::FilePath>* older_dirs) { 70 base::FilePath base_dir = GetSwiftShaderBaseDirectory(); 71 bool found = false; 72 base::FileEnumerator file_enumerator( 73 base_dir, false, base::FileEnumerator::DIRECTORIES); 74 for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); 75 path = file_enumerator.Next()) { 76 Version version(path.BaseName().MaybeAsASCII()); 77 if (!version.IsValid()) 78 continue; 79 if (version.CompareTo(*latest) > 0 && 80 base::PathExists(path.Append(kSwiftShaderEglName)) && 81 base::PathExists(path.Append(kSwiftShaderGlesName))) { 82 if (found && older_dirs) 83 older_dirs->push_back(*result); 84 *latest = version; 85 *result = path; 86 found = true; 87 } else { 88 if (older_dirs) 89 older_dirs->push_back(path); 90 } 91 } 92 return found; 93} 94 95void RegisterSwiftShaderWithChrome(const base::FilePath& path) { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 GpuDataManager::GetInstance()->RegisterSwiftShaderPath(path); 98} 99 100class SwiftShaderComponentInstaller : public ComponentInstaller { 101 public: 102 explicit SwiftShaderComponentInstaller(const Version& version); 103 104 virtual ~SwiftShaderComponentInstaller() {} 105 106 virtual void OnUpdateError(int error) OVERRIDE; 107 108 virtual bool Install(const base::DictionaryValue& manifest, 109 const base::FilePath& unpack_path) OVERRIDE; 110 111 virtual bool GetInstalledFile(const std::string& file, 112 base::FilePath* installed_file) OVERRIDE; 113 114 private: 115 Version current_version_; 116}; 117 118SwiftShaderComponentInstaller::SwiftShaderComponentInstaller( 119 const Version& version) 120 : current_version_(version) { 121 DCHECK(version.IsValid()); 122} 123 124void SwiftShaderComponentInstaller::OnUpdateError(int error) { 125 NOTREACHED() << "SwiftShader update error: " << error; 126} 127 128bool SwiftShaderComponentInstaller::Install( 129 const base::DictionaryValue& manifest, 130 const base::FilePath& unpack_path) { 131 std::string name; 132 manifest.GetStringASCII("name", &name); 133 if (name != kSwiftShaderManifestName) 134 return false; 135 std::string proposed_version; 136 manifest.GetStringASCII("version", &proposed_version); 137 Version version(proposed_version.c_str()); 138 if (!version.IsValid()) 139 return false; 140 if (current_version_.CompareTo(version) >= 0) 141 return false; 142 if (!base::PathExists(unpack_path.Append(kSwiftShaderEglName)) || 143 !base::PathExists(unpack_path.Append(kSwiftShaderGlesName))) 144 return false; 145 // Passed the basic tests. Time to install it. 146 base::FilePath path = 147 GetSwiftShaderBaseDirectory().AppendASCII(version.GetString()); 148 if (base::PathExists(path)) 149 return false; 150 if (!base::Move(unpack_path, path)) 151 return false; 152 // Installation is done. Now tell the rest of chrome. 153 current_version_ = version; 154 BrowserThread::PostTask(BrowserThread::UI, 155 FROM_HERE, 156 base::Bind(&RegisterSwiftShaderWithChrome, path)); 157 return true; 158} 159 160bool SwiftShaderComponentInstaller::GetInstalledFile( 161 const std::string& file, 162 base::FilePath* installed_file) { 163 return false; 164} 165 166void FinishSwiftShaderUpdateRegistration(ComponentUpdateService* cus, 167 const Version& version) { 168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 169 170 CrxComponent swiftshader; 171 swiftshader.name = "Swift Shader"; 172 swiftshader.installer = new SwiftShaderComponentInstaller(version); 173 swiftshader.version = version; 174 swiftshader.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]); 175 if (cus->RegisterComponent(swiftshader) != ComponentUpdateService::kOk) { 176 NOTREACHED() << "SwiftShader component registration fail"; 177 } 178} 179 180class UpdateChecker : public content::GpuDataManagerObserver { 181 public: 182 explicit UpdateChecker(ComponentUpdateService* cus); 183 184 virtual void OnGpuInfoUpdate() OVERRIDE; 185 186 private: 187 ComponentUpdateService* cus_; 188}; 189 190UpdateChecker::UpdateChecker(ComponentUpdateService* cus) : cus_(cus) { 191} 192 193void UpdateChecker::OnGpuInfoUpdate() { 194 GpuDataManager* gpu_data_manager = GpuDataManager::GetInstance(); 195 196 if (!gpu_data_manager->GpuAccessAllowed(NULL) || 197 gpu_data_manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) || 198 gpu_data_manager->ShouldUseSwiftShader()) { 199 gpu_data_manager->RemoveObserver(this); 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 201 base::FilePath path = GetSwiftShaderBaseDirectory(); 202 203 Version version(kNullVersion); 204 GetLatestSwiftShaderDirectory(&path, &version, NULL); 205 206 BrowserThread::PostTask( 207 BrowserThread::UI, 208 FROM_HERE, 209 base::Bind(&FinishSwiftShaderUpdateRegistration, cus_, version)); 210 } 211} 212 213#if defined(ENABLE_SWIFTSHADER) 214 215// Check if there already is a version of swiftshader installed, 216// and if so register it. 217void RegisterSwiftShaderPath(ComponentUpdateService* cus) { 218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 219 base::FilePath path = GetSwiftShaderBaseDirectory(); 220 if (!base::PathExists(path)) { 221 if (!base::CreateDirectory(path)) { 222 NOTREACHED() << "Could not create SwiftShader directory."; 223 return; 224 } 225 } 226 227 Version version(kNullVersion); 228 std::vector<base::FilePath> older_dirs; 229 if (GetLatestSwiftShaderDirectory(&path, &version, &older_dirs)) 230 BrowserThread::PostTask(BrowserThread::UI, 231 FROM_HERE, 232 base::Bind(&RegisterSwiftShaderWithChrome, path)); 233 234 UpdateChecker* update_checker = new UpdateChecker(cus); 235 GpuDataManager::GetInstance()->AddObserver(update_checker); 236 update_checker->OnGpuInfoUpdate(); 237 // We leak update_checker here, because it has to stick around for the life 238 // of the GpuDataManager. 239 240 // Remove older versions of SwiftShader. 241 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin(); 242 iter != older_dirs.end(); 243 ++iter) { 244 base::DeleteFile(*iter, true); 245 } 246} 247 248#endif // ENABLE_SWIFTSHADER 249 250} // namespace 251 252void RegisterSwiftShaderComponent(ComponentUpdateService* cus) { 253#if defined(ENABLE_SWIFTSHADER) 254 base::CPU cpu; 255 256 if (!cpu.has_sse2()) 257 return; 258 BrowserThread::PostTask(BrowserThread::FILE, 259 FROM_HERE, 260 base::Bind(&RegisterSwiftShaderPath, cus)); 261#endif 262} 263 264} // namespace component_updater 265