Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c47c3984 authored by Daniel Bright's avatar Daniel Bright
Browse files

Add apn throttle status notifications to QNS

* Added wiring for the apn unthrottled indication
* Added method to QNS that is notified when there is a change to
  the way an APN is throttled.

Test: Ran telephony tests
Test: Booted up device
Test: Checked for log message in
      NetworkAvailabilityProvider#onReportApnThrottleStatusChanged
Bug: 167434852
Change-Id: Ia4dd3036f583a97e42b6054019005df1b33dc33c
parent baae6129
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -11034,6 +11034,35 @@ package android.telephony.data {
    field public static final String TYPE_XCAP_STRING = "xcap";
  }
  public final class ApnThrottleStatus implements android.os.Parcelable {
    method public int describeContents();
    method public int getApnType();
    method public int getRetryType();
    method public int getSlotIndex();
    method public long getThrottleExpiryTimeMillis();
    method public int getThrottleType();
    method public int getTransportType();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ApnThrottleStatus> CREATOR;
    field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3
    field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2
    field public static final int RETRY_TYPE_NONE = 1; // 0x1
    field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2
    field public static final int THROTTLE_TYPE_NONE = 1; // 0x1
  }
  public static final class ApnThrottleStatus.Builder {
    ctor public ApnThrottleStatus.Builder();
    method @NonNull public android.telephony.data.ApnThrottleStatus build();
    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setApnType(int);
    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setNoThrottle();
    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setRetryType(int);
    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setSlotIndex(int);
    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setThrottleExpiryTimeMillis(long);
    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setTransportType(int);
    field public static final long NO_THROTTLE_EXPIRY_TIME = -1L; // 0xffffffffffffffffL
  }
  public final class DataCallResponse implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
@@ -11151,6 +11180,7 @@ package android.telephony.data {
    method public abstract void close();
    method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback);
    method public final int getSlotIndex();
    method public final void notifyApnUnthrottled(@NonNull String);
    method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
    method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback);
    method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
@@ -11161,6 +11191,7 @@ package android.telephony.data {
  }
  public class DataServiceCallback {
    method public void onApnUnthrottled(@NonNull String);
    method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>);
    method public void onDeactivateDataCallComplete(int);
    method public void onHandoverCancelled(int);
@@ -11186,6 +11217,7 @@ package android.telephony.data {
    ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int);
    method public abstract void close();
    method public final int getSlotIndex();
    method public void reportApnThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ApnThrottleStatus>);
    method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
  }
+20 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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.
 */

/** @hide */
package android.telephony.data;

parcelable ApnThrottleStatus;
+383 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 android.telephony.data;

import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation;

import java.util.Objects;

/**
 * Status information regarding the throttle status of an APN type.
 *
 * @hide
 */
@SystemApi
public final class ApnThrottleStatus implements Parcelable {
    /**
     * The APN type is not throttled.
     */
    public static final int THROTTLE_TYPE_NONE = 1;

    /**
     * The APN type is throttled until {@link android.os.SystemClock#elapsedRealtime()}
     * has reached {@link ApnThrottleStatus#getThrottleExpiryTimeMillis}
     */
    public static final int THROTTLE_TYPE_ELAPSED_TIME = 2;

    /** {@hide} */
    @IntDef(flag = true, prefix = {"THROTTLE_TYPE_"}, value = {
            ApnThrottleStatus.THROTTLE_TYPE_NONE,
            ApnThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME,
    })
    public @interface ThrottleType {
    }

    /**
     * The framework will not retry the APN type.
     */
    public static final int RETRY_TYPE_NONE = 1;

    /**
     * The next time the framework retries, it will attempt to establish a new connection.
     */
    public static final int RETRY_TYPE_NEW_CONNECTION = 2;

    /**
     * The next time the framework retires, it will retry to handover.
     */
    public static final int RETRY_TYPE_HANDOVER = 3;

    /** {@hide} */
    @IntDef(flag = true, prefix = {"RETRY_TYPE_"}, value = {
            ApnThrottleStatus.RETRY_TYPE_NONE,
            ApnThrottleStatus.RETRY_TYPE_NEW_CONNECTION,
            ApnThrottleStatus.RETRY_TYPE_HANDOVER,
    })
    public @interface RetryType {
    }

    private final int mSlotIndex;
    private final @AccessNetworkConstants.TransportType int mTransportType;
    private final @Annotation.ApnType int mApnType;
    private final long mThrottleExpiryTimeMillis;
    private final @RetryType int mRetryType;
    private final @ThrottleType int mThrottleType;

