Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm
Line
Count
Source (jump to first uncovered line)
1
//===-- PlatformiOSSimulatorCoreSimulatorSupport.cpp ----------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "PlatformiOSSimulatorCoreSimulatorSupport.h"
10
11
// C Includes
12
// C++ Includes
13
// Other libraries and framework includes
14
#include <CoreFoundation/CoreFoundation.h>
15
#include <Foundation/Foundation.h>
16
// Project includes
17
#include "lldb/Host/PseudoTerminal.h"
18
#include "lldb/Host/FileAction.h"
19
20
#include "llvm/ADT/StringRef.h"
21
22
using namespace lldb_private;
23
// CoreSimulator lives as part of Xcode, which means we can't really link
24
// against it, so we dlopen()
25
// it at runtime, and error out nicely if that fails
26
@interface SimServiceContext {
27
}
28
+ (id)sharedServiceContextForDeveloperDir:(NSString *)dir
29
                                    error:(NSError **)error;
30
@end
31
// However, the drawback is that the compiler will not know about the selectors
32
// we're trying to use
33
// until runtime; to appease clang in this regard, define a fake protocol on
34
// NSObject that exposes
35
// the needed interface names for us
36
@protocol LLDBCoreSimulatorSupport <NSObject>
37
- (id)defaultDeviceSetWithError:(NSError **)error;
38
- (NSArray *)devices;
39
- (id)deviceType;
40
- (NSString *)name;
41
- (NSString *)identifier;
42
- (NSString *)modelIdentifier;
43
- (NSString *)productFamily;
44
- (int32_t)productFamilyID;
45
- (id)runtime;
46
- (BOOL)available;
47
- (NSString *)versionString;
48
- (NSString *)buildVersionString;
49
- (BOOL)bootWithOptions:(NSDictionary *)options error:(NSError **)error;
50
- (NSUInteger)state;
51
- (BOOL)shutdownWithError:(NSError **)error;
52
- (NSUUID *)UDID;
53
- (BOOL)spawnWithPath:(NSString *)path
54
               options:(nullable NSDictionary<NSString *, id> *)options
55
      terminationQueue:(nullable dispatch_queue_t)terminationQueue
56
    terminationHandler:(nullable void (^)(int status))terminationHandler
57
                   pid:(pid_t *_Nullable)pid
58
                 error:(NSError *__autoreleasing _Nullable *_Nullable)error;
59
@end
60
61
0
CoreSimulatorSupport::Process::Process(lldb::pid_t p) : m_pid(p), m_error() {}
62
63
CoreSimulatorSupport::Process::Process(Status error)
64
0
    : m_pid(LLDB_INVALID_PROCESS_ID), m_error(error) {}
65
66
CoreSimulatorSupport::Process::Process(lldb::pid_t p, Status error)
67
0
    : m_pid(p), m_error(error) {}
68
69
0
CoreSimulatorSupport::DeviceType::DeviceType() : m_model_identifier() {}
70
71
CoreSimulatorSupport::DeviceType::DeviceType(id d)
72
0
    : m_dev(d), m_model_identifier() {}
73
74
0
CoreSimulatorSupport::DeviceType::operator bool() { return m_dev != nil; }
75
76
0
ConstString CoreSimulatorSupport::DeviceType::GetIdentifier() {
77
0
  return ConstString([[m_dev identifier] UTF8String]);
78
0
}
79
80
0
ConstString CoreSimulatorSupport::DeviceType::GetProductFamily() {
81
0
  return ConstString([[m_dev productFamily] UTF8String]);
82
0
}
83
84
CoreSimulatorSupport::DeviceType::ProductFamilyID
85
0
CoreSimulatorSupport::DeviceType::GetProductFamilyID() {
86
0
  return ProductFamilyID([m_dev productFamilyID]);
87
0
}
88
89
0
CoreSimulatorSupport::DeviceRuntime::DeviceRuntime() : m_os_version() {}
90
91
CoreSimulatorSupport::DeviceRuntime::DeviceRuntime(id d)
92
0
    : m_dev(d), m_os_version() {}
