// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40284755): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif // This is a helper application for launch_application_unittest.mm. This // application records several events by writing them to a named pipe; // the unit tests then use this information to verify that this helper was // launched in the correct manner. // The named pipe this writes to is equal to the name of the app bundle, // with .app replaced by .fifo. #import @interface AppDelegate : NSObject @end @implementation AppDelegate { NSArray* _command_line; NSURL* _fifo_url; NSRunningApplication* _running_app; } - (instancetype)initWithCommandLine:(NSArray*)command_line { self = [super init]; if (self) { _command_line = command_line; NSURL* bundle_url = NSBundle.mainBundle.bundleURL; _fifo_url = [bundle_url.URLByDeletingLastPathComponent URLByAppendingPathComponent: [bundle_url.lastPathComponent stringByReplacingOccurrencesOfString:@".app" withString:@".fifo"]]; _running_app = NSRunningApplication.currentApplication; [_running_app addObserver:self forKeyPath:@"activationPolicy" options:NSKeyValueObservingOptionNew context:nil]; } return self; } - (void)dealloc { [_running_app removeObserver:self forKeyPath:@"activationPolicy" context:nil]; } - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context { [self addLaunchEvent:@"activationPolicyChanged" withData:@{ @"activationPolicy" : change[@"new"], @"processIdentifier" : @(NSRunningApplication.currentApplication.processIdentifier), }]; } - (void)applicationDidFinishLaunching:(NSNotification*)notification { [self addLaunchEvent:@"applicationDidFinishLaunching" withData:@{ @"activationPolicy" : @(NSApp.activationPolicy), @"commandLine" : _command_line, @"processIdentifier" : @(NSRunningApplication.currentApplication.processIdentifier), }]; } - (void)application:(NSApplication*)app openURLs:(NSArray*)urls { [app replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; NSMutableArray* url_specs = [[NSMutableArray alloc] initWithCapacity:urls.count]; for (NSURL* url in urls) { [url_specs addObject:url.absoluteString]; } [self addLaunchEvent:@"openURLs" withData:@{ @"activationPolicy" : @(NSApp.activationPolicy), @"processIdentifier" : @(NSRunningApplication.currentApplication.processIdentifier), @"urls" : url_specs, }]; } - (void)addLaunchEvent:(NSString*)event { [self addLaunchEvent:event withData:nil]; } - (void)addLaunchEvent:(NSString*)event withData:(NSDictionary*)data { NSLog(@"Logging %@ with data %@", event, data); NSDictionary* event_dict = @{ @"name" : event, @"data" : data, }; // It is important to write this dictionary to the named pipe non-atomically, // as otherwise the write would replace the named pipe with a regular file // rather than writing to the pipe. NSData* plist_data = [NSPropertyListSerialization dataWithPropertyList:event_dict format:NSPropertyListXMLFormat_v1_0 options:0 error:nil]; [plist_data writeToURL:_fifo_url options:0 error:nil]; } @end __attribute__((visibility("default"))) int main(int argc, char** argv) { [NSApplication sharedApplication]; NSMutableArray* command_line = [[NSMutableArray alloc] initWithCapacity:argc]; for (int i = 0; i < argc; ++i) { [command_line addObject:[NSString stringWithUTF8String:argv[i]]]; } AppDelegate* delegate = [[AppDelegate alloc] initWithCommandLine:command_line]; NSApp.delegate = delegate; [NSApp run]; return 0; }