//
// experimentTool.m
// experimentTool
//
#import <Foundation/Foundation.h>
#import <Security/SecExperimentPriv.h>
#import <Security/SecTrustPriv.h>
#import <CoreFoundation/CFXPCBridge.h>
#import <xpc/xpc.h>
static NSString *kExperimentRunResultKeySkips = @"Skips";
static NSString *kExperimentRunResultKeyConfigurations = @"Configurations";
static NSString *kExperimentRunResultKeyRuns = @"Runs";
static NSDictionary<NSString *, NSObject *> *
run_experiment(const char *experiment_name, size_t num_runs, bool sampling_disabled)
{
__block size_t runs = 0;
__block size_t skips = 0;
__block NSMutableArray<NSDictionary *> *configurations = [[NSMutableArray<NSDictionary *> alloc] init];
for (size_t i = 0; i < num_runs; i++) {
(void)sec_experiment_run_with_sampling_disabled(experiment_name, ^bool(const char *identifier, xpc_object_t experiment_config) {
runs++;
NSDictionary* configuration = (__bridge_transfer NSDictionary*)_CFXPCCreateCFObjectFromXPCObject(experiment_config);
if (configuration != NULL) {
[configurations addObject:configuration];
}
return true;
}, ^(const char * _Nonnull identifier) {
skips++;
}, sampling_disabled);
}
return @{kExperimentRunResultKeyRuns: @(runs),
kExperimentRunResultKeySkips: @(skips),
kExperimentRunResultKeyConfigurations: configurations,
};
}
static void
usage(const char *argv[])
{
fprintf(stderr, "Usage: }
int
main(int argc, const char *argv[])
{
BOOL showUsage = NO;
int arg = 0;
char * const *gargv = (char * const *)argv;
char *experiment_name = NULL;
size_t num_runs = 0;
bool sampling_disabled = true;
bool update_asset = false;
bool read_asset = false;
while ((arg = getopt(argc, gargv, "e:n:sruh")) != -1) {
switch (arg) {
case 'e':
free(experiment_name); // Only the last instance of -e counts
experiment_name = strdup(optarg);
break;
case 'n':
num_runs = (size_t)atoi(optarg);
break;
case 's':
sampling_disabled = false;
break;
case 'r':
read_asset = true;
break;
case 'u':
update_asset = true;
break;
case 'h':
showUsage = YES;
break;
default:
fprintf(stderr, " free(experiment_name);
return -1;
}
}
if (optind != argc) {
fprintf(stderr, " free(experiment_name);
return -2;
}
if (showUsage) {
usage(argv);
free(experiment_name);
return EXIT_SUCCESS;
}
uint64_t version = 0;
if (update_asset) {
CFErrorRef update_error = NULL;
version = SecTrustOTASecExperimentGetUpdatedAsset(&update_error);
if (update_error != NULL) {
NSLog(@"Failed to fetch latest asset: free(experiment_name);
return -3;
} else {
NSLog(@"Fetched asset version: }
}
if (read_asset) {
CFErrorRef copy_error = NULL;
NSDictionary *asset = CFBridgingRelease(SecTrustOTASecExperimentCopyAsset(©_error));
if (copy_error != NULL) {
NSLog(@"Failed to copy asset: free(experiment_name);
return -4;
} else {
NSLog(@"Copied asset: }
}
if (num_runs > 0) {
NSLog(@"Running NSDictionary<NSString *, NSObject *> *results = run_experiment(experiment_name, num_runs, sampling_disabled);
[results enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSObject * _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"Experiment }];
} else {
NSLog(@"Not running experiment.");
}
free(experiment_name);
return EXIT_SUCCESS;
}