转自:杨充
https://juejin.cn/user/2330620379283064
public abstract class EventListener {
   // 按照请求顺序回调
    public void callStart(Call call) {}
    // 域名解析
    public void dnsStart(Call call, String domainName) {}
    public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {}
    // 释放当前Transmitter的RealConnection
    public void connectionReleased(Call call, Connection connection) {}
    public void connectionAcquired(call, result){};
    // 开始连接
    public void connectStart(call, route.socketAddress(), proxy){}
    // 请求
    public void requestHeadersStart(@NotNull Call call){}
    public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {}
    // 响应
    public void requestBodyStart(@NotNull Call call) {}
    public void requestBodyEnd(@NotNull Call call, long byteCount) {}
    // 结束
    public void callEnd(Call call) {}
    // 失败
    public void callFailed(Call call, IOException ioe) {}
}final class RealCall implements Call {
    @Override 
    public Response execute() throws IOException {
        eventListener.callStart(this);
        client.dispatcher().executed(this);
        Response result = getResponseWithInterceptorChain();
        if (result == null) throw new IOException("Canceled");
        return result;    
    }
 
    @Override 
    public void enqueue(Callback responseCallback) {
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }
}final class RealCall implements Call {
    @Override 
    public Response execute() throws IOException {
        try {
          client.dispatcher().executed(this);
          Response result = getResponseWithInterceptorChain();
          if (result == null) throw new IOException("Canceled");
          return result;
        } catch (IOException e) {
          eventListener.callFailed(this, e);
          throw e;
        }
    }
    final class AsyncCall extends NamedRunnable {
        @Override 
        protected void execute() {
            try {
                Response response = getResponseWithInterceptorChain();
            } catch (IOException e) {
                eventListener.callFailed(RealCall.this, e);
 
            }
        }
    }
}public final class StreamAllocation {
    public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
        ...
        if (e != null) {
          eventListener.callFailed(call, e);
        } else if (callEnd) {
          eventListener.callEnd(call);
        }
        ...
    }
}public final class StreamAllocation {
 
    public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
        ...
        if (e != null) {
          eventListener.callFailed(call, e);
        } else if (callEnd) {
          eventListener.callEnd(call);
        }
        ...
    }
 
    public void release() {
        ...
        if (releasedConnection != null) {
          eventListener.connectionReleased(call, releasedConnection);
          eventListener.callEnd(call);
        }
    }
}/** Prepares the socket addresses to attempt for the current proxy or host. */
  private void resetNextInetSocketAddress(Proxy proxy) throws IOException {
    if (proxy.type() == Proxy.Type.SOCKS) {
      inetSocketAddresses.add(InetSocketAddress.createUnresolved(socketHost, socketPort));
    } else {
      eventListener.dnsStart(call, socketHost);
 
      // Try each address for best behavior in mixed IPv4/IPv6 environments.
      List<InetAddress> addresses = address.dns().lookup(socketHost);
      if (addresses.isEmpty()) {
        throw new UnknownHostException(address.dns() + " returned no addresses for " + socketHost);
      }
 
      eventListener.dnsEnd(call, socketHost, addresses);
    }
  }public final class StreamAllocation {
 
  public StreamAllocation(ConnectionPool connectionPool, Address address, Call call,
      EventListener eventListener, Object callStackTrace) {
    this.routeSelector = new RouteSelector(address, routeDatabase(), call, eventListener);
  }
} private void connectSocket(int connectTimeout, int readTimeout, Call call,
      EventListener eventListener) throws IOException {
    Proxy proxy = route.proxy();
    Address address = route.address();
 
    rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
        ? address.socketFactory().createSocket()
        : new Socket(proxy);
 
    eventListener.connectStart(call, route.socketAddress(), proxy);
  }  public void connect(int connectTimeout, int readTimeout, int writeTimeout,
    while (true) {
      try {
        establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener);
        eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol);
        break;
      } catch (IOException e) {
        eventListener.connectFailed(call, route.socketAddress(), route.proxy(), null, e);
      }
  }
 
  private void connectTunnel(int connectTimeout, int readTimeout, int writeTimeout, Call call,
      EventListener eventListener) throws IOException {
    Request tunnelRequest = createTunnelRequest();
    HttpUrl url = tunnelRequest.url();
    for (int i = 0; i < MAX_TUNNEL_ATTEMPTS; i++) {
      connectSocket(connectTimeout, readTimeout, call, eventListener);
      eventListener.connectEnd(call, route.socketAddress(), route.proxy(), null);
    }
  }  private void establishProtocol(ConnectionSpecSelector connectionSpecSelector,
      int pingIntervalMillis, Call call, EventListener eventListener) throws IOException {
    if (route.address().sslSocketFactory() == null) {
      protocol = Protocol.HTTP_1_1;
      socket = rawSocket;
      return;
    }
 
    eventListener.secureConnectStart(call);
    connectTls(connectionSpecSelector);
    eventListener.secureConnectEnd(call, handshake);
  } private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
      int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
    synchronized (connectionPool) {
      if (result == null) {
        // 第一次查缓存 Attempt to get a connection from the pool.
        // Attempt to get a connection from the pool.
        Internal.instance.get(connectionPool, address, this, null);
      }
    }
 
    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
    }
 
    synchronized (connectionPool) {
      if (canceled) throw new IOException("Canceled");
 
      if (newRouteSelection) {
        //第二次查缓存
        List<Route> routes = routeSelection.getAll();
        for (int i = 0, size = routes.size(); i < size; i++) {
          Route route = routes.get(i);
          Internal.instance.get(connectionPool, address, this, route);
          if (connection != null) {
            foundPooledConnection = true;
            result = connection;
            this.route = route;
            break;
          }
        }
      }
 
      if (!foundPooledConnection) {
        //如果缓存没有,则新建连接
        route = selectedRoute;
        refusedStreamCount = 0;
        result = new RealConnection(connectionPool, selectedRoute);
        acquire(result, false);
      }
    }
 
    // If we found a pooled connection on the 2nd time around, we're done.
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
      return result;
    }
 
    // Do TCP + TLS handshakes. This is a blocking operation.
    result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
        connectionRetryEnabled, call, eventListener);
    routeDatabase().connected(result.route());
 
    eventListener.connectionAcquired(call, result);
    return result;
  }public final class CallServerInterceptor implements Interceptor {
 
  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();
 
    long sentRequestMillis = System.currentTimeMillis();
 
    realChain.eventListener().requestHeadersStart(realChain.call());
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);
 
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        realChain.eventListener().requestBodyStart(realChain.call());
        long contentLength = request.body().contentLength();
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
 
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
        realChain.eventListener().requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
      } 
    }
    return response;
  }
}public final class CallServerInterceptor implements Interceptor {
 
  @Override public Response intercept(Chain chain) throws IOException {
 
    Response.Builder responseBuilder = null;
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
        httpCodec.flushRequest();
        realChain.eventListener().responseHeadersStart(realChain.call());
        responseBuilder = httpCodec.readResponseHeaders(true);
      }
    }
 
    httpCodec.finishRequest();
 
    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }
 
    int code = response.code();
    if (code == 100) {
      // server sent a 100-continue even though we did not request one.
      // try again to read the actual response
      responseBuilder = httpCodec.readResponseHeaders(false);
 
      response = responseBuilder
              .request(request)
              .handshake(streamAllocation.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();
 
      code = response.code();
    }
 
    realChain.eventListener() .responseHeadersEnd(realChain.call(), response);
    return response;
  }
}public final class Http1Codec implements HttpCodec {
 
  @Override public ResponseBody openResponseBody(Response response) throws IOException {
    streamAllocation.eventListener.responseBodyStart(streamAllocation.call);
    String contentType = response.header("Content-Type");
 
    if (!HttpHeaders.hasBody(response)) {
      Source source = newFixedLengthSource(0);
      return new RealResponseBody(contentType, 0, Okio.buffer(source));
    }
 
    if ("chunked".equalsIgnoreCase(response.header("Transfer-Encoding"))) {
      Source source = newChunkedSource(response.request().url());
      return new RealResponseBody(contentType, -1L, Okio.buffer(source));
    }
 
    long contentLength = HttpHeaders.contentLength(response);
    if (contentLength != -1) {
      Source source = newFixedLengthSource(contentLength);
      return new RealResponseBody(contentType, contentLength, Okio.buffer(source));
    }
 
    return new RealResponseBody(contentType, -1L, Okio.buffer(newUnknownLengthSource()));
  }
}public final class StreamAllocation {
  public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
    eventListener.responseBodyEnd(call, bytesRead);
    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
    if (e != null) {
      eventListener.callFailed(call, e);
    } else if (callEnd) {
      eventListener.callEnd(call);
    }
  }
}/**
 * <pre>
 *     @author yangchong
 *     email  : yangchong211@163.com
 *     time  : 2019/07/22
 *     desc  : EventListener子类
 *     revise:
 * </pre>
 */
