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