Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26886241 authored by Xiao Ma's avatar Xiao Ma Committed by Gerrit Code Review
Browse files

Merge "Add IpReachabilityMonitor metrics."

parents f035c807 d9d3bccc
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1944,7 +1944,7 @@ public class IpClient extends StateMachine {
        }

        if (mIpReachabilityMonitor != null) {
            mIpReachabilityMonitor.probeAll();
            mIpReachabilityMonitor.probeAll(true /* dueToRoam */);
        }

        // Check whether to refresh previous IP lease on L2 roaming happened.
@@ -2419,7 +2419,7 @@ public class IpClient extends StateMachine {
                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
                    // roams.
                    if (mIpReachabilityMonitor != null) {
                        mIpReachabilityMonitor.probeAll();
                        mIpReachabilityMonitor.probeAll(false /* dueToRoam */);
                    }
                    break;

+103 −6
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.SystemClock;
import android.stats.connectivity.IpType;
import android.stats.connectivity.NudEventType;
import android.stats.connectivity.NudNeighborType;
import android.text.TextUtils;
import android.util.Log;

@@ -52,6 +55,7 @@ import com.android.internal.util.Preconditions;
import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.netlink.StructNdMsg;
import com.android.networkstack.R;
import com.android.networkstack.metrics.IpReachabilityMonitorMetrics;

import java.io.PrintWriter;
import java.net.Inet6Address;
@@ -170,6 +174,7 @@ public class IpReachabilityMonitor {
        void acquireWakeLock(long durationMs);
        IpNeighborMonitor makeIpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb);
        boolean isFeatureEnabled(Context context, String name, boolean defaultEnabled);
        IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics();

        static Dependencies makeDefault(Context context, String iface) {
            final String lockName = TAG + "." + iface;
@@ -191,6 +196,10 @@ public class IpReachabilityMonitor {
                    return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name,
                            defaultEnabled);
                }

                public IpReachabilityMonitorMetrics getIpReachabilityMonitorMetrics() {
                    return new IpReachabilityMonitorMetrics();
                }
            };
        }
    }