public class NetworkListener extends EventListener {
 
    private static final String TAG = "NetworkEventListener";
    private static AtomicInteger mNextRequestId = new AtomicInteger(0);
    private String mRequestId ;
 
    public static Factory get(){
        Factory factory = new Factory() {
            @NotNull
            @Override
            public EventListener create(@NotNull Call call) {
                return new NetworkListener();
            }
        };
        return factory;
    }
 
    @Override
    public void callStart(@NotNull Call call) {
        super.callStart(call);
        //mRequestId = mNextRequestId.getAndIncrement() + "";
        //getAndAdd,在多线程下使用cas保证原子性
        mRequestId = String.valueOf(mNextRequestId.getAndIncrement());
        ToolLogUtils.i(TAG+"-------callStart---requestId-----"+mRequestId);
        saveEvent(NetworkTraceBean.CALL_START);
        saveUrl(call.request().url().toString());
    }
 
    @Override
    public void dnsStart(@NotNull Call call, @NotNull String domainName) {
        super.dnsStart(call, domainName);
        ToolLogUtils.d(TAG, "dnsStart");
        saveEvent(NetworkTraceBean.DNS_START);
    }
 
    @Override
    public void dnsEnd(@NotNull Call call, @NotNull String domainName, @NotNull List<InetAddress> inetAddressList) {
        super.dnsEnd(call, domainName, inetAddressList);
        ToolLogUtils.d(TAG, "dnsEnd");
        saveEvent(NetworkTraceBean.DNS_END);
    }
 
    @Override
    public void connectStart(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy) {
        super.connectStart(call, inetSocketAddress, proxy);
        ToolLogUtils.d(TAG, "connectStart");
        saveEvent(NetworkTraceBean.CONNECT_START);
    }
 
    @Override
    public void secureConnectStart(@NotNull Call call) {
        super.secureConnectStart(call);
        ToolLogUtils.d(TAG, "secureConnectStart");
        saveEvent(NetworkTraceBean.SECURE_CONNECT_START);
    }
 
    @Override
    public void secureConnectEnd(@NotNull Call call, @Nullable Handshake handshake) {
        super.secureConnectEnd(call, handshake);
        ToolLogUtils.d(TAG, "secureConnectEnd");
        saveEvent(NetworkTraceBean.SECURE_CONNECT_END);
    }
 
    @Override
    public void connectEnd(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress,
                           @NotNull Proxy proxy, @Nullable Protocol protocol) {
        super.connectEnd(call, inetSocketAddress, proxy, protocol);
        ToolLogUtils.d(TAG, "connectEnd");
        saveEvent(NetworkTraceBean.CONNECT_END);
    }
 
    @Override
    public void connectFailed(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy, @Nullable Protocol protocol, @NotNull IOException ioe) {
        super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
        ToolLogUtils.d(TAG, "connectFailed");
    }
 
    @Override
    public void requestHeadersStart(@NotNull Call call) {
        super.requestHeadersStart(call);
        ToolLogUtils.d(TAG, "requestHeadersStart");
        saveEvent(NetworkTraceBean.REQUEST_HEADERS_START);
    }
 
    @Override
    public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {
        super.requestHeadersEnd(call, request);
        ToolLogUtils.d(TAG, "requestHeadersEnd");
        saveEvent(NetworkTraceBean.REQUEST_HEADERS_END);
    }
 
    @Override
    public void requestBodyStart(@NotNull Call call) {
        super.requestBodyStart(call);
        ToolLogUtils.d(TAG, "requestBodyStart");
        saveEvent(NetworkTraceBean.REQUEST_BODY_START);
    }
 
    @Override
    public void requestBodyEnd(@NotNull Call call, long byteCount) {
        super.requestBodyEnd(call, byteCount);
        ToolLogUtils.d(TAG, "requestBodyEnd");
        saveEvent(NetworkTraceBean.REQUEST_BODY_END);
    }
 
    @Override
    public void responseHeadersStart(@NotNull Call call) {
        super.responseHeadersStart(call);
        ToolLogUtils.d(TAG, "responseHeadersStart");
        saveEvent(NetworkTraceBean.RESPONSE_HEADERS_START);
    }
 
    @Override
    public void responseHeadersEnd(@NotNull Call call, @NotNull Response response) {
        super.responseHeadersEnd(call, response);
        ToolLogUtils.d(TAG, "responseHeadersEnd");
        saveEvent(NetworkTraceBean.RESPONSE_HEADERS_END);
    }
 
    @Override
    public void responseBodyStart(@NotNull Call call) {
        super.responseBodyStart(call);
        ToolLogUtils.d(TAG, "responseBodyStart");
        saveEvent(NetworkTraceBean.RESPONSE_BODY_START);
    }
 
    @Override
    public void responseBodyEnd(@NotNull Call call, long byteCount) {
        super.responseBodyEnd(call, byteCount);
        ToolLogUtils.d(TAG, "responseBodyEnd");
        saveEvent(NetworkTraceBean.RESPONSE_BODY_END);
    }
 
    @Override
    public void callEnd(@NotNull Call call) {
        super.callEnd(call);
        ToolLogUtils.d(TAG, "callEnd");
        saveEvent(NetworkTraceBean.CALL_END);
        generateTraceData();
        NetWorkUtils.timeoutChecker(mRequestId);
    }
 
    @Override
    public void callFailed(@NotNull Call call, @NotNull IOException ioe) {
        super.callFailed(call, ioe);
        ToolLogUtils.d(TAG, "callFailed");
    }
 
    private void generateTraceData(){
        NetworkTraceBean traceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
        Map<String, Long> eventsTimeMap = traceModel.getNetworkEventsMap();
        Map<String, Long> traceList = traceModel.getTraceItemList();
        traceList.put(NetworkTraceBean.TRACE_NAME_TOTAL,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CALL_START, NetworkTraceBean.CALL_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_DNS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.DNS_START, NetworkTraceBean.DNS_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_SECURE_CONNECT,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.SECURE_CONNECT_START, NetworkTraceBean.SECURE_CONNECT_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_CONNECT,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CONNECT_START, NetworkTraceBean.CONNECT_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_HEADERS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_HEADERS_START, NetworkTraceBean.REQUEST_HEADERS_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_BODY,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_BODY_START, NetworkTraceBean.REQUEST_BODY_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_HEADERS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_HEADERS_START, NetworkTraceBean.RESPONSE_HEADERS_END));
        traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_BODY,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_BODY_START, NetworkTraceBean.RESPONSE_BODY_END));
    }
 
    private void saveEvent(String eventName){
        NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
        Map<String, Long> networkEventsMap = networkTraceModel.getNetworkEventsMap();
        networkEventsMap.put(eventName, SystemClock.elapsedRealtime());
    }
 
    private void saveUrl(String url){
        NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
        networkTraceModel.setUrl(url);
    }
 
}


https://github.com/yangchong211/YCAndroidTool 
– EOF –
 
  