Merge "[AF06] Fill file attributes metrics" into main

This commit is contained in:
Junyu Lai 2023-12-26 04:34:05 +00:00 • committed by Gerrit Code Review
commit 46afd1b4cb
6 changed files with 106 additions and 13 deletions

View file

@ -29,15 +29,19 @@ import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FIL
import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.NetworkStatsCollection;
import android.net.NetworkStatsHistory;
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.ConnectivityStatsLog;
import java.io.File;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Helper class to log NetworkStats related metrics.
@ -94,11 +98,47 @@ public class NetworkStatsMetricsLogger {
}
}
/**
* Get file count and total byte count for the given directory and prefix.
*
* @return File count and total byte count as a pair, or 0s if met errors.
*/
private static Pair<Integer, Integer> getStatsFilesAttributes(
@Nullable File statsDir, @NonNull String prefix) {
if (statsDir == null) return new Pair<>(0, 0);
// Only counts the matching files.
// The files are named in the following format:
// <prefix>.<startTimestamp>-[<endTimestamp>]
// e.g. uid_tag.12345-
// See FileRotator#FileInfo for more detail.
final Pattern pattern = Pattern.compile("^" + prefix + "\\.[0-9]+-[0-9]*$");
// Ensure that base path exists.
statsDir.mkdirs();
int totalFiles = 0;
int totalBytes = 0;
for (String name : emptyIfNull(statsDir.list())) {
if (!pattern.matcher(name).matches()) continue;
totalFiles++;
// Cast to int is safe since stats persistent files are several MBs in total.
totalBytes += (int) (new File(statsDir, name).length());
}
return new Pair<>(totalFiles, totalBytes);
}
private static String [] emptyIfNull(@Nullable String [] array) {
return (array == null) ? new String[0] : array;
}
/**
* Log statistics from the NetworkStatsRecorder file reading process into statsd.
*/
public void logRecorderFileReading(@NonNull String prefix, int readLatencyMillis,
@NonNull NetworkStatsCollection collection) {
@Nullable File statsDir, @NonNull NetworkStatsCollection collection) {
final Set<Integer> uids = new HashSet<>();
final Map<NetworkStatsCollection.Key, NetworkStatsHistory> entries =
collection.getEntries();
@ -112,12 +152,12 @@ public class NetworkStatsMetricsLogger {
totalHistorySize += history.size();
}
// TODO: Fill file characteristics.
final Pair<Integer, Integer> fileAttributes = getStatsFilesAttributes(statsDir, prefix);
mDeps.writeRecorderFileReadingStats(prefixToRecorderType(prefix),
mReadIndex++,
readLatencyMillis,
0 /* fileCount */,
0 /* totalFileSize */,
fileAttributes.first /* fileCount */,
fileAttributes.second /* totalFileSize */,
entries.size(),
uids.size(),
totalHistorySize);

View file

@ -22,6 +22,7 @@ import static android.net.TrafficStats.MB_IN_BYTES;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.NetworkIdentitySet;
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
@ -45,6 +46,7 @@ import com.android.net.module.util.NetworkStatsUtils;
import libcore.io.IoUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -93,6 +95,8 @@ public class NetworkStatsRecorder {
private WeakReference<NetworkStatsCollection> mComplete;
private final NetworkStatsMetricsLogger mMetricsLogger = new NetworkStatsMetricsLogger();
@Nullable
private final File mStatsDir;
/**
* Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
@ -114,6 +118,7 @@ public class NetworkStatsRecorder {
mSinceBoot = new NetworkStatsCollection(mBucketDuration);
mPendingRewriter = null;
mStatsDir = null;
}
/**
@ -121,7 +126,7 @@ public class NetworkStatsRecorder {
*/
public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags,
boolean wipeOnError, boolean useFastDataInput) {
boolean wipeOnError, boolean useFastDataInput, @Nullable File statsDir) {
mRotator = Objects.requireNonNull(rotator, "missing FileRotator");
mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver");
mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager");
@ -136,6 +141,7 @@ public class NetworkStatsRecorder {
mSinceBoot = new NetworkStatsCollection(bucketDuration);
mPendingRewriter = new CombiningRewriter(mPending);
mStatsDir = statsDir;
}
public void setPersistThreshold(long thresholdBytes) {
@ -192,7 +198,8 @@ public class NetworkStatsRecorder {
// For legacy recorders which are used for data integrity check, which
// have wipeOnError flag unset, skip reporting metrics.
if (mWipeOnError) {
mMetricsLogger.logRecorderFileReading(mCookie, (int) (readEnd - readStart), res);
mMetricsLogger.logRecorderFileReading(mCookie, (int) (readEnd - readStart),
mStatsDir, res);
}
}
return res;

View file

@ -969,7 +969,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new NetworkStatsRecorder(new FileRotator(
baseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags,
wipeOnError, false /* useFastDataInput */);
wipeOnError, false /* useFastDataInput */, baseDir);
}
@GuardedBy("mStatsLock")

View file

@ -156,7 +156,8 @@ class NetworkStatsTest {
UID_COLLECTION_BUCKET_DURATION_MS,
false /* includeTags */,
false /* wipeOnError */,
useFastDataInput /* useFastDataInput */
useFastDataInput /* useFastDataInput */,
it
)
recorder.orLoadCompleteLocked
}

View file

@ -20,10 +20,12 @@ import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID;
import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG;
import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UID;
import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UIDTAG;
import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
@ -36,6 +38,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.net.NetworkIdentity;
import android.net.NetworkIdentitySet;
import android.net.NetworkStats;
@ -49,12 +52,17 @@ import com.android.metrics.NetworkStatsMetricsLogger;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import libcore.testing.io.TestIoUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@RunWith(DevSdkIgnoreRunner.class)
@ -78,7 +86,7 @@ public final class NetworkStatsRecorderTest {
private NetworkStatsRecorder buildRecorder(FileRotator rotator, boolean wipeOnError) {
return new NetworkStatsRecorder(rotator, mObserver, mDropBox, TEST_PREFIX,
HOUR_IN_MILLIS, false /* includeTags */, wipeOnError,
false /* useFastDataInput */);
false /* useFastDataInput */, null /* baseDir */);
}
@Test
@ -106,7 +114,7 @@ public final class NetworkStatsRecorderTest {
final NetworkStatsMetricsLogger.Dependencies deps =
mock(NetworkStatsMetricsLogger.Dependencies.class);
final NetworkStatsMetricsLogger logger = new NetworkStatsMetricsLogger(deps);
logger.logRecorderFileReading(PREFIX_XT, 888, collection);
logger.logRecorderFileReading(PREFIX_XT, 888, null /* statsDir */, collection);
verify(deps).writeRecorderFileReadingStats(
NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT,
1 /* readIndex */,
@ -119,7 +127,7 @@ public final class NetworkStatsRecorderTest {
);
// Write second time, verify the index increases.
logger.logRecorderFileReading(PREFIX_XT, 567, collection);
logger.logRecorderFileReading(PREFIX_XT, 567, null /* statsDir */, collection);
verify(deps).writeRecorderFileReadingStats(
NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT,
2 /* readIndex */,
@ -148,7 +156,7 @@ public final class NetworkStatsRecorderTest {
final NetworkStatsMetricsLogger.Dependencies deps =
mock(NetworkStatsMetricsLogger.Dependencies.class);
final NetworkStatsMetricsLogger logger = new NetworkStatsMetricsLogger(deps);
logger.logRecorderFileReading(PREFIX_UID, 123, collection);
logger.logRecorderFileReading(PREFIX_UID, 123, null /* statsDir */, collection);
verify(deps).writeRecorderFileReadingStats(
NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UID,
1 /* readIndex */,
@ -160,4 +168,41 @@ public final class NetworkStatsRecorderTest {
5 /* totalHistorySize */
);
}
@Test
public void testFileReadingMetrics_fileAttributes() throws IOException {
final NetworkStatsCollection collection = new NetworkStatsCollection(30);
// Create files for testing. Only the first and the third files should be counted,
// with total 26 (each char takes 2 bytes) bytes in the content.
final File statsDir = TestIoUtils.createTemporaryDirectory(getClass().getSimpleName());
write(statsDir, "uid_tag.1024-2048", "wanted");
write(statsDir, "uid_tag.1024-2048.backup", "");
write(statsDir, "uid_tag.2048-", "wanted2");
write(statsDir, "uid.2048-4096", "unwanted");
write(statsDir, "uid.2048-4096.backup", "unwanted2");
final NetworkStatsMetricsLogger.Dependencies deps =
mock(NetworkStatsMetricsLogger.Dependencies.class);
final NetworkStatsMetricsLogger logger = new NetworkStatsMetricsLogger(deps);
logger.logRecorderFileReading(PREFIX_UID_TAG, 678, statsDir, collection);
verify(deps).writeRecorderFileReadingStats(
NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UIDTAG,
1 /* readIndex */,
678 /* readLatencyMillis */,
2 /* fileCount */,
26 /* totalFileSize */,
0 /* keys */,
0 /* uids */,
0 /* totalHistorySize */
);
}
private void write(@NonNull File baseDir, @NonNull String name,
@NonNull String value) throws IOException {
final DataOutputStream out = new DataOutputStream(
new FileOutputStream(new File(baseDir, name)));
out.writeChars(value);
out.close();
}
}

View file

@ -2231,7 +2231,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
return new NetworkStatsRecorder(new FileRotator(
directory, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
observer, dropBox, prefix, config.bucketDuration, includeTags, wipeOnError,
false /* useFastDataInput */);
false /* useFastDataInput */, directory);
}
private NetworkStatsCollection getLegacyCollection(String prefix, boolean includeTags) {