93
94
0
CoreSimulatorSupport::DeviceRuntime::operator bool() { return m_dev != nil; }
95
96
0
bool CoreSimulatorSupport::DeviceRuntime::IsAvailable() {
97
0
  return [m_dev available];
98
0
}
99
100
0
CoreSimulatorSupport::Device::Device() : m_dev_type(), m_dev_runtime() {}
101
102
CoreSimulatorSupport::Device::Device(id d)
103
0
    : m_dev(d), m_dev_type(), m_dev_runtime() {}
104
105
0
CoreSimulatorSupport::Device::operator bool() { return m_dev != nil; }
106
107
0
CoreSimulatorSupport::Device::State CoreSimulatorSupport::Device::GetState() {
108
0
  return (State)([m_dev state]);
109
0
}
110
111
CoreSimulatorSupport::ModelIdentifier::ModelIdentifier(const std::string &mi)
112
0
    : m_family(), m_versions() {
113
0
  bool first_digit = false;
114
0
  unsigned int val = 0;
115
116
0
  for (char c : mi) {
117
0
    if (::isdigit(c)) {
118
0
      if (!first_digit)
119
0
        first_digit = true;
120
0
      val = 10 * val + (c - '0');
121
0
    } else if (c == ',') {
122
0
      if (first_digit) {
123
0
        m_versions.push_back(val);
124
0
        val = 0;
125
0
      } else
126
0
        m_family.push_back(c);
127
0
    } else {
128
0
      if (first_digit) {
129
0
        m_family.clear();
130
0
        m_versions.clear();
131
0
        return;
132
0
      } else {
133
0
        m_family.push_back(c);
134
0
      }
135
0
    }
136
0
  }
137
138
0
  if (first_digit)
139
0
    m_versions.push_back(val);
140
0
}
141
142
CoreSimulatorSupport::ModelIdentifier::ModelIdentifier()
143
0
    : ModelIdentifier("") {}
Unexecuted instantiation: CoreSimulatorSupport::ModelIdentifier::ModelIdentifier()
Unexecuted instantiation: CoreSimulatorSupport::ModelIdentifier::ModelIdentifier()
144
145
CoreSimulatorSupport::OSVersion::OSVersion(const std::string &ver,
146
                                           const std::string &build)