    /**
     * The slot index that the status applies to.
     *
     * @return the slot index
     */
    public int getSlotIndex() {
        return mSlotIndex;
    }

    /**
     * The type of transport that the status applies to.
     *
     * @return the transport type
     */
    @AccessNetworkConstants.TransportType
    public int getTransportType() {
        return mTransportType;
    }

    /**
     * The APN type that the status applies to.
     *
     * @return the apn type
     */
    @Annotation.ApnType
    public int getApnType() {
        return mApnType;
    }

    /**
     * The type of throttle applied to the APN type.
     *
     * @return the throttle type
     */
    @ThrottleType
    public int getThrottleType() {
        return mThrottleType;
    }

    /**
     * Indicates the type of request that the framework will make the next time it retries
     * to call {@link IDataService#setupDataCall}.
     *
     * @return the retry type
     */
    @RetryType
    public int getRetryType() {
        return mRetryType;
    }

    /**
     * Gets the time at which the throttle expires.  The value is based off of
     * {@link SystemClock#elapsedRealtime}.
     *
     * This value only applies when the throttle type is set to
     * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
     *
     * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
     *
     * @return the time at which the throttle expires
     */
    @ElapsedRealtimeLong
    public long getThrottleExpiryTimeMillis() {
        return mThrottleExpiryTimeMillis;
    }

    private ApnThrottleStatus(int slotIndex,
            @AccessNetworkConstants.TransportType int transportType,
            @Annotation.ApnType int apnTypes,
            @ThrottleType int throttleType,
            long throttleExpiryTimeMillis,
            @RetryType int retryType) {
        mSlotIndex = slotIndex;
        mTransportType = transportType;
        mApnType = apnTypes;
        mThrottleType = throttleType;
        mThrottleExpiryTimeMillis = throttleExpiryTimeMillis;
        mRetryType = retryType;
    }

