1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130

base / mac / test / launch_application_test_helper_main.m [blame]

// 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 <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
@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<NSURL*>*)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;
}