XCUIApplicationProcessDelay.m 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /**
  2. * Copyright (c) 2015-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. */
  9. #import "XCUIApplicationProcessDelay.h"
  10. #import <objc/runtime.h>
  11. #import "XCUIApplicationProcess.h"
  12. #import "FBLogger.h"
  13. static void (*orig_set_event_loop_has_idled)(id, SEL, BOOL);
  14. static NSTimeInterval eventloopIdleDelay = 0;
  15. static BOOL isSwizzled = NO;
  16. // '-[XCUIApplicationProcess setEventLoopHasIdled:]' can be called from different queues.
  17. // Lets lock the setup and access to the 'eventloopIdleDelay' variable
  18. static NSLock * lock = nil;
  19. @implementation XCUIApplicationProcessDelay
  20. #pragma clang diagnostic push
  21. #pragma clang diagnostic ignored "-Wobjc-load-method"
  22. + (void)load
  23. {
  24. lock = [[NSLock alloc] init];
  25. }
  26. #pragma clang diagnostic pop
  27. + (void)setEventLoopHasIdledDelay:(NSTimeInterval)delay
  28. {
  29. [lock lock];
  30. if (!isSwizzled && delay < DBL_EPSILON) {
  31. // don't swizzle methods until we need to
  32. [lock unlock];
  33. return;
  34. }
  35. eventloopIdleDelay = delay;
  36. if (isSwizzled) {
  37. [lock unlock];
  38. return;
  39. }
  40. [self swizzleSetEventLoopHasIdled];
  41. [lock unlock];
  42. }
  43. + (void)disableEventLoopDelay
  44. {
  45. // Once the methods were swizzled they stay like that since the only change in the implementation
  46. // is the thread sleep, which is skipped on setting it to zero.
  47. [self setEventLoopHasIdledDelay:0];
  48. }
  49. + (void)swizzleSetEventLoopHasIdled {
  50. Method original = class_getInstanceMethod([XCUIApplicationProcess class], @selector(setEventLoopHasIdled:));
  51. if (original == nil) {
  52. [FBLogger log:@"Could not find method -[XCUIApplicationProcess setEventLoopHasIdled:]"];
  53. return;
  54. }
  55. #pragma clang diagnostic push
  56. #pragma clang diagnostic ignored "-Wcast-function-type-strict"
  57. orig_set_event_loop_has_idled = (void(*)(id, SEL, BOOL)) method_getImplementation(original);
  58. #pragma clang diagnostic pop
  59. Method replace = class_getClassMethod([XCUIApplicationProcessDelay class], @selector(setEventLoopHasIdled:));
  60. method_setImplementation(original, method_getImplementation(replace));
  61. isSwizzled = YES;
  62. }
  63. + (void)setEventLoopHasIdled:(BOOL)idled {
  64. [lock lock];
  65. NSTimeInterval delay = eventloopIdleDelay;
  66. [lock unlock];
  67. if (delay > 0.0) {
  68. [FBLogger verboseLog:[NSString stringWithFormat:@"Delaying -[XCUIApplicationProcess setEventLoopHasIdled:] by %.2f seconds", delay]];
  69. [NSThread sleepForTimeInterval:delay];
  70. }
  71. orig_set_event_loop_has_idled(self, _cmd, idled);
  72. }
  73. @end