summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt6
-rw-r--r--core/api/system-current.txt4
-rw-r--r--telephony/java/android/telephony/PreciseDataConnectionState.java118
-rw-r--r--telephony/java/android/telephony/data/DataCallResponse.java52
-rw-r--r--telephony/java/android/telephony/data/DataService.java81
-rw-r--r--telephony/java/android/telephony/data/IDataService.aidl3
-rw-r--r--telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl3
-rw-r--r--telephony/java/android/telephony/data/QualifiedNetworksService.java97
8 files changed, 353 insertions, 11 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index fec797e64f8f..8d1cacafcbae 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -44638,10 +44638,16 @@ package android.telephony {
method public int getLastCauseCode();
method @Nullable public android.net.LinkProperties getLinkProperties();
method public int getNetworkType();
+ method @FlaggedApi("com.android.internal.telephony.flags.network_validation") public int getNetworkValidationStatus();
method public int getState();
method public int getTransportType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
+ field @FlaggedApi("com.android.internal.telephony.flags.network_validation") public static final int NETWORK_VALIDATION_FAILURE = 4; // 0x4
+ field @FlaggedApi("com.android.internal.telephony.flags.network_validation") public static final int NETWORK_VALIDATION_IN_PROGRESS = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.network_validation") public static final int NETWORK_VALIDATION_NOT_REQUESTED = 1; // 0x1
+ field @FlaggedApi("com.android.internal.telephony.flags.network_validation") public static final int NETWORK_VALIDATION_SUCCESS = 3; // 0x3
+ field @FlaggedApi("com.android.internal.telephony.flags.network_validation") public static final int NETWORK_VALIDATION_UNSUPPORTED = 0; // 0x0
}
public final class RadioAccessSpecifier implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6a5d07b95974..e2b343e2be2c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -14777,6 +14777,7 @@ package android.telephony.data {
method @Deprecated public int getMtu();
method public int getMtuV4();
method public int getMtuV6();
+ method @FlaggedApi("com.android.internal.telephony.flags.network_validation") public int getNetworkValidationStatus();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
method public int getPduSessionId();
method public int getProtocolType();
@@ -14813,6 +14814,7 @@ package android.telephony.data {
method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setMtu(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
+ method @FlaggedApi("com.android.internal.telephony.flags.network_validation") @NonNull public android.telephony.data.DataCallResponse.Builder setNetworkValidationStatus(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(@IntRange(from=android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET, to=15) int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
@@ -14892,6 +14894,7 @@ package android.telephony.data {
method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
method public final void notifyDataProfileUnthrottled(@NonNull android.telephony.data.DataProfile);
method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.network_validation") public void requestValidation(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
@@ -14953,6 +14956,7 @@ package android.telephony.data {
method public final int getSlotIndex();
method public void reportEmergencyDataNetworkPreferredTransportChanged(int);
method public void reportThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ThrottleStatus>);
+ method @FlaggedApi("com.android.internal.telephony.flags.network_validation") public void requestNetworkValidation(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
}
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 7f1c14b877d2..b568f07135b8 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -16,6 +16,8 @@
package android.telephony;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -37,8 +39,11 @@ import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;
import android.telephony.data.Qos;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.util.TelephonyUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -66,6 +71,53 @@ public final class PreciseDataConnectionState implements Parcelable {
private final LinkProperties mLinkProperties;
private final ApnSetting mApnSetting;
private final Qos mDefaultQos;
+ private final @NetworkValidationStatus int mNetworkValidationStatus;
+
+ /** @hide */
+ @IntDef(prefix = "NETWORK_VALIDATION_", value = {
+ NETWORK_VALIDATION_UNSUPPORTED,
+ NETWORK_VALIDATION_NOT_REQUESTED,
+ NETWORK_VALIDATION_IN_PROGRESS,
+ NETWORK_VALIDATION_SUCCESS,
+ NETWORK_VALIDATION_FAILURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NetworkValidationStatus {}
+
+ /**
+ * Unsupported. The unsupported state is used when the data network cannot support the network
+ * validation function for the current data connection state.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public static final int NETWORK_VALIDATION_UNSUPPORTED = 0;
+
+ /**
+ * Not Requested. The not requested status is used when the data network supports the network
+ * validation function, but no network validation is being performed yet.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public static final int NETWORK_VALIDATION_NOT_REQUESTED = 1;
+
+ /**
+ * In progress. The in progress state is used when the network validation process for the data
+ * network is in progress. This state is followed by either success or failure.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public static final int NETWORK_VALIDATION_IN_PROGRESS = 2;
+
+ /**
+ * Success. The Success status is used when network validation has been completed for the data
+ * network and the result is successful.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public static final int NETWORK_VALIDATION_SUCCESS = 3;
+
+ /**
+ * Failure. The Failure status is used when network validation has been completed for the data
+ * network and the result is failure.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public static final int NETWORK_VALIDATION_FAILURE = 4;
/**
* Constructor
@@ -87,7 +139,7 @@ public final class PreciseDataConnectionState implements Parcelable {
.setApnTypeBitmask(apnTypes)
.setApnName(apn)
.setEntryName(apn)
- .build(), null);
+ .build(), null, NETWORK_VALIDATION_UNSUPPORTED);
}
@@ -109,7 +161,8 @@ public final class PreciseDataConnectionState implements Parcelable {
private PreciseDataConnectionState(@TransportType int transportType, int id,
@DataState int state, @NetworkType int networkType,
@Nullable LinkProperties linkProperties, @DataFailureCause int failCause,
- @Nullable ApnSetting apnSetting, @Nullable Qos defaultQos) {
+ @Nullable ApnSetting apnSetting, @Nullable Qos defaultQos,
+ @NetworkValidationStatus int networkValidationStatus) {
mTransportType = transportType;
mId = id;
mState = state;
@@ -118,6 +171,7 @@ public final class PreciseDataConnectionState implements Parcelable {
mFailCause = failCause;
mApnSetting = apnSetting;
mDefaultQos = defaultQos;
+ mNetworkValidationStatus = networkValidationStatus;
}
/**
@@ -140,6 +194,7 @@ public final class PreciseDataConnectionState implements Parcelable {
mDefaultQos = in.readParcelable(
Qos.class.getClassLoader(),
android.telephony.data.Qos.class);
+ mNetworkValidationStatus = in.readInt();
}
/**
@@ -289,6 +344,16 @@ public final class PreciseDataConnectionState implements Parcelable {
return mDefaultQos;
}
+ /**
+ * Returns the network validation state.
+ *
+ * @return the network validation status of the data call
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public @NetworkValidationStatus int getNetworkValidationStatus() {
+ return mNetworkValidationStatus;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -304,6 +369,7 @@ public final class PreciseDataConnectionState implements Parcelable {
out.writeInt(mFailCause);
out.writeParcelable(mApnSetting, flags);
out.writeParcelable(mDefaultQos, flags);
+ out.writeInt(mNetworkValidationStatus);
}
public static final @NonNull Parcelable.Creator<PreciseDataConnectionState> CREATOR
@@ -321,7 +387,7 @@ public final class PreciseDataConnectionState implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mTransportType, mId, mState, mNetworkType, mFailCause,
- mLinkProperties, mApnSetting, mDefaultQos);
+ mLinkProperties, mApnSetting, mDefaultQos, mNetworkValidationStatus);
}
@@ -337,7 +403,8 @@ public final class PreciseDataConnectionState implements Parcelable {
&& mFailCause == that.mFailCause
&& Objects.equals(mLinkProperties, that.mLinkProperties)
&& Objects.equals(mApnSetting, that.mApnSetting)
- && Objects.equals(mDefaultQos, that.mDefaultQos);
+ && Objects.equals(mDefaultQos, that.mDefaultQos)
+ && mNetworkValidationStatus == that.mNetworkValidationStatus;
}
@NonNull
@@ -354,11 +421,34 @@ public final class PreciseDataConnectionState implements Parcelable {
sb.append(", link properties: " + mLinkProperties);
sb.append(", default QoS: " + mDefaultQos);
sb.append(", fail cause: " + DataFailCause.toString(mFailCause));
+ sb.append(", network validation status: "
+ + networkValidationStatusToString(mNetworkValidationStatus));
return sb.toString();
}
/**
+ * Convert a network validation status to string.
+ *
+ * @param networkValidationStatus network validation status.
+ * @return string of validation status.
+ *
+ * @hide
+ */
+ @NonNull
+ public static String networkValidationStatusToString(
+ @NetworkValidationStatus int networkValidationStatus) {
+ switch (networkValidationStatus) {
+ case NETWORK_VALIDATION_UNSUPPORTED: return "unsupported";
+ case NETWORK_VALIDATION_NOT_REQUESTED: return "not requested";
+ case NETWORK_VALIDATION_IN_PROGRESS: return "in progress";
+ case NETWORK_VALIDATION_SUCCESS: return "success";
+ case NETWORK_VALIDATION_FAILURE: return "failure";
+ default: return Integer.toString(networkValidationStatus);
+ }
+ }
+
+ /**
* {@link PreciseDataConnectionState} builder
*
* @hide
@@ -394,6 +484,10 @@ public final class PreciseDataConnectionState implements Parcelable {
/** The Default QoS for this EPS/5GS bearer or null otherwise */
private @Nullable Qos mDefaultQos;
+ /** The network validation status for the data connection. */
+ private @NetworkValidationStatus int mNetworkValidationStatus =
+ NETWORK_VALIDATION_UNSUPPORTED;
+
/**
* Set the transport type of the data connection.
*
@@ -486,13 +580,27 @@ public final class PreciseDataConnectionState implements Parcelable {
}
/**
+ * Set the network validation state for the data connection.
+ *
+ * @param networkValidationStatus the network validation status of the data call
+ * @return The builder
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public @NonNull Builder setNetworkValidationStatus(
+ @NetworkValidationStatus int networkValidationStatus) {
+ mNetworkValidationStatus = networkValidationStatus;
+ return this;
+ }
+
+ /**
* Build the {@link PreciseDataConnectionState} instance.
*
* @return The {@link PreciseDataConnectionState} instance
*/
public PreciseDataConnectionState build() {
return new PreciseDataConnectionState(mTransportType, mId, mState, mNetworkType,
- mLinkProperties, mFailCause, mApnSetting, mDefaultQos);
+ mLinkProperties, mFailCause, mApnSetting, mDefaultQos,
+ mNetworkValidationStatus);
}
}
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index c7f0c5f753db..9dd83d1438e2 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -17,6 +17,7 @@
package android.telephony.data;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -27,9 +28,11 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Annotation.DataFailureCause;
import android.telephony.DataFailCause;
+import android.telephony.PreciseDataConnectionState;
import android.telephony.data.ApnSetting.ProtocolType;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -123,7 +126,6 @@ public final class DataCallResponse implements Parcelable {
* Indicates that the pdu session id is not set.
*/
public static final int PDU_SESSION_ID_NOT_SET = 0;
-
private final @DataFailureCause int mCause;
private final long mSuggestedRetryTime;
private final int mId;
@@ -143,6 +145,7 @@ public final class DataCallResponse implements Parcelable {
private final List<QosBearerSession> mQosBearerSessions;
private final NetworkSliceInfo mSliceInfo;
private final List<TrafficDescriptor> mTrafficDescriptors;
+ private final @PreciseDataConnectionState.NetworkValidationStatus int mNetworkValidationStatus;
/**
* @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
@@ -185,7 +188,8 @@ public final class DataCallResponse implements Parcelable {
HANDOVER_FAILURE_MODE_LEGACY, PDU_SESSION_ID_NOT_SET,
null /* defaultQos */, Collections.emptyList() /* qosBearerSessions */,
null /* sliceInfo */,
- Collections.emptyList() /* trafficDescriptors */);
+ Collections.emptyList(), /* trafficDescriptors */
+ PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);
}
private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id,
@@ -196,7 +200,8 @@ public final class DataCallResponse implements Parcelable {
@HandoverFailureMode int handoverFailureMode, int pduSessionId,
@Nullable Qos defaultQos, @NonNull List<QosBearerSession> qosBearerSessions,
@Nullable NetworkSliceInfo sliceInfo,
- @NonNull List<TrafficDescriptor> trafficDescriptors) {
+ @NonNull List<TrafficDescriptor> trafficDescriptors,
+ @PreciseDataConnectionState.NetworkValidationStatus int networkValidationStatus) {
mCause = cause;
mSuggestedRetryTime = suggestedRetryTime;
mId = id;
@@ -216,6 +221,7 @@ public final class DataCallResponse implements Parcelable {
mQosBearerSessions = new ArrayList<>(qosBearerSessions);
mSliceInfo = sliceInfo;
mTrafficDescriptors = new ArrayList<>(trafficDescriptors);
+ mNetworkValidationStatus = networkValidationStatus;
if (mLinkStatus == LINK_STATUS_ACTIVE
|| mLinkStatus == LINK_STATUS_DORMANT) {
@@ -270,6 +276,7 @@ public final class DataCallResponse implements Parcelable {
source.readList(mTrafficDescriptors,
TrafficDescriptor.class.getClassLoader(),
android.telephony.data.TrafficDescriptor.class);
+ mNetworkValidationStatus = source.readInt();
}
/**
@@ -442,6 +449,17 @@ public final class DataCallResponse implements Parcelable {
return Collections.unmodifiableList(mTrafficDescriptors);
}
+ /**
+ * Return the network validation status that was initiated by {@link
+ * DataService.DataServiceProvider#requestValidation}
+ *
+ * @return The network validation status of data connection.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public @PreciseDataConnectionState.NetworkValidationStatus int getNetworkValidationStatus() {
+ return mNetworkValidationStatus;
+ }
+
@NonNull
@Override
public String toString() {
@@ -466,6 +484,8 @@ public final class DataCallResponse implements Parcelable {
.append(" qosBearerSessions=").append(mQosBearerSessions)
.append(" sliceInfo=").append(mSliceInfo)
.append(" trafficDescriptors=").append(mTrafficDescriptors)
+ .append(" networkValidationStatus=").append(PreciseDataConnectionState
+ .networkValidationStatusToString(mNetworkValidationStatus))
.append("}");
return sb.toString();
}
@@ -504,7 +524,8 @@ public final class DataCallResponse implements Parcelable {
&& mQosBearerSessions.containsAll(other.mQosBearerSessions) // non-null
&& Objects.equals(mSliceInfo, other.mSliceInfo)
&& mTrafficDescriptors.size() == other.mTrafficDescriptors.size() // non-null
- && mTrafficDescriptors.containsAll(other.mTrafficDescriptors); // non-null
+ && mTrafficDescriptors.containsAll(other.mTrafficDescriptors) // non-null
+ && mNetworkValidationStatus == other.mNetworkValidationStatus;
}
@Override
@@ -513,7 +534,7 @@ public final class DataCallResponse implements Parcelable {
mInterfaceName, Set.copyOf(mAddresses), Set.copyOf(mDnsAddresses),
Set.copyOf(mGatewayAddresses), Set.copyOf(mPcscfAddresses), mMtu, mMtuV4, mMtuV6,
mHandoverFailureMode, mPduSessionId, mDefaultQos, Set.copyOf(mQosBearerSessions),
- mSliceInfo, Set.copyOf(mTrafficDescriptors));
+ mSliceInfo, Set.copyOf(mTrafficDescriptors), mNetworkValidationStatus);
}
@Override
@@ -542,6 +563,7 @@ public final class DataCallResponse implements Parcelable {
dest.writeList(mQosBearerSessions);
dest.writeParcelable(mSliceInfo, flags);
dest.writeList(mTrafficDescriptors);
+ dest.writeInt(mNetworkValidationStatus);
}
public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR =
@@ -629,6 +651,9 @@ public final class DataCallResponse implements Parcelable {
private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>();
+ private @PreciseDataConnectionState.NetworkValidationStatus int mNetworkValidationStatus =
+ PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED;
+
/**
* Default constructor for Builder.
*/
@@ -905,6 +930,20 @@ public final class DataCallResponse implements Parcelable {
}
/**
+ * Set the network validation status that corresponds to the state of the network validation
+ * request started by {@link DataService.DataServiceProvider#requestValidation}
+ *
+ * @param status The network validation status.
+ * @return The same instance of the builder.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public @NonNull Builder setNetworkValidationStatus(
+ @PreciseDataConnectionState.NetworkValidationStatus int status) {
+ mNetworkValidationStatus = status;
+ return this;
+ }
+
+ /**
* Build the DataCallResponse.
*
* @return the DataCallResponse object.
@@ -913,7 +952,8 @@ public final class DataCallResponse implements Parcelable {
return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId,
- mDefaultQos, mQosBearerSessions, mSliceInfo, mTrafficDescriptors);
+ mDefaultQos, mQosBearerSessions, mSliceInfo, mTrafficDescriptors,
+ mNetworkValidationStatus);
}
}
}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index d8b2cbebdf28..80e91a330185 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -16,6 +16,8 @@
package android.telephony.data;
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -26,6 +28,7 @@ import android.app.Service;
import android.content.Intent;
import android.net.LinkProperties;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
@@ -36,6 +39,9 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.flags.Flags;
+import com.android.internal.util.FunctionalUtils;
import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
@@ -44,6 +50,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Base class of data service. Services that extend DataService must register the service in
@@ -113,11 +121,14 @@ public abstract class DataService extends Service {
private static final int DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED = 14;
private static final int DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED = 15;
private static final int DATA_SERVICE_INDICATION_APN_UNTHROTTLED = 16;
+ private static final int DATA_SERVICE_REQUEST_VALIDATION = 17;
private final HandlerThread mHandlerThread;
private final DataServiceHandler mHandler;
+ private final Executor mHandlerExecutor;
+
private final SparseArray<DataServiceProvider> mServiceMap = new SparseArray<>();
/** @hide */
@@ -379,6 +390,43 @@ public abstract class DataService extends Service {
}
}
+ /**
+ * Request validation check to see if the network is working properly for a given data call.
+ *
+ * <p>This request is completed immediately after submitting the request to the data service
+ * provider and receiving {@link DataServiceCallback.ResultCode}, and progress status or
+ * validation results are notified through {@link
+ * DataCallResponse#getNetworkValidationStatus}.
+ *
+ * <p> If the network validation request is submitted successfully, {@link
+ * DataServiceCallback#RESULT_SUCCESS} is passed to {@code resultCodeCallback}. If the
+ * network validation feature is not supported by the data service provider itself, {@link
+ * DataServiceCallback#RESULT_ERROR_UNSUPPORTED} is passed to {@code resultCodeCallback}.
+ * See {@link DataServiceCallback.ResultCode} for the type of response that indicates
+ * whether the request was successfully submitted or had an error.
+ *
+ * <p>In response to this network validation request, providers can validate the data call
+ * in their own way. For example, in IWLAN, the DPD (Dead Peer Detection) can be used as a
+ * tool to check whether a data call is alive.
+ *
+ * @param cid The identifier of the data call which is provided in {@link DataCallResponse}
+ * @param executor The callback executor for the response.
+ * @param resultCodeCallback Listener for the {@link DataServiceCallback.ResultCode} that
+ * request validation to the DataService and checks if the request has been submitted.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public void requestValidation(int cid,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull @DataServiceCallback.ResultCode Consumer<Integer> resultCodeCallback) {
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(resultCodeCallback, "resultCodeCallback cannot be null");
+
+ Log.d(TAG, "requestValidation: " + cid);
+
+ // The default implementation is to return unsupported.
+ executor.execute(() -> resultCodeCallback
+ .accept(DataServiceCallback.RESULT_ERROR_UNSUPPORTED));
+ }
/**
* Notify the system that current data call list changed. Data service must invoke this
@@ -537,6 +585,17 @@ public abstract class DataService extends Service {
}
}
+ private static final class ValidationRequest {
+ public final int cid;
+ public final Executor executor;
+ public final IIntegerConsumer callback;
+ ValidationRequest(int cid, Executor executor, IIntegerConsumer callback) {
+ this.cid = cid;
+ this.executor = executor;
+ this.callback = callback;
+ }
+ }
+
private class DataServiceHandler extends Handler {
DataServiceHandler(Looper looper) {
@@ -679,6 +738,15 @@ public abstract class DataService extends Service {
loge("Failed to call onApnUnthrottled. " + e);
}
break;
+ case DATA_SERVICE_REQUEST_VALIDATION:
+ if (serviceProvider == null) break;
+ ValidationRequest validationRequest = (ValidationRequest) message.obj;
+ serviceProvider.requestValidation(
+ validationRequest.cid,
+ validationRequest.executor,
+ FunctionalUtils
+ .ignoreRemoteException(validationRequest.callback::accept));
+ break;
}
}
}
@@ -691,6 +759,7 @@ public abstract class DataService extends Service {
mHandlerThread.start();
mHandler = new DataServiceHandler(mHandlerThread.getLooper());
+ mHandlerExecutor = new HandlerExecutor(mHandler);
log("Data service created");
}
@@ -853,6 +922,18 @@ public abstract class DataService extends Service {
mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED,
slotIndex, 0, callback).sendToTarget();
}
+
+ @Override
+ public void requestValidation(int slotIndex, int cid, IIntegerConsumer resultCodeCallback) {
+ if (resultCodeCallback == null) {
+ loge("requestValidation: resultCodeCallback is null");
+ return;
+ }
+ ValidationRequest validationRequest =
+ new ValidationRequest(cid, mHandlerExecutor, resultCodeCallback);
+ mHandler.obtainMessage(DATA_SERVICE_REQUEST_VALIDATION,
+ slotIndex, 0, validationRequest).sendToTarget();
+ }
}
private void log(String s) {
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 134694694a0e..15f88815ec6b 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -22,6 +22,8 @@ import android.telephony.data.IDataServiceCallback;
import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
+import com.android.internal.telephony.IIntegerConsumer;
+
/**
* {@hide}
*/
@@ -46,4 +48,5 @@ oneway interface IDataService
void cancelHandover(int slotId, int cid, IDataServiceCallback callback);
void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback);
void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback);
+ void requestValidation(int slotId, int cid, IIntegerConsumer callback);
}
diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl
index 32ffdbc2121c..bdd212afd4b0 100644
--- a/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl
@@ -16,6 +16,8 @@
package android.telephony.data;
+import com.android.internal.telephony.IIntegerConsumer;
+
/**
* The qualified networks service call back interface
* @hide
@@ -23,4 +25,5 @@ package android.telephony.data;
oneway interface IQualifiedNetworksServiceCallback
{
void onQualifiedNetworkTypesChanged(int apnTypes, in int[] qualifiedNetworkTypes);
+ void onNetworkValidationRequested(int networkCapability, IIntegerConsumer callback);
}
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 56f0f9f13772..c3ba09248298 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -16,6 +16,8 @@
package android.telephony.data;
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.Service;
@@ -29,13 +31,23 @@ import android.os.RemoteException;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.NetCapability;
+import android.telephony.PreciseDataConnectionState;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.FeatureFlagsImpl;
+import com.android.internal.telephony.flags.Flags;
+import com.android.internal.util.FunctionalUtils;
import com.android.telephony.Rlog;
import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Base class of the qualified networks service, which is a vendor service providing up-to-date
@@ -69,6 +81,10 @@ public abstract class QualifiedNetworksService extends Service {
private static final int QNS_UPDATE_QUALIFIED_NETWORKS = 4;
private static final int QNS_APN_THROTTLE_STATUS_CHANGED = 5;
private static final int QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED = 6;
+ private static final int QNS_REQUEST_NETWORK_VALIDATION = 7;
+
+ /** Feature flags */
+ private static final FeatureFlags sFeatureFlag = new FeatureFlagsImpl();
private final HandlerThread mHandlerThread;
@@ -208,6 +224,72 @@ public abstract class QualifiedNetworksService extends Service {
}
/**
+ * Request network validation to the connected data network for given a network capability.
+ *
+ * <p>This network validation can only be performed when a data network is in connected
+ * state, and will not be triggered if the data network does not support network validation
+ * feature or network validation is not in connected state.
+ *
+ * <p>See {@link DataServiceCallback.ResultCode} for the type of response that indicates
+ * whether the request was successfully submitted or had an error.
+ *
+ * <p>If network validation is requested, monitor network validation status in {@link
+ * PreciseDataConnectionState#getNetworkValidationStatus()}.
+ *
+ * @param networkCapability A network capability. (Note that only APN-type capabilities are
+ * supported.
+ * @param executor executor The callback executor that responds whether the request has been
+ * successfully submitted or not.
+ * @param resultCodeCallback A callback to determine whether the request was successfully
+ * submitted or not.
+ */
+ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
+ public void requestNetworkValidation(
+ @NetCapability int networkCapability,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull @DataServiceCallback.ResultCode Consumer<Integer> resultCodeCallback) {
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(resultCodeCallback, "resultCodeCallback cannot be null");
+
+ if (!sFeatureFlag.networkValidation()) {
+ loge("networkValidation feature is disabled");
+ executor.execute(
+ () ->
+ resultCodeCallback.accept(
+ DataServiceCallback.RESULT_ERROR_UNSUPPORTED));
+ return;
+ }
+
+ IIntegerConsumer callback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> resultCodeCallback.accept(result));
+ }
+ };
+
+ // Move to the internal handler and process it.
+ mHandler.obtainMessage(
+ QNS_REQUEST_NETWORK_VALIDATION,
+ mSlotIndex,
+ 0,
+ new NetworkValidationRequestData(networkCapability, callback))
+ .sendToTarget();
+ }
+
+ /** Process a network validation request on the internal handler. */
+ private void onRequestNetworkValidation(NetworkValidationRequestData data) {
+ try {
+ log("onRequestNetworkValidation");
+ // Callback to request a network validation.
+ mCallback.onNetworkValidationRequested(data.mNetworkCapability, data.mCallback);
+ } catch (RemoteException | NullPointerException e) {
+ loge("Failed to call onRequestNetworkValidation. " + e);
+ FunctionalUtils.ignoreRemoteException(data.mCallback::accept)
+ .accept(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ }
+ }
+
+ /**
* Called when the qualified networks provider is removed. The extended class should
* implement this method to perform cleanup works.
*/
@@ -280,6 +362,10 @@ public abstract class QualifiedNetworksService extends Service {
if (provider == null) break;
provider.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
break;
+
+ case QNS_REQUEST_NETWORK_VALIDATION:
+ if (provider == null) break;
+ provider.onRequestNetworkValidation((NetworkValidationRequestData) message.obj);
}
}
}
@@ -364,6 +450,17 @@ public abstract class QualifiedNetworksService extends Service {
}
}
+ private static final class NetworkValidationRequestData {
+ final @NetCapability int mNetworkCapability;
+ final IIntegerConsumer mCallback;
+
+ private NetworkValidationRequestData(@NetCapability int networkCapability,
+ @NonNull IIntegerConsumer callback) {
+ mNetworkCapability = networkCapability;
+ mCallback = callback;
+ }
+ }
+
private void log(String s) {
Rlog.d(TAG, s);
}