1// Copyright 2023 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifdef UNSAFE_BUFFERS_BUILD 6// TODO(crbug.com/40284755): Remove this and spanify to fix the errors. 7#pragma allow_unsafe_buffers 8#endif 9 10// This is a helper application for launch_application_unittest.mm. This 11// application records several events by writing them to a named pipe; 12// the unit tests then use this information to verify that this helper was 13// launched in the correct manner. 14// The named pipe this writes to is equal to the name of the app bundle, 15// with .app replaced by .fifo. 16 17#import <Cocoa/Cocoa.h> 18 19@interface AppDelegate : NSObject <NSApplicationDelegate> 20@end 21 22@implementation AppDelegate { 23 NSArray* _command_line; 24 NSURL* _fifo_url; 25 NSRunningApplication* _running_app; 26} 27 28- (instancetype)initWithCommandLine:(NSArray*)command_line { 29 self = [super init]; 30 if (self) { 31 _command_line = command_line; 32 NSURL* bundle_url = NSBundle.mainBundle.bundleURL; 33 _fifo_url = [bundle_url.URLByDeletingLastPathComponent 34 URLByAppendingPathComponent: 35 [bundle_url.lastPathComponent 36 stringByReplacingOccurrencesOfString:@".app" 37 withString:@".fifo"]]; 38 _running_app = NSRunningApplication.currentApplication; 39 [_running_app addObserver:self 40 forKeyPath:@"activationPolicy" 41 options:NSKeyValueObservingOptionNew 42 context:nil]; 43 } 44 return self; 45} 46 47- (void)dealloc { 48 [_running_app removeObserver:self forKeyPath:@"activationPolicy" context:nil]; 49} 50 51- (void)observeValueForKeyPath:(NSString*)keyPath 52 ofObject:(id)object 53 change:(NSDictionary*)change 54 context:(void*)context { 55 [self 56 addLaunchEvent:@"activationPolicyChanged" 57 withData:@{ 58 @"activationPolicy" : change[@"new"], 59 @"processIdentifier" : 60 @(NSRunningApplication.currentApplication.processIdentifier), 61 }]; 62} 63 64- (void)applicationDidFinishLaunching:(NSNotification*)notification { 65 [self 66 addLaunchEvent:@"applicationDidFinishLaunching" 67 withData:@{ 68 @"activationPolicy" : @(NSApp.activationPolicy), 69 @"commandLine" : _command_line, 70 @"processIdentifier" : 71 @(NSRunningApplication.currentApplication.processIdentifier), 72 }]; 73} 74 75- (void)application:(NSApplication*)app openURLs:(NSArray<NSURL*>*)urls { 76 [app replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; 77 78 NSMutableArray* url_specs = 79 [[NSMutableArray alloc] initWithCapacity:urls.count]; 80 for (NSURL* url in urls) { 81 [url_specs addObject:url.absoluteString]; 82 } 83 [self 84 addLaunchEvent:@"openURLs" 85 withData:@{ 86 @"activationPolicy" : @(NSApp.activationPolicy), 87 @"processIdentifier" : 88 @(NSRunningApplication.currentApplication.processIdentifier), 89 @"urls" : url_specs, 90 }]; 91} 92 93- (void)addLaunchEvent:(NSString*)event { 94 [self addLaunchEvent:event withData:nil]; 95} 96 97- (void)addLaunchEvent:(NSString*)event withData:(NSDictionary*)data { 98 NSLog(@"Logging %@ with data %@", event, data); 99 NSDictionary* event_dict = @{ 100 @"name" : event, 101 @"data" : data, 102 }; 103 // It is important to write this dictionary to the named pipe non-atomically, 104 // as otherwise the write would replace the named pipe with a regular file 105 // rather than writing to the pipe. 106 NSData* plist_data = [NSPropertyListSerialization 107 dataWithPropertyList:event_dict 108 format:NSPropertyListXMLFormat_v1_0 109 options:0 110 error:nil]; 111 [plist_data writeToURL:_fifo_url options:0 error:nil]; 112} 113 114@end 115 116__attribute__((visibility("default"))) int main(int argc, char** argv) { 117 [NSApplication sharedApplication]; 118 119 NSMutableArray* command_line = [[NSMutableArray alloc] initWithCapacity:argc]; 120 for (int i = 0; i < argc; ++i) { 121 [command_line addObject:[NSString stringWithUTF8String:argv[i]]]; 122 } 123 124 AppDelegate* delegate = 125 [[AppDelegate alloc] initWithCommandLine:command_line]; 126 NSApp.delegate = delegate; 127 128 [NSApp run]; 129 return 0; 130} 131