summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author sangyun <sangyun@google.com> 2024-03-15 10:23:18 +0900
committer sangyun <sangyun@google.com> 2024-03-22 05:34:10 +0900
commitd048c8bf63ef6cddef5e6e1784d17192e12dd69b (patch)
tree4352cbd8f3bcec33b29aae7afa35b261320ffb6b
parent199bedac673b2c351fa95ce6632cc472afea4777 (diff)
Logs atom for data network validation
When network validation is completed, it is recorded in metrics. Network validation begins when a request is received from QNS and a response is recorded as success, failure, not supported, etc. Bug: 327257377 Test: atest DataNetworkValidationStatsTest PersistAtomsStorageTest Change-Id: Ib2db3bb340bd3048250111b83bea4526117c5a5a
-rw-r--r--proto/src/persist_atoms.proto18
-rw-r--r--src/java/com/android/internal/telephony/data/DataNetwork.java18
-rw-r--r--src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java205
-rw-r--r--src/java/com/android/internal/telephony/metrics/MetricsCollector.java30
-rw-r--r--src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java70
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java295
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java151
7 files changed, 786 insertions, 1 deletions
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index e54c969a7c..fb89155979 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -23,7 +23,7 @@ option java_outer_classname = "PersistAtomsProto";
// Holds atoms to store on persist storage in case of power cycle or process crash.
// NOTE: using int64 rather than google.protobuf.Timestamp for timestamps simplifies implementation.
-// Next id: 70
+// Next id: 72
message PersistAtoms {
/* Aggregated RAT usage during the call. */
repeated VoiceCallRatUsage voice_call_rat_usage = 1;
@@ -231,6 +231,12 @@ message PersistAtoms {
/* Timestamp of last satellite_sos_message_recommender pull. */
optional int64 satellite_sos_message_recommender_pull_timestamp_millis = 69;
+
+ /* Data Network Validation statistics and information. */
+ repeated DataNetworkValidation data_network_validation = 70;
+
+ /* Timestamp of last data_network_validation pull. */
+ optional int64 data_network_validation_pull_timestamp_millis = 71;
}
// The canonical versions of the following enums live in:
@@ -694,3 +700,13 @@ message SatelliteSosMessageRecommender {
optional int32 recommending_handover_type = 7;
optional bool is_satellite_allowed_in_current_location = 8;
}
+
+message DataNetworkValidation {
+ optional int32 network_type = 1;
+ optional int32 apn_type_bitmask = 2;
+ optional int32 signal_strength = 3;
+ optional int32 validation_result = 4;
+ optional int64 elapsed_time_in_millis = 5;
+ optional bool handover_attempted = 6;
+ optional int32 network_validation_count = 7;
+}
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index bd98403a41..a718b903f8 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -103,6 +103,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthE
import com.android.internal.telephony.data.TelephonyNetworkAgent.TelephonyNetworkAgentCallback;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.metrics.DataCallSessionStats;
+import com.android.internal.telephony.metrics.DataNetworkValidationStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FunctionalUtils;
@@ -552,6 +553,9 @@ public class DataNetwork extends StateMachine {
/** Metrics of per data network connection. */
private final DataCallSessionStats mDataCallSessionStats;
+ /** Metrics of per data network validation. */
+ private final @NonNull DataNetworkValidationStats mDataNetworkValidationStats;
+
/**
* The unique context id assigned by the data service in {@link DataCallResponse#getId()}. One
* for {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN} and one for
@@ -986,6 +990,7 @@ public class DataNetwork extends StateMachine {
mDataNetworkControllerCallback);
mDataConfigManager = mDataNetworkController.getDataConfigManager();
mDataCallSessionStats = new DataCallSessionStats(mPhone);
+ mDataNetworkValidationStats = new DataNetworkValidationStats(mPhone);
mDataNetworkCallback = callback;
mDataProfile = dataProfile;
if (dataProfile.getTrafficDescriptor() != null) {
@@ -1919,6 +1924,9 @@ public class DataNetwork extends StateMachine {
if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
unregisterForWwanEvents();
}
+ // Since NetworkValidation is able to request only in the Connected state,
+ // if ever connected, log for onDataNetworkDisconnected.
+ mDataNetworkValidationStats.onDataNetworkDisconnected(getDataNetworkType());
} else {
mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback
.onSetupDataFailed(DataNetwork.this,
@@ -3511,6 +3519,8 @@ public class DataNetwork extends StateMachine {
DataService.REQUEST_REASON_HANDOVER, mLinkProperties, mPduSessionId,
mNetworkSliceInfo, mHandoverDataProfile.getTrafficDescriptor(), true,
obtainMessage(EVENT_HANDOVER_RESPONSE, retryEntry));
+
+ mDataNetworkValidationStats.onHandoverAttempted();
}
/**
@@ -3705,6 +3715,11 @@ public class DataNetwork extends StateMachine {
// Request validation directly from the data service.
mDataServiceManagers.get(mTransport).requestNetworkValidation(
mCid.get(mTransport), obtainMessage(EVENT_DATA_NETWORK_VALIDATION_RESPONSE));
+
+ int apnTypeBitmask = mDataProfile.getApnSetting() != null
+ ? mDataProfile.getApnSetting().getApnTypeBitmask() : ApnSetting.TYPE_NONE;
+ mDataNetworkValidationStats.onRequestNetworkValidation(apnTypeBitmask);
+
log("handleDataNetworkValidationRequest, network validation requested");
}
@@ -3753,6 +3768,9 @@ public class DataNetwork extends StateMachine {
mNetworkValidationStatus = networkValidationStatus;
notifyPreciseDataConnectionState();
}
+
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ mNetworkValidationStatus, getDataNetworkType());
}
/**
diff --git a/src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java b/src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java
new file mode 100644
index 0000000000..fdac834562
--- /dev/null
+++ b/src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2024 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.internal.telephony.metrics;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.PreciseDataConnectionState;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.TelephonyStatsLog;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
+
+/**
+ * DataNetworkValidationStats logs the atoms for response after a validation request from the
+ * DataNetwork in framework.
+ */
+public class DataNetworkValidationStats {
+
+ private static final String TAG = DataNetworkValidationStats.class.getSimpleName();
+
+ @NonNull
+ private final Phone mPhone;
+
+ @NonNull
+ private final PersistAtomsStorage mAtomsStorage =
+ PhoneFactory.getMetricsCollector().getAtomsStorage();
+
+ @Nullable
+ private DataNetworkValidation mDataNetworkValidation;
+
+ @ElapsedRealtimeLong
+ private long mRequestedTimeInMillis;
+
+ /** constructor */
+ public DataNetworkValidationStats(@NonNull Phone phone) {
+ mPhone = phone;
+ }
+
+
+ /**
+ * Create a new ongoing atom when NetworkValidation requested.
+ *
+ * Create a data network validation proto for a new atom record and write the start time to
+ * calculate the elapsed time required.
+ *
+ * @param apnTypeBitMask APN type bitmask of DataNetwork.
+ */
+ public void onRequestNetworkValidation(@ApnType int apnTypeBitMask) {
+ if (mDataNetworkValidation == null) {
+ mDataNetworkValidation = getDefaultProto(apnTypeBitMask);
+ mRequestedTimeInMillis = getTimeMillis();
+ }
+ }
+
+ /** Mark the Handover Attempt field as true if validation was requested */
+ public void onHandoverAttempted() {
+ if (mDataNetworkValidation != null) {
+ mDataNetworkValidation.handoverAttempted = true;
+ }
+ }
+
+ /**
+ * Called when data network is disconnected.
+ *
+ * Since network validation is based on the data network, validation must also end when the data
+ * network is disconnected. At this time, validation has not been completed, save an atom as
+ * unspecified. and clear.
+ *
+ * @param networkType Current Network Type of the Data Network.
+ */
+ public void onDataNetworkDisconnected(@NetworkType int networkType) {
+ // Nothing to do, if never requested validation
+ if (mDataNetworkValidation == null) {
+ return;
+ }
+
+ // Set data for and atom.
+ calcElapsedTime();
+ mDataNetworkValidation.networkType = networkType;
+ mDataNetworkValidation.signalStrength = mPhone.getSignalStrength().getLevel();
+ mDataNetworkValidation.validationResult = TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_UNSPECIFIED;
+
+ // Store.
+ mAtomsStorage.addDataNetworkValidation(mDataNetworkValidation);
+
+ // clear all values.
+ clear();
+ }
+
+ /**
+ * Store an atom by updated state.
+ *
+ * Called when the validation status is updated, and saves the atom when a failure or success
+ * result is received.
+ *
+ * @param status Data Network Validation Status.
+ * @param networkType Current Network Type of the Data Network.
+ */
+ public void onUpdateNetworkValidationState(
+ @PreciseDataConnectionState.NetworkValidationStatus int status,
+ @NetworkType int networkType) {
+ // Nothing to do, if never requested validation
+ if (mDataNetworkValidation == null) {
+ return;
+ }
+
+ switch (status) {
+ // Immediately after requesting validation, these messages may occur. In this case,
+ // ignore it and wait for the next update.
+ case PreciseDataConnectionState.NETWORK_VALIDATION_NOT_REQUESTED: // fall-through
+ case PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS:
+ return;
+ // If status is unsupported, NetworkValidation should not be requested initially. logs
+ // this for abnormal tracking.
+ case PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED:
+ mDataNetworkValidation.validationResult = TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_NOT_SUPPORTED;
+ break;
+ // Success or failure corresponds to the result, store an atom.
+ case PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS:
+ case PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE:
+ mDataNetworkValidation.validationResult = status;
+ break;
+ }
+
+ // Set data for and atom.
+ calcElapsedTime();
+ mDataNetworkValidation.networkType = networkType;
+ mDataNetworkValidation.signalStrength = mPhone.getSignalStrength().getLevel();
+
+ // Store.
+ mAtomsStorage.addDataNetworkValidation(mDataNetworkValidation);
+
+ // clear all values.
+ clear();
+ }
+
+ /**
+ * Calculate the current time required based on when network validation is requested.
+ */
+ private void calcElapsedTime() {
+ if (mDataNetworkValidation != null && mRequestedTimeInMillis != 0) {
+ mDataNetworkValidation.elapsedTimeInMillis = getTimeMillis() - mRequestedTimeInMillis;
+ }
+ }
+
+ /**
+ * Returns current time in millis from boot.
+ */
+ @VisibleForTesting
+ @ElapsedRealtimeLong
+ protected long getTimeMillis() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Clear all values.
+ */
+ private void clear() {
+ mDataNetworkValidation = null;
+ mRequestedTimeInMillis = 0;
+ }
+
+
+ /** Creates a DataNetworkValidation proto with default values. */
+ @NonNull
+ private DataNetworkValidation getDefaultProto(@ApnType int apnTypeBitmask) {
+ DataNetworkValidation proto = new DataNetworkValidation();
+ proto.networkType =
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_UNKNOWN;
+ proto.apnTypeBitmask = apnTypeBitmask;
+ proto.signalStrength =
+ TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ proto.validationResult =
+ TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_UNSPECIFIED;
+ proto.elapsedTimeInMillis = 0;
+ proto.handoverAttempted = false;
+ proto.networkValidationCount = 1;
+ return proto;
+ }
+}
+
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index d7f07c58e9..5eb0894636 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -20,6 +20,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ID_TABLE_
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_DATA_SERVICE_SWITCH;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION;
+import static com.android.internal.telephony.TelephonyStatsLog.DATA_NETWORK_VALIDATION;
import static com.android.internal.telephony.TelephonyStatsLog.DEVICE_TELEPHONY_PROPERTIES;
import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO;
import static com.android.internal.telephony.TelephonyStatsLog.GBA_EVENT;
@@ -72,6 +73,7 @@ import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
import com.android.internal.telephony.nano.PersistAtomsProto.EmergencyNumbersInfo;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
@@ -226,6 +228,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
registerAtom(SATELLITE_OUTGOING_DATAGRAM);
registerAtom(SATELLITE_PROVISION);
registerAtom(SATELLITE_SOS_MESSAGE_RECOMMENDER);
+ registerAtom(DATA_NETWORK_VALIDATION);
Rlog.d(TAG, "registered");
} else {
Rlog.e(TAG, "could not get StatsManager, atoms not registered");
@@ -320,6 +323,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
return pullSatelliteProvision(data);
case SATELLITE_SOS_MESSAGE_RECOMMENDER:
return pullSatelliteSosMessageRecommender(data);
+ case DATA_NETWORK_VALIDATION:
+ return pullDataNetworkValidation(data);
default:
Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag));
return StatsManager.PULL_SKIP;
@@ -940,6 +945,19 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
}
}
+ private int pullDataNetworkValidation(@NonNull List<StatsEvent> data) {
+ DataNetworkValidation[] dataNetworkValidations =
+ mStorage.getDataNetworkValidation(mPowerCorrelatedMinCooldownMillis);
+ if (dataNetworkValidations != null) {
+ Arrays.stream(dataNetworkValidations)
+ .forEach(d -> data.add(buildStatsEvent(d)));
+ return StatsManager.PULL_SUCCESS;
+ } else {
+ Rlog.w(TAG, "DATA_NETWORK_VALIDATION pull too frequent, skipping");
+ return StatsManager.PULL_SKIP;
+ }
+ }
+
/** Registers a pulled atom ID {@code atomId}. */
private void registerAtom(int atomId) {
mStatsManager.setPullAtomCallback(atomId, /* metadata= */ null,
@@ -1395,6 +1413,18 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
stats.isSatelliteAllowedInCurrentLocation);
}
+ private static StatsEvent buildStatsEvent(DataNetworkValidation stats) {
+ return TelephonyStatsLog.buildStatsEvent(
+ DATA_NETWORK_VALIDATION,
+ stats.networkType,
+ stats.apnTypeBitmask,
+ stats.signalStrength,
+ stats.validationResult,
+ stats.elapsedTimeInMillis,
+ stats.handoverAttempted,
+ stats.networkValidationCount);
+ }
+
/** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
static Phone[] getPhonesIfAny() {
try {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index f3fe8fa333..8553b48a4b 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -33,6 +33,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.CarrierIdMismatch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent;
@@ -173,6 +174,9 @@ public class PersistAtomsStorage {
private final int mMaxNumSatelliteStats;
private final int mMaxNumSatelliteControllerStats = 1;
+ /** Maximum number of data network validation to store during pulls. */
+ private final int mMaxNumDataNetworkValidation;
+
/** Stores persist atoms and persist states of the puller. */
@VisibleForTesting protected PersistAtoms mAtoms;
@@ -223,6 +227,7 @@ public class PersistAtomsStorage {
mMaxNumGbaEventStats = 5;
mMaxOutgoingShortCodeSms = 5;
mMaxNumSatelliteStats = 5;
+ mMaxNumDataNetworkValidation = 5;
} else {
mMaxNumVoiceCallSessions = 50;
mMaxNumSms = 25;
@@ -247,6 +252,7 @@ public class PersistAtomsStorage {
mMaxNumGbaEventStats = 10;
mMaxOutgoingShortCodeSms = 10;
mMaxNumSatelliteStats = 15;
+ mMaxNumDataNetworkValidation = 15;
}
mAtoms = loadAtomsFromFile();
@@ -791,6 +797,25 @@ public class PersistAtomsStorage {
saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
}
+ /** Adds a data network validation to the storage. */
+ public synchronized void addDataNetworkValidation(DataNetworkValidation dataNetworkValidation) {
+ DataNetworkValidation existingStats = find(dataNetworkValidation);
+ if (existingStats != null) {
+ int count = existingStats.networkValidationCount
+ + dataNetworkValidation.networkValidationCount;
+ long elapsedTime = ((dataNetworkValidation.elapsedTimeInMillis
+ * dataNetworkValidation.networkValidationCount) + (
+ existingStats.elapsedTimeInMillis * existingStats.networkValidationCount))
+ / count;
+ existingStats.networkValidationCount = count;
+ existingStats.elapsedTimeInMillis = elapsedTime;
+ } else {
+ mAtoms.dataNetworkValidation = insertAtRandomPlace(
+ mAtoms.dataNetworkValidation, dataNetworkValidation, mMaxNumDataCallSessions);
+ }
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
+ }
+
/**
* Returns and clears the voice call sessions if last pulled longer than {@code
* minIntervalMillis} ago, otherwise returns {@code null}.
@@ -1449,6 +1474,24 @@ public class PersistAtomsStorage {
}
}
+ /**
+ * Returns and clears the data network validation if last pulled longer than {@code
+ * minIntervalMillis} ago, otherwise returns {@code null}.
+ */
+ @Nullable
+ public synchronized DataNetworkValidation[] getDataNetworkValidation(long minIntervalMillis) {
+ long wallTime = getWallTimeMillis();
+ if (wallTime - mAtoms.dataNetworkValidationPullTimestampMillis > minIntervalMillis) {
+ mAtoms.dataNetworkValidationPullTimestampMillis = wallTime;
+ DataNetworkValidation[] previousDataNetworkValidation = mAtoms.dataNetworkValidation;
+ mAtoms.dataNetworkValidation = new DataNetworkValidation[0];
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
+ return previousDataNetworkValidation;
+ } else {
+ return null;
+ }
+ }
+
/** Saves {@link PersistAtoms} to a file in private storage immediately. */
public synchronized void flushAtoms() {
saveAtomsToFile(0);
@@ -1599,6 +1642,12 @@ public class PersistAtomsStorage {
atoms.satelliteSosMessageRecommender = sanitizeAtoms(
atoms.satelliteSosMessageRecommender, SatelliteSosMessageRecommender.class,
mMaxNumSatelliteStats);
+ atoms.dataNetworkValidation =
+ sanitizeAtoms(
+ atoms.dataNetworkValidation,
+ DataNetworkValidation.class,
+ mMaxNumDataNetworkValidation
+ );
// out of caution, sanitize also the timestamps
atoms.voiceCallRatUsagePullTimestampMillis =
@@ -1661,6 +1710,8 @@ public class PersistAtomsStorage {
sanitizeTimestamp(atoms.satelliteProvisionPullTimestampMillis);
atoms.satelliteSosMessageRecommenderPullTimestampMillis =
sanitizeTimestamp(atoms.satelliteSosMessageRecommenderPullTimestampMillis);
+ atoms.dataNetworkValidationPullTimestampMillis =
+ sanitizeTimestamp(atoms.dataNetworkValidationPullTimestampMillis);
return atoms;
} catch (NoSuchFileException e) {
Rlog.d(TAG, "PersistAtoms file not found");
@@ -2084,6 +2135,24 @@ public class PersistAtomsStorage {
}
/**
+ * Returns SatelliteOutgoingDatagram atom that has same values or {@code null}
+ * if it does not exist.
+ */
+ private @Nullable DataNetworkValidation find(DataNetworkValidation key) {
+ for (DataNetworkValidation stats : mAtoms.dataNetworkValidation) {
+ if (stats.networkType == key.networkType
+ && stats.apnTypeBitmask == key.apnTypeBitmask
+ && stats.signalStrength == key.signalStrength
+ && stats.validationResult == key.validationResult
+ && stats.handoverAttempted == key.handoverAttempted) {
+ return stats;
+ }
+ }
+ return null;
+ }
+
+
+ /**
* Inserts a new element in a random position in an array with a maximum size.
*
* <p>If the array is full, merge with existing item if possible or replace one item randomly.
@@ -2339,6 +2408,7 @@ public class PersistAtomsStorage {
atoms.satelliteOutgoingDatagramPullTimestampMillis = currentTime;
atoms.satelliteProvisionPullTimestampMillis = currentTime;
atoms.satelliteSosMessageRecommenderPullTimestampMillis = currentTime;
+ atoms.dataNetworkValidationPullTimestampMillis = currentTime;
Rlog.d(TAG, "created new PersistAtoms");
return atoms;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java
new file mode 100644
index 0000000000..b9493b9725
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2024 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.internal.telephony.metrics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.telephony.PreciseDataConnectionState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyStatsLog;
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.PersistAtomsProto;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+/** Test DataNetworkValidationStats */
+public class DataNetworkValidationStatsTest extends TelephonyTest {
+
+ /** Initial time at starting tests */
+ private static final Long STARTED_TIME_IN_MILLIS = 5000000L;
+
+ private TestableDataNetworkValidationStats mDataNetworkValidationStats;
+
+ /** Test Class for override elapsed time */
+ private static class TestableDataNetworkValidationStats extends DataNetworkValidationStats {
+ private long mSystemClockInMillis;
+ TestableDataNetworkValidationStats(Phone phone) {
+ super(phone);
+ mSystemClockInMillis = STARTED_TIME_IN_MILLIS;
+ }
+
+ @Override
+ protected long getTimeMillis() {
+ return mSystemClockInMillis;
+ }
+
+ public void elapseTimeInMillis(long elapse) {
+ mSystemClockInMillis += elapse;
+ }
+ }
+
+ @Before
+ public void setup() throws Exception {
+ super.setUp(getClass().getSimpleName());
+
+ mDataNetworkValidationStats = new TestableDataNetworkValidationStats(mPhone);
+ doReturn(SignalStrength.SIGNAL_STRENGTH_GREAT).when(mSignalStrength).getLevel();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mDataNetworkValidationStats = null;
+ super.tearDown();
+ }
+
+ @Test
+ public void testRequestDataNetworkValidation() {
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithSuccessStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_LTE,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_GREAT,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_SUCCESS,
+ proto.validationResult);
+ assertEquals(100L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithFailureStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_EMERGENCY);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onHandoverAttempted();
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS,
+ TelephonyManager.NETWORK_TYPE_IWLAN);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_IWLAN,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_EMERGENCY, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_GREAT,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_SUCCESS,
+ proto.validationResult);
+ assertEquals(200L, proto.elapsedTimeInMillis);
+ assertTrue(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithInProgressStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_NOT_REQUESTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithNotRequestedStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_NOT_REQUESTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithUnsupportedStatus() {
+
+ // Set up
+ doReturn(SignalStrength.SIGNAL_STRENGTH_POOR).when(mSignalStrength).getLevel();
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(300L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_LTE,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_POOR,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_NOT_SUPPORTED,
+ proto.validationResult);
+ assertEquals(300L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+
+ @Test
+ public void testOnDataNetworkDisconnected() {
+
+ // Set up
+ doReturn(SignalStrength.SIGNAL_STRENGTH_POOR).when(mSignalStrength).getLevel();
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(300L);
+ mDataNetworkValidationStats.onDataNetworkDisconnected(TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_LTE,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_POOR,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_UNSPECIFIED,
+ proto.validationResult);
+ assertEquals(300L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationState_DupStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE,
+ TelephonyManager.NETWORK_TYPE_NR);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_UMTS,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_GREAT,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_SUCCESS,
+ proto.validationResult);
+ assertEquals(200L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
index 75ef7ec13b..bc79a564ed 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
@@ -62,10 +62,13 @@ import android.annotation.Nullable;
import android.content.Context;
import android.os.Build;
import android.telephony.DisconnectCause;
+import android.telephony.PreciseDataConnectionState;
import android.telephony.SatelliteProtoEnums;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyProtoEnums;
+import android.telephony.data.ApnSetting;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.SipDelegateManager;
@@ -76,6 +79,7 @@ import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent;
@@ -286,6 +290,12 @@ public class PersistAtomsStorageTest extends TelephonyTest {
private SatelliteSosMessageRecommender mSatelliteSosMessageRecommender2;
private SatelliteSosMessageRecommender[] mSatelliteSosMessageRecommenders;
+ private DataNetworkValidation mDataNetworkValidationLte1;
+ private DataNetworkValidation mDataNetworkValidationLte2;
+ private DataNetworkValidation mDataNetworkValidationIwlan1;
+ private DataNetworkValidation mDataNetworkValidationIwlan2;
+ private DataNetworkValidation[] mDataNetworkValidations;
+
private void makeTestData() {
// MO call with SRVCC (LTE to UMTS)
mCall1Proto = new VoiceCallSession();
@@ -1070,6 +1080,10 @@ public class PersistAtomsStorageTest extends TelephonyTest {
mOutgoingShortCodeSms = new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1,
mOutgoingShortCodeSms2};
+
+ generateTestSatelliteData();
+
+ generateTestDataNetworkValidationsData();
}
private void generateTestSatelliteData() {
@@ -1216,6 +1230,61 @@ public class PersistAtomsStorageTest extends TelephonyTest {
};
}
+ private void generateTestDataNetworkValidationsData() {
+
+ // for LTE #1
+ mDataNetworkValidationLte1 = new DataNetworkValidation();
+ mDataNetworkValidationLte1.networkType = TelephonyManager.NETWORK_TYPE_LTE;
+ mDataNetworkValidationLte1.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationLte1.signalStrength = SignalStrength.SIGNAL_STRENGTH_GREAT;
+ mDataNetworkValidationLte1.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS;
+ mDataNetworkValidationLte1.elapsedTimeInMillis = 100L;
+ mDataNetworkValidationLte1.handoverAttempted = false;
+ mDataNetworkValidationLte1.networkValidationCount = 1;
+
+ // for LTE #2
+ mDataNetworkValidationLte2 = new DataNetworkValidation();
+ mDataNetworkValidationLte2.networkType = TelephonyManager.NETWORK_TYPE_LTE;
+ mDataNetworkValidationLte2.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationLte2.signalStrength = SignalStrength.SIGNAL_STRENGTH_GREAT;
+ mDataNetworkValidationLte2.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS;
+ mDataNetworkValidationLte2.elapsedTimeInMillis = 100L;
+ mDataNetworkValidationLte2.handoverAttempted = false;
+ mDataNetworkValidationLte2.networkValidationCount = 1;
+
+ // for IWLAN #1
+ mDataNetworkValidationIwlan1 = new DataNetworkValidation();
+ mDataNetworkValidationIwlan1.networkType = TelephonyManager.NETWORK_TYPE_IWLAN;
+ mDataNetworkValidationIwlan1.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationIwlan1.signalStrength = SignalStrength.SIGNAL_STRENGTH_POOR;
+ mDataNetworkValidationIwlan1.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE;
+ mDataNetworkValidationIwlan1.elapsedTimeInMillis = 10000L;
+ mDataNetworkValidationIwlan1.handoverAttempted = false;
+ mDataNetworkValidationIwlan1.networkValidationCount = 1;
+
+ // for IWLAN #2
+ mDataNetworkValidationIwlan2 = new DataNetworkValidation();
+ mDataNetworkValidationIwlan2.networkType = TelephonyManager.NETWORK_TYPE_IWLAN;
+ mDataNetworkValidationIwlan2.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationIwlan2.signalStrength = SignalStrength.SIGNAL_STRENGTH_POOR;
+ mDataNetworkValidationIwlan2.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE;
+ mDataNetworkValidationIwlan2.elapsedTimeInMillis = 30000L;
+ mDataNetworkValidationIwlan2.handoverAttempted = false;
+ mDataNetworkValidationIwlan2.networkValidationCount = 1;
+
+ mDataNetworkValidations =
+ new DataNetworkValidation[] {
+ mDataNetworkValidationLte1,
+ mDataNetworkValidationLte1,
+ mDataNetworkValidationIwlan1,
+ mDataNetworkValidationIwlan2,
+ };
+ }
+
private static class TestablePersistAtomsStorage extends PersistAtomsStorage {
private long mTimeMillis = START_TIME_MILLIS;
@@ -1381,6 +1450,10 @@ public class PersistAtomsStorageTest extends TelephonyTest {
mSatelliteSosMessageRecommender1 = null;
mSatelliteSosMessageRecommender2 = null;
mSatelliteSosMessageRecommenders = null;
+ mDataNetworkValidationLte1 = null;
+ mDataNetworkValidationLte2 = null;
+ mDataNetworkValidationIwlan1 = null;
+ mDataNetworkValidationIwlan2 = null;
super.tearDown();
}
@@ -4513,6 +4586,77 @@ public class PersistAtomsStorageTest extends TelephonyTest {
@Test
@SmallTest
+ public void addDataNetworkValidation_newEntry() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte1);
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationIwlan1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ // There should be 2 DataNetworkValidation
+ verifyCurrentStateSavedToFileOnce();
+ DataNetworkValidation[] output = mPersistAtomsStorage.getDataNetworkValidation(0L);
+ assertProtoArrayEqualsIgnoringOrder(
+ new DataNetworkValidation[] {
+ mDataNetworkValidationLte1, mDataNetworkValidationIwlan1},
+ output);
+ }
+
+ @Test
+ public void addDataNetworkValidation_existingEntry() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ int expectedNetworkValidationCount =
+ mDataNetworkValidationLte1.networkValidationCount
+ + mDataNetworkValidationLte2.networkValidationCount;
+
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte1);
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte2);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ DataNetworkValidation expected = copyOf(mDataNetworkValidationLte1);
+ expected.networkValidationCount = expectedNetworkValidationCount;
+
+ // There should be 1 DataNetworkValidation
+ verifyCurrentStateSavedToFileOnce();
+ DataNetworkValidation[] output =
+ mPersistAtomsStorage.getDataNetworkValidation(0L);
+ assertProtoArrayEqualsIgnoringOrder(
+ new DataNetworkValidation[] {expected},
+ output);
+ }
+
+ @Test
+ public void addDataNetworkValidation_tooManyEntries() throws Exception {
+
+ // Set up
+ doReturn(false).when(mPackageManager).hasSystemFeature(anyString());
+
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ // Currently, the maximum number that can be stored for DataNetworkValidation in Atom
+ // storage is 15. Try saving excess.
+ int maxNumDataNetworkValidation = 20;
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte1);
+ for (int i = 0; i < maxNumDataNetworkValidation; i++) {
+ DataNetworkValidation copied = copyOf(mDataNetworkValidationLte1);
+ copied.apnTypeBitmask = mDataNetworkValidationLte1.apnTypeBitmask + i;
+ mPersistAtomsStorage.addDataNetworkValidation(copied);
+ }
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ // There should be less than or equal to maxNumDataNetworkValidation
+ verifyCurrentStateSavedToFileOnce();
+ DataNetworkValidation[] output =
+ mPersistAtomsStorage.getDataNetworkValidation(0L);
+ assertTrue(output.length <= maxNumDataNetworkValidation);
+ }
+
+ @Test
+ @SmallTest
public void clearAtoms() throws Exception {
createTestFile(START_TIME_MILLIS);
mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
@@ -4596,6 +4740,8 @@ public class PersistAtomsStorageTest extends TelephonyTest {
atoms.satelliteProvisionPullTimestampMillis = lastPullTimeMillis;
atoms.satelliteSosMessageRecommender = mSatelliteSosMessageRecommenders;
atoms.satelliteSosMessageRecommenderPullTimestampMillis = lastPullTimeMillis;
+ atoms.dataNetworkValidation = mDataNetworkValidations;
+ atoms.dataNetworkValidationPullTimestampMillis = lastPullTimeMillis;
FileOutputStream stream = new FileOutputStream(mTestFile);
stream.write(PersistAtoms.toByteArray(atoms));
stream.close();
@@ -4759,6 +4905,11 @@ public class PersistAtomsStorageTest extends TelephonyTest {
return SatelliteSosMessageRecommender.parseFrom(MessageNano.toByteArray(source));
}
+ private static DataNetworkValidation copyOf(DataNetworkValidation source)
+ throws Exception {
+ return DataNetworkValidation.parseFrom(MessageNano.toByteArray(source));
+ }
+
private void assertAllPullTimestampEquals(long timestamp) {
assertEquals(
timestamp,