Skip to content

SMCallTrace 调用栈顺序问题 #19

@chipengliu

Description

@chipengliu

问题1、拼接调用栈路径path顺序不正确

- (void)viewDidLoad {
    [super viewDidLoad];
    UIWebView *webview = [[UIWebView alloc] init];
    [self.view addSubview:webview];
    NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
    NSURLRequest *req = [[NSURLRequest alloc] initWithURL:url];
    [webview loadRequest:req];
    webview.frame = self.view.bounds;

    [self testMethod1];
}

- (void)testMethod1 {
    NSString *imgName = [NSString stringWithFormat:@"guide_1"];
    NSString *path = [[NSBundle mainBundle] pathForResource:imgName ofType:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    self.view.backgroundColor = [UIColor colorWithPatternImage:image];
    
    [self testMethod2];
}

- (void)testMethod2 {
    [self testMethod3];
}

- (void)testMethod3 {
    NSString *imgName = [NSString stringWithFormat:@"guide_3"];
    NSString *path = [[NSBundle mainBundle] pathForResource:imgName ofType:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    self.view.backgroundColor = [UIColor colorWithPatternImage:image];
    
    UIGraphicsBeginImageContext(self.view.frame.size);
    [image drawInRect:self.view.bounds];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    self.view.backgroundColor = [UIColor colorWithPatternImage:image];
}

这里UIWebView某些回调方法是通过异步回到主线程执行,看起来多线程打印的调用栈路径是错误的,打印出来的信息是:

 0| +[UIWebView alloc]
 path[UIWebView alloc]
 0| -[UIWebView init]
 path[UIWebView init]
 0| -[ViewController testMethod1]
 path[ViewController testMethod1]
 1|   -[ViewController testMethod2]
 path[ViewController testMethod1] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[ViewController testMethod1] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[ViewController testMethod1] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[ViewController testMethod1] - [UIImage imageWithContentsOfFile:]
 0| -[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[ViewController testMethod2]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [UIImage imageWithContentsOfFile:]
 0| -[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[ViewController testMethod2]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIImage imageWithContentsOfFile:]
 0| -[_WebSafeForwarder webView:didCommitLoadForFrame:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:]
 1|   -[UIWebBrowserView webView:didCommitLoadForFrame:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[ViewController testMethod2]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIImage imageWithContentsOfFile:]
 0| -[_WebSafeForwarder webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:]
 1|   -[UIWebBrowserView webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didFinishLoadForFrame:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didFinishLoadForFrame:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didFinishLoadForFrame:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebBrowserView webView:didCommitLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[ViewController testMethod2]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIImage imageWithContentsOfFile:]
 0| -[_WebSafeForwarder webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:]
 1|   -[UIWebViewWebViewDelegate webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:didFinishLoadForFrame:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:didFinishLoadForFrame:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:didFinishLoadForFrame:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebBrowserView webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didFinishLoadForFrame:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didFinishLoadForFrame:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didFinishLoadForFrame:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebBrowserView webView:didCommitLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   -[ViewController testMethod2]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIImage imageWithContentsOfFile:]

如果在loadRecords方法第二层循环加上break,看起才是正常的

    for (NSUInteger i = 0; i < count; i++) {
        SMCallTraceTimeCostModel *model = arr[i];
        if (model.callDepth > 0) {
            [arr removeObjectAtIndex:i];
            //Todo:不需要循环,直接设置下一个,然后判断好边界就行
            for (NSUInteger j = i; j < count - 1; j++) {
                //下一个深度小的话就开始将后面的递归的往 sub array 里添加
                if (arr[j].callDepth + 1 == model.callDepth) {
                    NSMutableArray *sub = (NSMutableArray *)arr[j].subCosts;
                    if (!sub) {
                        sub = [NSMutableArray new];
                        arr[j].subCosts = sub;
                    }
                    [sub insertObject:model atIndex:0];
                    break;//->fix 找到父节点结束遍历
                }
            }
            i--;
            count--;
        }
    }

加了break 之后输出

 0| +[UIWebView alloc]
 path[UIWebView alloc]
 0| -[UIWebView init]
 path[UIWebView init]
 0| -[ViewController testMethod1]
 path[ViewController testMethod1]
 1|   -[ViewController testMethod2]
 path[ViewController testMethod1] - [ViewController testMethod2]
 2|     -[ViewController testMethod3]
 path[ViewController testMethod1] - [ViewController testMethod2] - [ViewController testMethod3]
 3|       -[UIImage drawInRect:]
 path[ViewController testMethod1] - [ViewController testMethod2] - [ViewController testMethod3] - [UIImage drawInRect:]
 1|   +[UIImage imageWithContentsOfFile:]
 path[ViewController testMethod1] - [UIImage imageWithContentsOfFile:]
 0| -[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForNavigationAction:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]
 0| -[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 1|   -[UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 path[_WebSafeForwarder webView:decidePolicyForMIMEType:request:frame:decisionListener:] - [UIWebViewWebViewDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]
 0| -[_WebSafeForwarder webView:didCommitLoadForFrame:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:]
 1|   -[UIWebBrowserView webView:didCommitLoadForFrame:]
 path[_WebSafeForwarder webView:didCommitLoadForFrame:] - [UIWebBrowserView webView:didCommitLoadForFrame:]
 0| -[_WebSafeForwarder webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:]
 1|   -[UIWebViewWebViewDelegate webView:didFinishLoadForFrame:]
 path[_WebSafeForwarder webView:didFinishLoadForFrame:] - [UIWebViewWebViewDelegate webView:didFinishLoadForFrame:]

问题2、debug由于hook objc_msgSend 导致 堆栈信息不全

在同一行代码用bt命令打印堆栈
hook前
hook前

hook后
hook后


问题3、无法检测viewDidLoad, viewWillAppear 等一些UIKit的方法

目前发现 UIViewController、UIResponder 等一些方法是无法记录的

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions