summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/mac/mock_launchd.cc177
-rw-r--r--chrome/common/mac/mock_launchd.h24
-rw-r--r--chrome/common/service_process_util.h24
-rw-r--r--chrome/common/service_process_util_linux.cc23
-rw-r--r--chrome/common/service_process_util_mac.mm20
-rw-r--r--chrome/common/service_process_util_posix.cc24
-rw-r--r--chrome/common/service_process_util_unittest.cc3
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());