147
0
    : m_versions(), m_build(build) {
148
0
  bool any = false;
149
0
  unsigned int val = 0;
150
0
  for (char c : ver) {
151
0
    if (c == '.') {
152
0
      m_versions.push_back(val);
153
0
      val = 0;
154
0
    } else if (::isdigit(c)) {
155
0
      val = 10 * val + (c - '0');
156
0
      any = true;
157
0
    } else {
158
0
      m_versions.clear();
159
0
      return;
160
0
    }
161
0
  }
162
0
  if (any)
163
0
    m_versions.push_back(val);
164
0
}
165
166
0
CoreSimulatorSupport::OSVersion::OSVersion() : OSVersion("", "") {}
Unexecuted instantiation: CoreSimulatorSupport::OSVersion::OSVersion()
Unexecuted instantiation: CoreSimulatorSupport::OSVersion::OSVersion()
167
168
CoreSimulatorSupport::ModelIdentifier
169
0
CoreSimulatorSupport::DeviceType::GetModelIdentifier() {
170
0
  if (!m_model_identifier.hasValue()) {
171
0
    auto utf8_model_id = [[m_dev modelIdentifier] UTF8String];
172
0
    if (utf8_model_id && *utf8_model_id)
173
0
      m_model_identifier = ModelIdentifier(utf8_model_id);
174
0
  }
175
176
0
  if (m_model_identifier.hasValue())
177
0
    return m_model_identifier.getValue();
178
0
  else
179
0
    return ModelIdentifier();
180
0
}
181
182
CoreSimulatorSupport::OSVersion
183
0
CoreSimulatorSupport::DeviceRuntime::GetVersion() {
184
0
  if (!m_os_version.hasValue()) {
185
0
    auto utf8_ver_string = [[m_dev versionString] UTF8String];
186
0
    auto utf8_build_ver = [[m_dev buildVersionString] UTF8String];
187
0
    if (utf8_ver_string && *utf8_ver_string && utf8_build_ver &&
188
0
        *utf8_build_ver) {
189
0
      m_os_version = OSVersion(utf8_ver_string, utf8_build_ver);
190
0
    }
191
0
  }
192
193
0
  if (m_os_version.hasValue())
194
0
    return m_os_version.getValue();
195
0
  return OSVersion();
196
0
}
197
198
0
std::string CoreSimulatorSupport::DeviceType::GetName() {
199
0
  auto utf8_name = [[m_dev name] UTF8String];
200
0
  if (utf8_name)
201
0
    return std::string(utf8_name);
202
0
  return "";
203
0
}
204
205
0
std::string CoreSimulatorSupport::Device::GetName() const {
206
0
  auto utf8_name = [[m_dev name] UTF8String];
207
0
  if (utf8_name)
208
0
    return std::string(utf8_name);
209
0
  return "";
210
0
}
211
212
0
std::string CoreSimulatorSupport::Device::GetUDID() const {
213
0
  auto utf8_udid = [[[m_dev UDID] UUIDString] UTF8String];
214
0
  if (utf8_udid)
215
0
    return std::string(utf8_udid);
216
0
  else
217
0
    return std::string();
218
0
}
219
220
0
CoreSimulatorSupport::DeviceType CoreSimulatorSupport::Device::GetDeviceType() {
221
0
  if (!m_dev_type.hasValue())
222
0
    m_dev_type = DeviceType([m_dev deviceType]);
223
224
0
  return m_dev_type.getValue();
225
0
}
226
227
CoreSimulatorSupport::DeviceRuntime
228
0
CoreSimulatorSupport::Device::GetDeviceRuntime() {
229
0
  if (!m_dev_runtime.hasValue())
230
0
    m_dev_runtime = DeviceRuntime([m_dev runtime]);
231
232
0
  return m_dev_runtime.getValue();
233
0
}
234
235
bool CoreSimulatorSupport::
236
operator>(const CoreSimulatorSupport::OSVersion &lhs,
237
0
          const CoreSimulatorSupport::OSVersion &rhs) {
238
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
239
0
    unsigned int l = lhs.GetVersionAtIndex(i);
240
0
    unsigned int r = rhs.GetVersionAtIndex(i);
241
0
    if (l > r)
242
0
      return true;
243
0
  }
244
0
  return false;
245
0
}
246
247
bool CoreSimulatorSupport::
248
operator>(const CoreSimulatorSupport::ModelIdentifier &lhs,
249
0
          const CoreSimulatorSupport::ModelIdentifier &rhs) {
250
0
  if (lhs.GetFamily() != rhs.GetFamily())
251
0
    return false;
252
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
253
0
    unsigned int l = lhs.GetVersionAtIndex(i);
254
0
    unsigned int r = rhs.GetVersionAtIndex(i);
255
0
    if (l > r)
256
0
      return true;
257
0
  }
258
0
  return false;
259
0
}
260
261
bool CoreSimulatorSupport::
262
operator<(const CoreSimulatorSupport::OSVersion &lhs,
263
0
          const CoreSimulatorSupport::OSVersion &rhs) {
264
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
265
0
    unsigned int l = lhs.GetVersionAtIndex(i);
266
0
    unsigned int r = rhs.GetVersionAtIndex(i);
267
0
    if (l < r)
268
0
      return true;
269
0
  }
270
0
  return false;
271
0
}
272
273
bool CoreSimulatorSupport::
274
operator<(const CoreSimulatorSupport::ModelIdentifier &lhs,
275
0
          const CoreSimulatorSupport::ModelIdentifier &rhs) {
276
0
  if (lhs.GetFamily() != rhs.GetFamily())
277
0
    return false;
278
279
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
280
0
    unsigned int l = lhs.GetVersionAtIndex(i);
281
0
    unsigned int r = rhs.GetVersionAtIndex(i);
282
0
    if (l < r)
283
0
      return true;
284
0
  }
