typedef NS_OPTIONS(NSUInteger, AspectOptions) { AspectPositionAfter = 0, /// 在原方法实现调用之后调用 Called after the original implementation (default) AspectPositionInstead = 1, /// 将会替换原方法的实现。 Will replace the original implementation. AspectPositionBefore = 2, /// 在原方法调用之前调用。 Called before the original implementation. AspectOptionAutomaticRemoval = 1 << 3 /// 在第一次执行之后自动移除hook Will remove the hook after the first execution. };
// Check against the blacklist. NSString *selectorName = NSStringFromSelector(selector); //如果当前的selectorName在disallowedSelectorList中不允许hook抛出错误 if ([disallowedSelectorList containsObject:selectorName]) { NSString *errorDescription = [NSString stringWithFormat:@"Selector %@ is blacklisted.", selectorName]; AspectError(AspectErrorSelectorBlacklisted, errorDescription); returnNO; }
// Additional checks. AspectOptions position = options & AspectPositionFilter; //不允许在dealloc之后 或者替换dealloc if ([selectorName isEqualToString:@"dealloc"] && position != AspectPositionBefore) { NSString *errorDesc = @"AspectPositionBefore is the only valid position when hooking dealloc."; AspectError(AspectErrorSelectorDeallocPosition, errorDesc); returnNO; }
// Search for the current class and the class hierarchy IF we are modifying a class object if (class_isMetaClass(object_getClass(self))) { Class klass = [selfclass]; NSMutableDictionary *swizzledClassesDict = aspect_getSwizzledClassesDict(); Class currentClass = [selfclass];
AspectTracker *tracker = swizzledClassesDict[currentClass]; //是否在子类已经hook过了 if ([tracker subclassHasHookedSelectorName:selectorName]) { NSSet *subclassTracker = [tracker subclassTrackersHookingSelectorName:selectorName]; NSSet *subclassNames = [subclassTracker valueForKey:@"trackedClassName"]; NSString *errorDescription = [NSString stringWithFormat:@"Error: %@ already hooked subclasses: %@. A method can only be hooked once per class hierarchy.", selectorName, subclassNames]; AspectError(AspectErrorSelectorAlreadyHookedInClassHierarchy, errorDescription); returnNO; }
do { //获取当前类的tracker tracker = swizzledClassesDict[currentClass]; //查看是否有hook了当前selector if ([tracker.selectorNames containsObject:selectorName]) { if (klass == currentClass) { // Already modified and topmost! returnYES; } //在当前类中已经hook过 NSString *errorDescription = [NSString stringWithFormat:@"Error: %@ already hooked in %@. A method can only be hooked once per class hierarchy.", selectorName, NSStringFromClass(currentClass)]; AspectError(AspectErrorSelectorAlreadyHookedInClassHierarchy, errorDescription); returnNO; } } while ((currentClass = class_getSuperclass(currentClass))); //经过上面合法性hook判断和类方法不允许重复替换的检查后,到此,就可以把要hook的信息记录下来,用AspectTracker标记 //当前类tracker -- 待hook方法 // 父tracker -- 待hook方法 // 父tracker -- 待hook方法 currentClass = klass; AspectTracker *subclassTracker = nil; do { //当前类的tracker tracker = swizzledClassesDict[currentClass]; //如果没有的话则新建tracker if (!tracker) { tracker = [[AspectTracker alloc] initWithTrackedClass:currentClass]; swizzledClassesDict[(id<NSCopying>)currentClass] = tracker; } //非第一次则添加到subclassTracker if (subclassTracker) { [tracker addSubclassTracker:subclassTracker hookingSelectorName:selectorName]; } else { //第一次添加到tracker [tracker.selectorNames addObject:selectorName]; } // All superclasses get marked as having a subclass that is modified. subclassTracker = tracker; }while ((currentClass = class_getSuperclass(currentClass))); } else { returnYES; } returnYES; }
// Before hooks. aspect_invoke(classContainer.beforeAspects, info); aspect_invoke(objectContainer.beforeAspects, info);
// Instead hooks. BOOL respondsToAlias = YES; if (objectContainer.insteadAspects.count || classContainer.insteadAspects.count) { aspect_invoke(classContainer.insteadAspects, info); aspect_invoke(objectContainer.insteadAspects, info); }else { Class klass = object_getClass(invocation.target); do { if ((respondsToAlias = [klassinstancesRespondToSelector:aliasSelector])) { [invocationinvoke]; break; } }while (!respondsToAlias && (klass = class_getSuperclass(klass))); }
// After hooks. aspect_invoke(classContainer.afterAspects, info); aspect_invoke(objectContainer.afterAspects, info);
//如果hook没有被正常执行,那么就应该执行原来的方法。 // If no hooks are installed, call original implementation (usually to throw an exception) if (!respondsToAlias) { invocation.selector = originalSelector; SEL originalForwardInvocationSEL = NSSelectorFromString(AspectsForwardInvocationSelectorName); if ([selfrespondsToSelector:originalForwardInvocationSEL]) { ((void( *)(id, SEL, NSInvocation *))objc_msgSend)(self, originalForwardInvocationSEL, invocation); }else { [selfdoesNotRecognizeSelector:invocation.selector]; } }
// Remove any hooks that are queued for deregistration. [aspectsToRemovemakeObjectsPerformSelector:@selector(remove)]; }
首先进入这里的时候会通过关联属性来获取aspect_selector对应的属性值,如果有被hook的话则会获取到存放hook切片信息的切片容器AspectsContainer。我们使用invocation信息创建AspectInfo, 然后调用aspect_invoke宏来执行AspectsContainer中的beforeAspects,insteadAspects,以及afterAspects,如果insteadAspects为空的话,则直接执行子类的aliasSelector。我们之前已经提到过了,在aspect_prepareClassAndHookSelector方法中会在子类添加一个aspect_selector的方法它指向selector实现,所以这里会执行原来方法中的selector。如果respondsToAlias = NO 表示instancesRespondToSelector返回NO,表示调用了一个没有实现的方法,所以走原来类的消息转发机制。
我们最后再来看下aspect_invoke这个宏:
#define aspect_invoke(aspects, info) \ for (AspectIdentifier *aspect in aspects) {\ [aspect invokeWithInfo:info];\ if (aspect.options & AspectOptionAutomaticRemoval) { \ aspectsToRemove = [aspectsToRemove?:@[] arrayByAddingObject:aspect]; \ } \ }
// Be extra paranoid. We already check that on hook registration. if (numberOfArguments > originalInvocation.methodSignature.numberOfArguments) { AspectLogError(@"Block has too many arguments. Not calling %@", info); returnNO; }
// The `self` of the block will be the AspectInfo. Optional. if (numberOfArguments > 1) { [blockInvocation setArgument:&info atIndex:1]; } void *argBuf = NULL; for (NSUInteger idx = 2; idx < numberOfArguments; idx++) { constchar *type = [originalInvocation.methodSignature getArgumentTypeAtIndex:idx]; NSUInteger argSize; NSGetSizeAndAlignment(type, &argSize, NULL); if (!(argBuf = reallocf(argBuf, argSize))) { AspectLogError(@"Failed to allocate memory for block invocation."); returnNO; } //循环把originalInvocation中取出参数,赋值到argBuf中,然后再赋值到blockInvocation里 [originalInvocation getArgument:argBuf atIndex:idx]; [blockInvocation setArgument:argBuf atIndex:idx]; } //最后把self.block赋值给blockInvocation的Target [blockInvocation invokeWithTarget:self.block]; if (argBuf != NULL) { free(argBuf); } returnYES; }