diff options
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/mac/mock_launchd.cc | 177 | ||||
-rw-r--r-- | chrome/common/mac/mock_launchd.h | 24 | ||||
-rw-r--r-- | chrome/common/service_process_util.h | 24 | ||||
-rw-r--r-- | chrome/common/service_process_util_linux.cc | 23 | ||||
-rw-r--r-- | chrome/common/service_process_util_mac.mm | 20 | ||||
-rw-r--r-- | chrome/common/service_process_util_posix.cc | 24 | ||||
-rw-r--r-- | chrome/common/service_process_util_unittest.cc | 3 |
7 files changed, 240 insertions, 55 deletions
diff --git a/chrome/common/mac/mock_launchd.cc b/chrome/common/mac/mock_launchd.cc index f9310df..2f130b59 100644 --- a/chrome/common/mac/mock_launchd.cc +++ b/chrome/common/mac/mock_launchd.cc @@ -4,15 +4,29 @@ #include "chrome/common/mac/mock_launchd.h" +#include <CoreFoundation/CoreFoundation.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "base/basictypes.h" #include "base/file_path.h" #include "base/file_util.h" +#include "base/mac/foundation_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/message_loop.h" +#include "base/process_util.h" +#include "base/string_util.h" #include "base/stringprintf.h" #include "base/sys_string_conversions.h" +#include "chrome/common/chrome_version_info.h" #include "chrome/common/mac/launchd.h" +#include "chrome/common/service_process_util.h" #include "testing/gtest/include/gtest/gtest.h" +static sockaddr_un* throwaway_sockaddr_un; +static const size_t kMaxPipeNameLength = + sizeof(throwaway_sockaddr_un->sun_path); + // static bool MockLaunchd::MakeABundle(const FilePath& dst, const std::string& name, @@ -36,6 +50,8 @@ bool MockLaunchd::MakeABundle(const FilePath& dst, return false; } + chrome::VersionInfo version_info; + const char* info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" " @@ -44,19 +60,23 @@ bool MockLaunchd::MakeABundle(const FilePath& dst, "<dict>\n" " <key>CFBundleDevelopmentRegion</key>\n" " <string>English</string>\n" + " <key>CFBundleExecutable</key>\n" + " <string>%s</string>\n" " <key>CFBundleIdentifier</key>\n" " <string>com.test.%s</string>\n" " <key>CFBundleInfoDictionaryVersion</key>\n" " <string>6.0</string>\n" - " <key>CFBundleExecutable</key>\n" + " <key>CFBundleShortVersionString</key>\n" " <string>%s</string>\n" " <key>CFBundleVersion</key>\n" " <string>1</string>\n" "</dict>\n" "</plist>\n"; - std::string info_plist_data = base::StringPrintf(info_plist_format, - name.c_str(), - name.c_str()); + std::string info_plist_data = + base::StringPrintf(info_plist_format, + name.c_str(), + name.c_str(), + version_info.Version().c_str()); len = info_plist_data.length(); if (file_util::WriteFile(info_plist, info_plist_data.c_str(), len) != len) { return false; @@ -73,21 +93,82 @@ bool MockLaunchd::MakeABundle(const FilePath& dst, return bundle.get(); } +MockLaunchd::MockLaunchd(const FilePath& file, MessageLoop* loop, + bool create_socket, bool as_service) + : file_(file), + message_loop_(loop), + create_socket_(create_socket), + as_service_(as_service), + restart_called_(false), + remove_called_(false), + job_called_(false), + checkin_called_(false), + write_called_(false), + delete_called_(false) { + std::string pipe_suffix("_SOCKET"); + FilePath socket_path = file_; + while (socket_path.value().length() + pipe_suffix.length() > + kMaxPipeNameLength - 2) { + socket_path = socket_path.DirName(); + } + pipe_name_ = socket_path.value() + pipe_suffix; +} + +MockLaunchd::~MockLaunchd() { +} + CFDictionaryRef MockLaunchd::CopyExports() { - ADD_FAILURE(); - return NULL; + if (!create_socket_) { + ADD_FAILURE(); + return NULL; + } + + CFStringRef env_var = + base::mac::NSToCFCast(GetServiceProcessLaunchDSocketEnvVar()); + base::mac::ScopedCFTypeRef<CFStringRef> socket_path( + CFStringCreateWithCString(kCFAllocatorDefault, pipe_name_.c_str(), + kCFStringEncodingUTF8)); + const void *keys[] = { env_var }; + const void *values[] = { socket_path }; + COMPILE_ASSERT(arraysize(keys) == arraysize(values), array_sizes_must_match); + return CFDictionaryCreate(kCFAllocatorDefault, + keys, + values, + arraysize(keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); } CFDictionaryRef MockLaunchd::CopyJobDictionary(CFStringRef label) { - ADD_FAILURE(); - return NULL; + if (!as_service_) { + scoped_ptr<MultiProcessLock> running_lock( + TakeNamedLock(pipe_name_, false)); + if (running_lock.get()) + return NULL; + } + + CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM); + CFStringRef program_pid = CFSTR(LAUNCH_JOBKEY_PID); + const void *keys[] = { program, program_pid }; + base::mac::ScopedCFTypeRef<CFStringRef> path( + base::SysUTF8ToCFStringRef(file_.value())); + int process_id = base::GetCurrentProcId(); + base::mac::ScopedCFTypeRef<CFNumberRef> pid( + CFNumberCreate(NULL, kCFNumberIntType, &process_id)); + const void *values[] = { path, pid }; + COMPILE_ASSERT(arraysize(keys) == arraysize(values), array_sizes_must_match); + return CFDictionaryCreate(kCFAllocatorDefault, + keys, + values, + arraysize(keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); } CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) { checkin_called_ = true; CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM); CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS); - const void *keys[] = { program, program_args }; base::mac::ScopedCFTypeRef<CFStringRef> path( base::SysUTF8ToCFStringRef(file_.value())); const void *array_values[] = { path.get() }; @@ -96,7 +177,78 @@ CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) { array_values, 1, &kCFTypeArrayCallBacks)); - const void *values[] = { path, args }; + + if (!create_socket_) { + const void *keys[] = { program, program_args }; + const void *values[] = { path, args }; + COMPILE_ASSERT(arraysize(keys) == arraysize(values), + array_sizes_must_match); + return CFDictionaryCreate(kCFAllocatorDefault, + keys, + values, + arraysize(keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + + CFStringRef socket_key = CFSTR(LAUNCH_JOBKEY_SOCKETS); + int local_pipe = -1; + EXPECT_TRUE(as_service_); + + // Create unix_addr structure. + struct sockaddr_un unix_addr = {0}; + unix_addr.sun_family = AF_UNIX; + size_t path_len = + base::strlcpy(unix_addr.sun_path, pipe_name_.c_str(), kMaxPipeNameLength); + DCHECK_EQ(pipe_name_.length(), path_len); + unix_addr.sun_len = SUN_LEN(&unix_addr); + + CFSocketSignature signature; + signature.protocolFamily = PF_UNIX; + signature.socketType = SOCK_STREAM; + signature.protocol = 0; + size_t unix_addr_len = offsetof(struct sockaddr_un, + sun_path) + path_len + 1; + base::mac::ScopedCFTypeRef<CFDataRef> address( + CFDataCreate(NULL, reinterpret_cast<UInt8*>(&unix_addr), unix_addr_len)); + signature.address = address; + + CFSocketRef socket = + CFSocketCreateWithSocketSignature(NULL, &signature, NULL, NULL, NULL); + + local_pipe = CFSocketGetNative(socket); + EXPECT_NE(-1, local_pipe); + if (local_pipe == -1) { + if (error) { + *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, + errno, NULL); + } + return NULL; + } + + base::mac::ScopedCFTypeRef<CFNumberRef> socket_fd( + CFNumberCreate(NULL, kCFNumberIntType, &local_pipe)); + const void *socket_array_values[] = { socket_fd }; + base::mac::ScopedCFTypeRef<CFArrayRef> sockets( + CFArrayCreate(kCFAllocatorDefault, + socket_array_values, + 1, + &kCFTypeArrayCallBacks)); + CFStringRef socket_dict_key = CFSTR("ServiceProcessSocket"); + const void *socket_keys[] = { socket_dict_key }; + const void *socket_values[] = { sockets }; + COMPILE_ASSERT(arraysize(socket_keys) == arraysize(socket_values), + socket_array_sizes_must_match); + base::mac::ScopedCFTypeRef<CFDictionaryRef> socket_dict( + CFDictionaryCreate(kCFAllocatorDefault, + socket_keys, + socket_values, + arraysize(socket_keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + const void *keys[] = { program, program_args, socket_key }; + const void *values[] = { path, args, socket_dict }; + COMPILE_ASSERT(arraysize(keys) == arraysize(values), array_sizes_must_match); return CFDictionaryCreate(kCFAllocatorDefault, keys, values, @@ -143,3 +295,8 @@ bool MockLaunchd::DeletePlist(Domain domain, delete_called_ = true; return true; } + +void MockLaunchd::SignalReady() { + ASSERT_TRUE(as_service_); + running_lock_.reset(TakeNamedLock(pipe_name_, true)); +} diff --git a/chrome/common/mac/mock_launchd.h b/chrome/common/mac/mock_launchd.h index 5d043c6..b1a76bb 100644 --- a/chrome/common/mac/mock_launchd.h +++ b/chrome/common/mac/mock_launchd.h @@ -8,9 +8,13 @@ #include <launch.h> +#include <string> + #include "base/file_path.h" #include "base/mac/scoped_cftyperef.h" +#include "base/memory/scoped_ptr.h" #include "chrome/common/mac/launchd.h" +#include "chrome/common/multi_process_lock.h" class MessageLoop; @@ -23,16 +27,9 @@ class MockLaunchd : public Launchd { FilePath* bundle_root, FilePath* executable); - MockLaunchd(const FilePath& file, MessageLoop* loop) - : file_(file), - message_loop_(loop), - restart_called_(false), - remove_called_(false), - checkin_called_(false), - write_called_(false), - delete_called_(false) { - } - virtual ~MockLaunchd() { } + MockLaunchd(const FilePath& file, MessageLoop* loop, + bool create_socket, bool as_service); + virtual ~MockLaunchd(); virtual CFDictionaryRef CopyExports() OVERRIDE; virtual CFDictionaryRef CopyJobDictionary(CFStringRef label) OVERRIDE; @@ -55,6 +52,8 @@ class MockLaunchd : public Launchd { Type type, CFStringRef name) OVERRIDE; + void SignalReady(); + bool restart_called() const { return restart_called_; } bool remove_called() const { return remove_called_; } bool checkin_called() const { return checkin_called_; } @@ -63,9 +62,14 @@ class MockLaunchd : public Launchd { private: FilePath file_; + std::string pipe_name_; MessageLoop* message_loop_; + scoped_ptr<MultiProcessLock> running_lock_; + bool create_socket_; + bool as_service_; bool restart_called_; bool remove_called_; + bool job_called_; bool checkin_called_; bool write_called_; bool delete_called_; diff --git a/chrome/common/service_process_util.h b/chrome/common/service_process_util.h index 427bfcd..9d044d4 100644 --- a/chrome/common/service_process_util.h +++ b/chrome/common/service_process_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -15,6 +15,15 @@ #include "ipc/ipc_channel_handle.h" class CommandLine; +class MultiProcessLock; + +#if defined(OS_MACOSX) +#ifdef __OBJC__ +@class NSString; +#else +class NSString; +#endif +#endif namespace base { class MessageLoopProxy; @@ -33,6 +42,19 @@ std::string GetServiceProcessScopedName(const std::string& append_str); std::string GetServiceProcessScopedVersionedName(const std::string& append_str); #endif // OS_MACOSX +#if defined(OS_MACOSX) +// Return the name that is used to extract the socket path out of the +// dictionary provided by launchd. +NSString* GetServiceProcessLaunchDSocketEnvVar(); +#endif + +#if defined(OS_POSIX) +// Attempts to take a lock named |name|. If |waiting| is true then this will +// make multiple attempts to acquire the lock. +// Caller is responsible for ownership of the MultiProcessLock. +MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting); +#endif + // The following methods are used in a process that acts as a client to the // service process (typically the browser process). // -------------------------------------------------------------------------- diff --git a/chrome/common/service_process_util_linux.cc b/chrome/common/service_process_util_linux.cc index 457a50c..0e912d0 100644 --- a/chrome/common/service_process_util_linux.cc +++ b/chrome/common/service_process_util_linux.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -18,27 +18,6 @@ namespace { -// Attempts to take a lock named |name|. If |waiting| is true then this will -// make multiple attempts to acquire the lock. -// Caller is responsible for ownership of the MultiProcessLock. -MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) { - scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name)); - if (lock == NULL) return NULL; - bool got_lock = false; - for (int i = 0; i < 10; ++i) { - if (lock->TryLock()) { - got_lock = true; - break; - } - if (!waiting) break; - base::PlatformThread::Sleep(100 * i); - } - if (!got_lock) { - lock.reset(); - } - return lock.release(); -} - MultiProcessLock* TakeServiceInitializingLock(bool waiting) { std::string lock_name = GetServiceProcessScopedName("_service_initializing"); diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm index 1345788..7ea7926 100644 --- a/chrome/common/service_process_util_mac.mm +++ b/chrome/common/service_process_util_mac.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -60,15 +60,6 @@ NSString* GetServiceProcessLaunchDSocketKey() { return @"ServiceProcessSocket"; } -NSString* GetServiceProcessLaunchDSocketEnvVar() { - NSString *label = GetServiceProcessLaunchDLabel(); - NSString *env_var = [label stringByReplacingOccurrencesOfString:@"." - withString:@"_"]; - env_var = [env_var stringByAppendingString:@"_SOCKET"]; - env_var = [env_var uppercaseString]; - return env_var; -} - bool GetParentFSRef(const FSRef& child, FSRef* parent) { return FSGetCatalogInfo(&child, 0, NULL, NULL, NULL, parent) == noErr; } @@ -96,6 +87,15 @@ class ExecFilePathWatcherDelegate : public FilePathWatcher::Delegate { } // namespace +NSString* GetServiceProcessLaunchDSocketEnvVar() { + NSString *label = GetServiceProcessLaunchDLabel(); + NSString *env_var = [label stringByReplacingOccurrencesOfString:@"." + withString:@"_"]; + env_var = [env_var stringByAppendingString:@"_SOCKET"]; + env_var = [env_var uppercaseString]; + return env_var; +} + // Gets the name of the service process IPC channel. IPC::ChannelHandle GetServiceProcessChannel() { base::mac::ScopedNSAutoreleasePool pool; diff --git a/chrome/common/service_process_util_posix.cc b/chrome/common/service_process_util_posix.cc index 95c92fb..eb753cf 100644 --- a/chrome/common/service_process_util_posix.cc +++ b/chrome/common/service_process_util_posix.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -9,11 +9,33 @@ #include "base/eintr_wrapper.h" #include "base/message_loop_proxy.h" #include "base/synchronization/waitable_event.h" +#include "chrome/common/multi_process_lock.h" namespace { int g_signal_socket = -1; } +// Attempts to take a lock named |name|. If |waiting| is true then this will +// make multiple attempts to acquire the lock. +// Caller is responsible for ownership of the MultiProcessLock. +MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) { + scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name)); + if (lock == NULL) return NULL; + bool got_lock = false; + for (int i = 0; i < 10; ++i) { + if (lock->TryLock()) { + got_lock = true; + break; + } + if (!waiting) break; + base::PlatformThread::Sleep(100 * i); + } + if (!got_lock) { + lock.reset(); + } + return lock.release(); +} + ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor( const base::Closure& terminate_task) : terminate_task_(terminate_task) { diff --git a/chrome/common/service_process_util_unittest.cc b/chrome/common/service_process_util_unittest.cc index 5de195d..c402fb6 100644 --- a/chrome/common/service_process_util_unittest.cc +++ b/chrome/common/service_process_util_unittest.cc @@ -265,7 +265,8 @@ class ServiceProcessStateFileManipulationTest : public ::testing::Test { "Test", &bundle_path_, &executable_path_)); - mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_)); + mock_launchd_.reset(new MockLaunchd(executable_path_, &loop_, + false, false)); scoped_launchd_instance_.reset( new Launchd::ScopedInstance(mock_launchd_.get())); ASSERT_TRUE(service_process_state_.Initialize()); |