Permalink
Browse files

Made XPC service calls asynchronous

  • Loading branch information...
1 parent dbd2b9b commit 6fc58a1025587fee8b8a1f64ea53270ddf8c2dba @erikaderstedt committed Aug 9, 2012
Showing with 95 additions and 45 deletions.
  1. +34 −13 SUBasicUpdateDriver.m
  2. +1 −0 SUConstants.h
  3. +1 −0 SUConstants.m
  4. +2 −2 SUXPC.h
  5. +51 −28 SUXPC.m
  6. +6 −2 sandbox_service.m
View
@@ -266,17 +266,21 @@ - (void)unarchiverDidFail:(SUUnarchiver *)ua
- (BOOL)shouldInstallSynchronously { return NO; }
+- (BOOL)shouldUseXPC
+{
+ BOOL running10_7 = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
+ BOOL useXPC = running10_7 && [[NSFileManager defaultManager] fileExistsAtPath:
+ [[host bundlePath] stringByAppendingPathComponent:@"Contents/XPCServices/com.andymatuschak.Sparkle.SandboxService.xpc"]];
+ return useXPC;
+}
+
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
if (![updater mayUpdateAndRestart])
{
[self abortUpdate];
return;
}
-
- BOOL running10_7 = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
- BOOL useXPC = running10_7 && [[NSFileManager defaultManager] fileExistsAtPath:
- [[host bundlePath] stringByAppendingPathComponent:@"Contents/XPCServices/com.andymatuschak.Sparkle.SandboxService.xpc"]];
// Give the host app an opportunity to postpone the install and relaunch.
static BOOL postponedOnce = NO;
@@ -307,11 +311,25 @@ - (void)installWithToolAndRelaunch:(BOOL)relaunch
#endif
// Only the paranoid survive: if there's already a stray copy of relaunch there, we would have problems.
- BOOL copiedRelaunchTool = FALSE;
- if( useXPC )
- copiedRelaunchTool = [SUXPC copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error];
- else
- copiedRelaunchTool = [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error];
+ if( [self shouldUseXPC] )
+ {
+ [SUXPC copyPathWithAuthentication:relaunchPathToCopy overPath:targetPath temporaryName:nil completionHandler:^(NSError *xpcError) {
+ if (xpcError != nil)
+ NSLog(@"Error during asynchronous XPC call to copyPath: %@", xpcError);
+ [self finishRelaunchAfterSuccessfulCopying:(xpcError == nil) fromPath:relaunchPathToCopy toPath:targetPath relaunch:relaunch];
+ }];
+ }
+ else
+ {
+ BOOL copiedRelaunchTool = [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error];
+ [self finishRelaunchAfterSuccessfulCopying:copiedRelaunchTool fromPath:relaunchPathToCopy toPath:targetPath relaunch:relaunch];
+ }
+}
+
+- (void)finishRelaunchAfterSuccessfulCopying:(BOOL)copiedRelaunchTool fromPath:(NSString *)relaunchPathToCopy toPath:(NSString *)targetPath relaunch:(BOOL)relaunch
+{
+
+ NSError *error = nil;
if( copiedRelaunchTool )
relaunchPath = [targetPath retain];
else
@@ -334,12 +352,15 @@ - (void)installWithToolAndRelaunch:(BOOL)relaunch
pathToRelaunch = [[updater delegate] pathToRelaunchForUpdater:updater];
NSString *relaunchToolPath = [relaunchPath stringByAppendingPathComponent: @"/Contents/MacOS/finish_installation"];
NSArray *arguments = [NSArray arrayWithObjects:[host bundlePath], pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil];
- if( useXPC )
- [SUXPC launchTaskWithLaunchPath: relaunchToolPath arguments:arguments];
+ if( [self shouldUseXPC] )
+ [SUXPC launchTaskWithLaunchPath: relaunchToolPath arguments:arguments completionHandler:^{
+ [NSApp terminate:self];
+ }];
else
+ {
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:arguments];
-
- [NSApp terminate:self];
+ [NSApp terminate:self];
+ }
}
- (void)cleanUpDownload
View
@@ -87,6 +87,7 @@ extern OSStatus SUMissingInstallerToolError;
extern OSStatus SURelaunchError;
extern OSStatus SUInstallationError;
extern OSStatus SUDowngradeError;
+extern OSStatus SUXPCServiceError;
// -----------------------------------------------------------------------------
View
@@ -55,3 +55,4 @@
OSStatus SURelaunchError = 4004;
OSStatus SUInstallationError = 4005;
OSStatus SUDowngradeError = 4006;
+OSStatus SUXPCServiceError = 4007;
View
@@ -10,7 +10,7 @@
@interface SUXPC : NSObject
-+ (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp error:(NSError **)error;
-+ (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments;
++ (void)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp completionHandler:(void (^)(NSError *error))completionHandler;
++ (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments completionHandler: (void (^)(void))completionHandler ;
@end
View
79 SUXPC.m
@@ -12,15 +12,37 @@
@implementation SUXPC
-+ (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp error:(NSError **)error {
- xpc_connection_t connection = xpc_connection_create("com.andymatuschak.Sparkle.SandboxService", NULL);
- xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
- xpc_dictionary_apply(event, ^bool(const char *key, xpc_object_t value) {
- NSLog(@"XPC %s: %s", key, xpc_string_get_string_ptr(value));
- return true;
- });
- });
- xpc_connection_resume(connection);
++ (xpc_connection_t)getSandboxXPCService {
+ __block xpc_connection_t serviceConnection =
+ xpc_connection_create("com.andymatuschak.Sparkle.SandboxService", dispatch_get_main_queue());
+
+ if (!serviceConnection) {
+ NSLog(@"Can't connect to XPC service");
+ return (NULL);
+ }
+
+ xpc_connection_set_event_handler(serviceConnection, ^(xpc_object_t event) {
+ xpc_type_t type = xpc_get_type(event);
+
+ if (type == XPC_TYPE_ERROR) {
+
+ if (event == XPC_ERROR_CONNECTION_INVALID) {
+ // The service is invalid. Either the service name supplied to
+ // xpc_connection_create() is incorrect or we (this process) have
+ // canceled the service; we can do any cleanup of appliation
+ // state at this point.
+ xpc_release(serviceConnection);
+ }
+ }
+ });
+
+ // Need to resume the service in order for it to process messages.
+ xpc_connection_resume(serviceConnection);
+ return (serviceConnection);
+}
+
++ (void)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp completionHandler:(void (^)(NSError *error))completionHandler {
+ xpc_connection_t connection = [self getSandboxXPCService];
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "id", "copy_path");
@@ -32,20 +54,25 @@ + (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temp
if( tmp )
xpc_dictionary_set_string(message, "tmp", [tmp UTF8String]);
- xpc_object_t response = xpc_connection_send_message_with_reply_sync(connection, message);
- xpc_type_t type = xpc_get_type(response);
- return type == XPC_TYPE_DICTIONARY;
+ xpc_connection_send_message_with_reply(connection, message, dispatch_get_main_queue(), ^(xpc_object_t response) {
+ const char *errorString = xpc_dictionary_get_string(response, "errorLocalizedDescription");
+ if (errorString != NULL)
+ {
+ NSError *error = [NSError errorWithDomain:SUSparkleErrorDomain
+ code:SUXPCServiceError
+ userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithCString:errorString encoding:NSUTF8StringEncoding]
+ forKey:NSLocalizedDescriptionKey]];
+ completionHandler(error);
+ }
+ else
+ {
+ completionHandler(nil);
+ }
+ });
}
-+ (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments {
- xpc_connection_t connection = xpc_connection_create("com.andymatuschak.Sparkle.SandboxService", NULL);
- xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
- xpc_dictionary_apply(event, ^bool(const char *key, xpc_object_t value) {
- NSLog(@"XPC %s: %s", key, xpc_string_get_string_ptr(value));
- return true;
- });
- });
- xpc_connection_resume(connection);
++ (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments completionHandler: (void (^)(void))completionHandler {
+ xpc_connection_t connection = [self getSandboxXPCService];
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "id", "launch_task");
@@ -60,13 +87,9 @@ + (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments
xpc_dictionary_set_value(message, "arguments", array);
- xpc_object_t response = xpc_connection_send_message_with_reply_sync(connection, message);
- xpc_type_t type = xpc_get_type(response);
- BOOL success = (type == XPC_TYPE_DICTIONARY);
-
- if (!success) {
- NSLog(@"XPC launch error");
- }
+ xpc_connection_send_message_with_reply(connection, message, dispatch_get_current_queue(), ^(xpc_object_t response) {
+ completionHandler();
+ });
}
@end
View
@@ -29,7 +29,7 @@ static void peer_event_handler(xpc_connection_t peer, xpc_object_t event)
const char *identifier = xpc_dictionary_get_string(event, "id");
BOOL copyPath = strcmp(identifier, "copy_path") == 0;
BOOL launchTask = strcmp(identifier, "launch_task") == 0;
-
+
if( copyPath )
{
const char *src = xpc_dictionary_get_string(event, "source");
@@ -41,10 +41,14 @@ static void peer_event_handler(xpc_connection_t peer, xpc_object_t event)
NSString *targetPath = dst ? [manager stringWithFileSystemRepresentation:dst length:strlen(dst)] : nil;
NSString *temporaryName = tmp ? [NSString stringWithUTF8String:tmp] : nil;
NSError *error = nil;
- [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: temporaryName error: &error];
+ BOOL result = [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: temporaryName error: &error];
// send response to indicate ok
xpc_object_t reply = xpc_dictionary_create_reply(event);
+ if (! result && error != nil) {
+ xpc_dictionary_set_int64(reply, "errorCode", [error code]);
+ xpc_dictionary_set_string(reply, "errorLocalizedDescription", [[error localizedDescription] cStringUsingEncoding:NSUTF8StringEncoding]);
+ }
xpc_connection_send_message(peer, reply);
}
else if( launchTask )

0 comments on commit 6fc58a1

Please sign in to comment.