| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/process_singleton.h" | 5 #include "chrome/browser/process_singleton.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <signal.h> | 8 #include <signal.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 #include <sys/un.h> | 10 #include <sys/un.h> |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 ASSERT_GT(len, 0); | 153 ASSERT_GT(len, 0); |
| 154 std::string cookie(buf, len); | 154 std::string cookie(buf, len); |
| 155 | 155 |
| 156 base::FilePath remote_cookie_path = socket_target_path.DirName(). | 156 base::FilePath remote_cookie_path = socket_target_path.DirName(). |
| 157 Append(chrome::kSingletonCookieFilename); | 157 Append(chrome::kSingletonCookieFilename); |
| 158 len = readlink(remote_cookie_path.value().c_str(), buf, PATH_MAX); | 158 len = readlink(remote_cookie_path.value().c_str(), buf, PATH_MAX); |
| 159 ASSERT_GT(len, 0); | 159 ASSERT_GT(len, 0); |
| 160 EXPECT_EQ(cookie, std::string(buf, len)); | 160 EXPECT_EQ(cookie, std::string(buf, len)); |
| 161 } | 161 } |
| 162 | 162 |
| 163 ProcessSingleton::NotifyResult NotifyOtherProcess( | 163 ProcessSingleton::NotifyResult NotifyOtherProcess(bool override_kill) { |
| 164 bool override_kill, | |
| 165 base::TimeDelta timeout) { | |
| 166 scoped_ptr<TestableProcessSingleton> process_singleton( | 164 scoped_ptr<TestableProcessSingleton> process_singleton( |
| 167 CreateProcessSingleton()); | 165 CreateProcessSingleton()); |
| 168 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); | 166 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); |
| 169 command_line.AppendArg("about:blank"); | 167 command_line.AppendArg("about:blank"); |
| 170 if (override_kill) { | 168 if (override_kill) { |
| 171 process_singleton->OverrideCurrentPidForTesting( | 169 process_singleton->OverrideCurrentPidForTesting( |
| 172 base::GetCurrentProcId() + 1); | 170 base::GetCurrentProcId() + 1); |
| 173 process_singleton->OverrideKillCallbackForTesting( | 171 process_singleton->OverrideKillCallbackForTesting( |
| 174 base::Bind(&ProcessSingletonPosixTest::KillCallback, | 172 base::Bind(&ProcessSingletonPosixTest::KillCallback, |
| 175 base::Unretained(this))); | 173 base::Unretained(this))); |
| 176 } | 174 } |
| 177 | 175 |
| 178 return process_singleton->NotifyOtherProcessWithTimeout( | 176 return process_singleton->NotifyOtherProcessWithTimeout( |
| 179 command_line, timeout.InSeconds(), true); | 177 command_line, kRetryAttempts, timeout(), true); |
| 180 } | 178 } |
| 181 | 179 |
| 182 // A helper method to call ProcessSingleton::NotifyOtherProcessOrCreate(). | 180 // A helper method to call ProcessSingleton::NotifyOtherProcessOrCreate(). |
| 183 ProcessSingleton::NotifyResult NotifyOtherProcessOrCreate( | 181 ProcessSingleton::NotifyResult NotifyOtherProcessOrCreate( |
| 184 const std::string& url, | 182 const std::string& url) { |
| 185 base::TimeDelta timeout) { | |
| 186 scoped_ptr<TestableProcessSingleton> process_singleton( | 183 scoped_ptr<TestableProcessSingleton> process_singleton( |
| 187 CreateProcessSingleton()); | 184 CreateProcessSingleton()); |
| 188 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); | 185 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); |
| 189 command_line.AppendArg(url); | 186 command_line.AppendArg(url); |
| 190 return process_singleton->NotifyOtherProcessWithTimeoutOrCreate( | 187 return process_singleton->NotifyOtherProcessWithTimeoutOrCreate( |
| 191 command_line, timeout.InSeconds()); | 188 command_line, kRetryAttempts, timeout()); |
| 192 } | 189 } |
| 193 | 190 |
| 194 void CheckNotified() { | 191 void CheckNotified() { |
| 195 ASSERT_TRUE(process_singleton_on_thread_ != NULL); | 192 ASSERT_TRUE(process_singleton_on_thread_ != NULL); |
| 196 ASSERT_EQ(1u, process_singleton_on_thread_->callback_command_lines_.size()); | 193 ASSERT_EQ(1u, process_singleton_on_thread_->callback_command_lines_.size()); |
| 197 bool found = false; | 194 bool found = false; |
| 198 for (size_t i = 0; | 195 for (size_t i = 0; |
| 199 i < process_singleton_on_thread_->callback_command_lines_[0].size(); | 196 i < process_singleton_on_thread_->callback_command_lines_[0].size(); |
| 200 ++i) { | 197 ++i) { |
| 201 if (process_singleton_on_thread_->callback_command_lines_[0][i] == | 198 if (process_singleton_on_thread_->callback_command_lines_[0][i] == |
| (...skipping 23 matching lines...) Expand all Loading... |
| 225 signal_event_.Signal(); | 222 signal_event_.Signal(); |
| 226 } | 223 } |
| 227 | 224 |
| 228 base::FilePath user_data_path_; | 225 base::FilePath user_data_path_; |
| 229 base::FilePath lock_path_; | 226 base::FilePath lock_path_; |
| 230 base::FilePath socket_path_; | 227 base::FilePath socket_path_; |
| 231 base::FilePath cookie_path_; | 228 base::FilePath cookie_path_; |
| 232 int kill_callbacks_; | 229 int kill_callbacks_; |
| 233 | 230 |
| 234 private: | 231 private: |
| 232 static const int kRetryAttempts = 2; |
| 233 |
| 234 base::TimeDelta timeout() const { |
| 235 return TestTimeouts::tiny_timeout() * kRetryAttempts; |
| 236 } |
| 237 |
| 235 void CreateProcessSingletonInternal() { | 238 void CreateProcessSingletonInternal() { |
| 236 ASSERT_TRUE(!process_singleton_on_thread_); | 239 ASSERT_TRUE(!process_singleton_on_thread_); |
| 237 process_singleton_on_thread_ = CreateProcessSingleton(); | 240 process_singleton_on_thread_ = CreateProcessSingleton(); |
| 238 ASSERT_EQ(ProcessSingleton::PROCESS_NONE, | 241 ASSERT_EQ(ProcessSingleton::PROCESS_NONE, |
| 239 process_singleton_on_thread_->NotifyOtherProcessOrCreate()); | 242 process_singleton_on_thread_->NotifyOtherProcessOrCreate()); |
| 240 } | 243 } |
| 241 | 244 |
| 242 void DestructProcessSingleton() { | 245 void DestructProcessSingleton() { |
| 243 ASSERT_TRUE(process_singleton_on_thread_); | 246 ASSERT_TRUE(process_singleton_on_thread_); |
| 244 delete process_singleton_on_thread_; | 247 delete process_singleton_on_thread_; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 264 // If this test flakes, use http://crbug.com/74554. | 267 // If this test flakes, use http://crbug.com/74554. |
| 265 TEST_F(ProcessSingletonPosixTest, CheckSocketFile) { | 268 TEST_F(ProcessSingletonPosixTest, CheckSocketFile) { |
| 266 CreateProcessSingletonOnThread(); | 269 CreateProcessSingletonOnThread(); |
| 267 VerifyFiles(); | 270 VerifyFiles(); |
| 268 } | 271 } |
| 269 | 272 |
| 270 // TODO(james.su@gmail.com): port following tests to Windows. | 273 // TODO(james.su@gmail.com): port following tests to Windows. |
| 271 // Test success case of NotifyOtherProcess(). | 274 // Test success case of NotifyOtherProcess(). |
| 272 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessSuccess) { | 275 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessSuccess) { |
| 273 CreateProcessSingletonOnThread(); | 276 CreateProcessSingletonOnThread(); |
| 274 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, | 277 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, NotifyOtherProcess(true)); |
| 275 NotifyOtherProcess(true, TestTimeouts::action_timeout())); | |
| 276 CheckNotified(); | 278 CheckNotified(); |
| 277 } | 279 } |
| 278 | 280 |
| 279 // Test failure case of NotifyOtherProcess(). | 281 // Test failure case of NotifyOtherProcess(). |
| 280 // Disabled, http://crbug.com/407065 . | 282 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessFailure) { |
| 281 TEST_F(ProcessSingletonPosixTest, DISABLED_NotifyOtherProcessFailure) { | |
| 282 CreateProcessSingletonOnThread(); | 283 CreateProcessSingletonOnThread(); |
| 283 | 284 |
| 284 BlockWorkerThread(); | 285 BlockWorkerThread(); |
| 285 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, | 286 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, NotifyOtherProcess(true)); |
| 286 NotifyOtherProcess(true, TestTimeouts::action_timeout())); | |
| 287 | |
| 288 ASSERT_EQ(1, kill_callbacks_); | 287 ASSERT_EQ(1, kill_callbacks_); |
| 289 UnblockWorkerThread(); | 288 UnblockWorkerThread(); |
| 290 } | 289 } |
| 291 | 290 |
| 292 // Test that we don't kill ourselves by accident if a lockfile with the same pid | 291 // Test that we don't kill ourselves by accident if a lockfile with the same pid |
| 293 // happens to exist. | 292 // happens to exist. |
| 294 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessNoSuicide) { | 293 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessNoSuicide) { |
| 295 CreateProcessSingletonOnThread(); | 294 CreateProcessSingletonOnThread(); |
| 296 // Replace lockfile with one containing our own pid. | 295 // Replace lockfile with one containing our own pid. |
| 297 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 296 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
| 298 std::string symlink_content = base::StringPrintf( | 297 std::string symlink_content = base::StringPrintf( |
| 299 "%s%c%u", | 298 "%s%c%u", |
| 300 net::GetHostName().c_str(), | 299 net::GetHostName().c_str(), |
| 301 '-', | 300 '-', |
| 302 base::GetCurrentProcId()); | 301 base::GetCurrentProcId()); |
| 303 EXPECT_EQ(0, symlink(symlink_content.c_str(), lock_path_.value().c_str())); | 302 EXPECT_EQ(0, symlink(symlink_content.c_str(), lock_path_.value().c_str())); |
| 304 | 303 |
| 305 // Remove socket so that we will not be able to notify the existing browser. | 304 // Remove socket so that we will not be able to notify the existing browser. |
| 306 EXPECT_EQ(0, unlink(socket_path_.value().c_str())); | 305 EXPECT_EQ(0, unlink(socket_path_.value().c_str())); |
| 307 | 306 |
| 308 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, | 307 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, NotifyOtherProcess(false)); |
| 309 NotifyOtherProcess(false, TestTimeouts::action_timeout())); | |
| 310 // If we've gotten to this point without killing ourself, the test succeeded. | 308 // If we've gotten to this point without killing ourself, the test succeeded. |
| 311 } | 309 } |
| 312 | 310 |
| 313 // Test that we can still notify a process on the same host even after the | 311 // Test that we can still notify a process on the same host even after the |
| 314 // hostname changed. | 312 // hostname changed. |
| 315 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessHostChanged) { | 313 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessHostChanged) { |
| 316 CreateProcessSingletonOnThread(); | 314 CreateProcessSingletonOnThread(); |
| 317 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 315 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
| 318 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 316 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
| 319 | 317 |
| 320 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, | 318 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, NotifyOtherProcess(false)); |
| 321 NotifyOtherProcess(false, TestTimeouts::action_timeout())); | |
| 322 CheckNotified(); | 319 CheckNotified(); |
| 323 } | 320 } |
| 324 | 321 |
| 325 // Test that we fail when lock says process is on another host and we can't | 322 // Test that we fail when lock says process is on another host and we can't |
| 326 // notify it over the socket. | 323 // notify it over the socket. |
| 327 // Disabled, http://crbug.com/407065 . | 324 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessDifferingHost) { |
| 328 TEST_F(ProcessSingletonPosixTest, DISABLED_NotifyOtherProcessDifferingHost) { | |
| 329 CreateProcessSingletonOnThread(); | 325 CreateProcessSingletonOnThread(); |
| 330 | 326 |
| 331 BlockWorkerThread(); | 327 BlockWorkerThread(); |
| 332 | 328 |
| 333 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 329 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
| 334 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 330 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
| 335 | 331 |
| 336 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, | 332 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcess(false)); |
| 337 NotifyOtherProcess(false, TestTimeouts::action_timeout())); | |
| 338 | 333 |
| 339 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); | 334 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); |
| 340 | 335 |
| 341 UnblockWorkerThread(); | 336 UnblockWorkerThread(); |
| 342 } | 337 } |
| 343 | 338 |
| 344 // Test that we fail when lock says process is on another host and we can't | 339 // Test that we fail when lock says process is on another host and we can't |
| 345 // notify it over the socket. | 340 // notify it over the socket. |
| 346 // Disabled, http://crbug.com/407065 . | 341 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessOrCreate_DifferingHost) { |
| 347 TEST_F(ProcessSingletonPosixTest, | |
| 348 DISABLED_NotifyOtherProcessOrCreate_DifferingHost) { | |
| 349 CreateProcessSingletonOnThread(); | 342 CreateProcessSingletonOnThread(); |
| 350 | 343 |
| 351 BlockWorkerThread(); | 344 BlockWorkerThread(); |
| 352 | 345 |
| 353 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 346 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
| 354 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 347 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
| 355 | 348 |
| 356 std::string url("about:blank"); | 349 std::string url("about:blank"); |
| 357 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, | 350 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcessOrCreate(url)); |
| 358 NotifyOtherProcessOrCreate(url, TestTimeouts::action_timeout())); | |
| 359 | 351 |
| 360 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); | 352 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); |
| 361 | 353 |
| 362 UnblockWorkerThread(); | 354 UnblockWorkerThread(); |
| 363 } | 355 } |
| 364 | 356 |
| 365 // Test that Create fails when another browser is using the profile directory. | 357 // Test that Create fails when another browser is using the profile directory. |
| 366 TEST_F(ProcessSingletonPosixTest, CreateFailsWithExistingBrowser) { | 358 TEST_F(ProcessSingletonPosixTest, CreateFailsWithExistingBrowser) { |
| 367 CreateProcessSingletonOnThread(); | 359 CreateProcessSingletonOnThread(); |
| 368 | 360 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 399 CreateProcessSingletonOnThread(); | 391 CreateProcessSingletonOnThread(); |
| 400 // Change the cookie. | 392 // Change the cookie. |
| 401 EXPECT_EQ(0, unlink(cookie_path_.value().c_str())); | 393 EXPECT_EQ(0, unlink(cookie_path_.value().c_str())); |
| 402 EXPECT_EQ(0, symlink("INCORRECTCOOKIE", cookie_path_.value().c_str())); | 394 EXPECT_EQ(0, symlink("INCORRECTCOOKIE", cookie_path_.value().c_str())); |
| 403 | 395 |
| 404 // Also change the hostname, so the remote does not retry. | 396 // Also change the hostname, so the remote does not retry. |
| 405 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 397 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
| 406 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 398 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
| 407 | 399 |
| 408 std::string url("about:blank"); | 400 std::string url("about:blank"); |
| 409 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, | 401 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcessOrCreate(url)); |
| 410 NotifyOtherProcessOrCreate(url, TestTimeouts::action_timeout())); | |
| 411 } | 402 } |
| 412 | 403 |
| 413 #if defined(OS_MACOSX) | 404 #if defined(OS_MACOSX) |
| 414 // Test that if there is an existing lock file, and we could not flock() | 405 // Test that if there is an existing lock file, and we could not flock() |
| 415 // it, then exit. | 406 // it, then exit. |
| 416 TEST_F(ProcessSingletonPosixTest, CreateRespectsOldMacLock) { | 407 TEST_F(ProcessSingletonPosixTest, CreateRespectsOldMacLock) { |
| 417 scoped_ptr<TestableProcessSingleton> process_singleton( | 408 scoped_ptr<TestableProcessSingleton> process_singleton( |
| 418 CreateProcessSingleton()); | 409 CreateProcessSingleton()); |
| 419 base::ScopedFD lock_fd(HANDLE_EINTR( | 410 base::ScopedFD lock_fd(HANDLE_EINTR( |
| 420 open(lock_path_.value().c_str(), O_RDWR | O_CREAT | O_EXLOCK, 0644))); | 411 open(lock_path_.value().c_str(), O_RDWR | O_CREAT | O_EXLOCK, 0644))); |
| 421 ASSERT_TRUE(lock_fd.is_valid()); | 412 ASSERT_TRUE(lock_fd.is_valid()); |
| 422 EXPECT_FALSE(process_singleton->Create()); | 413 EXPECT_FALSE(process_singleton->Create()); |
| 423 base::File::Info info; | 414 base::File::Info info; |
| 424 EXPECT_TRUE(base::GetFileInfo(lock_path_, &info)); | 415 EXPECT_TRUE(base::GetFileInfo(lock_path_, &info)); |
| 425 EXPECT_FALSE(info.is_directory); | 416 EXPECT_FALSE(info.is_directory); |
| 426 EXPECT_FALSE(info.is_symbolic_link); | 417 EXPECT_FALSE(info.is_symbolic_link); |
| 427 } | 418 } |
| 428 | 419 |
| 429 // Test that if there is an existing lock file, and it's not locked, we replace | 420 // Test that if there is an existing lock file, and it's not locked, we replace |
| 430 // it. | 421 // it. |
| 431 TEST_F(ProcessSingletonPosixTest, CreateReplacesOldMacLock) { | 422 TEST_F(ProcessSingletonPosixTest, CreateReplacesOldMacLock) { |
| 432 scoped_ptr<TestableProcessSingleton> process_singleton( | 423 scoped_ptr<TestableProcessSingleton> process_singleton( |
| 433 CreateProcessSingleton()); | 424 CreateProcessSingleton()); |
| 434 EXPECT_EQ(0, base::WriteFile(lock_path_, "", 0)); | 425 EXPECT_EQ(0, base::WriteFile(lock_path_, "", 0)); |
| 435 EXPECT_TRUE(process_singleton->Create()); | 426 EXPECT_TRUE(process_singleton->Create()); |
| 436 VerifyFiles(); | 427 VerifyFiles(); |
| 437 } | 428 } |
| 438 #endif // defined(OS_MACOSX) | 429 #endif // defined(OS_MACOSX) |
| OLD | NEW |