@@ -204,10 +213,14 @@ public class IpReachabilityMonitor {
    private final IpConnectivityLog mMetricsLog;
    private final Context mContext;
    private final INetd mNetd;
    private final IpReachabilityMonitorMetrics mIpReachabilityMetrics;
    private LinkProperties mLinkProperties = new LinkProperties();
    private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
    // Time in milliseconds of the last forced probe request.
    private volatile long mLastProbeTimeMs;
    // Time in milliseconds of the last forced probe request due to roam or CMD_CONFIRM.
    private long mLastProbeDueToRoamMs;
    private long mLastProbeDueToConfirmMs;
    private int mNumSolicits;
    private int mInterSolicitIntervalMs;
    @NonNull
@@ -269,6 +282,7 @@ public class IpReachabilityMonitor {
                    }
                });
        mIpNeighborMonitor.start();
        mIpReachabilityMetrics = dependencies.getIpReachabilityMonitorMetrics();
    }

    public void stop() {
@@ -332,6 +346,13 @@ public class IpReachabilityMonitor {
        return false;
    }

    private boolean isNeighborDnsServer(@NonNull final NeighborEvent event) {
        for (InetAddress dns : mLinkProperties.getDnsServers()) {
            if (event.ip.equals(dns)) return true;
        }
        return false;
    }

    private boolean isMulticastResolicitEnabled() {
        return mDependencies.isFeatureEnabled(mContext, IP_REACHABILITY_MCAST_RESOLICIT_VERSION,
                false /* defaultEnabled */);
@@ -433,7 +454,7 @@ public class IpReachabilityMonitor {
            // an InetAddress argument.
            mCallback.notifyLost(ip, logMsg);
        }
        logNudFailed(lostProvisioning);
        logNudFailed(event, lostProvisioning);
    }

    private void maybeRestoreNeighborParameters() {
@@ -457,7 +478,13 @@ public class IpReachabilityMonitor {
        return !mUsingMultinetworkPolicyTracker || mCm.shouldAvoidBadWifi();
    }

    public void probeAll() {
    /**
     * Force probe to verify whether or not the critical on-link neighbours are still reachable.
     *
     * @param dueToRoam indicate on which situation forced probe has been sent, e.g., on post
     *                  roaming or receiving CMD_CONFIRM from IpClient.
     */
    public void probeAll(boolean dueToRoam) {
        setNeighbourParametersPostRoaming();

        final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
@@ -478,6 +505,11 @@ public class IpReachabilityMonitor {
            logEvent(IpReachabilityEvent.PROBE, rval);
        }
        mLastProbeTimeMs = SystemClock.elapsedRealtime();
        if (dueToRoam) {
            mLastProbeDueToRoamMs = mLastProbeTimeMs;
        } else {
            mLastProbeDueToConfirmMs = mLastProbeTimeMs;
        }
    }

    private long getProbeWakeLockDuration() {
@@ -537,16 +569,81 @@ public class IpReachabilityMonitor {
        mInterSolicitIntervalMs = interSolicitIntervalMs;
    }

    private boolean isFromProbe() {
        final long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
        return duration < getProbeWakeLockDuration();
    }

    private boolean isProbedNudFailureDueToRoam() {
        // Check to which probe expiry the curren timestamp gets close when NUD failure event
        // happens, theoretically that indicates which probe event(due to roam or CMD_CONFIRM)
        // was triggered eariler.
        //
        // Note that this would be incorrect if the probe or confirm was so long ago that the
        // probe duration has already expired. That cannot happen because isFromProbe would return
        // false, and this method is only called on NUD failures due to probes.
        final long probeExpiryAfterRoam = mLastProbeDueToRoamMs + getProbeWakeLockDuration();
        final long probeExpiryAfterConfirm =
                mLastProbeDueToConfirmMs + getProbeWakeLockDuration();
        final long currentTime = SystemClock.elapsedRealtime();
        return Math.abs(probeExpiryAfterRoam - currentTime)
                < Math.abs(probeExpiryAfterConfirm - currentTime);
    }

    private void logEvent(int probeType, int errorCode) {
        int eventType = probeType | (errorCode & 0xff);
        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
    }

    private void logNudFailed(boolean lostProvisioning) {
        long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
        boolean isFromProbe = (duration < getProbeWakeLockDuration());
        int eventType = nudFailureEventType(isFromProbe, lostProvisioning);
    private void logNudFailed(final NeighborEvent event, boolean lostProvisioning) {
        final int eventType = nudFailureEventType(isFromProbe(), lostProvisioning);
        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
        logNeighborLostEvent(event, lostProvisioning);
    }

    /**
     * Returns the neighbor type code corresponding to the given conditions.
     */
    private NudNeighborType getNeighborType(final NeighborEvent event) {
        final boolean isGateway = isNeighborDefaultRouter(event);
        final boolean isDnsServer = isNeighborDnsServer(event);

        if (isGateway && isDnsServer) return NudNeighborType.NUD_NEIGHBOR_BOTH;
        if (isGateway && !isDnsServer) return NudNeighborType.NUD_NEIGHBOR_GATEWAY;
        if (!isGateway && isDnsServer) return NudNeighborType.NUD_NEIGHBOR_DNS;
        return NudNeighborType.NUD_NEIGHBOR_UNKNOWN;
    }

    /**
     * Returns the NUD failure event type code corresponding to the given conditions.
     */
    private static NudEventType getNudFailureEventType(boolean isFromProbe, boolean isDueToRoam,
            boolean isProvisioningLost) {
        if (!isFromProbe) {
            return isProvisioningLost
                    ? NudEventType.NUD_ORGANIC_FAILED_CRITICAL
                    : NudEventType.NUD_ORGANIC_FAILED;
        }
        return isProvisioningLost
                ? isDueToRoam
                        ? NudEventType.NUD_POST_ROAMING_FAILED_CRITICAL
                        : NudEventType.NUD_CONFIRM_FAILED_CRITICAL
                : isDueToRoam
                        ? NudEventType.NUD_POST_ROAMING_FAILED
                        : NudEventType.NUD_CONFIRM_FAILED;
    }

    /**
     * Log NUD failure metrics with new Westworld APIs while the function using mMetricsLog API
     * still sends the legacy metrics, @see #logNudFailed.
     */
    private void logNeighborLostEvent(final NeighborEvent event, boolean isProvisioningLost) {
        final IpType ipType = (event.ip instanceof Inet6Address) ? IpType.IPV6 : IpType.IPV4;
        mIpReachabilityMetrics.setNudIpType(ipType);
        mIpReachabilityMetrics.setNudNeighborType(getNeighborType(event));
        mIpReachabilityMetrics.setNudEventType(getNudFailureEventType(isFromProbe(),
                isProbedNudFailureDueToRoam(), isProvisioningLost));
        mIpReachabilityMetrics.statsWrite();
    }

    /**
+9 −9
Original line number Diff line number Diff line
@@ -157,17 +157,17 @@ public class IpProvisioningMetrics {
        mStatsBuilder.setDhcpSession(mDhcpSessionBuilder);
        mStatsBuilder.setProvisioningDurationMicros(mWatch.stop());
        mStatsBuilder.setRandomNumber((int) (Math.random() * 1000));
        final NetworkIpProvisioningReported Stats = mStatsBuilder.build();
        final byte[] DhcpSession = Stats.getDhcpSession().toByteArray();
        final NetworkIpProvisioningReported stats = mStatsBuilder.build();
        final byte[] DhcpSession = stats.getDhcpSession().toByteArray();
        NetworkStackStatsLog.write(NetworkStackStatsLog.NETWORK_IP_PROVISIONING_REPORTED,
                Stats.getTransportType().getNumber(),
                Stats.getIpv4LatencyMicros(),
                Stats.getIpv6LatencyMicros(),
                Stats.getProvisioningDurationMicros(),
                Stats.getDisconnectCode().getNumber(),
                stats.getTransportType().getNumber(),
                stats.getIpv4LatencyMicros(),
                stats.getIpv6LatencyMicros(),
                stats.getProvisioningDurationMicros(),
                stats.getDisconnectCode().getNumber(),
                DhcpSession,
                Stats.getRandomNumber());
                stats.getRandomNumber());
        mWatch.reset();
        return Stats;
        return stats;
    }
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.networkstack.metrics;

import android.stats.connectivity.IpType;
import android.stats.connectivity.NudEventType;
import android.stats.connectivity.NudNeighborType;

/**
 * Class to record the network stack IpReachabilityMonitor metrics into statsd.
 *
 * This class is not thread-safe, and should always be accessed from the same thread.
 *
 * @hide
 */
public class IpReachabilityMonitorMetrics {
    private final NetworkIpReachabilityMonitorReported.Builder mStatsBuilder =
            NetworkIpReachabilityMonitorReported.newBuilder();

    /**
     * Write the NUD event type into mStatsBuilder.
     */
    public void setNudEventType(final NudEventType type) {
        mStatsBuilder.setEventType(type);
    }

    /**
     * Write the NUD probe type(IPv4 or IPv6) into mStatsBuilder.
     */
    public void setNudIpType(final IpType type) {
        mStatsBuilder.setIpType(type);
    }

    /**
     * Write the NUD probe neighbor type into mStatsBuilder.
     */
    public void setNudNeighborType(final NudNeighborType type) {
        mStatsBuilder.setNeighborType(type);
    }

    /**
     * Write the NetworkIpReachabilityMonitorReported proto into statsd.
     */
    public NetworkIpReachabilityMonitorReported statsWrite() {
        final NetworkIpReachabilityMonitorReported stats = mStatsBuilder.build();
        NetworkStackStatsLog.write(NetworkStackStatsLog.NETWORK_IP_REACHABILITY_MONITOR_REPORTED,
                stats.getEventType().getNumber(),
                stats.getIpType().getNumber(),
                stats.getNeighborType().getNumber());
        return stats;
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -172,3 +172,19 @@ message NetworkStackQuirkReported {
    // Record each Quirk event
    optional .android.stats.connectivity.NetworkQuirkEvent event = 2;
}

/**
 * Logs Neighbor Unreachability Detection probe event.
 * Logged from:
 * src/com/android/networkstack/metrics/IpReachabilityMonitorMetrics.java
 */
message NetworkIpReachabilityMonitorReported {
    // Neighbor Unreachability Detection event.
    optional .android.stats.connectivity.NudEventType event_type = 1;

    // NUD probe based on IPv4 ARP or IPv6 ND packet.
    optional .android.stats.connectivity.IpType ip_type = 2;

    // NUD neighbor type, default gateway, DNS server or both.
    optional .android.stats.connectivity.NudNeighborType neighbor_type = 3;
}
Loading