6 #import <Foundation/Foundation.h>
7 #import <Security/SecExperimentPriv.h>
8 #import <Security/SecTrustPriv.h>
9 #import <CoreFoundation/CFXPCBridge.h>
12 static NSString *kExperimentRunResultKeySkips = @"Skips";
13 static NSString *kExperimentRunResultKeyConfigurations = @"Configurations";
14 static NSString *kExperimentRunResultKeyRuns = @"Runs";
16 static NSDictionary<NSString *, NSObject *> *
17 run_experiment(const char *experiment_name, size_t num_runs, bool sampling_disabled)
19 __block size_t runs = 0;
20 __block size_t skips = 0;
21 __block NSMutableArray<NSDictionary *> *configurations = [[NSMutableArray<NSDictionary *> alloc] init];
22 for (size_t i = 0; i < num_runs; i++) {
23 (void)sec_experiment_run_with_sampling_disabled(experiment_name, ^bool(const char *identifier, xpc_object_t experiment_config) {
25 NSDictionary* configuration = (__bridge_transfer NSDictionary*)_CFXPCCreateCFObjectFromXPCObject(experiment_config);
26 if (configuration != NULL) {
27 [configurations addObject:configuration];
30 }, ^(const char * _Nonnull identifier) {
32 }, sampling_disabled);
35 return @{kExperimentRunResultKeyRuns: @(runs),
36 kExperimentRunResultKeySkips: @(skips),
37 kExperimentRunResultKeyConfigurations: configurations,
42 usage(const char *argv[])
44 fprintf(stderr, "Usage: %s [-h] [-s] [-e <experiment>] [-n <number of runs>]\n", argv[0]);
48 main(int argc, const char *argv[])
52 char * const *gargv = (char * const *)argv;
53 char *experiment_name = NULL;
55 bool sampling_disabled = true;
56 bool update_asset = false;
57 bool read_asset = false;
58 while ((arg = getopt(argc, gargv, "e:n:sruh")) != -1) {
61 free(experiment_name); // Only the last instance of -e counts
62 experiment_name = strdup(optarg);
65 num_runs = (size_t)atoi(optarg);
68 sampling_disabled = false;
80 fprintf(stderr, "%s: FAILURE: unknown option \"%c\"\n", argv[0], arg);
81 free(experiment_name);
87 fprintf(stderr, "%s: FAILURE: argument missing parameter \"%c\"\n", argv[0], arg);
88 free(experiment_name);
94 free(experiment_name);
100 CFErrorRef update_error = NULL;
101 version = SecTrustOTASecExperimentGetUpdatedAsset(&update_error);
102 if (update_error != NULL) {
103 NSLog(@"Failed to fetch latest asset: %@", (__bridge NSError *)update_error);
104 free(experiment_name);
107 NSLog(@"Fetched asset version: %zu", (size_t)version);
112 CFErrorRef copy_error = NULL;
113 NSDictionary *asset = CFBridgingRelease(SecTrustOTASecExperimentCopyAsset(©_error));
114 if (copy_error != NULL) {
115 NSLog(@"Failed to copy asset: %@", copy_error);
116 free(experiment_name);
119 NSLog(@"Copied asset: %@", asset);
124 NSLog(@"Running %zu experiments with asset verison %llu", num_runs, version);
125 NSDictionary<NSString *, NSObject *> *results = run_experiment(experiment_name, num_runs, sampling_disabled);
126 [results enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSObject * _Nonnull obj, BOOL * _Nonnull stop) {
127 NSLog(@"Experiment %@: %@", key, obj);
130 NSLog(@"Not running experiment.");
133 free(experiment_name);