diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9994462531b2a..72f9d749865b7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -132,6 +132,7 @@ import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; @@ -1992,13 +1993,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return ret; } - private boolean argsContain(String[] args, String target) { - for (String arg : args) { - if (target.equals(arg)) return true; - } - return false; - } - private void dumpNetworkDiagnostics(IndentingPrintWriter pw) { final List netDiags = new ArrayList(); final long DIAG_TIME_MS = 5000; @@ -2027,10 +2021,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; if (asProto) return; - if (argsContain(args, DIAG_ARG)) { + if (ArrayUtils.contains(args, DIAG_ARG)) { dumpNetworkDiagnostics(pw); return; - } else if (argsContain(args, TETHERING_ARG)) { + } else if (ArrayUtils.contains(args, TETHERING_ARG)) { mTethering.dump(fd, pw, args); return; } @@ -2098,7 +2092,7 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.println(); mMultipathPolicyTracker.dump(pw); - if (argsContain(args, SHORT_ARG) == false) { + if (ArrayUtils.contains(args, SHORT_ARG) == false) { pw.println(); synchronized (mValidationLogs) { pw.println("mValidationLogs (most recent first):"); diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index f4278196b5766..ac745985417e1 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -20,6 +20,7 @@ import android.content.Context; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; +import android.net.ip.IpClient; import android.net.metrics.ApfProgramEvent; import android.net.metrics.IpConnectivityLog; import android.os.Binder; @@ -269,10 +270,12 @@ final public class IpConnectivityMetrics extends SystemService { // Dump the rolling buffer of metrics event and pretty print events using a human readable // format. Also print network dns/connect statistics and default network event time series. static final String CMD_LIST = "list"; - // By default any other argument will fall into the default case which is remapped to the - // "list" command. This includes most notably bug reports collected by dumpsys.cpp with - // the "-a" argument. - static final String CMD_DEFAULT = CMD_LIST; + // Dump all IpClient logs ("ipclient"). + static final String CMD_IPCLIENT = IpClient.DUMP_ARG; + // By default any other argument will fall into the default case which is the equivalent + // of calling both the "list" and "ipclient" commands. This includes most notably bug + // reports collected by dumpsys.cpp with the "-a" argument. + static final String CMD_DEFAULT = ""; @Override public int logEvent(ConnectivityMetricsEvent event) { @@ -292,9 +295,20 @@ final public class IpConnectivityMetrics extends SystemService { case CMD_PROTO: cmdListAsProto(pw); return; - case CMD_LIST: // fallthrough + case CMD_IPCLIENT: { + final String[] ipclientArgs = ((args != null) && (args.length > 1)) + ? Arrays.copyOfRange(args, 1, args.length) + : null; + IpClient.dumpAllLogs(pw, ipclientArgs); + return; + } + case CMD_LIST: + cmdList(pw); + return; default: cmdList(pw); + pw.println(""); + IpClient.dumpAllLogs(pw, null); return; } } diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index d6999ddf07f60..63ae09a79379e 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -54,6 +54,7 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.R; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IState; import com.android.internal.util.Preconditions; @@ -74,6 +75,7 @@ import java.util.Objects; import java.util.List; import java.util.Set; import java.util.StringJoiner; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -100,6 +102,36 @@ public class IpClient extends StateMachine { private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class }; private static final SparseArray sWhatToString = MessageUtils.findMessageNames(sMessageClasses); + // Two static concurrent hashmaps of interface name to logging classes. + // One holds StateMachine logs and the other connectivity packet logs. + private static final ConcurrentHashMap sSmLogs = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap sPktLogs = new ConcurrentHashMap<>(); + + // If |args| is non-empty, assume it's a list of interface names for which + // we should print IpClient logs (filter out all others). + public static void dumpAllLogs(PrintWriter writer, String[] args) { + for (String ifname : sSmLogs.keySet()) { + if (!ArrayUtils.isEmpty(args) && !ArrayUtils.contains(args, ifname)) continue; + + writer.println(String.format("--- BEGIN %s ---", ifname)); + + final SharedLog smLog = sSmLogs.get(ifname); + if (smLog != null) { + writer.println("State machine log:"); + smLog.dump(null, writer, null); + } + + writer.println(""); + + final LocalLog pktLog = sPktLogs.get(ifname); + if (pktLog != null) { + writer.println("Connectivity packet log:"); + pktLog.readOnlyLocalLog().dump(null, writer, null); + } + + writer.println(String.format("--- END %s ---", ifname)); + } + } /** * Callbacks for handling IpClient events. @@ -680,8 +712,10 @@ public class IpClient extends StateMachine { mShutdownLatch = new CountDownLatch(1); mNwService = deps.getNMS(); - mLog = new SharedLog(MAX_LOG_RECORDS, mTag); - mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS); + sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag)); + mLog = sSmLogs.get(mInterfaceName); + sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS)); + mConnectivityPacketLog = sPktLogs.get(mInterfaceName); mMsgStateLogger = new MessageHandlingLogger(); // TODO: Consider creating, constructing, and passing in some kind of