Summary: This PR fixes the crash mentioned [here](https://github.com/facebook/flipper/issues/1674#issuecomment-754402609) in the https://github.com/facebook/flipper/issues/1674 . The issue was that logging `NSLog(@"%@", [self valueForKey:@"_methodDescription"]);` in the swizzled network delegate class used to cause a crash. The cause of this was the nil `methodDescription.types` sent to `class_addMethod`. In the following change we do not add a method to the class which doesn't implement the selector, we will anyway listen for those events from the base NSURLSession class. Removing the `class_addMethod`, fixes both the issue mentioned [here](https://github.com/facebook/flipper/issues/1674#issuecomment-754402609) in https://github.com/facebook/flipper/issues/1674. This PR also fixes an issue where no network calls where logged in Flipper when the iOS version was 14, the reason was that the URLSessionResume task was not properly swizzled for 14. ## Changelog - Do not add a runtime method to the delegate which doesn't implement a responder - Fix swizzling logic of the URLSession task resume method for ios 14 Pull Request resolved: https://github.com/facebook/flipper/pull/1810 Test Plan: - I ran the sample app and checked that the network calls are logged. - I copy pasted the changes in RN project and verified that the issues mentioned in https://github.com/facebook/flipper/issues/1674 doesn't happen and also verified that the network calls being hit from JS and Native code gets logged in Flipper. Verified with IsolatedSwizzles.zip mentioned over [here](https://github.com/facebook/flipper/issues/1674#issuecomment-754726174). Also verified by copy pasting the code in the fresh RN project. Reviewed By: fabiomassimo Differential Revision: D25801510 Pulled By: mweststrate fbshipit-source-id: 53ef574696d2abbdbfc2b6d94769327cdfa8aa2b
128 lines
3.7 KiB
Plaintext
Executable File
128 lines
3.7 KiB
Plaintext
Executable File
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "FLEXUtility.h"
|
|
|
|
#include <assert.h>
|
|
#include <mach/mach.h>
|
|
#include <mach/mach_time.h>
|
|
#import <objc/runtime.h>
|
|
#import <zlib.h>
|
|
|
|
#import <ImageIO/ImageIO.h>
|
|
|
|
@implementation FLEXUtility
|
|
|
|
+ (SEL)swizzledSelectorForSelector:(SEL)selector {
|
|
return NSSelectorFromString(
|
|
[NSString stringWithFormat:@"_flex_swizzle_%x_%@",
|
|
arc4random(),
|
|
NSStringFromSelector(selector)]);
|
|
}
|
|
|
|
+ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector
|
|
class:(Class)cls {
|
|
if ([cls instancesRespondToSelector:selector]) {
|
|
unsigned int numMethods = 0;
|
|
Method* methods = class_copyMethodList(cls, &numMethods);
|
|
|
|
BOOL implementsSelector = NO;
|
|
for (int index = 0; index < numMethods; index++) {
|
|
SEL methodSelector = method_getName(methods[index]);
|
|
if (selector == methodSelector) {
|
|
implementsSelector = YES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(methods);
|
|
|
|
if (!implementsSelector) {
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
+ (void)replaceImplementationOfKnownSelector:(SEL)originalSelector
|
|
onClass:(Class)className
|
|
withBlock:(id)block
|
|
swizzledSelector:(SEL)swizzledSelector {
|
|
// This method is only intended for swizzling methods that are know to exist
|
|
// on the class. Bail if that isn't the case.
|
|
Method originalMethod = class_getInstanceMethod(className, originalSelector);
|
|
if (!originalMethod) {
|
|
return;
|
|
}
|
|
|
|
IMP implementation = imp_implementationWithBlock(block);
|
|
class_addMethod(
|
|
className,
|
|
swizzledSelector,
|
|
implementation,
|
|
method_getTypeEncoding(originalMethod));
|
|
Method newMethod = class_getInstanceMethod(className, swizzledSelector);
|
|
method_exchangeImplementations(originalMethod, newMethod);
|
|
}
|
|
|
|
+ (void)replaceImplementationOfSelector:(SEL)selector
|
|
withSelector:(SEL)swizzledSelector
|
|
forClass:(Class)cls
|
|
withMethodDescription:
|
|
(struct objc_method_description)methodDescription
|
|
implementationBlock:(id)implementationBlock
|
|
undefinedBlock:(id)undefinedBlock {
|
|
if ([self instanceRespondsButDoesNotImplementSelector:selector class:cls]) {
|
|
return;
|
|
}
|
|
|
|
IMP implementation = imp_implementationWithBlock((id)(
|
|
[cls instancesRespondToSelector:selector] ? implementationBlock
|
|
: undefinedBlock));
|
|
|
|
Method oldMethod = class_getInstanceMethod(cls, selector);
|
|
if (oldMethod) {
|
|
objc_method_description* description = method_getDescription(oldMethod);
|
|
class_addMethod(cls, swizzledSelector, implementation, description->types);
|
|
Method newMethod = class_getInstanceMethod(cls, swizzledSelector);
|
|
method_exchangeImplementations(oldMethod, newMethod);
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation NSNumber (SonarUtility)
|
|
|
|
+ (NSNumber*)random {
|
|
int64_t identifier;
|
|
arc4random_buf(&identifier, sizeof(int64_t));
|
|
return @(identifier);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation NSDate (SonarUtility)
|
|
|
|
+ (uint64_t)getTimeNanoseconds {
|
|
static struct mach_timebase_info tb_info = {0};
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
__unused int ret = mach_timebase_info(&tb_info);
|
|
assert(0 == ret);
|
|
});
|
|
|
|
return (mach_absolute_time() * tb_info.numer) / tb_info.denom;
|
|
}
|
|
|
|
+ (uint64_t)timestamp {
|
|
const uint64_t nowNanoSeconds = [self getTimeNanoseconds];
|
|
return nowNanoSeconds / 1000000;
|
|
}
|
|
|
|
@end
|