Merge "Support NetworkStatsEventLogger" into main
This commit is contained in:
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.net;
|
||||||
|
|
||||||
|
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||||
|
|
||||||
|
import android.annotation.IntDef;
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.util.IndentingPrintWriter;
|
||||||
|
import android.util.LocalLog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for NetworkStatsService to log events.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class NetworkStatsEventLogger {
|
||||||
|
static final int POLL_REASON_DUMPSYS = 0;
|
||||||
|
static final int POLL_REASON_FORCE_UPDATE = 1;
|
||||||
|
static final int POLL_REASON_GLOBAL_ALERT = 2;
|
||||||
|
static final int POLL_REASON_NETWORK_STATUS_CHANGED = 3;
|
||||||
|
static final int POLL_REASON_OPEN_SESSION = 4;
|
||||||
|
static final int POLL_REASON_PERIODIC = 5;
|
||||||
|
static final int POLL_REASON_RAT_CHANGED = 6;
|
||||||
|
static final int POLL_REASON_REG_CALLBACK = 7;
|
||||||
|
static final int POLL_REASON_REMOVE_UIDS = 8;
|
||||||
|
static final int POLL_REASON_UPSTREAM_CHANGED = 9;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef(prefix = { "POLL_REASON_" }, value = {
|
||||||
|
POLL_REASON_DUMPSYS,
|
||||||
|
POLL_REASON_FORCE_UPDATE,
|
||||||
|
POLL_REASON_GLOBAL_ALERT,
|
||||||
|
POLL_REASON_NETWORK_STATUS_CHANGED,
|
||||||
|
POLL_REASON_OPEN_SESSION,
|
||||||
|
POLL_REASON_PERIODIC,
|
||||||
|
POLL_REASON_RAT_CHANGED,
|
||||||
|
POLL_REASON_REMOVE_UIDS,
|
||||||
|
POLL_REASON_REG_CALLBACK,
|
||||||
|
POLL_REASON_UPSTREAM_CHANGED
|
||||||
|
})
|
||||||
|
public @interface PollReason {
|
||||||
|
}
|
||||||
|
static final int MAX_POLL_REASON = POLL_REASON_UPSTREAM_CHANGED;
|
||||||
|
|
||||||
|
@VisibleForTesting(visibility = PRIVATE)
|
||||||
|
public static final int MAX_EVENTS_LOGS = 50;
|
||||||
|
private final LocalLog mEventChanges = new LocalLog(MAX_EVENTS_LOGS);
|
||||||
|
private final int[] mPollEventCounts = new int[MAX_POLL_REASON + 1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a poll event.
|
||||||
|
*
|
||||||
|
* @param flags Flags used when polling. See NetworkStatsService#FLAG_PERSIST_*.
|
||||||
|
* @param event The event of polling to be logged.
|
||||||
|
*/
|
||||||
|
public void logPollEvent(int flags, @NonNull PollEvent event) {
|
||||||
|
mEventChanges.log("Poll(flags=" + flags + ", " + event + ")");
|
||||||
|
mPollEventCounts[event.reason]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print poll counts per reason into the given stream.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(visibility = PRIVATE)
|
||||||
|
public void dumpPollCountsPerReason(@NonNull IndentingPrintWriter pw) {
|
||||||
|
pw.println("Poll counts per reason:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
for (int i = 0; i <= MAX_POLL_REASON; i++) {
|
||||||
|
pw.println(PollEvent.pollReasonNameOf(i) + ": " + mPollEventCounts[i]);
|
||||||
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print recent poll events into the given stream.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(visibility = PRIVATE)
|
||||||
|
public void dumpRecentPollEvents(@NonNull IndentingPrintWriter pw) {
|
||||||
|
pw.println("Recent poll events:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
mEventChanges.reverseDump(pw);
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the object's state into the given stream.
|
||||||
|
*/
|
||||||
|
public void dump(@NonNull IndentingPrintWriter pw) {
|
||||||
|
dumpPollCountsPerReason(pw);
|
||||||
|
dumpRecentPollEvents(pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PollEvent {
|
||||||
|
public final int reason;
|
||||||
|
|
||||||
|
public PollEvent(@PollReason int reason) {
|
||||||
|
if (reason < 0 || reason > MAX_POLL_REASON) {
|
||||||
|
throw new IllegalArgumentException("Unsupported poll reason: " + reason);
|
||||||
|
}
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PollEvent{" + "reason=" + pollReasonNameOf(reason) + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the given reason.
|
||||||
|
*
|
||||||
|
* If the reason does not have a String representation, returns its integer representation.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String pollReasonNameOf(@PollReason int reason) {
|
||||||
|
switch (reason) {
|
||||||
|
case POLL_REASON_DUMPSYS: return "DUMPSYS";
|
||||||
|
case POLL_REASON_FORCE_UPDATE: return "FORCE_UPDATE";
|
||||||
|
case POLL_REASON_GLOBAL_ALERT: return "GLOBAL_ALERT";
|
||||||
|
case POLL_REASON_NETWORK_STATUS_CHANGED: return "NETWORK_STATUS_CHANGED";
|
||||||
|
case POLL_REASON_OPEN_SESSION: return "OPEN_SESSION";
|
||||||
|
case POLL_REASON_PERIODIC: return "PERIODIC";
|
||||||
|
case POLL_REASON_RAT_CHANGED: return "RAT_CHANGED";
|
||||||
|
case POLL_REASON_REMOVE_UIDS: return "REMOVE_UIDS";
|
||||||
|
case POLL_REASON_REG_CALLBACK: return "REG_CALLBACK";
|
||||||
|
case POLL_REASON_UPSTREAM_CHANGED: return "UPSTREAM_CHANGED";
|
||||||
|
default: return Integer.toString(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,6 +66,17 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS;
|
|||||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||||
import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport;
|
import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport;
|
||||||
import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
|
import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_PERIODIC;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_DUMPSYS;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_FORCE_UPDATE;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_GLOBAL_ALERT;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_NETWORK_STATUS_CHANGED;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_OPEN_SESSION;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REG_CALLBACK;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REMOVE_UIDS;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_UPSTREAM_CHANGED;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.PollEvent;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -281,6 +292,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
static final String NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME = "import.attempts";
|
static final String NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME = "import.attempts";
|
||||||
static final String NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME = "import.successes";
|
static final String NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME = "import.successes";
|
||||||
static final String NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME = "import.fallbacks";
|
static final String NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME = "import.fallbacks";
|
||||||
|
static final String CONFIG_ENABLE_NETWORK_STATS_EVENT_LOGGER =
|
||||||
|
"enable_network_stats_event_logger";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final NetworkStatsFactory mStatsFactory;
|
private final NetworkStatsFactory mStatsFactory;
|
||||||
@@ -441,6 +454,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
* Map from key {@code OpenSessionKey} to count of opened sessions. This is for recording
|
* Map from key {@code OpenSessionKey} to count of opened sessions. This is for recording
|
||||||
* the caller of open session and it is only for debugging.
|
* the caller of open session and it is only for debugging.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Move to NetworkStatsEventLogger to centralize event logging.
|
||||||
@GuardedBy("mOpenSessionCallsLock")
|
@GuardedBy("mOpenSessionCallsLock")
|
||||||
private final HashMap<OpenSessionKey, Integer> mOpenSessionCallsPerCaller = new HashMap<>();
|
private final HashMap<OpenSessionKey, Integer> mOpenSessionCallsPerCaller = new HashMap<>();
|
||||||
|
|
||||||
@@ -513,20 +527,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_PERFORM_POLL: {
|
case MSG_PERFORM_POLL: {
|
||||||
performPoll(FLAG_PERSIST_ALL);
|
performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent((int) msg.obj));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSG_NOTIFY_NETWORK_STATUS: {
|
case MSG_NOTIFY_NETWORK_STATUS: {
|
||||||
synchronized (mStatsLock) {
|
synchronized (mStatsLock) {
|
||||||
// If no cached states, ignore.
|
// If no cached states, ignore.
|
||||||
if (mLastNetworkStateSnapshots == null) break;
|
if (mLastNetworkStateSnapshots == null) break;
|
||||||
handleNotifyNetworkStatus(
|
handleNotifyNetworkStatus(mDefaultNetworks, mLastNetworkStateSnapshots,
|
||||||
mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
|
mActiveIface, maybeCreatePollEvent((int) msg.obj));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSG_PERFORM_POLL_REGISTER_ALERT: {
|
case MSG_PERFORM_POLL_REGISTER_ALERT: {
|
||||||
performPoll(FLAG_PERSIST_NETWORK);
|
performPoll(FLAG_PERSIST_NETWORK,
|
||||||
|
maybeCreatePollEvent(POLL_REASON_GLOBAL_ALERT));
|
||||||
registerGlobalAlert();
|
registerGlobalAlert();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -612,6 +627,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
mStatsMapB = mDeps.getStatsMapB();
|
mStatsMapB = mDeps.getStatsMapB();
|
||||||
mAppUidStatsMap = mDeps.getAppUidStatsMap();
|
mAppUidStatsMap = mDeps.getAppUidStatsMap();
|
||||||
mIfaceStatsMap = mDeps.getIfaceStatsMap();
|
mIfaceStatsMap = mDeps.getIfaceStatsMap();
|
||||||
|
// To prevent any possible races, the flag is not allowed to change until rebooting.
|
||||||
|
mSupportEventLogger = mDeps.supportEventLogger(mContext);
|
||||||
|
if (mSupportEventLogger) {
|
||||||
|
mEventLogger = new NetworkStatsEventLogger();
|
||||||
|
} else {
|
||||||
|
mEventLogger = null;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Remove bpfNetMaps creation and always start SkDestroyListener
|
// TODO: Remove bpfNetMaps creation and always start SkDestroyListener
|
||||||
// Following code is for the experiment to verify the SkDestroyListener refactoring. Based
|
// Following code is for the experiment to verify the SkDestroyListener refactoring. Based
|
||||||
@@ -840,6 +862,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap, Handler handler) {
|
IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap, Handler handler) {
|
||||||
return new SkDestroyListener(cookieTagMap, handler, new SharedLog(TAG));
|
return new SkDestroyListener(cookieTagMap, handler, new SharedLog(TAG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether event logger feature is supported.
|
||||||
|
*/
|
||||||
|
public boolean supportEventLogger(Context ctx) {
|
||||||
|
return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
|
||||||
|
ctx, CONFIG_ENABLE_NETWORK_STATS_EVENT_LOGGER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1432,7 +1462,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
| NetworkStatsManager.FLAG_POLL_FORCE)) != 0) {
|
| NetworkStatsManager.FLAG_POLL_FORCE)) != 0) {
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
performPoll(FLAG_PERSIST_ALL);
|
performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_OPEN_SESSION));
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
@@ -1828,7 +1858,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface);
|
handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface,
|
||||||
|
maybeCreatePollEvent(POLL_REASON_NETWORK_STATUS_CHANGED));
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
@@ -1845,7 +1876,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
performPoll(FLAG_PERSIST_ALL);
|
// TODO: Log callstack for system server callers.
|
||||||
|
performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_FORCE_UPDATE));
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
@@ -1902,7 +1934,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create baseline stats
|
// Create baseline stats
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL));
|
mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL,
|
||||||
|
POLL_REASON_REG_CALLBACK));
|
||||||
|
|
||||||
return normalizedRequest;
|
return normalizedRequest;
|
||||||
}
|
}
|
||||||
@@ -1999,7 +2032,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
new TetheringManager.TetheringEventCallback() {
|
new TetheringManager.TetheringEventCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onUpstreamChanged(@Nullable Network network) {
|
public void onUpstreamChanged(@Nullable Network network) {
|
||||||
performPoll(FLAG_PERSIST_NETWORK);
|
performPoll(FLAG_PERSIST_NETWORK,
|
||||||
|
maybeCreatePollEvent(POLL_REASON_UPSTREAM_CHANGED));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2008,7 +2042,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
// on background handler thread, and verified UPDATE_DEVICE_STATS
|
// on background handler thread, and verified UPDATE_DEVICE_STATS
|
||||||
// permission above.
|
// permission above.
|
||||||
performPoll(FLAG_PERSIST_ALL);
|
performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_PERIODIC));
|
||||||
|
|
||||||
// verify that we're watching global alert
|
// verify that we're watching global alert
|
||||||
registerGlobalAlert();
|
registerGlobalAlert();
|
||||||
@@ -2072,19 +2106,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
public void handleOnCollapsedRatTypeChanged() {
|
public void handleOnCollapsedRatTypeChanged() {
|
||||||
// Protect service from frequently updating. Remove pending messages if any.
|
// Protect service from frequently updating. Remove pending messages if any.
|
||||||
mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS);
|
mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS);
|
||||||
mHandler.sendMessageDelayed(
|
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS,
|
||||||
mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay());
|
POLL_REASON_RAT_CHANGED), mSettings.getPollDelay());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleNotifyNetworkStatus(
|
private void handleNotifyNetworkStatus(
|
||||||
Network[] defaultNetworks,
|
Network[] defaultNetworks,
|
||||||
NetworkStateSnapshot[] snapshots,
|
NetworkStateSnapshot[] snapshots,
|
||||||
String activeIface) {
|
String activeIface,
|
||||||
|
@Nullable PollEvent event) {
|
||||||
synchronized (mStatsLock) {
|
synchronized (mStatsLock) {
|
||||||
mWakeLock.acquire();
|
mWakeLock.acquire();
|
||||||
try {
|
try {
|
||||||
mActiveIface = activeIface;
|
mActiveIface = activeIface;
|
||||||
handleNotifyNetworkStatusLocked(defaultNetworks, snapshots);
|
handleNotifyNetworkStatusLocked(defaultNetworks, snapshots, event);
|
||||||
} finally {
|
} finally {
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
}
|
}
|
||||||
@@ -2098,7 +2133,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
*/
|
*/
|
||||||
@GuardedBy("mStatsLock")
|
@GuardedBy("mStatsLock")
|
||||||
private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
|
private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
|
||||||
@NonNull NetworkStateSnapshot[] snapshots) {
|
@NonNull NetworkStateSnapshot[] snapshots, @Nullable PollEvent event) {
|
||||||
if (!mSystemReady) return;
|
if (!mSystemReady) return;
|
||||||
if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()");
|
if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()");
|
||||||
|
|
||||||
@@ -2108,7 +2143,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
|
|
||||||
// poll, but only persist network stats to keep codepath fast. UID stats
|
// poll, but only persist network stats to keep codepath fast. UID stats
|
||||||
// will be persisted during next alarm poll event.
|
// will be persisted during next alarm poll event.
|
||||||
performPollLocked(FLAG_PERSIST_NETWORK);
|
performPollLocked(FLAG_PERSIST_NETWORK, event);
|
||||||
|
|
||||||
// Rebuild active interfaces based on connected networks
|
// Rebuild active interfaces based on connected networks
|
||||||
mActiveIfaces.clear();
|
mActiveIfaces.clear();
|
||||||
@@ -2325,12 +2360,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performPoll(int flags) {
|
private void performPoll(int flags, @Nullable PollEvent event) {
|
||||||
synchronized (mStatsLock) {
|
synchronized (mStatsLock) {
|
||||||
mWakeLock.acquire();
|
mWakeLock.acquire();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
performPollLocked(flags);
|
performPollLocked(flags, event);
|
||||||
} finally {
|
} finally {
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
}
|
}
|
||||||
@@ -2342,11 +2377,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
* {@link NetworkStatsHistory}.
|
* {@link NetworkStatsHistory}.
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mStatsLock")
|
@GuardedBy("mStatsLock")
|
||||||
private void performPollLocked(int flags) {
|
private void performPollLocked(int flags, @Nullable PollEvent event) {
|
||||||
if (!mSystemReady) return;
|
if (!mSystemReady) return;
|
||||||
if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
|
if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
|
||||||
Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
|
Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
|
||||||
|
|
||||||
|
if (mSupportEventLogger) {
|
||||||
|
mEventLogger.logPollEvent(flags, event);
|
||||||
|
}
|
||||||
|
|
||||||
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
|
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
|
||||||
final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
|
final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
|
||||||
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
|
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
|
||||||
@@ -2546,7 +2585,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
|
if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
|
||||||
|
|
||||||
// Perform one last poll before removing
|
// Perform one last poll before removing
|
||||||
performPollLocked(FLAG_PERSIST_ALL);
|
performPollLocked(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_REMOVE_UIDS));
|
||||||
|
|
||||||
mUidRecorder.removeUidsLocked(uids);
|
mUidRecorder.removeUidsLocked(uids);
|
||||||
mUidTagRecorder.removeUidsLocked(uids);
|
mUidTagRecorder.removeUidsLocked(uids);
|
||||||
@@ -2629,7 +2668,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (poll) {
|
if (poll) {
|
||||||
performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
|
performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE,
|
||||||
|
maybeCreatePollEvent(POLL_REASON_DUMPSYS));
|
||||||
pw.println("Forced poll");
|
pw.println("Forced poll");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2689,6 +2729,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
pw.println("(failed to dump platform legacy stats import counters)");
|
pw.println("(failed to dump platform legacy stats import counters)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pw.println(CONFIG_ENABLE_NETWORK_STATS_EVENT_LOGGER + ": " + mSupportEventLogger);
|
||||||
|
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
||||||
@@ -2746,6 +2787,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
|
if (mSupportEventLogger) {
|
||||||
|
mEventLogger.dump(pw);
|
||||||
|
}
|
||||||
|
|
||||||
pw.println("Stats Providers:");
|
pw.println("Stats Providers:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
invokeForAllStatsProviderCallbacks((cb) -> {
|
invokeForAllStatsProviderCallbacks((cb) -> {
|
||||||
@@ -3215,6 +3260,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final boolean mSupportEventLogger;
|
||||||
|
@GuardedBy("mStatsLock")
|
||||||
|
@Nullable
|
||||||
|
private final NetworkStatsEventLogger mEventLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a PollEvent instance if the feature is enabled.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public PollEvent maybeCreatePollEvent(@NetworkStatsEventLogger.PollReason int reason) {
|
||||||
|
if (mSupportEventLogger) {
|
||||||
|
return new PollEvent(reason);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
|
private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
|
||||||
@Override
|
@Override
|
||||||
public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
|
public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.net
|
||||||
|
|
||||||
|
import android.util.IndentingPrintWriter
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.MAX_POLL_REASON
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_DUMPSYS
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_FORCE_UPDATE
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_GLOBAL_ALERT
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_NETWORK_STATUS_CHANGED
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_OPEN_SESSION
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_PERIODIC
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REG_CALLBACK
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.PollEvent
|
||||||
|
import com.android.server.net.NetworkStatsEventLogger.PollEvent.pollReasonNameOf
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import java.io.StringWriter
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
const val TEST_PERSIST_FLAG = 0x101
|
||||||
|
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
class NetworkStatsEventLoggerTest {
|
||||||
|
val logger = NetworkStatsEventLogger()
|
||||||
|
val stringWriter = TestStringWriter()
|
||||||
|
val pw = IndentingPrintWriter(stringWriter)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDump_invalid() {
|
||||||
|
// Verify it won't crash.
|
||||||
|
logger.dump(pw)
|
||||||
|
// Clear output buffer.
|
||||||
|
stringWriter.getOutputAndClear()
|
||||||
|
|
||||||
|
// Verify log invalid event throws. And nothing output in the dump.
|
||||||
|
val invalidReasons = listOf(-1, MAX_POLL_REASON + 1)
|
||||||
|
invalidReasons.forEach {
|
||||||
|
assertFailsWith<IllegalArgumentException> {
|
||||||
|
logger.logPollEvent(TEST_PERSIST_FLAG, PollEvent(it))
|
||||||
|
}
|
||||||
|
logger.dumpRecentPollEvents(pw)
|
||||||
|
val output = stringWriter.getOutputAndClear()
|
||||||
|
assertStringNotContains(output, pollReasonNameOf(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDump_valid() {
|
||||||
|
// Choose arbitrary set of reasons for testing.
|
||||||
|
val loggedReasons = listOf(
|
||||||
|
POLL_REASON_GLOBAL_ALERT,
|
||||||
|
POLL_REASON_FORCE_UPDATE,
|
||||||
|
POLL_REASON_DUMPSYS,
|
||||||
|
POLL_REASON_PERIODIC,
|
||||||
|
POLL_REASON_RAT_CHANGED
|
||||||
|
)
|
||||||
|
val nonLoggedReasons = listOf(
|
||||||
|
POLL_REASON_NETWORK_STATUS_CHANGED,
|
||||||
|
POLL_REASON_OPEN_SESSION,
|
||||||
|
POLL_REASON_REG_CALLBACK)
|
||||||
|
|
||||||
|
// Add some valid records.
|
||||||
|
loggedReasons.forEach {
|
||||||
|
logger.logPollEvent(TEST_PERSIST_FLAG, PollEvent(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect dumps.
|
||||||
|
logger.dumpRecentPollEvents(pw)
|
||||||
|
val outputRecentEvents = stringWriter.getOutputAndClear()
|
||||||
|
logger.dumpPollCountsPerReason(pw)
|
||||||
|
val outputCountsPerReason = stringWriter.getOutputAndClear()
|
||||||
|
|
||||||
|
// Verify the output contains at least necessary information.
|
||||||
|
loggedReasons.forEach {
|
||||||
|
// Verify all events are shown in the recent event dump.
|
||||||
|
val eventString = PollEvent(it).toString()
|
||||||
|
assertStringContains(outputRecentEvents, TEST_PERSIST_FLAG.toString())
|
||||||
|
assertStringContains(eventString, pollReasonNameOf(it))
|
||||||
|
assertStringContains(outputRecentEvents, eventString)
|
||||||
|
// Verify counts are 1 for each reason.
|
||||||
|
assertCountForReason(outputCountsPerReason, it, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the output remains untouched for other reasons.
|
||||||
|
nonLoggedReasons.forEach {
|
||||||
|
assertStringNotContains(outputRecentEvents, PollEvent(it).toString())
|
||||||
|
assertCountForReason(outputCountsPerReason, it, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDump_maxEventLogs() {
|
||||||
|
// Choose arbitrary reason.
|
||||||
|
val reasonToBeTested = POLL_REASON_PERIODIC
|
||||||
|
val repeatCount = NetworkStatsEventLogger.MAX_EVENTS_LOGS * 2
|
||||||
|
|
||||||
|
// Collect baseline.
|
||||||
|
logger.dumpRecentPollEvents(pw)
|
||||||
|
val lineCountBaseLine = getLineCount(stringWriter.getOutputAndClear())
|
||||||
|
|
||||||
|
repeat(repeatCount) {
|
||||||
|
logger.logPollEvent(TEST_PERSIST_FLAG, PollEvent(reasonToBeTested))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect dump.
|
||||||
|
logger.dumpRecentPollEvents(pw)
|
||||||
|
val lineCountAfterTest = getLineCount(stringWriter.getOutputAndClear())
|
||||||
|
|
||||||
|
// Verify line count increment is limited.
|
||||||
|
assertEquals(
|
||||||
|
NetworkStatsEventLogger.MAX_EVENTS_LOGS,
|
||||||
|
lineCountAfterTest - lineCountBaseLine
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify count per reason increased for the testing reason.
|
||||||
|
logger.dumpPollCountsPerReason(pw)
|
||||||
|
val outputCountsPerReason = stringWriter.getOutputAndClear()
|
||||||
|
for (reason in 0..MAX_POLL_REASON) {
|
||||||
|
assertCountForReason(
|
||||||
|
outputCountsPerReason,
|
||||||
|
reason,
|
||||||
|
if (reason == reasonToBeTested) repeatCount else 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLineCount(multilineString: String) = multilineString.lines().size
|
||||||
|
|
||||||
|
private fun assertStringContains(got: String, want: String) {
|
||||||
|
assertTrue(got.contains(want), "Wanted: $want, but got: $got")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertStringNotContains(got: String, unwant: String) {
|
||||||
|
assertFalse(got.contains(unwant), "Unwanted: $unwant, but got: $got")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert the reason and the expected count are at the same line.
|
||||||
|
*/
|
||||||
|
private fun assertCountForReason(dump: String, reason: Int, expectedCount: Int) {
|
||||||
|
// Matches strings like "GLOBAL_ALERT: 50" but not too strict since the format might change.
|
||||||
|
val regex = Regex(pollReasonNameOf(reason) + "[^0-9]+" + expectedCount)
|
||||||
|
assertEquals(
|
||||||
|
1,
|
||||||
|
regex.findAll(dump).count(),
|
||||||
|
"Unexpected output: $dump " + " for reason: " + pollReasonNameOf(reason)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestStringWriter : StringWriter() {
|
||||||
|
fun getOutputAndClear() = toString().also { buffer.setLength(0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,6 +64,8 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS;
|
|||||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||||
|
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED;
|
||||||
|
import static com.android.server.net.NetworkStatsEventLogger.PollEvent.pollReasonNameOf;
|
||||||
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
|
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
|
||||||
import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME;
|
import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME;
|
||||||
import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME;
|
import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME;
|
||||||
@@ -525,6 +527,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap, Handler handler) {
|
IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap, Handler handler) {
|
||||||
return mSkDestroyListener;
|
return mSkDestroyListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportEventLogger(@NonNull Context cts) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2674,4 +2681,14 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
|
|||||||
doReturn(null).when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
|
doReturn(null).when(mBpfInterfaceMapUpdater).getIfNameByIndex(10 /* index */);
|
||||||
doTestDumpIfaceStatsMap("unknown");
|
doTestDumpIfaceStatsMap("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basic test to ensure event logger dump is called.
|
||||||
|
// Note that tests to ensure detailed correctness is done in the dedicated tests.
|
||||||
|
// See NetworkStatsEventLoggerTest.
|
||||||
|
@Test
|
||||||
|
public void testDumpEventLogger() {
|
||||||
|
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
|
||||||
|
final String dump = getDump();
|
||||||
|
assertDumpContains(dump, pollReasonNameOf(POLL_REASON_RAT_CHANGED));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user