Home | History | Annotate | Download | only in connectivity
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.connectivity;
     18 
     19 import static android.net.NetworkCapabilities.MAX_TRANSPORT;
     20 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
     21 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
     22 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
     23 import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN;
     24 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
     25 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
     26 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
     27 
     28 import android.net.ConnectivityManager;
     29 import android.net.ConnectivityMetricsEvent;
     30 import android.net.metrics.ApfProgramEvent;
     31 import android.net.metrics.ApfStats;
     32 import android.net.metrics.DefaultNetworkEvent;
     33 import android.net.metrics.DhcpClientEvent;
     34 import android.net.metrics.DhcpErrorEvent;
     35 import android.net.metrics.DnsEvent;
     36 import android.net.metrics.ConnectStats;
     37 import android.net.metrics.IpManagerEvent;
     38 import android.net.metrics.IpReachabilityEvent;
     39 import android.net.metrics.NetworkEvent;
     40 import android.net.metrics.RaEvent;
     41 import android.net.metrics.ValidationProbeEvent;
     42 import android.net.metrics.WakeupStats;
     43 import android.os.Parcelable;
     44 import android.util.SparseArray;
     45 import android.util.SparseIntArray;
     46 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
     47 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
     48 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
     49 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;
     50 import java.io.IOException;
     51 import java.util.ArrayList;
     52 import java.util.List;
     53 
     54 
     55 /** {@hide} */
     56 final public class IpConnectivityEventBuilder {
     57     private IpConnectivityEventBuilder() {
     58     }
     59 
     60     public static byte[] serialize(int dropped, List<IpConnectivityEvent> events)
     61             throws IOException {
     62         final IpConnectivityLog log = new IpConnectivityLog();
     63         log.events = events.toArray(new IpConnectivityEvent[events.size()]);
     64         log.droppedEvents = dropped;
     65         if ((log.events.length > 0) || (dropped > 0)) {
     66             // Only write version number if log has some information at all.
     67             log.version = IpConnectivityMetrics.VERSION;
     68         }
     69         return IpConnectivityLog.toByteArray(log);
     70     }
     71 
     72     public static List<IpConnectivityEvent> toProto(List<ConnectivityMetricsEvent> eventsIn) {
     73         final ArrayList<IpConnectivityEvent> eventsOut = new ArrayList<>(eventsIn.size());
     74         for (ConnectivityMetricsEvent in : eventsIn) {
     75             final IpConnectivityEvent out = toProto(in);
     76             if (out == null) {
     77                 continue;
     78             }
     79             eventsOut.add(out);
     80         }
     81         return eventsOut;
     82     }
     83 
     84     public static IpConnectivityEvent toProto(ConnectivityMetricsEvent ev) {
     85         final IpConnectivityEvent out = buildEvent(ev.netId, ev.transports, ev.ifname);
     86         out.timeMs = ev.timestamp;
     87         if (!setEvent(out, ev.data)) {
     88             return null;
     89         }
     90         return out;
     91     }
     92 
     93     public static IpConnectivityEvent toProto(ConnectStats in) {
     94         IpConnectivityLogClass.ConnectStatistics stats =
     95                 new IpConnectivityLogClass.ConnectStatistics();
     96         stats.connectCount = in.connectCount;
     97         stats.connectBlockingCount = in.connectBlockingCount;
     98         stats.ipv6AddrCount = in.ipv6ConnectCount;
     99         stats.latenciesMs = in.latencies.toArray();
    100         stats.errnosCounters = toPairArray(in.errnos);
    101         final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
    102         out.setConnectStatistics(stats);
    103         return out;
    104     }
    105 
    106 
    107     public static IpConnectivityEvent toProto(DnsEvent in) {
    108         IpConnectivityLogClass.DNSLookupBatch dnsLookupBatch =
    109                 new IpConnectivityLogClass.DNSLookupBatch();
    110         in.resize(in.eventCount);
    111         dnsLookupBatch.eventTypes = bytesToInts(in.eventTypes);
    112         dnsLookupBatch.returnCodes = bytesToInts(in.returnCodes);
    113         dnsLookupBatch.latenciesMs = in.latenciesMs;
    114         final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
    115         out.setDnsLookupBatch(dnsLookupBatch);
    116         return out;
    117     }
    118 
    119     public static IpConnectivityEvent toProto(WakeupStats in) {
    120         IpConnectivityLogClass.WakeupStats wakeupStats =
    121                 new IpConnectivityLogClass.WakeupStats();
    122         in.updateDuration();
    123         wakeupStats.durationSec = in.durationSec;
    124         wakeupStats.totalWakeups = in.totalWakeups;
    125         wakeupStats.rootWakeups = in.rootWakeups;
    126         wakeupStats.systemWakeups = in.systemWakeups;
    127         wakeupStats.nonApplicationWakeups = in.nonApplicationWakeups;
    128         wakeupStats.applicationWakeups = in.applicationWakeups;
    129         wakeupStats.noUidWakeups = in.noUidWakeups;
    130         wakeupStats.l2UnicastCount = in.l2UnicastCount;
    131         wakeupStats.l2MulticastCount = in.l2MulticastCount;
    132         wakeupStats.l2BroadcastCount = in.l2BroadcastCount;
    133         wakeupStats.ethertypeCounts = toPairArray(in.ethertypes);
    134         wakeupStats.ipNextHeaderCounts = toPairArray(in.ipNextHeaders);
    135         final IpConnectivityEvent out = buildEvent(0, 0, in.iface);
    136         out.setWakeupStats(wakeupStats);
    137         return out;
    138     }
    139 
    140     public static IpConnectivityEvent toProto(DefaultNetworkEvent in) {
    141         IpConnectivityLogClass.DefaultNetworkEvent ev =
    142                 new IpConnectivityLogClass.DefaultNetworkEvent();
    143         ev.finalScore = in.finalScore;
    144         ev.initialScore = in.initialScore;
    145         ev.ipSupport = ipSupportOf(in);
    146         ev.defaultNetworkDurationMs = in.durationMs;
    147         ev.validationDurationMs = in.validatedMs;
    148         ev.previousDefaultNetworkLinkLayer = transportsToLinkLayer(in.previousTransports);
    149         final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
    150         if (in.transports == 0) {
    151             // Set link layer to NONE for events representing the absence of a default network.
    152             out.linkLayer = IpConnectivityLogClass.NONE;
    153         }
    154         out.setDefaultNetworkEvent(ev);
    155         return out;
    156     }
    157 
    158     private static IpConnectivityEvent buildEvent(int netId, long transports, String ifname) {
    159         final IpConnectivityEvent ev = new IpConnectivityEvent();
    160         ev.networkId = netId;
    161         ev.transports = transports;
    162         if (ifname != null) {
    163             ev.ifName = ifname;
    164         }
    165         inferLinkLayer(ev);
    166         return ev;
    167     }
    168 
    169     private static boolean setEvent(IpConnectivityEvent out, Parcelable in) {
    170         if (in instanceof DhcpErrorEvent) {
    171             setDhcpErrorEvent(out, (DhcpErrorEvent) in);
    172             return true;
    173         }
    174 
    175         if (in instanceof DhcpClientEvent) {
    176             setDhcpClientEvent(out, (DhcpClientEvent) in);
    177             return true;
    178         }
    179 
    180         if (in instanceof IpManagerEvent) {
    181             setIpManagerEvent(out, (IpManagerEvent) in);
    182             return true;
    183         }
    184 
    185         if (in instanceof IpReachabilityEvent) {
    186             setIpReachabilityEvent(out, (IpReachabilityEvent) in);
    187             return true;
    188         }
    189 
    190         if (in instanceof NetworkEvent) {
    191             setNetworkEvent(out, (NetworkEvent) in);
    192             return true;
    193         }
    194 
    195         if (in instanceof ValidationProbeEvent) {
    196             setValidationProbeEvent(out, (ValidationProbeEvent) in);
    197             return true;
    198         }
    199 
    200         if (in instanceof ApfProgramEvent) {
    201             setApfProgramEvent(out, (ApfProgramEvent) in);
    202             return true;
    203         }
    204 
    205         if (in instanceof ApfStats) {
    206             setApfStats(out, (ApfStats) in);
    207             return true;
    208         }
    209 
    210         if (in instanceof RaEvent) {
    211             setRaEvent(out, (RaEvent) in);
    212             return true;
    213         }
    214 
    215         return false;
    216     }
    217 
    218     private static void setDhcpErrorEvent(IpConnectivityEvent out, DhcpErrorEvent in) {
    219         IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
    220         dhcpEvent.setErrorCode(in.errorCode);
    221         out.setDhcpEvent(dhcpEvent);
    222     }
    223 
    224     private static void setDhcpClientEvent(IpConnectivityEvent out, DhcpClientEvent in) {
    225         IpConnectivityLogClass.DHCPEvent dhcpEvent = new IpConnectivityLogClass.DHCPEvent();
    226         dhcpEvent.setStateTransition(in.msg);
    227         dhcpEvent.durationMs = in.durationMs;
    228         out.setDhcpEvent(dhcpEvent);
    229     }
    230 
    231     private static void setIpManagerEvent(IpConnectivityEvent out, IpManagerEvent in) {
    232         IpConnectivityLogClass.IpProvisioningEvent ipProvisioningEvent =
    233                 new IpConnectivityLogClass.IpProvisioningEvent();
    234         ipProvisioningEvent.eventType = in.eventType;
    235         ipProvisioningEvent.latencyMs = (int) in.durationMs;
    236         out.setIpProvisioningEvent(ipProvisioningEvent);
    237     }
    238 
    239     private static void setIpReachabilityEvent(IpConnectivityEvent out, IpReachabilityEvent in) {
    240         IpConnectivityLogClass.IpReachabilityEvent ipReachabilityEvent =
    241                 new IpConnectivityLogClass.IpReachabilityEvent();
    242         ipReachabilityEvent.eventType = in.eventType;
    243         out.setIpReachabilityEvent(ipReachabilityEvent);
    244     }
    245 
    246     private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
    247         IpConnectivityLogClass.NetworkEvent networkEvent =
    248                 new IpConnectivityLogClass.NetworkEvent();
    249         networkEvent.eventType = in.eventType;
    250         networkEvent.latencyMs = (int) in.durationMs;
    251         out.setNetworkEvent(networkEvent);
    252     }
    253 
    254     private static void setValidationProbeEvent(IpConnectivityEvent out, ValidationProbeEvent in) {
    255         IpConnectivityLogClass.ValidationProbeEvent validationProbeEvent =
    256                 new IpConnectivityLogClass.ValidationProbeEvent();
    257         validationProbeEvent.latencyMs = (int) in.durationMs;
    258         validationProbeEvent.probeType = in.probeType;
    259         validationProbeEvent.probeResult = in.returnCode;
    260         out.setValidationProbeEvent(validationProbeEvent);
    261     }
    262 
    263     private static void setApfProgramEvent(IpConnectivityEvent out, ApfProgramEvent in) {
    264         IpConnectivityLogClass.ApfProgramEvent apfProgramEvent =
    265                 new IpConnectivityLogClass.ApfProgramEvent();
    266         apfProgramEvent.lifetime = in.lifetime;
    267         apfProgramEvent.effectiveLifetime = in.actualLifetime;
    268         apfProgramEvent.filteredRas = in.filteredRas;
    269         apfProgramEvent.currentRas = in.currentRas;
    270         apfProgramEvent.programLength = in.programLength;
    271         if (isBitSet(in.flags, ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)) {
    272             apfProgramEvent.dropMulticast = true;
    273         }
    274         if (isBitSet(in.flags, ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)) {
    275             apfProgramEvent.hasIpv4Addr = true;
    276         }
    277         out.setApfProgramEvent(apfProgramEvent);
    278     }
    279 
    280     private static void setApfStats(IpConnectivityEvent out, ApfStats in) {
    281         IpConnectivityLogClass.ApfStatistics apfStatistics =
    282                 new IpConnectivityLogClass.ApfStatistics();
    283         apfStatistics.durationMs = in.durationMs;
    284         apfStatistics.receivedRas = in.receivedRas;
    285         apfStatistics.matchingRas = in.matchingRas;
    286         apfStatistics.droppedRas = in.droppedRas;
    287         apfStatistics.zeroLifetimeRas = in.zeroLifetimeRas;
    288         apfStatistics.parseErrors = in.parseErrors;
    289         apfStatistics.programUpdates = in.programUpdates;
    290         apfStatistics.programUpdatesAll = in.programUpdatesAll;
    291         apfStatistics.programUpdatesAllowingMulticast = in.programUpdatesAllowingMulticast;
    292         apfStatistics.maxProgramSize = in.maxProgramSize;
    293         out.setApfStatistics(apfStatistics);
    294     }
    295 
    296     private static void setRaEvent(IpConnectivityEvent out, RaEvent in) {
    297         IpConnectivityLogClass.RaEvent raEvent = new IpConnectivityLogClass.RaEvent();
    298         raEvent.routerLifetime = in.routerLifetime;
    299         raEvent.prefixValidLifetime = in.prefixValidLifetime;
    300         raEvent.prefixPreferredLifetime = in.prefixPreferredLifetime;
    301         raEvent.routeInfoLifetime = in.routeInfoLifetime;
    302         raEvent.rdnssLifetime = in.rdnssLifetime;
    303         raEvent.dnsslLifetime = in.dnsslLifetime;
    304         out.setRaEvent(raEvent);
    305     }
    306 
    307     private static int[] bytesToInts(byte[] in) {
    308         final int[] out = new int[in.length];
    309         for (int i = 0; i < in.length; i++) {
    310             out[i] = in[i] & 0xFF;
    311         }
    312         return out;
    313     }
    314 
    315     private static Pair[] toPairArray(SparseIntArray counts) {
    316         final int s = counts.size();
    317         Pair[] pairs = new Pair[s];
    318         for (int i = 0; i < s; i++) {
    319             Pair p = new Pair();
    320             p.key = counts.keyAt(i);
    321             p.value = counts.valueAt(i);
    322             pairs[i] = p;
    323         }
    324         return pairs;
    325     }
    326 
    327     private static int ipSupportOf(DefaultNetworkEvent in) {
    328         if (in.ipv4 && in.ipv6) {
    329             return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
    330         }
    331         if (in.ipv6) {
    332             return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
    333         }
    334         if (in.ipv4) {
    335             return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
    336         }
    337         return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
    338     }
    339 
    340     private static boolean isBitSet(int flags, int bit) {
    341         return (flags & (1 << bit)) != 0;
    342     }
    343 
    344     private static void inferLinkLayer(IpConnectivityEvent ev) {
    345         int linkLayer = IpConnectivityLogClass.UNKNOWN;
    346         if (ev.transports != 0) {
    347             linkLayer = transportsToLinkLayer(ev.transports);
    348         } else if (ev.ifName != null) {
    349             linkLayer = ifnameToLinkLayer(ev.ifName);
    350         }
    351         if (linkLayer == IpConnectivityLogClass.UNKNOWN) {
    352             return;
    353         }
    354         ev.linkLayer = linkLayer;
    355         ev.ifName = "";
    356     }
    357 
    358     private static int transportsToLinkLayer(long transports) {
    359         switch (Long.bitCount(transports)) {
    360             case 0:
    361                 return IpConnectivityLogClass.UNKNOWN;
    362             case 1:
    363                 int t = Long.numberOfTrailingZeros(transports);
    364                 return transportToLinkLayer(t);
    365             default:
    366                 return IpConnectivityLogClass.MULTIPLE;
    367         }
    368     }
    369 
    370     private static int transportToLinkLayer(int transport) {
    371         if (0 <= transport && transport < TRANSPORT_LINKLAYER_MAP.length) {
    372             return TRANSPORT_LINKLAYER_MAP[transport];
    373         }
    374         return IpConnectivityLogClass.UNKNOWN;
    375     }
    376 
    377     private static final int[] TRANSPORT_LINKLAYER_MAP = new int[MAX_TRANSPORT + 1];
    378     static {
    379         TRANSPORT_LINKLAYER_MAP[TRANSPORT_CELLULAR]   = IpConnectivityLogClass.CELLULAR;
    380         TRANSPORT_LINKLAYER_MAP[TRANSPORT_WIFI]       = IpConnectivityLogClass.WIFI;
    381         TRANSPORT_LINKLAYER_MAP[TRANSPORT_BLUETOOTH]  = IpConnectivityLogClass.BLUETOOTH;
    382         TRANSPORT_LINKLAYER_MAP[TRANSPORT_ETHERNET]   = IpConnectivityLogClass.ETHERNET;
    383         TRANSPORT_LINKLAYER_MAP[TRANSPORT_VPN]        = IpConnectivityLogClass.UNKNOWN;
    384         TRANSPORT_LINKLAYER_MAP[TRANSPORT_WIFI_AWARE] = IpConnectivityLogClass.WIFI_NAN;
    385         TRANSPORT_LINKLAYER_MAP[TRANSPORT_LOWPAN]     = IpConnectivityLogClass.LOWPAN;
    386     };
    387 
    388     private static int ifnameToLinkLayer(String ifname) {
    389         // Do not try to catch all interface names with regexes, instead only catch patterns that
    390         // are cheap to check, and otherwise fallback on postprocessing in aggregation layer.
    391         for (int i = 0; i < KNOWN_PREFIX; i++) {
    392             String pattern = IFNAME_PREFIXES[i];
    393             if (ifname.startsWith(pattern)) {
    394                 return IFNAME_LINKLAYERS[i];
    395             }
    396         }
    397         return IpConnectivityLogClass.UNKNOWN;
    398     }
    399 
    400     private static final int KNOWN_PREFIX = 7;
    401     private static final String[] IFNAME_PREFIXES = new String[KNOWN_PREFIX];
    402     private static final int[] IFNAME_LINKLAYERS = new int[KNOWN_PREFIX];
    403     static {
    404         // Ordered from most likely link layer to least likely.
    405         IFNAME_PREFIXES[0] = "rmnet";
    406         IFNAME_LINKLAYERS[0] = IpConnectivityLogClass.CELLULAR;
    407 
    408         IFNAME_PREFIXES[1] = "wlan";
    409         IFNAME_LINKLAYERS[1] = IpConnectivityLogClass.WIFI;
    410 
    411         IFNAME_PREFIXES[2] = "bt-pan";
    412         IFNAME_LINKLAYERS[2] = IpConnectivityLogClass.BLUETOOTH;
    413 
    414         IFNAME_PREFIXES[3] = "p2p";
    415         IFNAME_LINKLAYERS[3] = IpConnectivityLogClass.WIFI_P2P;
    416 
    417         IFNAME_PREFIXES[4] = "aware";
    418         IFNAME_LINKLAYERS[4] = IpConnectivityLogClass.WIFI_NAN;
    419 
    420         IFNAME_PREFIXES[5] = "eth";
    421         IFNAME_LINKLAYERS[5] = IpConnectivityLogClass.ETHERNET;
    422 
    423         IFNAME_PREFIXES[6] = "wpan";
    424         IFNAME_LINKLAYERS[6] = IpConnectivityLogClass.LOWPAN;
    425     }
    426 }
    427