Skip to content

Commit

Permalink
mac cleanup: drop GTM service management dependencies
Browse files Browse the repository at this point in the history
This change:

1) Adds mac::services::GetJobInfo and mac::services::CheckIn, which replace
   two GTM functions;
2) Changes Launchd and MockLaunchd to use these functions instead of the GTM
   ones;
3) Simplifies ServiceProcessControlMac somewhat as a result

This removes all remaining dependencies on the GTM service management code. The
next step in this work is to remove dependencies on GTMUILocalizer.

Bug: 903800
Change-Id: Ib6a4fe13cb8586a8ae0f6323ff5cafa4870ed636
Reviewed-on: https://chromium-review.googlesource.com/c/1396442
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Elly Fong-Jones <ellyjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#621214}
  • Loading branch information
Elly Fong-Jones authored and Commit Bot committed Jan 9, 2019
1 parent 8f74ca1 commit f65d67a
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include "chrome/common/service_process_util_posix.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/google_toolbox_for_mac/src/Foundation/GTMServiceManagement.h"

using content::BrowserThread;

Expand Down
12 changes: 8 additions & 4 deletions chrome/common/mac/launchd.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "base/macros.h"
#include "base/memory/singleton.h"
#include "chrome/common/mac/service_management.h"

class Launchd {
public:
Expand All @@ -33,11 +34,14 @@ class Launchd {

virtual ~Launchd();

// Return a dictionary with the launchd entries for job labeled |name|.
virtual CFDictionaryRef CopyJobDictionary(CFStringRef label);
virtual bool GetJobInfo(const std::string& label,
mac::services::JobInfo* info);

// Return a dictionary for launchd process.
virtual CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error);
// Checks in with launchd, retrieving |info| in the process. The |socket_key|
// argument is the name of a socket to extract from the job's sockets
// dictionary (see launchd.plist(5)).
virtual bool CheckIn(const std::string& socket_key,
mac::services::JobCheckinInfo* info);

// Remove a launchd process from launchd.
virtual bool RemoveJob(const std::string& label);
Expand Down
11 changes: 6 additions & 5 deletions chrome/common/mac/launchd.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#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 {

Expand Down Expand Up @@ -88,12 +87,14 @@

Launchd::~Launchd() { }

CFDictionaryRef Launchd::CopyJobDictionary(CFStringRef label) {
return GTMSMJobCopyDictionary(label);
bool Launchd::GetJobInfo(const std::string& label,
mac::services::JobInfo* info) {
return mac::services::GetJobInfo(label, info);
}

CFDictionaryRef Launchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
return GTMSMCopyJobCheckInDictionary(error);
bool Launchd::CheckIn(const std::string& socket_key,
mac::services::JobCheckinInfo* info) {
return mac::services::CheckIn(socket_key, info);
}

bool Launchd::RemoveJob(const std::string& label) {
Expand Down
6 changes: 4 additions & 2 deletions chrome/common/mac/mock_launchd.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ class MockLaunchd : public Launchd {
bool as_service);
~MockLaunchd() override;

CFDictionaryRef CopyJobDictionary(CFStringRef label) override;
CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error) override;
bool GetJobInfo(const std::string& label,
mac::services::JobInfo* info) override;
bool CheckIn(const std::string& socket_key,
mac::services::JobCheckinInfo* info) override;
bool RemoveJob(const std::string& label) override;
bool RestartJob(Domain domain,
Type type,
Expand Down
102 changes: 36 additions & 66 deletions chrome/common/mac/mock_launchd.mm
Original file line number Diff line number Diff line change
Expand Up @@ -108,51 +108,28 @@

MockLaunchd::~MockLaunchd() {}

CFDictionaryRef MockLaunchd::CopyJobDictionary(CFStringRef label) {
bool MockLaunchd::GetJobInfo(const std::string& label,
mac::services::JobInfo* info) {
if (!as_service_) {
std::unique_ptr<MultiProcessLock> running_lock(
TakeNamedLock(pipe_name_, false));
if (running_lock.get())
return NULL;
return false;
}

CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
CFStringRef program_pid = CFSTR(LAUNCH_JOBKEY_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(base::size(keys) == base::size(values),
"keys must have the same number of elements as values");
return CFDictionaryCreate(kCFAllocatorDefault, keys, values, base::size(keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
info->program = file_.value();
info->pid = base::GetCurrentProcId();
return true;
}

CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
bool MockLaunchd::CheckIn(const std::string& socket_key,
mac::services::JobCheckinInfo* info) {
checkin_called_ = true;
CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS);
base::ScopedCFTypeRef<CFStringRef> path(
base::SysUTF8ToCFStringRef(file_.value()));
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(base::size(keys) == base::size(values),
"keys must have the same number of elements as values");
return CFDictionaryCreate(kCFAllocatorDefault, keys, values,
base::size(keys), &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}

CFStringRef socket_key = CFSTR(LAUNCH_JOBKEY_SOCKETS);
info->program = file_.value();
if (!create_socket_)
return true;

int local_pipe = -1;
EXPECT_TRUE(as_service_);

Expand All @@ -177,36 +154,12 @@
CFSocketCreateWithSocketSignature(NULL, &signature, 0, 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;
}
EXPECT_NE(-1, local_pipe) << "errno: " << errno;
if (local_pipe == -1)
return false;

base::ScopedCFTypeRef<CFNumberRef> socket_fd(
CFNumberCreate(NULL, kCFNumberIntType, &local_pipe));
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(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, 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, base::size(keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
info->socket = local_pipe;
return true;
}

bool MockLaunchd::RemoveJob(const std::string& label) {
Expand All @@ -227,8 +180,25 @@
CFMutableDictionaryRef MockLaunchd::CreatePlistFromFile(Domain domain,
Type type,
CFStringRef name) {
base::ScopedCFTypeRef<CFDictionaryRef> dict(CopyDictionaryByCheckingIn(NULL));
return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict);
mac::services::JobCheckinInfo info;
NSString* socket_key = @"ServiceProcessSocket";
if (!CheckIn(base::SysNSStringToUTF8(socket_key), &info))
return nil;

NSString* ns_program = base::SysUTF8ToNSString(info.program);

NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:@{
@LAUNCH_JOBKEY_PROGRAM : ns_program,
@LAUNCH_JOBKEY_PROGRAMARGUMENTS : @[ ns_program ],
}];

if (create_socket_) {
dict[@LAUNCH_JOBKEY_SOCKETS] = @{socket_key : @(info.socket)};
}

// Callers expect to be given a reference but dictionaryWithDictionary: is
// autoreleased, so it's necessary to do a manual retain here.
return base::mac::NSToCFCast([dict retain]);
}

bool MockLaunchd::WritePlistToFile(Domain domain,
Expand Down
24 changes: 24 additions & 0 deletions chrome/common/mac/service_management.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,30 @@
#include <string>
#include <vector>

#include "base/files/scoped_file.h"
#include "base/optional.h"

namespace mac {
namespace services {

struct JobInfo {
JobInfo();
JobInfo(const JobInfo& other);
~JobInfo();

std::string program;
base::Optional<int> pid;
};

struct JobCheckinInfo {
JobCheckinInfo();
JobCheckinInfo(const JobCheckinInfo& info);
~JobCheckinInfo();

std::string program;
int socket;
};

struct JobOptions {
JobOptions();
JobOptions(const JobOptions& other);
Expand Down Expand Up @@ -44,6 +65,9 @@ struct JobOptions {
bool auto_launch;
};

bool GetJobInfo(const std::string& label, JobInfo* info);
bool CheckIn(const std::string& socket_key, JobCheckinInfo* info);

bool SubmitJob(const JobOptions& options);
bool RemoveJob(const std::string& label);

Expand Down
95 changes: 95 additions & 0 deletions chrome/common/mac/service_management.mm
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,47 @@ int ErrnoFromLaunchData(launch_data_t data) {
return launch_data_get_errno(data);
}

bool StringFromLaunchDataDictEntry(launch_data_t dict,
const char* key,
std::string* value) {
launch_data_t entry = launch_data_dict_lookup(dict, key);
if (!entry || launch_data_get_type(entry) != LAUNCH_DATA_STRING)
return false;
*value = std::string(launch_data_get_string(entry));
return true;
}

bool IntFromLaunchDataDictEntry(launch_data_t dict,
const char* key,
int* value) {
launch_data_t entry = launch_data_dict_lookup(dict, key);
if (!entry || launch_data_get_type(entry) != LAUNCH_DATA_INTEGER)
return false;
*value = launch_data_get_integer(entry);
return true;
}

// Extracts the first integer value from |dict[key]|, which is itself an array,
// and returns it in |*value|. This means that the type of dict is:
// map<string, array<int>>
bool FirstIntFromLaunchDataDictEntry(launch_data_t dict,
const char* key,
int* value) {
launch_data_t array = launch_data_dict_lookup(dict, key);
if (!array || launch_data_get_type(array) != LAUNCH_DATA_ARRAY ||
launch_data_array_get_count(array) == 0) {
return false;
}
launch_data_t entry = launch_data_array_get_index(array, 0);
if (launch_data_get_type(entry) == LAUNCH_DATA_INTEGER)
*value = launch_data_get_integer(entry);
else if (launch_data_get_type(entry) == LAUNCH_DATA_FD)
*value = launch_data_get_fd(entry);
else
return false;
return true;
}

ScopedLaunchData DoServiceOp(const char* verb,
const std::string& label,
int* error) {
Expand Down Expand Up @@ -135,10 +176,64 @@ ScopedLaunchData DoServiceOp(const char* verb,
namespace mac {
namespace services {

JobInfo::JobInfo() = default;
JobInfo::JobInfo(const JobInfo& other) = default;
JobInfo::~JobInfo() = default;

JobCheckinInfo::JobCheckinInfo() = default;
JobCheckinInfo::JobCheckinInfo(const JobCheckinInfo& other) = default;
JobCheckinInfo::~JobCheckinInfo() = default;

JobOptions::JobOptions() = default;
JobOptions::JobOptions(const JobOptions& other) = default;
JobOptions::~JobOptions() = default;

bool GetJobInfo(const std::string& label, JobInfo* info) {
int error = 0;
ScopedLaunchData resp = DoServiceOp(LAUNCH_KEY_GETJOB, label, &error);

if (error)
return false;

std::string program;
if (!StringFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PROGRAM,
&program))
return false;

info->program = program;
int pid;
if (IntFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PID, &pid))
info->pid = pid;

return true;
}

bool CheckIn(const std::string& socket_key, JobCheckinInfo* info) {
ScopedLaunchData resp =
SendLaunchMessage(LaunchDataFromString(LAUNCH_KEY_CHECKIN));

if (launch_data_get_type(resp.get()) != LAUNCH_DATA_DICTIONARY)
return false;

std::string program;
if (!StringFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PROGRAM,
&program))
return false;

launch_data_t sockets = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);

if (launch_data_get_type(sockets) != LAUNCH_DATA_DICTIONARY)
return false;

int socket_fd;
if (!FirstIntFromLaunchDataDictEntry(sockets, socket_key.c_str(), &socket_fd))
return false;

info->program = program;
info->socket = socket_fd;
return true;
}

bool SubmitJob(const JobOptions& options) {
base::scoped_nsobject<NSDictionary> options_dict =
DictionaryForJobOptions(options);
Expand Down
Loading

0 comments on commit f65d67a

Please sign in to comment.