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

Commit ca0aaca9 authored by Jack Yu's avatar Jack Yu Committed by Automerger Merge Worker
Browse files

Added data retry support am: 22603e8d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/17074175

Change-Id: I03e7bb9b4b6485928241c5d766a90eb866751288
parents 87b6d085 22603e8d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.RegistrantList;
import android.telephony.Annotation.NetCapability;
import android.telephony.Annotation.NetworkType;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
@@ -185,7 +186,7 @@ public class DataConfigManager extends Handler {
     * @param capability The network capability
     * @return The priority range from 0 ~ 100. 100 is the highest priority.
     */
    public int getNetworkCapabilityPriority(int capability) {
    public int getNetworkCapabilityPriority(@NetCapability int capability) {
        if (mNetworkCapabilityPriorityMap.containsKey(capability)) {
            return mNetworkCapabilityPriorityMap.get(capability);
        }
+1 −7
Original line number Diff line number Diff line
@@ -21,9 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.data.DataProfile;

import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

/**
@@ -31,10 +29,6 @@ import java.util.Set;
 * establishing a data network.
 */
public class DataEvaluation {
    /** For time stamp formatting in debug message use only. */
    private static final SimpleDateFormat TIME_FORMAT =
            new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);

    /** The reason for this evaluation */
    private final DataEvaluationReason mDataEvaluationReason;

@@ -279,7 +273,7 @@ public class DataEvaluation {
            evaluationStr.append(" ").append(mDataAllowedReason);
        }
        evaluationStr.append(", candidate profile=" + mCandidateDataProfile);
        evaluationStr.append(", time=" + TIME_FORMAT.format(mEvaluatedTime));
        evaluationStr.append(", time=" + DataUtils.getReadableSystemTime(mEvaluatedTime));
        return evaluationStr.toString();
    }

+10 −5
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.net.Uri;
import android.os.AsyncResult;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.AccessNetworkConstants.TransportType;
@@ -162,7 +163,6 @@ public class DataNetwork extends StateMachine {
    private static final int DEFAULT_INTERNET_NETWORK_SCORE = 50;
    private static final int OTHER_NETWORK_SCORE = 45;

    /** @hide */
    @IntDef(prefix = {"DEACTIVATION_REASON_"},
            value = {
                    TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED,
@@ -297,6 +297,7 @@ public class DataNetwork extends StateMachine {
         * Called when data setup failed.
         *
         * @param dataNetwork The data network.
         * @param requestList The network requests attached to this data network.
         * @param cause The fail cause of setup data network.
         * @param retryDurationMillis The network suggested data retry duration in milliseconds as
         * specified in 3GPP TS 24.302 section 8.2.9.1. The {@link DataProfile} associated to this
@@ -305,7 +306,8 @@ public class DataNetwork extends StateMachine {
         * data retry should not occur. {@link DataCallResponse#RETRY_DURATION_UNDEFINED} indicates
         * network did not suggest any retry duration.
         */
        void onSetupDataFailed(@NonNull DataNetwork dataNetwork, @DataFailureCause int cause,
        void onSetupDataFailed(@NonNull DataNetwork dataNetwork,
                @NonNull NetworkRequestList requestList, @DataFailureCause int cause,
                long retryDurationMillis);

        /**
@@ -429,6 +431,7 @@ public class DataNetwork extends StateMachine {
        mDataConfigManager = mDataNetworkController.getDataConfigManager();
        mDataNetworkCallback = callback;
        mDataProfile = dataProfile;
        dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
        mAttachedNetworkRequestList.addAll(networkRequestList);
        mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, INVALID_CID);
        mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, INVALID_CID);
@@ -907,8 +910,8 @@ public class DataNetwork extends StateMachine {
        // Get the highest priority network request.
        TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0);

        mPreferredTransport = mDataNetworkController
                .getPreferredTransportTypeForNetworkRequest(networkRequest);
        mPreferredTransport = mAccessNetworksManager.getPreferredTransportByNetworkCapability(
                networkRequest.getHighestPriorityNetworkCapability());
        if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) {
            mTransport = mPreferredTransport;
        }
@@ -1232,8 +1235,10 @@ public class DataNetwork extends StateMachine {
            // Setup data failed.
            long retry = response != null ? response.getRetryDurationMillis()
                    : DataCallResponse.RETRY_DURATION_UNDEFINED;
            NetworkRequestList requestList = new NetworkRequestList(mAttachedNetworkRequestList);
            detachAllNetworkRequests();
            mDataNetworkCallback.onSetupDataFailed(DataNetwork.this, failCause, retry);
            mDataNetworkCallback.onSetupDataFailed(DataNetwork.this, requestList,
                    failCause, retry);
            transitionTo(mDisconnectedState);
        }
    }
+94 −52
Original line number Diff line number Diff line
@@ -41,13 +41,11 @@ import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.SimState;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataProfile;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;

@@ -60,6 +58,7 @@ import com.android.internal.telephony.data.DataEvaluation.DataAllowedReason;
import com.android.internal.telephony.data.DataEvaluation.DataDisallowedReason;
import com.android.internal.telephony.data.DataEvaluation.DataEvaluationReason;
import com.android.internal.telephony.data.DataNetwork.DataValidationResult;
import com.android.internal.telephony.data.DataRetryManager.DataRetryEntry;
import com.android.internal.telephony.dataconnection.AccessNetworksManager;
import com.android.telephony.Rlog;

@@ -79,7 +78,7 @@ import java.util.stream.Collectors;
 * create and manage all the mobile data networks.
 */
public class DataNetworkController extends Handler {
    private final boolean VDBG;
    private static final boolean VDBG = false;

    /** Event for data config updated. */
    private static final int EVENT_DATA_CONFIG_UPDATED = 1;
@@ -114,6 +113,9 @@ public class DataNetworkController extends Handler {
    /** Event for data profile changed. */
    private static final int EVENT_DATA_PROFILES_CHANGED = 11;

    /** Event for data retry. */
    private static final int EVENT_DATA_RETRY = 12;

    private final Phone mPhone;
    private final String mLogTag;
    private final LocalLog mLocalLog = new LocalLog(128);
@@ -123,13 +125,14 @@ public class DataNetworkController extends Handler {
    private final @NonNull DataProfileManager mDataProfileManager;
    private final @NonNull DataStallRecoveryManager mDataStallRecoveryManager;
    private final @NonNull AccessNetworksManager mAccessNetworksManager;
    private final @NonNull DataRetryManager mDataRetryManager;
    private final @NonNull SparseArray<DataServiceManager> mDataServiceManagers =
            new SparseArray<>();

    /**
     * The list of all network requests.
     */
    private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList();
    private final @NonNull NetworkRequestList mAllNetworkRequestList = new NetworkRequestList();

    /**
     * The current data network list, including the ones that are connected, connecting, or
@@ -192,6 +195,15 @@ public class DataNetworkController extends Handler {
        public NetworkRequestList() {
        }

        /**
         * Copy constructor
         *
         * @param requestList The network request list.
         */
        public NetworkRequestList(NetworkRequestList requestList) {
            this.addAll(requestList);
        }

        /**
         * Constructor
         *
@@ -201,6 +213,7 @@ public class DataNetworkController extends Handler {
            this();
            add(newRequest);
        }

        /**
         * Add the network request to the list. Note that the item will be inserted to the position
         * based on the priority.
@@ -261,6 +274,11 @@ public class DataNetworkController extends Handler {
            return null;
        }

        @Override
        public String toString() {
            return "[NetworkRequestList: size=" + size() + ", leading by " + get(0) + "]";
        }

        /**
         * Dump the network request list.
         *
@@ -286,7 +304,6 @@ public class DataNetworkController extends Handler {
        super(looper);
        mPhone = phone;
        mLogTag = "DNC-" + mPhone.getPhoneId();
        VDBG = Rlog.isLoggable(mLogTag, Log.VERBOSE);
        log("DataNetworkController created.");

        mAccessNetworksManager = phone.getAccessNetworksManager();
@@ -303,6 +320,7 @@ public class DataNetworkController extends Handler {
                .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), looper);
        mDataStallRecoveryManager = new DataStallRecoveryManager(mPhone, this, mDataServiceManagers
                .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), looper);
        mDataRetryManager = new DataRetryManager(mPhone, this, looper);

        registerAllEvents();
    }
@@ -316,6 +334,8 @@ public class DataNetworkController extends Handler {
        filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);

        mDataRetryManager.registerForDataRetryCallback(dataRetryEntry ->
                sendMessage(obtainMessage(EVENT_DATA_RETRY, dataRetryEntry)));
        mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED);
        mDataStallRecoveryManager.registerForDataStallReestablishEvent(this,
                EVENT_DATA_STALL_ACTION_REESTABLISH);
@@ -376,6 +396,10 @@ public class DataNetworkController extends Handler {
                sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS,
                        DataEvaluationReason.DATA_PROFILES_CHANGED));
                break;
            case EVENT_DATA_RETRY:
                DataRetryEntry dataRetryEntry = (DataRetryEntry) msg.obj;
                setupDataNetwork(dataRetryEntry.dataProfile, null, dataRetryEntry);
                break;
            default:
                loge("Unexpected event " + msg.what);
        }
@@ -401,7 +425,7 @@ public class DataNetworkController extends Handler {
     * @param networkRequest The network request.
     */
    private void onAddNetworkRequest(@NonNull TelephonyNetworkRequest networkRequest) {
        if (!mNetworkRequestList.add(networkRequest)) {
        if (!mAllNetworkRequestList.add(networkRequest)) {
            loge("onAddNetworkRequest: Duplicate network request. " + networkRequest);
            return;
        }
@@ -437,7 +461,7 @@ public class DataNetworkController extends Handler {
        if (evaluation.isDataAllowed()) {
            DataProfile dataProfile = evaluation.getCandidateDataProfile();
            if (dataProfile != null) {
                setupDataNetwork(dataProfile, new NetworkRequestList(networkRequest));
                setupDataNetwork(dataProfile, new NetworkRequestList(networkRequest), null);
            }
        }
    }
@@ -515,33 +539,6 @@ public class DataNetworkController extends Handler {
        return true;
    }

    /**
     * Get the preferred transport type for the network request. If this network request is used
     * to setup the data network, it will be setup on the preferred transport.
     *
     * @param networkRequest The network request.
     * @return The preferred transport type.
     */
    public @TransportType int getPreferredTransportTypeForNetworkRequest(
            @NonNull TelephonyNetworkRequest networkRequest) {
        int highestPriority = 0;
        int highestPriorityApnType = ApnSetting.TYPE_NONE;
        // A network request might contain several APN-type capabilities. Extract the APN type that
        // which has the highest priority.
        for (int capability : networkRequest.getCapabilities()) {
            int apnType = DataUtils.networkCapabilityToApnType(capability);
            if (apnType != ApnSetting.TYPE_NONE) {
                int priority = mDataConfigManager.getNetworkCapabilityPriority(capability);
                if (priority > highestPriority) {
                    highestPriority = priority;
                    highestPriorityApnType = apnType;
                }
            }
        }

        return mAccessNetworksManager.getPreferredTransport(highestPriorityApnType);
    }

    /**
     * Evaluate a network request. The goal is to find a suitable {@link DataProfile} that can be
     * used to setup the data network.
@@ -562,7 +559,8 @@ public class DataNetworkController extends Handler {
            return evaluation;
        }

        int transport = getPreferredTransportTypeForNetworkRequest(networkRequest);
        int transport = mAccessNetworksManager.getPreferredTransportByNetworkCapability(
                networkRequest.getHighestPriorityNetworkCapability());
        int regState = getDataRegistrationState(transport);
        if (shouldCheckRegistrationState()
                && regState != NetworkRegistrationInfo.REGISTRATION_STATE_HOME
@@ -648,7 +646,7 @@ public class DataNetworkController extends Handler {
        // First, try to group similar network request together.
        Map<Set<Integer>, NetworkRequestList> requestsMap = new ArrayMap<>();
        int count = 0;
        for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) {
        for (TelephonyNetworkRequest networkRequest : mAllNetworkRequestList) {
            if (networkRequest.getState() == TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED) {
                Set<Integer> key = Arrays.stream(networkRequest.getCapabilities()).boxed()
                        .collect(Collectors.toSet());
@@ -663,7 +661,10 @@ public class DataNetworkController extends Handler {
        }

        log("Re-evaluating " + count + " unsatisfied network requests in " + requestsMap.size()
                + " groups.");
                + " groups, " + requestsMap.keySet().stream()
                .map(capsSet -> DataUtils.networkCapabilitiesToString(
                        capsSet.stream().mapToInt(Number::intValue).toArray()))
                .collect(Collectors.joining(",")));

        // Second, see if any existing network can satisfy those network requests.
        for (NetworkRequestList requestList : requestsMap.values()) {
@@ -678,7 +679,7 @@ public class DataNetworkController extends Handler {
            if (evaluation.isDataAllowed()) {
                DataProfile dataProfile = evaluation.getCandidateDataProfile();
                if (dataProfile != null) {
                    setupDataNetwork(dataProfile, requestList);
                    setupDataNetwork(dataProfile, requestList, null);
                }
            }
        }
@@ -702,7 +703,7 @@ public class DataNetworkController extends Handler {
        // TODO: TelephonyNetworkRequest should be used after DcTracker and other legacy data stacks
        //  are removed.
        // temp solution: find the original telephony network request.
        TelephonyNetworkRequest networkRequest = mNetworkRequestList.stream()
        TelephonyNetworkRequest networkRequest = mAllNetworkRequestList.stream()
                .filter(nr -> nr.getNativeNetworkRequest().equals(request))
                .findFirst()
                .orElse(null);
@@ -710,7 +711,7 @@ public class DataNetworkController extends Handler {
            return;
        }

        if (!mNetworkRequestList.remove(networkRequest)) {
        if (!mAllNetworkRequestList.remove(networkRequest)) {
            loge("onRemoveNetworkRequest: Network request does not exist. " + networkRequest);
            return;
        }
@@ -739,7 +740,7 @@ public class DataNetworkController extends Handler {
     * Update each network request's priority.
     */
    private void updateNetworkRequestsPriority() {
        for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) {
        for (TelephonyNetworkRequest networkRequest : mAllNetworkRequestList) {
            networkRequest.updatePriority();
        }
    }
@@ -748,10 +749,15 @@ public class DataNetworkController extends Handler {
     * Setup data network.
     *
     * @param dataProfile The data profile to setup the data network.
     * @param networkRequestList The network requests associated with the data network.
     * @param networkRequestList The network requests associated with the data network. {@code null}
     * indicates that all unsatisfied network requests that can be satisfied by the data profile
     * will be used to attach to the created network.
     * @param dataRetryEntry Data retry entry. {@code null} if this data network setup is not
     * initiated by a data retry.
     */
    private void setupDataNetwork(@NonNull DataProfile dataProfile,
            @NonNull NetworkRequestList networkRequestList) {
            @Nullable NetworkRequestList networkRequestList,
            @Nullable DataRetryEntry dataRetryEntry) {
        log("onSetupDataNetwork: dataProfile=" + dataProfile);
        for (DataNetwork dataNetwork : mDataNetworkList) {
            if (dataNetwork.getDataProfile().equals(dataProfile)) {
@@ -761,22 +767,46 @@ public class DataNetworkController extends Handler {
            }
        }

        // If the provided network request list is empty, then find all unsatisfied network requests
        // that can be satisfied by this data profile.
        if (networkRequestList == null || networkRequestList.isEmpty()) {
            networkRequestList = new NetworkRequestList();
            networkRequestList.addAll(mAllNetworkRequestList.stream()
                    .filter(request -> request.getState()
                            == TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED)
                    .filter(request -> dataProfile.canSatisfy(request.getCapabilities()))
                    .collect(Collectors.toList()));
        }

        if (networkRequestList.isEmpty()) {
            log("Can't find any unsatisfied network requests that can be satisfied by this data "
                    + "profile.");
            return;
        }

        logl("Creating data network with " + dataProfile + ", and attaching "
                + networkRequestList.size() + " network requests to it.");
        DataNetwork network = new DataNetwork(mPhone, getLooper(), mDataServiceManagers,
        mDataNetworkList.add(new DataNetwork(mPhone, getLooper(), mDataServiceManagers,
                dataProfile, networkRequestList, new DataNetwork.DataNetworkCallback() {
                    @Override
                    public void onSetupDataFailed(@NonNull DataNetwork dataNetwork,
                            @DataFailureCause int cause, long retryDurationMillis) {
                            @NonNull NetworkRequestList requestList, @DataFailureCause int cause,
                            long retryDurationMillis) {
                        post(() -> {
                            if (dataRetryEntry != null) {
                                dataRetryEntry.setState(DataRetryEntry.RETRY_STATE_FAILED);
                            }
                            DataNetworkController.this.onDataNetworkSetupDataFailed(
                                    dataNetwork, cause, retryDurationMillis);
                                    dataNetwork, requestList, cause, retryDurationMillis);
                        });
                    }

                    @Override
                    public void onConnected(@NonNull DataNetwork dataNetwork) {
                        post(() -> {
                            if (dataRetryEntry != null) {
                                dataRetryEntry.setState(DataRetryEntry.RETRY_STATE_SUCCEEDED);
                            }
                            DataNetworkController.this.onDataNetworkConnected(dataNetwork);
                        });
                    }
@@ -816,20 +846,24 @@ public class DataNetworkController extends Handler {
                                    dataNetwork, cause);
                        });
                    }
                });
        mDataNetworkList.add(network);
                }));
    }

    /**
     * Called when setup data network failed.
     *
     * @param dataNetwork The data network.
     * @param requestList The network requests attached to the data network.
     * @param cause The fail cause
     * @param retryDurationMillis The retry timer suggested by the network/data service.
     */
    private void onDataNetworkSetupDataFailed(@NonNull DataNetwork dataNetwork,
            @DataFailureCause int cause, long retryDurationMillis) {
        // TODO: Should perform retry here.

            @NonNull NetworkRequestList requestList, @DataFailureCause int cause,
            long retryDurationMillis) {
        mDataNetworkList.remove(dataNetwork);
        // Data retry manager will determine if retry is needed. If needed, retry will be scheduled.
        mDataRetryManager.evaluateDataRetry(dataNetwork.getDataProfile(), requestList, cause,
                retryDurationMillis);
    }

    /**
@@ -955,6 +989,7 @@ public class DataNetworkController extends Handler {
            }
        }
    }

    /**
     * @return Data config manager instance.
     */
@@ -962,6 +997,13 @@ public class DataNetworkController extends Handler {
        return mDataConfigManager;
    }

    /**
     * @return Data profile manager instance.
     */
    public @NonNull DataProfileManager getDataProfileManager() {
        return mDataProfileManager;
    }

    /**
     * Get data network type based on transport.
     *
@@ -1066,7 +1108,7 @@ public class DataNetworkController extends Handler {

        pw.println("All telephony network requests:");
        pw.increaseIndent();
        for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) {
        for (TelephonyNetworkRequest networkRequest : mAllNetworkRequestList) {
            pw.println(networkRequest);
        }
        pw.decreaseIndent();
+31 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.os.Message;
import android.os.RegistrantList;
import android.provider.Telephony;
import android.telephony.Annotation;
import android.telephony.Annotation.NetCapability;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -36,6 +37,7 @@ import android.util.IndentingPrintWriter;
import android.util.LocalLog;

import com.android.internal.telephony.Phone;
import com.android.internal.telephony.dataconnection.AccessNetworksManager;
import com.android.telephony.Rlog;

import java.io.FileDescriptor;
@@ -57,10 +59,18 @@ public class DataProfileManager extends Handler {
    private final String mLogTag;
    private final LocalLog mLocalLog = new LocalLog(128);

    /** Data network controller. */
    private final @NonNull DataNetworkController mDataNetworkController;

    /** Data config manager. */
    private final @NonNull DataConfigManager mDataConfigManager;

    /** Cellular data service. */
    private final @NonNull DataServiceManager mWwanDataServiceManager;

    /** Access networks manager. */
    private final @NonNull AccessNetworksManager mAccessNetworksManager;

    /** All data profiles for the current carrier. */
    private final @NonNull List<DataProfile> mAllDataProfiles = new ArrayList<>();

@@ -94,7 +104,7 @@ public class DataProfileManager extends Handler {
        mDataNetworkController = dataNetworkController;
        mWwanDataServiceManager = dataServiceManager;
        mDataConfigManager = dataNetworkController.getDataConfigManager();

        mAccessNetworksManager = phone.getAccessNetworksManager();

        mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED);
    }
@@ -335,8 +345,8 @@ public class DataProfileManager extends Handler {
        }

        // Step 3: Check if the remaining data profiles can used in current data RAT.
        int transport = mDataNetworkController
                .getPreferredTransportTypeForNetworkRequest(networkRequest);
        int transport = mAccessNetworksManager.getPreferredTransportByNetworkCapability(
                networkRequest.getHighestPriorityNetworkCapability());
        NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo(
                NetworkRegistrationInfo.DOMAIN_PS, transport);
        int dataRat = nri.getAccessNetworkTechnology();
@@ -372,6 +382,21 @@ public class DataProfileManager extends Handler {
        return dataProfiles.get(0);
    }

    /**
     * Get data profiles that can satisfy given network capabilities.
     *
     * @param networkCapabilities The network capabilities.
     * @return data profiles that can satisfy given network capabilities.
     */
    public @NonNull List<DataProfile> getDataProfilesForNetworkCapabilities(
            @NonNull @NetCapability int[] networkCapabilities) {
        return mAllDataProfiles.stream()
                .filter(dp -> dp.canSatisfy(networkCapabilities))
                .sorted((dp1, dp2) ->
                        Long.compare(dp1.getLastSetupTimestamp(), dp2.getLastSetupTimestamp()))
                .collect(Collectors.toList());
    }

    /**
     * Register for data profiles changed changed event.
     *
@@ -422,7 +447,9 @@ public class DataProfileManager extends Handler {
        pw.println("Data profiles for the current carrier:");
        pw.increaseIndent();
        for (DataProfile dp : mAllDataProfiles) {
            pw.println(dp);
            pw.print(dp);
            pw.print(", last setup time: " + DataUtils.elapsedTimeToString(
                    dp.getLastSetupTimestamp()));
        }
        pw.decreaseIndent();
        pw.println("Preferred data profile:");
Loading