Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: gin/v8_initializer.cc

Issue 1127183004: Add retry logic to V8Initializer snapshot loading files for suspected A/V problem. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporate review comments on patch set 1. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/app/content_main_runner.cc ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "gin/v8_initializer.h" 5 #include "gin/v8_initializer.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/files/file.h" 8 #include "base/files/file.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/files/memory_mapped_file.h" 10 #include "base/files/memory_mapped_file.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
12 #include "base/rand_util.h" 13 #include "base/rand_util.h"
13 #include "base/strings/sys_string_conversions.h" 14 #include "base/strings/sys_string_conversions.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/time/time.h"
14 #include "crypto/sha2.h" 17 #include "crypto/sha2.h"
15 18
16 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) 19 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
17 #if defined(OS_MACOSX) 20 #if defined(OS_MACOSX)
18 #include "base/mac/foundation_util.h" 21 #include "base/mac/foundation_util.h"
19 #endif // OS_MACOSX 22 #endif // OS_MACOSX
20 #include "base/path_service.h" 23 #include "base/path_service.h"
21 #endif // V8_USE_EXTERNAL_STARTUP_DATA 24 #endif // V8_USE_EXTERNAL_STARTUP_DATA
22 25
23 namespace gin { 26 namespace gin {
(...skipping 11 matching lines...) Expand all
35 #elif defined(OS_POSIX) 38 #elif defined(OS_POSIX)
36 base::DIR_EXE; 39 base::DIR_EXE;
37 #elif defined(OS_WIN) 40 #elif defined(OS_WIN)
38 base::DIR_MODULE; 41 base::DIR_MODULE;
39 #endif // OS_ANDROID 42 #endif // OS_ANDROID
40 #endif // !OS_MACOSX 43 #endif // !OS_MACOSX
41 44
42 const char kNativesFileName[] = "natives_blob.bin"; 45 const char kNativesFileName[] = "natives_blob.bin";
43 const char kSnapshotFileName[] = "snapshot_blob.bin"; 46 const char kSnapshotFileName[] = "snapshot_blob.bin";
44 47
48 // Constants for snapshot loading retries taken from:
49 // https://support.microsoft.com/en-us/kb/316609.
50 const int kMaxOpenAttempts = 5;
51 const int kOpenRetryDelayMillis = 250;
52
45 void GetV8FilePaths(base::FilePath* natives_path_out, 53 void GetV8FilePaths(base::FilePath* natives_path_out,
46 base::FilePath* snapshot_path_out) { 54 base::FilePath* snapshot_path_out) {
47 #if !defined(OS_MACOSX) 55 #if !defined(OS_MACOSX)
48 base::FilePath data_path; 56 base::FilePath data_path;
49 PathService::Get(kV8SnapshotBasePathKey, &data_path); 57 PathService::Get(kV8SnapshotBasePathKey, &data_path);
50 DCHECK(!data_path.empty()); 58 DCHECK(!data_path.empty());
51 59
52 *natives_path_out = data_path.AppendASCII(kNativesFileName); 60 *natives_path_out = data_path.AppendASCII(kNativesFileName);
53 *snapshot_path_out = data_path.AppendASCII(kSnapshotFileName); 61 *snapshot_path_out = data_path.AppendASCII(kSnapshotFileName);
54 #else // !defined(OS_MACOSX) 62 #else // !defined(OS_MACOSX)
55 base::ScopedCFTypeRef<CFStringRef> natives_file_name( 63 base::ScopedCFTypeRef<CFStringRef> natives_file_name(
56 base::SysUTF8ToCFStringRef(kNativesFileName)); 64 base::SysUTF8ToCFStringRef(kNativesFileName));
57 *natives_path_out = 65 *natives_path_out =
58 base::mac::PathForFrameworkBundleResource(natives_file_name); 66 base::mac::PathForFrameworkBundleResource(natives_file_name);
59 base::ScopedCFTypeRef<CFStringRef> snapshot_file_name( 67 base::ScopedCFTypeRef<CFStringRef> snapshot_file_name(
60 base::SysUTF8ToCFStringRef(kSnapshotFileName)); 68 base::SysUTF8ToCFStringRef(kSnapshotFileName));
61 *snapshot_path_out = 69 *snapshot_path_out =
62 base::mac::PathForFrameworkBundleResource(snapshot_file_name); 70 base::mac::PathForFrameworkBundleResource(snapshot_file_name);
63 DCHECK(!natives_path_out->empty()); 71 DCHECK(!natives_path_out->empty());
64 DCHECK(!snapshot_path_out->empty()); 72 DCHECK(!snapshot_path_out->empty());
65 #endif // !defined(OS_MACOSX) 73 #endif // !defined(OS_MACOSX)
66 } 74 }
67 75
68 bool MapV8Files(base::File natives_file, 76 static bool MapV8Files(base::File natives_file,
69 base::File snapshot_file, 77 base::File snapshot_file,
70 base::MemoryMappedFile::Region natives_region = 78 base::MemoryMappedFile::Region natives_region =
71 base::MemoryMappedFile::Region::kWholeFile, 79 base::MemoryMappedFile::Region::kWholeFile,
72 base::MemoryMappedFile::Region snapshot_region = 80 base::MemoryMappedFile::Region snapshot_region =
73 base::MemoryMappedFile::Region::kWholeFile) { 81 base::MemoryMappedFile::Region::kWholeFile) {
74 g_mapped_natives = new base::MemoryMappedFile; 82 g_mapped_natives = new base::MemoryMappedFile;
75 if (!g_mapped_natives->IsValid()) { 83 if (!g_mapped_natives->IsValid()) {
76 if (!g_mapped_natives->Initialize(natives_file.Pass(), natives_region)) { 84 if (!g_mapped_natives->Initialize(natives_file.Pass(), natives_region)) {
77 delete g_mapped_natives; 85 delete g_mapped_natives;
78 g_mapped_natives = NULL; 86 g_mapped_natives = NULL;
79 LOG(FATAL) << "Couldn't mmap v8 natives data file"; 87 LOG(FATAL) << "Couldn't mmap v8 natives data file";
80 return false; 88 return false;
81 } 89 }
82 } 90 }
83 91
84 g_mapped_snapshot = new base::MemoryMappedFile; 92 g_mapped_snapshot = new base::MemoryMappedFile;
85 if (!g_mapped_snapshot->IsValid()) { 93 if (!g_mapped_snapshot->IsValid()) {
86 if (!g_mapped_snapshot->Initialize(snapshot_file.Pass(), snapshot_region)) { 94 if (!g_mapped_snapshot->Initialize(snapshot_file.Pass(), snapshot_region)) {
87 delete g_mapped_snapshot; 95 delete g_mapped_snapshot;
88 g_mapped_snapshot = NULL; 96 g_mapped_snapshot = NULL;
89 LOG(ERROR) << "Couldn't mmap v8 snapshot data file"; 97 LOG(ERROR) << "Couldn't mmap v8 snapshot data file";
90 return false; 98 return false;
91 } 99 }
92 } 100 }
93 101
94 return true; 102 return true;
95 } 103 }
96 104
105 static bool OpenV8File(const base::FilePath& path,
106 int flags,
107 base::File& file) {
108 // Re-try logic here is motivated by http://crbug.com/479537
109 // for A/V on Windows (https://support.microsoft.com/en-us/kb/316609).
110
111 // These match tools/metrics/histograms.xml
112 enum OpenV8FileResult {
113 OPENED = 0,
114 OPENED_RETRY,
115 FAILED_IN_USE,
116 FAILED_OTHER,
117 MAX_VALUE
118 };
119
120 OpenV8FileResult result = OpenV8FileResult::FAILED_IN_USE;
121 for (int attempt = 0; attempt < kMaxOpenAttempts; attempt++) {
122 file.Initialize(path, flags);
123 if (file.IsValid()) {
124 if (attempt == 0) {
125 result = OpenV8FileResult::OPENED;
126 break;
127 } else {
128 result = OpenV8FileResult::OPENED_RETRY;
129 break;
130 }
131 } else if (file.error_details() != base::File::FILE_ERROR_IN_USE) {
132 result = OpenV8FileResult::FAILED_OTHER;
133 break;
134 } else if (kMaxOpenAttempts - 1 != attempt) {
135 base::PlatformThread::Sleep(
136 base::TimeDelta::FromMilliseconds(kOpenRetryDelayMillis));
137 }
138 }
139
140 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.OpenV8File.Result",
141 result,
142 OpenV8FileResult::MAX_VALUE);
143
144 return result == OpenV8FileResult::OPENED
145 || result == OpenV8FileResult::OPENED_RETRY;
146 }
147
97 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) 148 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
98 bool VerifyV8SnapshotFile(base::MemoryMappedFile* snapshot_file, 149 bool VerifyV8SnapshotFile(base::MemoryMappedFile* snapshot_file,
99 const unsigned char* fingerprint) { 150 const unsigned char* fingerprint) {
100 unsigned char output[crypto::kSHA256Length]; 151 unsigned char output[crypto::kSHA256Length];
101 crypto::SHA256HashString( 152 crypto::SHA256HashString(
102 base::StringPiece(reinterpret_cast<const char*>(snapshot_file->data()), 153 base::StringPiece(reinterpret_cast<const char*>(snapshot_file->data()),
103 snapshot_file->length()), 154 snapshot_file->length()),
104 output, sizeof(output)); 155 output, sizeof(output));
105 return !memcmp(fingerprint, output, sizeof(output)); 156 return !memcmp(fingerprint, output, sizeof(output));
106 } 157 }
107 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA 158 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA
108 #endif // V8_USE_EXTERNAL_STARTUP_DATA 159 #endif // V8_USE_EXTERNAL_STARTUP_DATA
109 160
110 bool GenerateEntropy(unsigned char* buffer, size_t amount) { 161 bool GenerateEntropy(unsigned char* buffer, size_t amount) {
111 base::RandBytes(buffer, amount); 162 base::RandBytes(buffer, amount);
112 return true; 163 return true;
113 } 164 }
114 165
115 } // namespace 166 } // namespace
116 167
117 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) 168 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
118 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) 169 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
119 // Defined in gen/gin/v8_snapshot_fingerprint.cc 170 // Defined in gen/gin/v8_snapshot_fingerprint.cc
120 extern const unsigned char g_natives_fingerprint[]; 171 extern const unsigned char g_natives_fingerprint[];
121 extern const unsigned char g_snapshot_fingerprint[]; 172 extern const unsigned char g_snapshot_fingerprint[];
122 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA 173 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA
123 174
124 // static 175 // static
125 bool V8Initializer::LoadV8Snapshot() { 176 bool V8Initializer::LoadV8Snapshot() {
177
178 enum LoadV8SnapshotResult {
179 SUCCESS = 0,
180 FAILED_OPEN,
181 FAILED_MAP,
182 FAILED_VERIFY,
183 MAX_VALUE
184 };
185
126 if (g_mapped_natives && g_mapped_snapshot) 186 if (g_mapped_natives && g_mapped_snapshot)
127 return true; 187 return true;
128 188
129 base::FilePath natives_data_path; 189 base::FilePath natives_data_path;
130 base::FilePath snapshot_data_path; 190 base::FilePath snapshot_data_path;
131 GetV8FilePaths(&natives_data_path, &snapshot_data_path); 191 GetV8FilePaths(&natives_data_path, &snapshot_data_path);
132 192
193 base::File natives_file;
194 base::File snapshot_file;
133 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; 195 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
134 if (!MapV8Files(base::File(natives_data_path, flags),
135 base::File(snapshot_data_path, flags)))
136 return false;
137 196
197 LoadV8SnapshotResult result;
198 if (!OpenV8File(natives_data_path, flags, natives_file) ||
199 !OpenV8File(snapshot_data_path, flags, snapshot_file)) {
200 result = LoadV8SnapshotResult::FAILED_OPEN;
201 } else if (!MapV8Files(natives_file.Pass(), snapshot_file.Pass())) {
202 result = LoadV8SnapshotResult::FAILED_MAP;
138 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) 203 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
139 // TODO(oth) Remove these temporary CHECKs once http://crbug.com/479537 is 204 } else if (!VerifyV8SnapshotFile(g_mapped_natives, g_natives_fingerprint) ||
140 // fixed. These are just here to identify whether canary failures are 205 !VerifyV8SnapshotFile(g_mapped_snapshot, g_snapshot_fingerprint)) {
141 // due to verification or file/vm failures. 206 result = LoadV8SnapshotResult::FAILED_VERIFY;
142 bool natives_ok =
143 VerifyV8SnapshotFile(g_mapped_natives, g_natives_fingerprint);
144 CHECK(natives_ok);
145 bool snapshot_ok =
146 VerifyV8SnapshotFile(g_mapped_snapshot, g_snapshot_fingerprint);
147 CHECK(snapshot_ok);
148 return natives_ok && snapshot_ok;
149 #else
150 return true;
151 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA 207 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA
208 } else {
209 result = LoadV8SnapshotResult::SUCCESS;
210 }
211
212 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result",
213 result,
214 LoadV8SnapshotResult::MAX_VALUE);
215 return result == LoadV8SnapshotResult::SUCCESS;
152 } 216 }
153 217
154 // static 218 // static
155 bool V8Initializer::LoadV8SnapshotFromFD(base::PlatformFile natives_pf, 219 bool V8Initializer::LoadV8SnapshotFromFD(base::PlatformFile natives_pf,
156 int64 natives_offset, 220 int64 natives_offset,
157 int64 natives_size, 221 int64 natives_size,
158 base::PlatformFile snapshot_pf, 222 base::PlatformFile snapshot_pf,
159 int64 snapshot_offset, 223 int64 snapshot_offset,
160 int64 snapshot_size) { 224 int64 snapshot_size) {
161 if (g_mapped_natives && g_mapped_snapshot) 225 if (g_mapped_natives && g_mapped_snapshot)
(...skipping 18 matching lines...) Expand all
180 } 244 }
181 245
182 // static 246 // static
183 bool V8Initializer::OpenV8FilesForChildProcesses( 247 bool V8Initializer::OpenV8FilesForChildProcesses(
184 base::PlatformFile* natives_fd_out, 248 base::PlatformFile* natives_fd_out,
185 base::PlatformFile* snapshot_fd_out) { 249 base::PlatformFile* snapshot_fd_out) {
186 base::FilePath natives_data_path; 250 base::FilePath natives_data_path;
187 base::FilePath snapshot_data_path; 251 base::FilePath snapshot_data_path;
188 GetV8FilePaths(&natives_data_path, &snapshot_data_path); 252 GetV8FilePaths(&natives_data_path, &snapshot_data_path);
189 253
254 base::File natives_data_file;
255 base::File snapshot_data_file;
190 int file_flags = base::File::FLAG_OPEN | base::File::FLAG_READ; 256 int file_flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
191 base::File natives_data_file(natives_data_path, file_flags);
192 base::File snapshot_data_file(snapshot_data_path, file_flags);
193 257
194 if (!natives_data_file.IsValid() || !snapshot_data_file.IsValid()) 258 bool success = OpenV8File(natives_data_path, file_flags, natives_data_file) &&
195 return false; 259 OpenV8File(snapshot_data_path, file_flags, snapshot_data_file);
196 260 if (success) {
197 *natives_fd_out = natives_data_file.TakePlatformFile(); 261 *natives_fd_out = natives_data_file.TakePlatformFile();
198 *snapshot_fd_out = snapshot_data_file.TakePlatformFile(); 262 *snapshot_fd_out = snapshot_data_file.TakePlatformFile();
199 return true; 263 }
264 return success;
200 } 265 }
201 266
202 #endif // V8_USE_EXTERNAL_STARTUP_DATA 267 #endif // V8_USE_EXTERNAL_STARTUP_DATA
203 268
204 // static 269 // static
205 void V8Initializer::Initialize(gin::IsolateHolder::ScriptMode mode) { 270 void V8Initializer::Initialize(gin::IsolateHolder::ScriptMode mode) {
206 static bool v8_is_initialized = false; 271 static bool v8_is_initialized = false;
207 if (v8_is_initialized) 272 if (v8_is_initialized)
208 return; 273 return;
209 274
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 *natives_size_out = *snapshot_size_out = 0; 307 *natives_size_out = *snapshot_size_out = 0;
243 return; 308 return;
244 } 309 }
245 *natives_data_out = reinterpret_cast<const char*>(g_mapped_natives->data()); 310 *natives_data_out = reinterpret_cast<const char*>(g_mapped_natives->data());
246 *snapshot_data_out = reinterpret_cast<const char*>(g_mapped_snapshot->data()); 311 *snapshot_data_out = reinterpret_cast<const char*>(g_mapped_snapshot->data());
247 *natives_size_out = static_cast<int>(g_mapped_natives->length()); 312 *natives_size_out = static_cast<int>(g_mapped_natives->length());
248 *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length()); 313 *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length());
249 } 314 }
250 315
251 } // namespace gin 316 } // namespace gin
OLDNEW
« no previous file with comments | « content/app/content_main_runner.cc ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698