From 64901e5963f8e330a7a4a47ceeecfbb47d255dc2 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 19 Oct 2017 14:42:40 +0900 Subject: [PATCH 1/2] Extract logging of default network events This patch extracts the logging of DefaultNetworkEvent from inside ConnectivityService and move it to a new DefaultNetworkMetrics class. The DefaultNetworkMetrics is a singleton owned by the IpConnectivityMetrics singleton implementing the metrics service for core networking. ConnectivityService has access to this singleton via LocalServices. This class layout will allow to remove the Parcelable interface of DefaultNetworkEvent and will instead let the IpConnectivityMetrics service grab metrics from the DefaultNetworkMetrics directly. Bug: 34901696 Test: runtest frameworks-net Change-Id: I55694d89124272732aba114198776462372de18b --- .../android/server/ConnectivityService.java | 30 +++-------- .../connectivity/DefaultNetworkMetrics.java | 53 +++++++++++++++++++ .../connectivity/IpConnectivityMetrics.java | 19 +++++++ .../server/ConnectivityServiceTest.java | 13 +++++ 4 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5c11100f3417f..25c96d14e9ada 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -71,7 +71,6 @@ import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.UidRange; import android.net.Uri; -import android.net.metrics.DefaultNetworkEvent; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.util.MultinetworkPolicyTracker; @@ -129,6 +128,7 @@ import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; +import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.KeepaliveTracker; import com.android.server.connectivity.LingerMonitor; import com.android.server.connectivity.MockableSystemProperties; @@ -2283,7 +2283,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Let rematchAllNetworksAndRequests() below record a new default network event // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence // whose timestamps tell how long it takes to recover a default network. - logDefaultNetworkEvent(null, nai); + metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(null, nai); } notifyIfacesChangedForNetworkStats(); // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied @@ -5012,7 +5012,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // Notify system services that this network is up. makeDefault(newNetwork); // Log 0 -> X and Y -> X default network transitions, where X is the new default. - logDefaultNetworkEvent(newNetwork, oldDefaultNetwork); + metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent( + newNetwork, oldDefaultNetwork); // Have a new default network, release the transition wakelock in scheduleReleaseNetworkTransitionWakelock(); } @@ -5571,25 +5572,10 @@ public class ConnectivityService extends IConnectivityManager.Stub return ServiceManager.checkService(name) != null; } - private void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) { - int newNetid = NETID_UNSET; - int prevNetid = NETID_UNSET; - int[] transports = new int[0]; - boolean hadIPv4 = false; - boolean hadIPv6 = false; - - if (newNai != null) { - newNetid = newNai.network.netId; - transports = newNai.networkCapabilities.getTransportTypes(); - } - if (prevNai != null) { - prevNetid = prevNai.network.netId; - final LinkProperties lp = prevNai.linkProperties; - hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute(); - hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute(); - } - - mMetricsLog.log(new DefaultNetworkEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6)); + @VisibleForTesting + protected IpConnectivityMetrics.Logger metricsLogger() { + return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class), + "no IpConnectivityMetrics service"); } private void logNetworkEvent(NetworkAgentInfo nai, int evtype) { diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java new file mode 100644 index 0000000000000..c7c00bb3b6701 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import static android.net.ConnectivityManager.NETID_UNSET; + +import android.net.LinkProperties; +import android.net.metrics.DefaultNetworkEvent; +import android.net.metrics.IpConnectivityLog; + +/** + * Tracks events related to the default network for the purpose of default network metrics. + * {@hide} + */ +public class DefaultNetworkMetrics { + + private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); + + public void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) { + int newNetid = NETID_UNSET; + int prevNetid = NETID_UNSET; + int[] transports = new int[0]; + boolean hadIPv4 = false; + boolean hadIPv6 = false; + + if (newNai != null) { + newNetid = newNai.network.netId; + transports = newNai.networkCapabilities.getTransportTypes(); + } + if (prevNai != null) { + prevNetid = prevNai.network.netId; + final LinkProperties lp = prevNai.linkProperties; + hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute(); + hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute(); + } + + mMetricsLog.log(new DefaultNetworkEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6)); + } +} diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index f2445fa360065..25e541f17baf7 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -32,12 +32,15 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.Base64; import android.util.Log; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.RingBuffer; import com.android.internal.util.TokenBucket; +import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; + import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -112,6 +115,9 @@ final public class IpConnectivityMetrics extends SystemService { private final ToIntFunction mCapacityGetter; + @VisibleForTesting + final DefaultNetworkMetrics mDefaultNetworkMetrics = new DefaultNetworkMetrics(); + public IpConnectivityMetrics(Context ctx, ToIntFunction capacityGetter) { super(ctx); mCapacityGetter = capacityGetter; @@ -135,6 +141,8 @@ final public class IpConnectivityMetrics extends SystemService { publishBinderService(SERVICE_NAME, impl); publishBinderService(mNetdListener.SERVICE_NAME, mNetdListener); + + LocalServices.addService(Logger.class, new LoggerImpl()); } } @@ -366,4 +374,15 @@ final public class IpConnectivityMetrics extends SystemService { map.put(ApfProgramEvent.class, new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50)); return map; } + + /** Direct non-Binder interface for event producer clients within the system servers. */ + public interface Logger { + DefaultNetworkMetrics defaultNetworkMetrics(); + } + + private class LoggerImpl implements Logger { + public DefaultNetworkMetrics defaultNetworkMetrics() { + return mDefaultNetworkMetrics; + } + } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c2cb66d5e60aa..27a29b68e12db 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -104,6 +104,8 @@ import android.util.LogPrinter; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.server.connectivity.DefaultNetworkMetrics; +import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; @@ -156,6 +158,9 @@ public class ConnectivityServiceTest { private MockNetworkAgent mEthernetNetworkAgent; private Context mContext; + @Mock IpConnectivityMetrics.Logger mMetricsService; + @Mock DefaultNetworkMetrics mDefaultNetworkMetrics; + // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods // do not go through ConnectivityService but talk to netd directly, so they don't automatically // reflect the state of our test ConnectivityService. @@ -805,6 +810,11 @@ public class ConnectivityServiceTest { return Context.ETHERNET_SERVICE.equals(name); } + @Override + protected IpConnectivityMetrics.Logger metricsLogger() { + return mMetricsService; + } + public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() { return mLastCreatedNetworkMonitor; } @@ -833,6 +843,9 @@ public class ConnectivityServiceTest { public void setUp() throws Exception { mContext = InstrumentationRegistry.getContext(); + MockitoAnnotations.initMocks(this); + when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics); + // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . if (Looper.myLooper() == null) { From 1193a9c9ab24b879fd59231b30295847ba939fa0 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 19 Oct 2017 14:58:15 +0900 Subject: [PATCH 2/2] Remove Parcelable interface from DefaultNetworkEvent This patch takes advantage of the direct DefaultNetworkMetrics interface between ConnectivityService and IpConnectivityMetrics and removes the Parcelable interface from DefaultNetworkEvent. IpConnectivityMetrics, IpConnectivityEventBuilder and associated tests are updated as necessary. Bug: 34901696 Test: runtest frameworks-net Change-Id: I59b6e04fc126051320d08a422cfbd4d27042123e --- .../net/metrics/DefaultNetworkEvent.java | 79 ++---- .../connectivity/DefaultNetworkMetrics.java | 55 ++-- .../IpConnectivityEventBuilder.java | 27 +- .../connectivity/IpConnectivityMetrics.java | 5 + .../IpConnectivityEventBuilderTest.java | 21 +- .../IpConnectivityMetricsTest.java | 251 ++++++++++++++++-- 6 files changed, 308 insertions(+), 130 deletions(-) diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java index 28cf42f2fe28d..eb61c1532d497 100644 --- a/core/java/android/net/metrics/DefaultNetworkEvent.java +++ b/core/java/android/net/metrics/DefaultNetworkEvent.java @@ -16,73 +16,43 @@ package android.net.metrics; +import static android.net.ConnectivityManager.NETID_UNSET; + import android.net.NetworkCapabilities; -import android.os.Parcel; -import android.os.Parcelable; /** * An event recorded by ConnectivityService when there is a change in the default network. * {@hide} */ -public final class DefaultNetworkEvent implements Parcelable { +public class DefaultNetworkEvent { + // The ID of the network that has become the new default or NETID_UNSET if none. - public final int netId; + public int netId = NETID_UNSET; // The list of transport types of the new default network, for example TRANSPORT_WIFI, as // defined in NetworkCapabilities.java. - public final int[] transportTypes; + public int[] transportTypes = new int[0]; // The ID of the network that was the default before or NETID_UNSET if none. - public final int prevNetId; + public int prevNetId = NETID_UNSET; // Whether the previous network had IPv4/IPv6 connectivity. - public final boolean prevIPv4; - public final boolean prevIPv6; - - public DefaultNetworkEvent(int netId, int[] transportTypes, - int prevNetId, boolean prevIPv4, boolean prevIPv6) { - this.netId = netId; - this.transportTypes = transportTypes; - this.prevNetId = prevNetId; - this.prevIPv4 = prevIPv4; - this.prevIPv6 = prevIPv6; - } - - private DefaultNetworkEvent(Parcel in) { - this.netId = in.readInt(); - this.transportTypes = in.createIntArray(); - this.prevNetId = in.readInt(); - this.prevIPv4 = (in.readByte() > 0); - this.prevIPv6 = (in.readByte() > 0); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(netId); - out.writeIntArray(transportTypes); - out.writeInt(prevNetId); - out.writeByte(prevIPv4 ? (byte) 1 : (byte) 0); - out.writeByte(prevIPv6 ? (byte) 1 : (byte) 0); - } - - @Override - public int describeContents() { - return 0; - } + public boolean prevIPv4; + public boolean prevIPv6; @Override public String toString() { - String prevNetwork = String.valueOf(prevNetId); - String newNetwork = String.valueOf(netId); - if (prevNetId != 0) { - prevNetwork += ":" + ipSupport(); - } - if (netId != 0) { - newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes); - } - return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork); + String prevNetwork = String.valueOf(prevNetId); + String newNetwork = String.valueOf(netId); + if (prevNetId != 0) { + prevNetwork += ":" + ipSupport(); + } + if (netId != 0) { + newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes); + } + return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork); } private String ipSupport() { if (prevIPv4 && prevIPv6) { - return "DUAL"; + return "IPv4v6"; } if (prevIPv6) { return "IPv6"; @@ -92,15 +62,4 @@ public final class DefaultNetworkEvent implements Parcelable { } return "NONE"; } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public DefaultNetworkEvent createFromParcel(Parcel in) { - return new DefaultNetworkEvent(in); - } - - public DefaultNetworkEvent[] newArray(int size) { - return new DefaultNetworkEvent[size]; - } - }; } diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java index c7c00bb3b6701..8981db11f7f85 100644 --- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java +++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java @@ -16,38 +16,63 @@ package com.android.server.connectivity; -import static android.net.ConnectivityManager.NETID_UNSET; - import android.net.LinkProperties; import android.net.metrics.DefaultNetworkEvent; import android.net.metrics.IpConnectivityLog; +import com.android.internal.annotations.GuardedBy; +import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + /** * Tracks events related to the default network for the purpose of default network metrics. * {@hide} */ public class DefaultNetworkMetrics { - private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); + private static final int ROLLING_LOG_SIZE = 64; - public void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) { - int newNetid = NETID_UNSET; - int prevNetid = NETID_UNSET; - int[] transports = new int[0]; - boolean hadIPv4 = false; - boolean hadIPv6 = false; + // Event buffer used for metrics upload. The buffer is cleared when events are collected. + @GuardedBy("this") + private final List mEvents = new ArrayList<>(); + public synchronized void listEvents(PrintWriter pw) { + long localTimeMs = System.currentTimeMillis(); + for (DefaultNetworkEvent ev : mEvents) { + pw.println(ev); + } + } + + public synchronized void listEventsAsProto(PrintWriter pw) { + for (DefaultNetworkEvent ev : mEvents) { + pw.print(IpConnectivityEventBuilder.toProto(ev)); + } + } + + public synchronized void flushEvents(List out) { + for (DefaultNetworkEvent ev : mEvents) { + out.add(IpConnectivityEventBuilder.toProto(ev)); + } + mEvents.clear(); + } + + public synchronized void logDefaultNetworkEvent( + NetworkAgentInfo newNai, NetworkAgentInfo prevNai) { + DefaultNetworkEvent ev = new DefaultNetworkEvent(); if (newNai != null) { - newNetid = newNai.network.netId; - transports = newNai.networkCapabilities.getTransportTypes(); + ev.netId = newNai.network().netId; + ev.transportTypes = newNai.networkCapabilities.getTransportTypes(); } if (prevNai != null) { - prevNetid = prevNai.network.netId; + ev.prevNetId = prevNai.network().netId; final LinkProperties lp = prevNai.linkProperties; - hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute(); - hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute(); + ev.prevIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute(); + ev.prevIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute(); } - mMetricsLog.log(new DefaultNetworkEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6)); + mEvents.add(ev); } } diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java index 67e72167faa7b..3d71ecb50d9ff 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java @@ -132,6 +132,18 @@ final public class IpConnectivityEventBuilder { return out; } + public static IpConnectivityEvent toProto(DefaultNetworkEvent in) { + IpConnectivityLogClass.DefaultNetworkEvent ev = + new IpConnectivityLogClass.DefaultNetworkEvent(); + ev.networkId = netIdOf(in.netId); + ev.previousNetworkId = netIdOf(in.prevNetId); + ev.transportTypes = in.transportTypes; + ev.previousNetworkIpSupport = ipSupportOf(in); + final IpConnectivityEvent out = buildEvent(in.netId, 0, null); + out.setDefaultNetworkEvent(ev); + return out; + } + private static IpConnectivityEvent buildEvent(int netId, long transports, String ifname) { final IpConnectivityEvent ev = new IpConnectivityEvent(); ev.networkId = netId; @@ -164,11 +176,6 @@ final public class IpConnectivityEventBuilder { return true; } - if (in instanceof DefaultNetworkEvent) { - setDefaultNetworkEvent(out, (DefaultNetworkEvent) in); - return true; - } - if (in instanceof NetworkEvent) { setNetworkEvent(out, (NetworkEvent) in); return true; @@ -225,16 +232,6 @@ final public class IpConnectivityEventBuilder { out.setIpReachabilityEvent(ipReachabilityEvent); } - private static void setDefaultNetworkEvent(IpConnectivityEvent out, DefaultNetworkEvent in) { - IpConnectivityLogClass.DefaultNetworkEvent defaultNetworkEvent = - new IpConnectivityLogClass.DefaultNetworkEvent(); - defaultNetworkEvent.networkId = netIdOf(in.netId); - defaultNetworkEvent.previousNetworkId = netIdOf(in.prevNetId); - defaultNetworkEvent.transportTypes = in.transportTypes; - defaultNetworkEvent.previousNetworkIpSupport = ipSupportOf(in); - out.setDefaultNetworkEvent(defaultNetworkEvent); - } - private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) { IpConnectivityLogClass.NetworkEvent networkEvent = new IpConnectivityLogClass.NetworkEvent(); diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 25e541f17baf7..24217e6eef0bc 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -196,6 +196,8 @@ final public class IpConnectivityMetrics extends SystemService { final List protoEvents = IpConnectivityEventBuilder.toProto(events); + mDefaultNetworkMetrics.flushEvents(protoEvents); + if (mNetdListener != null) { mNetdListener.flushStatistics(protoEvents); } @@ -236,6 +238,7 @@ final public class IpConnectivityMetrics extends SystemService { if (mNetdListener != null) { mNetdListener.listAsProtos(pw); } + mDefaultNetworkMetrics.listEventsAsProto(pw); return; } @@ -245,6 +248,7 @@ final public class IpConnectivityMetrics extends SystemService { if (mNetdListener != null) { mNetdListener.list(pw); } + mDefaultNetworkMetrics.listEvents(pw); } /** @@ -262,6 +266,7 @@ final public class IpConnectivityMetrics extends SystemService { if (mNetdListener != null) { mNetdListener.list(pw); } + mDefaultNetworkMetrics.listEvents(pw); } private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) { diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java index 262417620ca2a..ad6ebf933776a 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java @@ -198,21 +198,20 @@ public class IpConnectivityEventBuilderTest { @Test public void testDefaultNetworkEventSerialization() { - ConnectivityMetricsEvent ev = describeIpEvent( - aType(DefaultNetworkEvent.class), - anInt(102), - anIntArray(1, 2, 3), - anInt(101), - aBool(true), - aBool(false)); + DefaultNetworkEvent ev = new DefaultNetworkEvent(); + ev.netId = 102; + ev.prevNetId = 101; + ev.transportTypes = new int[]{1, 2, 3}; + ev.prevIPv4 = true; + ev.prevIPv6 = true; String want = String.join("\n", "dropped_events: 0", "events <", " if_name: \"\"", " link_layer: 0", - " network_id: 0", - " time_ms: 1", + " network_id: 102", + " time_ms: 0", " transports: 0", " default_network_event <", " default_network_duration_ms: 0", @@ -226,7 +225,7 @@ public class IpConnectivityEventBuilderTest { " previous_network_id <", " network_id: 101", " >", - " previous_network_ip_support: 1", + " previous_network_ip_support: 3", " transport_types: 1", " transport_types: 2", " transport_types: 3", @@ -234,7 +233,7 @@ public class IpConnectivityEventBuilderTest { ">", "version: 2\n"); - verifySerialization(want, ev); + verifySerialization(want, IpConnectivityEventBuilder.toProto(ev)); } @Test diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index a395c480f57ac..6c1decc3b3b81 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -18,6 +18,7 @@ package com.android.server.connectivity; import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO; import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -30,6 +31,10 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.RouteInfo; import android.net.Network; import android.net.NetworkCapabilities; import android.net.metrics.ApfProgramEvent; @@ -41,18 +46,22 @@ import android.net.metrics.IpManagerEvent; import android.net.metrics.IpReachabilityEvent; import android.net.metrics.RaEvent; import android.net.metrics.ValidationProbeEvent; -import android.system.OsConstants; import android.os.Parcelable; import android.support.test.runner.AndroidJUnit4; +import android.system.OsConstants; import android.test.suitebuilder.annotation.SmallTest; import android.util.Base64; + +import com.android.internal.util.BitUtils; import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass; + import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; + import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -161,6 +170,144 @@ public class IpConnectivityMetricsTest { assertEquals("", output2); } + @Test + public void testDefaultNetworkEvents() throws Exception { + final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR}); + final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI}); + + NetworkAgentInfo[][] defaultNetworks = { + // nothing -> cell + {null, makeNai(100, 10, false, true, cell)}, + // cell -> wifi + {makeNai(100, 50, true, true, cell), makeNai(101, 20, true, false, wifi)}, + // wifi -> nothing + {makeNai(101, 60, true, false, wifi), null}, + // nothing -> cell + {null, makeNai(102, 10, true, true, cell)}, + // cell -> wifi + {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)}, + }; + + for (NetworkAgentInfo[] pair : defaultNetworks) { + mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(pair[1], pair[0]); + } + + String want = String.join("\n", + "dropped_events: 0", + "events <", + " if_name: \"\"", + " link_layer: 0", + " network_id: 100", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 100", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 0", + " >", + " previous_network_ip_support: 0", + " transport_types: 0", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 0", + " network_id: 101", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 101", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 100", + " >", + " previous_network_ip_support: 3", + " transport_types: 1", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 0", + " network_id: 0", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 0", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 101", + " >", + " previous_network_ip_support: 1", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 0", + " network_id: 102", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 102", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 0", + " >", + " previous_network_ip_support: 0", + " transport_types: 0", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 0", + " network_id: 103", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 103", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 102", + " >", + " previous_network_ip_support: 3", + " transport_types: 1", + " >", + ">", + "version: 2\n"); + + verifySerialization(want, getdump("flush")); + } + @Test public void testEndToEndLogging() throws Exception { // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto. @@ -194,7 +341,6 @@ public class IpConnectivityMetricsTest { Parcelable[] events = { new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), new DhcpClientEvent("SomeState", 192), - new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false), new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678), validationEv, apfStats, @@ -233,6 +379,13 @@ public class IpConnectivityMetricsTest { wakeupEvent("wlan0", 10008); wakeupEvent("rmnet0", 1000); + final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR}); + final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI}); + NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell); + NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi); + mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(cellNai, null); + mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(wifiNai, cellNai); + String want = String.join("\n", "dropped_events: 0", "events <", @@ -264,30 +417,6 @@ public class IpConnectivityMetricsTest { " network_id: 0", " time_ms: 300", " transports: 0", - " default_network_event <", - " default_network_duration_ms: 0", - " final_score: 0", - " initial_score: 0", - " ip_support: 0", - " network_id <", - " network_id: 102", - " >", - " no_default_network_duration_ms: 0", - " previous_network_id <", - " network_id: 101", - " >", - " previous_network_ip_support: 1", - " transport_types: 1", - " transport_types: 2", - " transport_types: 3", - " >", - ">", - "events <", - " if_name: \"\"", - " link_layer: 4", - " network_id: 0", - " time_ms: 400", - " transports: 0", " ip_provisioning_event <", " event_type: 1", " if_name: \"\"", @@ -298,7 +427,7 @@ public class IpConnectivityMetricsTest { " if_name: \"\"", " link_layer: 4", " network_id: 0", - " time_ms: 500", + " time_ms: 400", " transports: 0", " validation_probe_event <", " latency_ms: 40730", @@ -310,7 +439,7 @@ public class IpConnectivityMetricsTest { " if_name: \"\"", " link_layer: 4", " network_id: 0", - " time_ms: 600", + " time_ms: 500", " transports: 0", " apf_statistics <", " dropped_ras: 2", @@ -331,7 +460,7 @@ public class IpConnectivityMetricsTest { " if_name: \"\"", " link_layer: 4", " network_id: 0", - " time_ms: 700", + " time_ms: 600", " transports: 0", " ra_event <", " dnssl_lifetime: -1", @@ -344,6 +473,50 @@ public class IpConnectivityMetricsTest { ">", "events <", " if_name: \"\"", + " link_layer: 0", + " network_id: 100", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 100", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 0", + " >", + " previous_network_ip_support: 0", + " transport_types: 0", + " >", + ">", + "events <", + " if_name: \"\"", + " link_layer: 0", + " network_id: 101", + " time_ms: 0", + " transports: 0", + " default_network_event <", + " default_network_duration_ms: 0", + " final_score: 0", + " initial_score: 0", + " ip_support: 0", + " network_id <", + " network_id: 101", + " >", + " no_default_network_duration_ms: 0", + " previous_network_id <", + " network_id: 100", + " >", + " previous_network_ip_support: 2", + " transport_types: 1", + " >", + ">", + "events <", + " if_name: \"\"", " link_layer: 4", " network_id: 100", " time_ms: 0", @@ -471,6 +644,26 @@ public class IpConnectivityMetricsTest { mNetdListener.onWakeupEvent(prefix, uid, uid, 0); } + NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) { + NetworkAgentInfo nai = mock(NetworkAgentInfo.class); + when(nai.network()).thenReturn(new Network(netId)); + when(nai.getCurrentScore()).thenReturn(score); + nai.linkProperties = new LinkProperties(); + nai.networkCapabilities = new NetworkCapabilities(); + for (int t : BitUtils.unpackBits(transports)) { + nai.networkCapabilities.addTransportType(t); + } + if (ipv4) { + nai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.12/24")); + nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"))); + } + if (ipv6) { + nai.linkProperties.addLinkAddress(new LinkAddress("2001:db8:dead:beef:f00::a0/64")); + nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("::/0"))); + } + return nai; + } + List verifyEvents(int n, int timeoutMs) throws Exception { ArgumentCaptor captor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);