Commit 2788395c authored by Elly Fong-Jones's avatar Elly Fong-Jones Committed by Commit Bot

mac: drop dependencies on GTM service management, phase 1

This change drops uses of GTMSMJobRemove and GTMSMJobSubmit, and replaces themm
with uses of new functions in the mac::services namespace.

Bug: 903800
Change-Id: I0e38ddf3532274bd8ff0ea861f14707a183cd3ff
Reviewed-on: https://chromium-review.googlesource.com/c/1337823Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610864}
parent 9c0db623
......@@ -17,15 +17,8 @@
using content::BrowserThread;
void ServiceProcessControl::Launcher::DoRun() {
base::ScopedCFTypeRef<CFDictionaryRef> launchd_plist(
CreateServiceProcessLaunchdPlist(cmd_line_.get(), false));
CFErrorRef error = NULL;
if (!GTMSMJobSubmit(launchd_plist, &error)) {
LOG(ERROR) << error;
CFRelease(error);
} else {
launched_ = true;
}
launched_ = mac::services::SubmitJob(
GetServiceProcessJobOptions(cmd_line_.get(), false));
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
base::Bind(&Launcher::Notify, this));
}
......@@ -9,57 +9,39 @@
#include "base/mac/scoped_nsobject.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "chrome/common/mac/service_management.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/google_toolbox_for_mac/src/Foundation/GTMServiceManagement.h"
namespace {
// Returns the parameters needed to launch a really simple script from launchd.
NSDictionary* TestJobDictionary(NSString* label_ns) {
NSString* shell_script_ns = @"sleep 10; echo TestGTMSMJobSubmitRemove";
base::scoped_nsobject<NSMutableArray> job_arguments(
[[NSMutableArray alloc] init]);
[job_arguments addObject:@"/bin/sh"];
[job_arguments addObject:@"-c"];
[job_arguments addObject:shell_script_ns];
NSMutableDictionary* job_dictionary_ns = [NSMutableDictionary dictionary];
[job_dictionary_ns setObject:label_ns forKey:@LAUNCH_JOBKEY_LABEL];
[job_dictionary_ns setObject:[NSNumber numberWithBool:YES]
forKey:@LAUNCH_JOBKEY_RUNATLOAD];
[job_dictionary_ns setObject:job_arguments
forKey:@LAUNCH_JOBKEY_PROGRAMARGUMENTS];
return job_dictionary_ns;
};
} // namespace
TEST(ServiceProcessControlMac, TestGTMSMJobSubmitRemove) {
TEST(ServiceProcessControlMac, TestJobSubmitRemove) {
NSString* label_ns = @"com.chromium.ServiceProcessStateFileManipulationTest";
std::string label(label_ns.UTF8String);
CFStringRef label_cf = base::mac::NSToCFCast(label_ns);
// If the job is loaded or running, remove it.
pid_t pid = base::mac::PIDForJob(label);
CFErrorRef error = NULL;
if (pid >= 0)
ASSERT_TRUE(GTMSMJobRemove(label_cf, &error));
ASSERT_TRUE(mac::services::RemoveJob(label));
// The job should not be loaded or running.
pid = base::mac::PIDForJob(label);
EXPECT_LT(pid, 0);
// Submit a new job.
NSDictionary* job_dictionary_ns = TestJobDictionary(label_ns);
CFDictionaryRef job_dictionary_cf = base::mac::NSToCFCast(job_dictionary_ns);
ASSERT_TRUE(GTMSMJobSubmit(job_dictionary_cf, &error));
mac::services::JobOptions options;
options.label = label;
options.executable_path = "/bin/sh";
options.arguments = {"sh", "-c", "sleep 10; echo TestJobSubmitRemove"};
options.socket_name = "";
options.socket_key = "";
options.run_at_load = true;
options.auto_launch = false;
ASSERT_TRUE(mac::services::SubmitJob(options));
// The new job should be running.
pid = base::mac::PIDForJob(label);
EXPECT_GT(pid, 0);
// Remove the job.
ASSERT_TRUE(GTMSMJobRemove(label_cf, &error));
ASSERT_TRUE(mac::services::RemoveJob(label));
// Wait for the job to be killed.
base::TimeDelta timeout_in_ms = TestTimeouts::action_timeout();
......@@ -77,5 +59,5 @@ TEST(ServiceProcessControlMac, TestGTMSMJobSubmitRemove) {
EXPECT_LT(pid, 0);
// Attempting to remove the job again should fail.
EXPECT_FALSE(GTMSMJobRemove(label_cf, &error));
EXPECT_FALSE(mac::services::RemoveJob(label));
}
......@@ -146,6 +146,8 @@ static_library("common") {
"mac/cfbundle_blocker.mm",
"mac/launchd.h",
"mac/launchd.mm",
"mac/service_management.h",
"mac/service_management.mm",
"media/media_resource_provider.cc",
"media/media_resource_provider.h",
"media/webrtc_logging_message_data.cc",
......@@ -465,6 +467,8 @@ static_library("common") {
"//third_party/google_toolbox_for_mac",
"//third_party/mach_override",
]
libs = [ "ServiceManagement.framework" ]
}
if (enable_plugins) {
......
......@@ -40,7 +40,7 @@ class Launchd {
virtual CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error);
// Remove a launchd process from launchd.
virtual bool RemoveJob(CFStringRef label, CFErrorRef* error);
virtual bool RemoveJob(const std::string& label);
// Used by a process controlled by launchd to restart itself.
// |session_type| can be "Aqua", "LoginWindow", "Background", "StandardIO" or
......
......@@ -13,6 +13,7 @@
#include "base/process/launch.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/common/mac/service_management.h"
#include "third_party/google_toolbox_for_mac/src/Foundation/GTMServiceManagement.h"
namespace {
......@@ -95,8 +96,8 @@ CFDictionaryRef Launchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
return GTMSMCopyJobCheckInDictionary(error);
}
bool Launchd::RemoveJob(CFStringRef label, CFErrorRef* error) {
return GTMSMJobRemove(label, error);
bool Launchd::RemoveJob(const std::string& label) {
return mac::services::RemoveJob(label);
}
bool Launchd::RestartJob(Domain domain,
......
......@@ -39,7 +39,7 @@ class MockLaunchd : public Launchd {
CFDictionaryRef CopyJobDictionary(CFStringRef label) override;
CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error) override;
bool RemoveJob(CFStringRef label, CFErrorRef* error) override;
bool RemoveJob(const std::string& label) override;
bool RestartJob(Domain domain,
Type type,
CFStringRef name,
......
......@@ -19,6 +19,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
......@@ -41,7 +42,7 @@ bool MockLaunchd::MakeABundle(const base::FilePath& dst,
if (!base::CreateDirectory(mac_os)) {
return false;
}
const char *data = "#! testbundle\n";
const char* data = "#! testbundle\n";
int len = strlen(data);
if (base::WriteFile(*executable, data, len) != len) {
return false;
......@@ -71,9 +72,7 @@ bool MockLaunchd::MakeABundle(const base::FilePath& dst,
"</dict>\n"
"</plist>\n";
std::string info_plist_data =
base::StringPrintf(info_plist_format,
name.c_str(),
name.c_str(),
base::StringPrintf(info_plist_format, name.c_str(), name.c_str(),
version_info::GetVersionNumber().c_str());
len = info_plist_data.length();
if (base::WriteFile(info_plist, info_plist_data.c_str(), len) != len) {
......@@ -81,10 +80,8 @@ bool MockLaunchd::MakeABundle(const base::FilePath& dst,
}
const UInt8* bundle_root_path =
reinterpret_cast<const UInt8*>(bundle_root->value().c_str());
base::ScopedCFTypeRef<CFURLRef> url(
CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
bundle_root_path,
bundle_root->value().length(),
base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault, bundle_root_path, bundle_root->value().length(),
true));
base::ScopedCFTypeRef<CFBundleRef> bundle(
CFBundleCreate(kCFAllocatorDefault, url));
......@@ -109,8 +106,7 @@ MockLaunchd::MockLaunchd(
write_called_(false),
delete_called_(false) {}
MockLaunchd::~MockLaunchd() {
}
MockLaunchd::~MockLaunchd() {}
CFDictionaryRef MockLaunchd::CopyJobDictionary(CFStringRef label) {
if (!as_service_) {
......@@ -122,19 +118,16 @@ CFDictionaryRef MockLaunchd::CopyJobDictionary(CFStringRef label) {
CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
CFStringRef program_pid = CFSTR(LAUNCH_JOBKEY_PID);
const void *keys[] = { program, program_pid };
const void* keys[] = {program, program_pid};
base::ScopedCFTypeRef<CFStringRef> path(
base::SysUTF8ToCFStringRef(file_.value()));
int process_id = base::GetCurrentProcId();
base::ScopedCFTypeRef<CFNumberRef> pid(
CFNumberCreate(NULL, kCFNumberIntType, &process_id));
const void *values[] = { path, pid };
static_assert(arraysize(keys) == arraysize(values),
const void* values[] = {path, pid};
static_assert(base::size(keys) == base::size(values),
"keys must have the same number of elements as values");
return CFDictionaryCreate(kCFAllocatorDefault,
keys,
values,
arraysize(keys),
return CFDictionaryCreate(kCFAllocatorDefault, keys, values, base::size(keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
......@@ -145,20 +138,17 @@ CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS);
base::ScopedCFTypeRef<CFStringRef> path(
base::SysUTF8ToCFStringRef(file_.value()));
const void *array_values[] = { path.get() };
const void* array_values[] = {path.get()};
base::ScopedCFTypeRef<CFArrayRef> args(CFArrayCreate(
kCFAllocatorDefault, array_values, 1, &kCFTypeArrayCallBacks));
if (!create_socket_) {
const void *keys[] = { program, program_args };
const void *values[] = { path, args };
static_assert(arraysize(keys) == arraysize(values),
const void* keys[] = {program, program_args};
const void* values[] = {path, args};
static_assert(base::size(keys) == base::size(values),
"keys must have the same number of elements as values");
return CFDictionaryCreate(kCFAllocatorDefault,
keys,
values,
arraysize(keys),
&kCFTypeDictionaryKeyCallBacks,
return CFDictionaryCreate(kCFAllocatorDefault, keys, values,
base::size(keys), &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
......@@ -178,8 +168,7 @@ CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
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;
size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) + path_len + 1;
base::ScopedCFTypeRef<CFDataRef> address(
CFDataCreate(NULL, reinterpret_cast<UInt8*>(&unix_addr), unix_addr_len));
signature.address = address;
......@@ -191,43 +180,36 @@ CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
EXPECT_NE(-1, local_pipe);
if (local_pipe == -1) {
if (error) {
*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX,
errno, NULL);
*error =
CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, errno, NULL);
}
return NULL;
}
base::ScopedCFTypeRef<CFNumberRef> socket_fd(
CFNumberCreate(NULL, kCFNumberIntType, &local_pipe));
const void *socket_array_values[] = { socket_fd };
const void* socket_array_values[] = {socket_fd};
base::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 };
static_assert(arraysize(socket_keys) == arraysize(socket_values),
const void* socket_keys[] = {socket_dict_key};
const void* socket_values[] = {sockets};
static_assert(base::size(socket_keys) == base::size(socket_values),
"socket_keys must have the same number of elements "
"as socket_values");
base::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 };
static_assert(arraysize(keys) == arraysize(values),
base::ScopedCFTypeRef<CFDictionaryRef> socket_dict(CFDictionaryCreate(
kCFAllocatorDefault, socket_keys, socket_values, base::size(socket_keys),
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
const void* keys[] = {program, program_args, socket_key};
const void* values[] = {path, args, socket_dict};
static_assert(base::size(keys) == base::size(values),
"keys must have the same number of elements as values");
return CFDictionaryCreate(kCFAllocatorDefault,
keys,
values,
arraysize(keys),
return CFDictionaryCreate(kCFAllocatorDefault, keys, values, base::size(keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
bool MockLaunchd::RemoveJob(CFStringRef label, CFErrorRef* error) {
bool MockLaunchd::RemoveJob(const std::string& label) {
remove_called_ = true;
std::move(quit_closure_).Run();
return true;
......@@ -242,8 +224,7 @@ bool MockLaunchd::RestartJob(Domain domain,
return true;
}
CFMutableDictionaryRef MockLaunchd::CreatePlistFromFile(
Domain domain,
CFMutableDictionaryRef MockLaunchd::CreatePlistFromFile(Domain domain,
Type type,
CFStringRef name) {
base::ScopedCFTypeRef<CFDictionaryRef> dict(CopyDictionaryByCheckingIn(NULL));
......@@ -258,9 +239,7 @@ bool MockLaunchd::WritePlistToFile(Domain domain,
return true;
}
bool MockLaunchd::DeletePlist(Domain domain,
Type type,
CFStringRef name) {
bool MockLaunchd::DeletePlist(Domain domain, Type type, CFStringRef name) {
delete_called_ = true;
return true;
}
......
// Copyright 2018 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.
#ifndef CHROME_COMMON_MAC_SERVICE_MANAGEMENT_H_
#define CHROME_COMMON_MAC_SERVICE_MANAGEMENT_H_
#include <string>
#include <vector>
namespace mac {
namespace services {
struct JobOptions {
JobOptions();
JobOptions(const JobOptions& other);
~JobOptions();
std::string label;
// See launchd.plist(5) for details about these two fields. In short:
// - executable_path, if non-empty, is the absolute path to the executable
// for this job;
// - arguments[0] is the absolute *or relative* path to the executable if
// executable_path is empty; in either case, all of arguments is passed
// directly as argv to the job, meaning arguments[0] becomes argv[0]
// There are important caveats about the argument vector documented in the
// launchd.plist(5) man page.
std::string executable_path;
std::vector<std::string> arguments;
// See launchd.plist(5) "Sockets" for details about the meaning of these two
// fields. The socket_key field corresponds to a top-level key in the socket
// dictionary; the socket_name field corresponds to a pathname to a Unix
// domain socket (the SockPathName member in the Sockets dictionary).
std::string socket_name;
std::string socket_key;
// Whether to run this job immediately once it is loaded.
bool run_at_load;
// Whether to restart the job whenever it exits successfully. This also
// implicitly limits the job to interactive sessions only (i.e., the job will
// not run in system sessions).
bool auto_launch;
};
bool SubmitJob(const JobOptions& options);
bool RemoveJob(const std::string& label);
} // namespace services
} // namespace mac
#endif // CHROME_COMMON_MAC_SERVICE_MANAGEMENT_H_
// Copyright 2018 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.
#include "chrome/common/mac/service_management.h"
#import <CoreServices/CoreServices.h>
#import <Foundation/Foundation.h>
#import <ServiceManagement/ServiceManagement.h>
#include <errno.h>
#include <launch.h>
#include "base/compiler_specific.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "base/strings/sys_string_conversions.h"
namespace {
class ScopedLaunchData {
public:
explicit ScopedLaunchData(launch_data_type_t type)
: data_(launch_data_alloc(type)) {}
explicit ScopedLaunchData(launch_data_t data) : data_(data) {}
ScopedLaunchData(ScopedLaunchData&& other) : data_(other.release()) {}
~ScopedLaunchData() { reset(); }
void reset() {
if (data_)
launch_data_free(data_);
data_ = nullptr;
}
launch_data_t release() WARN_UNUSED_RESULT {
launch_data_t val = data_;
data_ = nullptr;
return val;
}
launch_data_t get() { return data_; }
operator launch_data_t() const { return data_; }
operator bool() const { return !!data_; }
private:
launch_data_t data_;
DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
};
ScopedLaunchData SendLaunchMessage(ScopedLaunchData&& msg) {
return ScopedLaunchData(launch_msg(msg));
}
ScopedLaunchData LaunchDataFromString(const std::string& string) {
ScopedLaunchData result(LAUNCH_DATA_STRING);
// launch_data_set_string() will make a copy of the passed-in string.
launch_data_set_string(result, string.c_str());
return result;
}
int ErrnoFromLaunchData(launch_data_t data) {
if (launch_data_get_type(data) != LAUNCH_DATA_ERRNO)
return EINVAL;
return launch_data_get_errno(data);
}
ScopedLaunchData DoServiceOp(const char* verb,
const std::string& label,
int* error) {
ScopedLaunchData msg(LAUNCH_DATA_DICTIONARY);
launch_data_dict_insert(msg, LaunchDataFromString(label).release(), verb);
ScopedLaunchData result(SendLaunchMessage(std::move(msg)));
if (!result)
*error = errno;
return result;
}
NSArray* NSArrayFromStringVector(const std::vector<std::string>& vec) {
NSMutableArray* args = [NSMutableArray arrayWithCapacity:vec.size()];
for (const auto& item : vec) {
[args addObject:base::SysUTF8ToNSString(item)];
}
return args;
}
base::scoped_nsobject<NSDictionary> DictionaryForJobOptions(
const mac::services::JobOptions& options) {
base::scoped_nsobject<NSMutableDictionary> opts(
[[NSMutableDictionary alloc] init]);
[opts setObject:base::SysUTF8ToNSString(options.label)
forKey:@LAUNCH_JOBKEY_LABEL];
if (!options.executable_path.empty()) {
[opts setObject:base::SysUTF8ToNSString(options.executable_path)
forKey:@LAUNCH_JOBKEY_PROGRAM];
}
if (!options.arguments.empty()) {
[opts setObject:NSArrayFromStringVector(options.arguments)
forKey:@LAUNCH_JOBKEY_PROGRAMARGUMENTS];
}
DCHECK_EQ(options.socket_name.empty(), options.socket_key.empty());
if (!options.socket_name.empty() && !options.socket_key.empty()) {
NSDictionary* inner_dict = [NSDictionary
dictionaryWithObject:base::SysUTF8ToNSString(options.socket_name)
forKey:@LAUNCH_JOBSOCKETKEY_PATHNAME];
NSDictionary* outer_dict = [NSDictionary
dictionaryWithObject:inner_dict
forKey:base::SysUTF8ToNSString(options.socket_key)];
[opts setObject:outer_dict forKey:@LAUNCH_JOBKEY_SOCKETS];
}
if (options.run_at_load || options.auto_launch) {
[opts setObject:@YES forKey:@LAUNCH_JOBKEY_RUNATLOAD];
}
if (options.auto_launch) {
[opts setObject:@{
@LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT : @NO
}
forKey:@LAUNCH_JOBKEY_KEEPALIVE];
[opts setObject:@"Aqua" forKey:@LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE];
}
return base::scoped_nsobject<NSDictionary>(opts.release());
}
} // namespace
namespace mac {
namespace services {
JobOptions::JobOptions() = default;
JobOptions::JobOptions(const JobOptions& other) = default;
JobOptions::~JobOptions() = default;
bool SubmitJob(const JobOptions& options) {
base::scoped_nsobject<NSDictionary> options_dict =
DictionaryForJobOptions(options);
return SMJobSubmit(kSMDomainUserLaunchd,
base::mac::NSToCFCast(options_dict.get()), nullptr,
nullptr);
}
bool RemoveJob(const std::string& label) {
int error = 0;
ScopedLaunchData resp = DoServiceOp(LAUNCH_KEY_REMOVEJOB, label, &error);
if (!error)
error = ErrnoFromLaunchData(resp.get());
// On macOS 10.10+, removing a running job yields EINPROGRESS but the
// operation completes eventually (but not necessarily by the time RemoveJob
// is done). See rdar://18398683 for details.
if (error == EINPROGRESS)
error = 0;
return !error;
}
} // namespace services
} // namespace mac
......@@ -104,14 +104,11 @@ mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName() {
bool ForceServiceProcessShutdown(const std::string& /* version */,
base::ProcessId /* process_id */) {
base::mac::ScopedNSAutoreleasePool pool;
CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel());
CFErrorRef err = NULL;
bool ret = Launchd::GetInstance()->RemoveJob(label, &err);
const std::string& label =
base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
bool ret = Launchd::GetInstance()->RemoveJob(label);
if (!ret) {
DLOG(ERROR) << "ForceServiceProcessShutdown: " << err << " "
<< base::SysCFStringRefToUTF8(label);
CFRelease(err);
DLOG(ERROR) << "ForceServiceProcessShutdown: " << label;
}
return ret;
}
......@@ -218,6 +215,24 @@ bool CheckServiceProcessReady() {
return ready;
}
mac::services::JobOptions GetServiceProcessJobOptions(
base::CommandLine* cmd_line,
bool for_auto_launch) {
mac::services::JobOptions options;
options.label = base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
options.executable_path = cmd_line->GetProgram().value();
options.arguments = cmd_line->argv();
options.socket_name = GetServiceProcessSocketName().value();
options.socket_key =
base::SysNSStringToUTF8(GetServiceProcessLaunchDSocketKey());
options.run_at_load = for_auto_launch;
options.auto_launch = for_auto_launch;
return options;
}
CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line,
bool for_auto_launch) {
base::mac::ScopedNSAutoreleasePool pool;
......@@ -443,12 +458,10 @@ void ExecFilePathWatcherCallback::NotifyPathChanged(const base::FilePath& path,
}
}
if (needs_shutdown) {
CFStringRef label =
base::mac::NSToCFCast(GetServiceProcessLaunchDLabel());
CFErrorRef err = NULL;
if (!Launchd::GetInstance()->RemoveJob(label, &err)) {
base::ScopedCFTypeRef<CFErrorRef> scoped_err(err);
DLOG(ERROR) << "RemoveJob " << err;
const std::string& label =
base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
if (!Launchd::GetInstance()->RemoveJob(label)) {
DLOG(ERROR) << "RemoveJob " << label;
// Exiting with zero, so launchd doesn't restart the process.
exit(0);
}
......
......@@ -25,12 +25,14 @@ MultiProcessLock* TakeServiceRunningLock(bool waiting);
#if defined(OS_MACOSX)
#include "base/files/file_path_watcher.h"
#include "base/mac/scoped_cftyperef.h"
#include "chrome/common/mac/service_management.h"
namespace base {
class CommandLine;
}
CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line,
mac::services::JobOptions GetServiceProcessJobOptions(
base::CommandLine* cmd_line,
bool for_auto_launch);
#endif // OS_MACOSX
......
......@@ -975,8 +975,8 @@ test("browser_tests") {
"../browser/usb/usb_browsertest.cc",
"../browser/web_bluetooth_browsertest.cc",
"../common/mac/app_mode_chrome_locator_browsertest.mm",
"../common/mac/mock_launchd.cc",
"../common/mac/mock_launchd.h",
"../common/mac/mock_launchd.mm",
"../common/time_format_browsertest.cc",
"../renderer/autofill/autofill_renderer_browsertest.cc",
"../renderer/autofill/fake_mojo_password_manager_driver.cc",
......@@ -2762,8 +2762,8 @@ test("unit_tests") {
"../common/heap_profiler_controller_unittest.cc",
"../common/ini_parser_unittest.cc",
"../common/mac/cfbundle_blocker_unittest.mm",
"../common/mac/mock_launchd.cc",
"../common/mac/mock_launchd.h",
"../common/mac/mock_launchd.mm",
"../common/media_router/issue_unittest.cc",
"../common/media_router/media_route_unittest.cc",
"../common/media_router/media_sink_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment