10d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi/* 20d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * Copyright (C) 2016 The Android Open Source Project 30d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * 40d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * Licensed under the Apache License, Version 2.0 (the "License"); 50d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * you may not use this file except in compliance with the License. 60d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * You may obtain a copy of the License at 70d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * 80d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * http://www.apache.org/licenses/LICENSE-2.0 90d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * 100d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * Unless required by applicable law or agreed to in writing, software 110d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * distributed under the License is distributed on an "AS IS" BASIS, 120d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * See the License for the specific language governing permissions and 140d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * limitations under the License. 150d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi */ 160d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 170d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichipackage android.net.metrics; 180d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 195eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichiimport android.net.NetworkCapabilities; 200d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichiimport android.system.OsConstants; 210d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichiimport android.util.IntArray; 220d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichiimport android.util.SparseIntArray; 23ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi 245eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichiimport com.android.internal.util.BitUtils; 250d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichiimport com.android.internal.util.TokenBucket; 260d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 270d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi/** 285eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi * A class that aggregates connect() statistics. 290d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi * {@hide} 300d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi */ 310d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichipublic class ConnectStats { 320d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi private final static int EALREADY = OsConstants.EALREADY; 330d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi private final static int EINPROGRESS = OsConstants.EINPROGRESS; 340d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 355eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi /** Network id of the network associated with the event, or 0 if unspecified. */ 365eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public final int netId; 375eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi /** Transports of the network associated with the event, as defined in NetworkCapabilities. */ 385eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public final long transports; 390d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi /** How many events resulted in a given errno. */ 405eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public final SparseIntArray errnos = new SparseIntArray(); 415eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi /** Latencies of successful blocking connects. TODO: add non-blocking connects latencies. */ 425eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public final IntArray latencies = new IntArray(); 430d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi /** TokenBucket for rate limiting latency recording. */ 445eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public final TokenBucket mLatencyTb; 450d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi /** Maximum number of latency values recorded. */ 465eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public final int mMaxLatencyRecords; 47ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi /** Total count of events */ 48ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi public int eventCount = 0; 490d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi /** Total count of successful connects. */ 505eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public int connectCount = 0; 51a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi /** Total count of successful connects done in blocking mode. */ 525eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public int connectBlockingCount = 0; 530d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi /** Total count of successful connects with IPv6 socket address. */ 545eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public int ipv6ConnectCount = 0; 550d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 565eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi public ConnectStats(int netId, long transports, TokenBucket tb, int maxLatencyRecords) { 575eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi this.netId = netId; 585eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi this.transports = transports; 590d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi mLatencyTb = tb; 600d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi mMaxLatencyRecords = maxLatencyRecords; 610d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 620d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 63ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi boolean addEvent(int errno, int latencyMs, String ipAddr) { 64ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi eventCount++; 650d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi if (isSuccess(errno)) { 66a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi countConnect(errno, ipAddr); 670d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi countLatency(errno, latencyMs); 68ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi return true; 690d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } else { 700d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi countError(errno); 71ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi return false; 720d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 730d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 740d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 75a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi private void countConnect(int errno, String ipAddr) { 765eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi connectCount++; 77a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi if (!isNonBlocking(errno)) { 785eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi connectBlockingCount++; 79a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi } 80a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi if (isIPv6(ipAddr)) { 815eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi ipv6ConnectCount++; 82a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi } 830d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 840d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 850d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi private void countLatency(int errno, int ms) { 860d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi if (isNonBlocking(errno)) { 870d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi // Ignore connect() on non-blocking sockets 880d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi return; 890d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 900d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi if (!mLatencyTb.get()) { 910d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi // Rate limited 920d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi return; 930d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 945eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi if (latencies.size() >= mMaxLatencyRecords) { 950d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi // Hard limit the total number of latency measurements. 960d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi return; 970d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 985eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi latencies.add(ms); 990d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 1000d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 1010d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi private void countError(int errno) { 1025eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi final int newcount = errnos.get(errno, 0) + 1; 1035eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi errnos.put(errno, newcount); 1040d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 1050d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 1060d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi private static boolean isSuccess(int errno) { 1070d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi return (errno == 0) || isNonBlocking(errno); 1080d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 1090d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 110ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi static boolean isNonBlocking(int errno) { 1110d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi // On non-blocking TCP sockets, connect() immediately returns EINPROGRESS. 1120d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi // On non-blocking TCP sockets that are connecting, connect() immediately returns EALREADY. 1130d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi return (errno == EINPROGRESS) || (errno == EALREADY); 1140d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 1150d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 1160d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi private static boolean isIPv6(String ipAddr) { 1170d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi return ipAddr.contains(":"); 1180d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi } 1190d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi 120a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi @Override 121a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi public String toString() { 122c867f787bc7b6ecd49fe3a9c638b34befc3922ecHugo Benichi StringBuilder builder = 123c867f787bc7b6ecd49fe3a9c638b34befc3922ecHugo Benichi new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", "); 1245eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi for (int t : BitUtils.unpackBits(transports)) { 1255eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi builder.append(NetworkCapabilities.transportNameOf(t)).append(", "); 1265eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi } 127ab20975c7485a0451d77e19d48ab8fe09e483927Hugo Benichi builder.append(String.format("%d events, ", eventCount)); 1285eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi builder.append(String.format("%d success, ", connectCount)); 1295eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi builder.append(String.format("%d blocking, ", connectBlockingCount)); 1305eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi builder.append(String.format("%d IPv6 dst", ipv6ConnectCount)); 1315eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi for (int i = 0; i < errnos.size(); i++) { 1325eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi String errno = OsConstants.errnoName(errnos.keyAt(i)); 1335eb9053c4e8c788b83cfcfd7bfd39f628dd4ca45Hugo Benichi int count = errnos.valueAt(i); 134a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi builder.append(String.format(", %s: %d", errno, count)); 135a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi } 136a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi return builder.append(")").toString(); 137a2decca4f25b6d3adfd396cdc475807985783babHugo Benichi } 1380d4a398b7846f26e4452180915ecb5a9d4566148Hugo Benichi} 139