• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *i
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.net;
18 
19 import static android.net.NetworkStats.SET_DEFAULT;
20 import static android.net.NetworkStats.SET_FOREGROUND;
21 import static android.net.NetworkStats.TAG_NONE;
22 import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID;
23 import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG;
24 import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT;
25 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
26 
27 import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UID;
28 import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UIDTAG;
29 import static com.android.server.ConnectivityStatsLog.NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT;
30 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
31 
32 import static org.mockito.Mockito.any;
33 import static org.mockito.Mockito.anyLong;
34 import static org.mockito.Mockito.doThrow;
35 import static org.mockito.Mockito.mock;
36 import static org.mockito.Mockito.never;
37 import static org.mockito.Mockito.reset;
38 import static org.mockito.Mockito.times;
39 import static org.mockito.Mockito.verify;
40 
41 import android.annotation.NonNull;
42 import android.net.NetworkIdentity;
43 import android.net.NetworkIdentitySet;
44 import android.net.NetworkStats;
45 import android.net.NetworkStatsCollection;
46 import android.os.DropBoxManager;
47 
48 import androidx.test.filters.SmallTest;
49 
50 import com.android.internal.util.FileRotator;
51 import com.android.metrics.NetworkStatsMetricsLogger;
52 import com.android.testutils.DevSdkIgnoreRule;
53 import com.android.testutils.DevSdkIgnoreRunner;
54 
55 import libcore.testing.io.TestIoUtils;
56 
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.Mock;
61 import org.mockito.MockitoAnnotations;
62 
63 import java.io.DataOutputStream;
64 import java.io.File;
65 import java.io.FileOutputStream;
66 import java.io.IOException;
67 
68 @RunWith(DevSdkIgnoreRunner.class)
69 @SmallTest
70 @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
71 public final class NetworkStatsRecorderTest {
72     private static final String TAG = NetworkStatsRecorderTest.class.getSimpleName();
73 
74     private static final String TEST_PREFIX = "test";
75     private static final int TEST_UID1 = 1234;
76     private static final int TEST_UID2 = 1235;
77 
78     @Mock private DropBoxManager mDropBox;
79     @Mock private NetworkStats.NonMonotonicObserver mObserver;
80 
81     @Before
setUp()82     public void setUp() {
83         MockitoAnnotations.initMocks(this);
84     }
85 
buildRecorder(FileRotator rotator, boolean wipeOnError)86     private NetworkStatsRecorder buildRecorder(FileRotator rotator, boolean wipeOnError) {
87         return new NetworkStatsRecorder(rotator, mObserver, mDropBox, TEST_PREFIX,
88                 HOUR_IN_MILLIS, false /* includeTags */, wipeOnError,
89                 false /* useFastDataInput */, null /* baseDir */);
90     }
91 
92     @Test
testWipeOnError()93     public void testWipeOnError() throws Exception {
94         final FileRotator rotator = mock(FileRotator.class);
95         final NetworkStatsRecorder wipeOnErrorRecorder = buildRecorder(rotator, true);
96 
97         // Assuming that the rotator gets an exception happened when read data.
98         doThrow(new IOException()).when(rotator).readMatching(any(), anyLong(), anyLong());
99         wipeOnErrorRecorder.getOrLoadPartialLocked(Long.MIN_VALUE, Long.MAX_VALUE);
100         // Verify that the files will be deleted.
101         verify(rotator, times(1)).deleteAll();
102         reset(rotator);
103 
104         final NetworkStatsRecorder noWipeOnErrorRecorder = buildRecorder(rotator, false);
105         doThrow(new IOException()).when(rotator).readMatching(any(), anyLong(), anyLong());
106         noWipeOnErrorRecorder.getOrLoadPartialLocked(Long.MIN_VALUE, Long.MAX_VALUE);
107         // Verify that the rotator won't delete files.
108         verify(rotator, never()).deleteAll();
109     }
110 
111     @Test
testFileReadingMetrics_empty()112     public void testFileReadingMetrics_empty() {
113         final NetworkStatsCollection collection = new NetworkStatsCollection(30);
114         final NetworkStatsMetricsLogger.Dependencies deps =
115                 mock(NetworkStatsMetricsLogger.Dependencies.class);
116         final NetworkStatsMetricsLogger logger = new NetworkStatsMetricsLogger(deps);
117         logger.logRecorderFileReading(PREFIX_XT, 888, null /* statsDir */, collection,
118                 false /* useFastDataInput */);
119         verify(deps).writeRecorderFileReadingStats(
120                 NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT,
121                 1 /* readIndex */,
122                 888 /* readLatencyMillis */,
123                 0 /* fileCount */,
124                 0 /* totalFileSize */,
125                 0 /* keys */,
126                 0 /* uids */,
127                 0 /* totalHistorySize */,
128                 false /* useFastDataInput */
129         );
130 
131         // Write second time, verify the index increases.
132         logger.logRecorderFileReading(PREFIX_XT, 567, null /* statsDir */, collection,
133                 true /* useFastDataInput */);
134         verify(deps).writeRecorderFileReadingStats(
135                 NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_XT,
136                 2 /* readIndex */,
137                 567 /* readLatencyMillis */,
138                 0 /* fileCount */,
139                 0 /* totalFileSize */,
140                 0 /* keys */,
141                 0 /* uids */,
142                 0 /* totalHistorySize */,
143                 true /* useFastDataInput */
144         );
145     }
146 
147     @Test
testFileReadingMetrics()148     public void testFileReadingMetrics() {
149         final NetworkStatsCollection collection = new NetworkStatsCollection(30);
150         final NetworkStats.Entry entry = new NetworkStats.Entry();
151         final NetworkIdentitySet identSet = new NetworkIdentitySet();
152         identSet.add(new NetworkIdentity.Builder().build());
153         // Empty entries will be skipped, put some ints to make sure they can be recorded.
154         entry.rxBytes = 1;
155 
156         collection.recordData(identSet, TEST_UID1, SET_DEFAULT, TAG_NONE, 0, 60, entry);
157         collection.recordData(identSet, TEST_UID2, SET_DEFAULT, TAG_NONE, 0, 60, entry);
158         collection.recordData(identSet, TEST_UID2, SET_FOREGROUND, TAG_NONE, 30, 60, entry);
159 
160         final NetworkStatsMetricsLogger.Dependencies deps =
161                 mock(NetworkStatsMetricsLogger.Dependencies.class);
162         final NetworkStatsMetricsLogger logger = new NetworkStatsMetricsLogger(deps);
163         logger.logRecorderFileReading(PREFIX_UID, 123, null /* statsDir */, collection,
164                 false /* useFastDataInput */);
165         verify(deps).writeRecorderFileReadingStats(
166                 NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UID,
167                 1 /* readIndex */,
168                 123 /* readLatencyMillis */,
169                 0 /* fileCount */,
170                 0 /* totalFileSize */,
171                 3 /* keys */,
172                 2 /* uids */,
173                 5 /* totalHistorySize */,
174                 false /* useFastDataInput */
175         );
176     }
177 
178     @Test
testFileReadingMetrics_fileAttributes()179     public void testFileReadingMetrics_fileAttributes() throws IOException {
180         final NetworkStatsCollection collection = new NetworkStatsCollection(30);
181 
182         // Create files for testing. Only the first and the third files should be counted,
183         // with total 26 (each char takes 2 bytes) bytes in the content.
184         final File statsDir = TestIoUtils.createTemporaryDirectory(getClass().getSimpleName());
185         write(statsDir, "uid_tag.1024-2048", "wanted");
186         write(statsDir, "uid_tag.1024-2048.backup", "");
187         write(statsDir, "uid_tag.2048-", "wanted2");
188         write(statsDir, "uid.2048-4096", "unwanted");
189         write(statsDir, "uid.2048-4096.backup", "unwanted2");
190 
191         final NetworkStatsMetricsLogger.Dependencies deps =
192                 mock(NetworkStatsMetricsLogger.Dependencies.class);
193         final NetworkStatsMetricsLogger logger = new NetworkStatsMetricsLogger(deps);
194         logger.logRecorderFileReading(PREFIX_UID_TAG, 678, statsDir, collection,
195                 false /* useFastDataInput */);
196         verify(deps).writeRecorderFileReadingStats(
197                 NETWORK_STATS_RECORDER_FILE_OPERATED__RECORDER_PREFIX__PREFIX_UIDTAG,
198                 1 /* readIndex */,
199                 678 /* readLatencyMillis */,
200                 2 /* fileCount */,
201                 26 /* totalFileSize */,
202                 0 /* keys */,
203                 0 /* uids */,
204                 0 /* totalHistorySize */,
205                 false /* useFastDataInput */
206         );
207     }
208 
write(@onNull File baseDir, @NonNull String name, @NonNull String value)209     private void write(@NonNull File baseDir, @NonNull String name,
210                        @NonNull String value) throws IOException {
211         final DataOutputStream out = new DataOutputStream(
212                 new FileOutputStream(new File(baseDir, name)));
213         out.writeChars(value);
214         out.close();
215     }
216 }
217