285
0
  return false;
286
0
}
287
288
bool CoreSimulatorSupport::
289
operator==(const CoreSimulatorSupport::OSVersion &lhs,
290
0
           const CoreSimulatorSupport::OSVersion &rhs) {
291
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
292
0
    unsigned int l = lhs.GetVersionAtIndex(i);
293
0
    unsigned int r = rhs.GetVersionAtIndex(i);
294
0
    if (l != r)
295
0
      return false;
296
0
  }
297
0
  return true;
298
0
}
299
300
bool CoreSimulatorSupport::
301
operator==(const CoreSimulatorSupport::ModelIdentifier &lhs,
302
0
           const CoreSimulatorSupport::ModelIdentifier &rhs) {
303
0
  if (lhs.GetFamily() != rhs.GetFamily())
304
0
    return false;
305
306
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
307
0
    unsigned int l = lhs.GetVersionAtIndex(i);
308
0
    unsigned int r = rhs.GetVersionAtIndex(i);
309
0
    if (l != r)
310
0
      return false;
311
0
  }
312
0
  return true;
313
0
}
314
315
bool CoreSimulatorSupport::
316
operator!=(const CoreSimulatorSupport::OSVersion &lhs,
317
0
           const CoreSimulatorSupport::OSVersion &rhs) {
318
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
319
0
    unsigned int l = lhs.GetVersionAtIndex(i);
320
0
    unsigned int r = rhs.GetVersionAtIndex(i);
321
0
    if (l != r)
322
0
      return true;
323
0
  }
324
0
  return false;