    private ApnThrottleStatus(@NonNull Parcel source) {
        mSlotIndex = source.readInt();
        mTransportType = source.readInt();
        mApnType = source.readInt();
        mThrottleExpiryTimeMillis = source.readLong();
        mRetryType = source.readInt();
        mThrottleType = source.readInt();
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mSlotIndex);
        dest.writeInt(mTransportType);
        dest.writeInt(mApnType);
        dest.writeLong(mThrottleExpiryTimeMillis);
        dest.writeInt(mRetryType);
        dest.writeInt(mThrottleType);
    }

    public static final @NonNull Parcelable.Creator<ApnThrottleStatus> CREATOR =
            new Parcelable.Creator<ApnThrottleStatus>() {
                @Override
                public ApnThrottleStatus createFromParcel(@NonNull Parcel source) {
                    return new ApnThrottleStatus(source);
                }

                @Override
                public ApnThrottleStatus[] newArray(int size) {
                    return new ApnThrottleStatus[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public int hashCode() {
        return Objects.hash(mSlotIndex, mApnType, mRetryType, mThrottleType,
                mThrottleExpiryTimeMillis, mTransportType);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        } else if (obj instanceof ApnThrottleStatus) {
            ApnThrottleStatus other = (ApnThrottleStatus) obj;
            return this.mSlotIndex == other.mSlotIndex
                    && this.mApnType == other.mApnType
                    && this.mRetryType == other.mRetryType
                    && this.mThrottleType == other.mThrottleType
                    && this.mThrottleExpiryTimeMillis == other.mThrottleExpiryTimeMillis
                    && this.mTransportType == other.mTransportType;
        } else {
            return false;
        }
    }

    @Override
    public String toString() {
        return "ApnThrottleStatus{"
                + "mSlotIndex=" + mSlotIndex
                + ", mTransportType=" + mTransportType
                + ", mApnType=" + ApnSetting.getApnTypeString(mApnType)
                + ", mThrottleExpiryTimeMillis=" + mThrottleExpiryTimeMillis
                + ", mRetryType=" + mRetryType
                + ", mThrottleType=" + mThrottleType
                + '}';
    }

    /**
     * Provides a convenient way to set the fields of an {@link ApnThrottleStatus} when creating a
     * new instance.
     *
     * <p>The example below shows how you might create a new {@code ApnThrottleStatus}:
     *
     * <pre><code>
     *
     * DataCallResponseApnThrottleStatus = new ApnThrottleStatus.Builder()
     *     .setSlotIndex(1)
     *     .setApnType({@link ApnSetting#TYPE_EMERGENCY})
     *     .setNoThrottle()
     *     .setRetryType({@link ApnThrottleStatus#RETRY_TYPE_NEW_CONNECTION})
     *     .build();
     * </code></pre>
     */
    public static final class Builder {
        private int mSlotIndex;
        private @AccessNetworkConstants.TransportType int mTransportType;
        private @Annotation.ApnType int mApnType;
        private long mThrottleExpiryTimeMillis;
        private @RetryType int mRetryType;
        private @ThrottleType int mThrottleType;
        public static final long NO_THROTTLE_EXPIRY_TIME =
                DataCallResponse.RETRY_DURATION_UNDEFINED;

        /**
         * Default constructor for the Builder.
         */
        public Builder() {
        }

        /**
         * Set the slot index.
         *
         * @param slotIndex the slot index.
         * @return The same instance of the builder.
         */
        @NonNull
        public Builder setSlotIndex(int slotIndex) {
            this.mSlotIndex = slotIndex;
            return this;
        }

        /**
         * Set the transport type.
         *
         * @param transportType the transport type.
         * @return The same instance of the builder.
         */
        @NonNull
        public Builder setTransportType(@AccessNetworkConstants.TransportType
                int transportType) {
            this.mTransportType = transportType;
            return this;
        }

        /**
         * Set the APN type.
         *
         * @param apnType  the APN type.
         * @return The same instance of the builder.
         */
        @NonNull
        public Builder setApnType(@Annotation.ApnType int apnType) {
            this.mApnType = apnType;
            return this;
        }

        /**
         * Sets the time at which the throttle will expire.  The value is based off of
         * {@link SystemClock#elapsedRealtime}.
         *
         * When setting this value, the throttle type is set to
         * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
         *
         * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
         *
         * @param throttleExpiryTimeMillis The elapsed time at which the throttle expires.
         *                                 Throws {@link IllegalArgumentException} for values less
         *                                 than 0.
         * @return The same instance of the builder.
         */
        @NonNull
        public Builder setThrottleExpiryTimeMillis(
                @ElapsedRealtimeLong long throttleExpiryTimeMillis) {
            if (throttleExpiryTimeMillis >= 0) {
                this.mThrottleExpiryTimeMillis = throttleExpiryTimeMillis;
                this.mThrottleType = THROTTLE_TYPE_ELAPSED_TIME;
            } else {
                throw new IllegalArgumentException("throttleExpiryTimeMillis must be greater than "
                        + "or equal to 0");
            }
            return this;
        }

        /**
         * Sets the status of the APN type as not being throttled.
         *
         * When setting this value, the throttle type is set to
         * {@link ApnThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to
         * {@link Builder#NO_THROTTLE_EXPIRY_TIME}.
         *
         * @return The same instance of the builder.
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        @NonNull
        public Builder setNoThrottle() {
            mThrottleType = THROTTLE_TYPE_NONE;
            mThrottleExpiryTimeMillis = NO_THROTTLE_EXPIRY_TIME;
            return this;
        }

        /**
         * Set the type of request that the framework will make the next time it retries
         * to call {@link IDataService#setupDataCall}.
         *
         * @param retryType the type of request
         * @return The same instance of the builder.
         */
        @NonNull
        public Builder setRetryType(@RetryType int retryType) {
            this.mRetryType = retryType;
            return this;
        }

        /**
         * Build the {@link ApnThrottleStatus}
         *
         * @return the {@link ApnThrottleStatus} object
         */
        @NonNull
        public ApnThrottleStatus build() {
            return new ApnThrottleStatus(
                    mSlotIndex,
                    mTransportType,
                    mApnType,
                    mThrottleType,
                    mThrottleExpiryTimeMillis,
                    mRetryType);
        }
    }
}
+83 −0
Original line number Diff line number Diff line
@@ -107,6 +107,9 @@ public abstract class DataService extends Service {
    private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED            = 11;
    private static final int DATA_SERVICE_REQUEST_START_HANDOVER                       = 12;
    private static final int DATA_SERVICE_REQUEST_CANCEL_HANDOVER                      = 13;
    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 final HandlerThread mHandlerThread;

@@ -129,6 +132,8 @@ public abstract class DataService extends Service {

        private final List<IDataServiceCallback> mDataCallListChangedCallbacks = new ArrayList<>();

        private final List<IDataServiceCallback> mApnUnthrottledCallbacks = new ArrayList<>();

        /**
         * Constructor
         * @param slotIndex SIM slot index the data service provider associated with.
@@ -326,6 +331,19 @@ public abstract class DataService extends Service {
            }
        }

        private void registerForApnUnthrottled(IDataServiceCallback callback) {
            synchronized (mApnUnthrottledCallbacks) {
                mApnUnthrottledCallbacks.add(callback);
            }
        }

        private void unregisterForApnUnthrottled(IDataServiceCallback callback) {
            synchronized (mApnUnthrottledCallbacks) {
                mApnUnthrottledCallbacks.remove(callback);
            }
        }


        /**
         * Notify the system that current data call list changed. Data service must invoke this
         * method whenever there is any data call status changed.
@@ -342,6 +360,21 @@ public abstract class DataService extends Service {
            }
        }

        /**
         * Notify the system that a given APN was unthrottled.
         *
         * @param apn Access Point Name defined by the carrier.
         */
        public final void notifyApnUnthrottled(@NonNull String apn) {
            synchronized (mApnUnthrottledCallbacks) {
                for (IDataServiceCallback callback : mApnUnthrottledCallbacks) {
                    mHandler.obtainMessage(DATA_SERVICE_INDICATION_APN_UNTHROTTLED,
                            mSlotIndex, 0, new ApnUnthrottledIndication(apn,
                                    callback)).sendToTarget();
                }
            }
        }

        /**
         * Called when the instance of data service is destroyed (e.g. got unbind or binder died)
         * or when the data service provider is removed. The extended class should implement this
@@ -429,6 +462,16 @@ public abstract class DataService extends Service {
        }
    }

    private static final class ApnUnthrottledIndication {
        public final String apn;
        public final IDataServiceCallback callback;
        ApnUnthrottledIndication(String apn,
                IDataServiceCallback callback) {
            this.apn = apn;
            this.callback = callback;
        }
    }

    private class DataServiceHandler extends Handler {

        DataServiceHandler(Looper looper) {
@@ -544,6 +587,26 @@ public abstract class DataService extends Service {
                            (cReq.callback != null)
                                    ? new DataServiceCallback(cReq.callback) : null);
                    break;
                case DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED:
                    if (serviceProvider == null) break;
                    serviceProvider.registerForApnUnthrottled((IDataServiceCallback) message.obj);
                    break;
                case DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED:
                    if (serviceProvider == null) break;
                    callback = (IDataServiceCallback) message.obj;
                    serviceProvider.unregisterForApnUnthrottled(callback);
                    break;
                case DATA_SERVICE_INDICATION_APN_UNTHROTTLED:
                    if (serviceProvider == null) break;
                    ApnUnthrottledIndication apnUnthrottledIndication =
                            (ApnUnthrottledIndication) message.obj;
                    try {
                        apnUnthrottledIndication.callback
                                .onApnUnthrottled(apnUnthrottledIndication.apn);
                    } catch (RemoteException e) {
                        loge("Failed to call onApnUnthrottled. " + e);
                    }
                    break;
            }
        }
    }
@@ -695,6 +758,26 @@ public abstract class DataService extends Service {
            mHandler.obtainMessage(DATA_SERVICE_REQUEST_CANCEL_HANDOVER,
                    slotIndex, 0, req).sendToTarget();
        }

        @Override
        public void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback) {
            if (callback == null) {
                loge("registerForUnthrottleApn: callback is null");
                return;
            }
            mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED, slotIndex,
                    0, callback).sendToTarget();
        }

        @Override
        public void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback) {
            if (callback == null) {
                loge("uregisterForUnthrottleApn: callback is null");
                return;
            }
            mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED,
                    slotIndex, 0, callback).sendToTarget();
        }
    }

    private void log(String s) {
+19 −1
Original line number Diff line number Diff line
@@ -248,4 +248,22 @@ public class DataServiceCallback {
                return "Missing case for result code=" + resultCode;
        }
    }

    /**
     * Indicates that the specified APN is no longer throttled.
     *
     * @param apn Access Point Name defined by the carrier.
     */
    public void onApnUnthrottled(@NonNull String apn) {
        if (mCallback != null) {
            try {
                if (DBG) Rlog.d(TAG, "onApnUnthrottled");
                mCallback.onApnUnthrottled(apn);
            } catch (RemoteException e) {
                Rlog.e(TAG, "onApnUnthrottled: remote exception", e);
            }
        } else {
            Rlog.e(TAG, "onApnUnthrottled: callback is null!");
        }
    }
}
Loading