325
0
}
326
327
bool CoreSimulatorSupport::
328
operator!=(const CoreSimulatorSupport::ModelIdentifier &lhs,
329
0
           const CoreSimulatorSupport::ModelIdentifier &rhs) {
330
0
  if (lhs.GetFamily() != rhs.GetFamily())
331
0
    return false;
332
333
0
  for (size_t i = 0; i < rhs.GetNumVersions(); i++) {
334
0
    unsigned int l = lhs.GetVersionAtIndex(i);
335
0
    unsigned int r = rhs.GetVersionAtIndex(i);
336
0
    if (l != r)
337
0
      return true;
338
0
  }
339
0
  return false;
340
0
}
341
342
0
bool CoreSimulatorSupport::Device::Boot(Status &err) {
343
0
  if (m_dev == nil) {
344
0
    err.SetErrorString("no valid simulator instance");
345
0
    return false;
346
0
  }
347
348
0
#define kSimDeviceBootPersist                                                  \
349
0
  @"persist" /* An NSNumber (boolean) indicating whether or not the session    \
350
                should outlive the calling process (default false) */
351
352
0
  NSDictionary *options = @{
353
0
    kSimDeviceBootPersist : @NO,
354
0
  };
355
356
0
#undef kSimDeviceBootPersist
357
358
0
  NSError *nserror;
359
0
  if ([m_dev bootWithOptions:options error:&nserror]) {
360
0
    err.Clear();
361
0
    return true;
362
0
  } else {
363
0
    err.SetErrorString([[nserror description] UTF8String]);
364
0
    return false;
365
0
  }
366
0
}
367
368
0
bool CoreSimulatorSupport::Device::Shutdown(Status &err) {
369
0
  NSError *nserror;
370
0
  if ([m_dev shutdownWithError:&nserror]) {
371
0
    err.Clear();
372
0
    return true;
373
0
  } else {
374
0
    err.SetErrorString([[nserror description] UTF8String]);
375
0
    return false;
376
0
  }
377
0
}
378
379
static Status HandleFileAction(ProcessLaunchInfo &launch_info,
380
                               NSMutableDictionary *options, NSString *key,
381
0
                               const int fd, lldb::FileSP &file) {
382
0
  Status error;
383
0
  const FileAction *file_action = launch_info.GetFileActionForFD(fd);
384
0
  if (file_action) {
385
0
    switch (file_action->GetAction()) {
386
0
    case FileAction::eFileActionNone:
387
0
      break;
388
389
0
    case FileAction::eFileActionClose:
390
0
      error.SetErrorStringWithFormat("close file action for %i not supported",
391
0
                                     fd);
392
0
      break;
393
394
0
    case FileAction::eFileActionDuplicate:
395
0
      error.SetErrorStringWithFormat(
396
0
          "duplication file action for %i not supported", fd);
397
0
      break;
398
399
0
    case FileAction::eFileActionOpen: {
400
0
      FileSpec file_spec = file_action->GetFileSpec();
401
0
      if (file_spec) {
402
0
        const int primary_fd = launch_info.GetPTY().GetPrimaryFileDescriptor();
403
0
        if (primary_fd != PseudoTerminal::invalid_fd) {
404
          // Check in case our file action open wants to open the secondary
405
0
          FileSpec secondary_spec(launch_info.GetPTY().GetSecondaryName());
406
0
          if (file_spec == secondary_spec) {
407
0
            int secondary_fd =
408
0
                launch_info.GetPTY().GetSecondaryFileDescriptor();
409
0
            if (secondary_fd == PseudoTerminal::invalid_fd) {
410
0
              if (llvm::Error Err = launch_info.GetPTY().OpenSecondary(O_RDWR))
411
0
                return Status(std::move(Err));
412
0
            }
413
0
            secondary_fd = launch_info.GetPTY().GetSecondaryFileDescriptor();
414
0
            assert(secondary_fd != PseudoTerminal::invalid_fd);
415
0
            [options setValue:[NSNumber numberWithInteger:secondary_fd]
416
0
                       forKey:key];
417
0
            return error; // Success
418
0
          }
419
0
        }
420
0
        Status posix_error;
421
0
        int oflag = file_action->GetActionArgument();
422
0
        int created_fd =
423
0
            open(file_spec.GetPath().c_str(), oflag, S_IRUSR | S_IWUSR);
424
0
        if (created_fd >= 0) {
425
0
          auto file_options = File::OpenOptions(0);
426
0
          if (oflag & O_RDWR)
427
0
            file_options |= File::eOpenOptionReadWrite;
428
0
          else if (oflag & O_WRONLY)
429
0
            file_options |= File::eOpenOptionWriteOnly;
430
0
          else if (oflag & O_RDONLY)
431
0
            file_options |= File::eOpenOptionReadOnly;
432
0
          file = std::make_shared<NativeFile>(created_fd, file_options, true);
433
0
          [options setValue:[NSNumber numberWithInteger:created_fd] forKey:key];
434
0
          return error; // Success
435
0
        } else {
436
0
          posix_error.SetErrorToErrno();
437
0
          error.SetErrorStringWithFormat("unable to open file '%s': %s",
438
0
                                         file_spec.GetPath().c_str(),
439
0
                                         posix_error.AsCString());
440
0
        }
441
0
      }
442
0
    } break;
443
0
    }
444
0
  }
445
0
  return error; // Success, no file action, nothing to do
446
0
}
447
448
CoreSimulatorSupport::Process
449
0
CoreSimulatorSupport::Device::Spawn(ProcessLaunchInfo &launch_info) {
450
0
#define kSimDeviceSpawnEnvironment                                             \
451
0
  @"environment" /* An NSDictionary (NSStrings -> NSStrings) of environment    \
452
                    key/values */
453
0
#define kSimDeviceSpawnStdin @"stdin"   /* An NSNumber corresponding to a fd */
454
0
#define kSimDeviceSpawnStdout @"stdout" /* An NSNumber corresponding to a fd   \
455
                                           */
456
0
#define kSimDeviceSpawnStderr @"stderr" /* An NSNumber corresponding to a fd   \
457
                                           */
458
0
#define kSimDeviceSpawnArguments                                               \
459
0
  @"arguments" /* An NSArray of strings to use as the argv array.  If not      \
460
                  provided, path will be argv[0] */
461
0
#define kSimDeviceSpawnWaitForDebugger                                         \
462
0
  @"wait_for_debugger" /* An NSNumber (bool) */
463
0
#define kSimDeviceSpawnStandalone @"standalone"
464
465
0
  NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
466
467
0
  options[kSimDeviceSpawnStandalone] = @(YES);
468
469
0
  if (launch_info.GetFlags().Test(lldb::eLaunchFlagDebug))
470
0
    [options setObject:@YES forKey:kSimDeviceSpawnWaitForDebugger];
471
472
0
  if (launch_info.GetArguments().GetArgumentCount()) {
473
0
    const Args &args(launch_info.GetArguments());
474
0
    NSMutableArray *args_array = [[NSMutableArray alloc] init];
475
0
    for (size_t idx = 0; idx < args.GetArgumentCount(); idx++)
476
0
      [args_array
477
0
          addObject:[NSString
478
0
                        stringWithUTF8String:args.GetArgumentAtIndex(idx)]];
479
480
0
    [options setObject:args_array forKey:kSimDeviceSpawnArguments];
481
0
  }
482
483
0
  NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init];
484
485
0
  for (const auto &KV : launch_info.GetEnvironment()) {
486
0
    NSString *key_ns = [NSString stringWithUTF8String:KV.first().str().c_str()];
487
0
    NSString *value_ns = [NSString stringWithUTF8String:KV.second.c_str()];
488
489
0
    [env_dict setValue:value_ns forKey:key_ns];
490
0
  }
491
492
0
  [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment];
493
494
0
  Status error;
495
0
  lldb::FileSP stdin_file;
496
0
  lldb::FileSP stdout_file;
497
0
  lldb::FileSP stderr_file;
498
0
  error = HandleFileAction(launch_info, options, kSimDeviceSpawnStdin,
499
0
                           STDIN_FILENO, stdin_file);
500
501
0
  if (error.Fail())
502
0
    return CoreSimulatorSupport::Process(error);
503
504
0
  error = HandleFileAction(launch_info, options, kSimDeviceSpawnStdout,
505
0
                           STDOUT_FILENO, stdout_file);
506
507
0
  if (error.Fail())
508
0
    return CoreSimulatorSupport::Process(error);
509
510
0
  error = HandleFileAction(launch_info, options, kSimDeviceSpawnStderr,
511
0
                           STDERR_FILENO, stderr_file);
512
513
0
  if (error.Fail())
514
0
    return CoreSimulatorSupport::Process(error);
515
516
0
#undef kSimDeviceSpawnEnvironment
517
0
#undef kSimDeviceSpawnStdin
518
0
#undef kSimDeviceSpawnStdout
519
0
#undef kSimDeviceSpawnStderr
520
0
#undef kSimDeviceSpawnWaitForDebugger
521
0
#undef kSimDeviceSpawnArguments
522
523
0
  NSError *nserror;
524
525
0
  pid_t pid;
526
0
  BOOL success = [m_dev
527
0
           spawnWithPath:[NSString stringWithUTF8String:launch_info
528
0
                                                            .GetExecutableFile()
529
0
                                                            .GetPath()
530
0
                                                            .c_str()]
531
0
                 options:options
532
0
        terminationQueue:nil
533
0
      terminationHandler:nil
534
0
                     pid:&pid
535
0
                   error:&nserror];
536
537
0
  if (!success) {
538
0
    const char *nserror_string = [[nserror description] UTF8String];
539
0
    error.SetErrorString(nserror_string ? nserror_string : "unable to launch");
540
0
  }
541
542
0
  return CoreSimulatorSupport::Process(pid, error);
543
0
}
544
545
CoreSimulatorSupport::DeviceSet
546
0
CoreSimulatorSupport::DeviceSet::GetAllDevices(const char *developer_dir) {
547
0
  if (!developer_dir || !developer_dir[0])
548
0
    return DeviceSet([NSArray new]);
549
550
0
  Class SimServiceContextClass = NSClassFromString(@"SimServiceContext");
551
0
  NSString *dev_dir = @(developer_dir);
552
0
  NSError *error = nil;
553
554
0
  id serviceContext =
555
0
      [SimServiceContextClass sharedServiceContextForDeveloperDir:dev_dir
556
0
                                                            error:&error];
557
0
  if (!serviceContext)
558
0
    return DeviceSet([NSArray new]);
559
560
0
  return DeviceSet([[serviceContext defaultDeviceSetWithError:&error] devices]);
561
0
}
562
563
CoreSimulatorSupport::DeviceSet
564
CoreSimulatorSupport::DeviceSet::GetAvailableDevices(
565
0
    const char *developer_dir) {
566
0
  return GetAllDevices(developer_dir).GetDevicesIf([](Device d) -> bool {
567
0
    return (d && d.GetDeviceType() && d.GetDeviceRuntime() &&
568
0
            d.GetDeviceRuntime().IsAvailable());
569
0
  });
570
0
}
571
572
0
size_t CoreSimulatorSupport::DeviceSet::GetNumDevices() {
573
0
  return [m_dev count];
574
0
}
575
576
CoreSimulatorSupport::Device
577
0
CoreSimulatorSupport::DeviceSet::GetDeviceAtIndex(size_t idx) {
578
0
  if (idx < GetNumDevices())
579
0
    return Device([m_dev objectAtIndex:idx]);
580
0
  return Device();
581
0
}
582
583
CoreSimulatorSupport::DeviceSet CoreSimulatorSupport::DeviceSet::GetDevicesIf(
584
0
    std::function<bool(CoreSimulatorSupport::Device)> f) {
585
0
  NSMutableArray *array = [[NSMutableArray alloc] init];
586
0
  for (NSUInteger i = 0; i < GetNumDevices(); i++) {
587
0
    Device d(GetDeviceAtIndex(i));
588
0
    if (f(d))
589
0
      [array addObject:(id)d.m_dev];
590
0
  }
591
592
0
  return DeviceSet(array);
593
0
}
594
595
void CoreSimulatorSupport::DeviceSet::ForEach(
596
0
    std::function<bool(const Device &)> f) {
597
0
  const size_t n = GetNumDevices();
598
0
  for (NSUInteger i = 0; i < n; ++i) {
599
0
    if (!f(GetDeviceAtIndex(i)))
600
0
      break;
601
0
  }
602
0
}
603
604
CoreSimulatorSupport::DeviceSet CoreSimulatorSupport::DeviceSet::GetDevices(
605
0
    CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id) {
606
0
  NSMutableArray *array = [[NSMutableArray alloc] init];
607
0
  const size_t n = GetNumDevices();
608
0
  for (NSUInteger i = 0; i < n; ++i) {
609
0
    Device d(GetDeviceAtIndex(i));
610
0
    if (d && d.GetDeviceType() &&
611
0
        d.GetDeviceType().GetProductFamilyID() == dev_id)
612
0
      [array addObject:(id)d.m_dev];
613
0
  }
614
615
0
  return DeviceSet(array);
616
0
}
617
618
CoreSimulatorSupport::Device CoreSimulatorSupport::DeviceSet::GetFanciest(
619
0
    CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id) {
620
0
  Device dev;
621
622
0
  for (NSUInteger i = 0; i < GetNumDevices(); i++) {
623
0
    Device d(GetDeviceAtIndex(i));
624
0
    if (d && d.GetDeviceType() &&
625
0
        d.GetDeviceType().GetProductFamilyID() == dev_id) {
626
0
      if (!dev)
627
0
        dev = d;
628
0
      else {
629
0
        if ((d.GetDeviceType().GetModelIdentifier() >
630
0
             dev.GetDeviceType().GetModelIdentifier()) ||
631
0
            d.GetDeviceRuntime().GetVersion() >
632
0
                dev.GetDeviceRuntime().GetVersion())
633
0
          dev = d;
634
0
      }
635
0
    }
636
0
  }
637
638
0
  return dev;
639
0
}