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

Commit f2488047 authored by Jack Yu's avatar Jack Yu
Browse files

Supported traffic descriptor based network capability

Added traffic descriptor based network capability support.
Allowed multiple network requests having same TD based
capability, but with different differentiators.

Fix: 214399881
Test: atest FrameworksTelephonyTests
Change-Id: Ie1b17b10fd52400b709f8376ec971fc49a58b037
parent 1045a9b4
Loading
Loading
Loading
Loading
+48 −14
Original line number Original line Diff line number Diff line
@@ -356,6 +356,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Collectors;


@@ -1003,10 +1004,19 @@ public class RILUtils {
                .setUser(dpi.user)
                .setUser(dpi.user)
                .setAlwaysOn(dpi.alwaysOn)
                .setAlwaysOn(dpi.alwaysOn)
                .build();
                .build();

        TrafficDescriptor td;
        try {
            td = convertHalTrafficDescriptor(dpi.trafficDescriptor);
        } catch (IllegalArgumentException e) {
            loge("convertToDataProfile: Failed to convert traffic descriptor. e=" + e);
            td = null;
        }

        return new DataProfile.Builder()
        return new DataProfile.Builder()
                .setType(dpi.type)
                .setType(dpi.type)
                .setPreferred(dpi.preferred)
                .setPreferred(dpi.preferred)
                .setTrafficDescriptor(convertHalTrafficDescriptor(dpi.trafficDescriptor))
                .setTrafficDescriptor(td)
                .setApnSetting(apnSetting)
                .setApnSetting(apnSetting)
                .build();
                .build();
    }
    }
@@ -3480,8 +3490,13 @@ public class RILUtils {
            sliceInfo = result.sliceInfo.getDiscriminator()
            sliceInfo = result.sliceInfo.getDiscriminator()
                    == android.hardware.radio.V1_6.OptionalSliceInfo.hidl_discriminator.noinit
                    == android.hardware.radio.V1_6.OptionalSliceInfo.hidl_discriminator.noinit
                    ? null : convertHalSliceInfo(result.sliceInfo.value());
                    ? null : convertHalSliceInfo(result.sliceInfo.value());
            trafficDescriptors = result.trafficDescriptors.stream().map(
            for (android.hardware.radio.V1_6.TrafficDescriptor td : result.trafficDescriptors) {
                    RILUtils::convertHalTrafficDescriptor).collect(Collectors.toList());
                try {
                    trafficDescriptors.add(RILUtils.convertHalTrafficDescriptor(td));
                } catch (IllegalArgumentException e) {
                    loge("convertHalDataCallResult: Failed to convert traffic descriptor. e=" + e);
                }
            }
        } else {
        } else {
            loge("Unsupported SetupDataCallResult " + dcResult);
            loge("Unsupported SetupDataCallResult " + dcResult);
            return null;
            return null;
@@ -3614,7 +3629,11 @@ public class RILUtils {
        }
        }
        List<TrafficDescriptor> trafficDescriptors = new ArrayList<>();
        List<TrafficDescriptor> trafficDescriptors = new ArrayList<>();
        for (android.hardware.radio.data.TrafficDescriptor td : result.trafficDescriptors) {
        for (android.hardware.radio.data.TrafficDescriptor td : result.trafficDescriptors) {
            try {
                trafficDescriptors.add(convertHalTrafficDescriptor(td));
                trafficDescriptors.add(convertHalTrafficDescriptor(td));
            } catch (IllegalArgumentException e) {
                loge("convertHalDataCallResult: Failed to convert traffic descriptor. e=" + e);
            }
        }
        }


        return new DataCallResponse.Builder()
        return new DataCallResponse.Builder()
@@ -3664,33 +3683,34 @@ public class RILUtils {
    }
    }


    private static TrafficDescriptor convertHalTrafficDescriptor(
    private static TrafficDescriptor convertHalTrafficDescriptor(
            android.hardware.radio.V1_6.TrafficDescriptor td) {
            android.hardware.radio.V1_6.TrafficDescriptor td) throws IllegalArgumentException {
        String dnn = td.dnn.getDiscriminator()
        String dnn = td.dnn.getDiscriminator()
                == android.hardware.radio.V1_6.OptionalDnn.hidl_discriminator.noinit
                == android.hardware.radio.V1_6.OptionalDnn.hidl_discriminator.noinit
                ? null : td.dnn.value();
                ? null : td.dnn.value();
        String osAppId = td.osAppId.getDiscriminator()
        byte[] osAppId = td.osAppId.getDiscriminator()
                == android.hardware.radio.V1_6.OptionalOsAppId.hidl_discriminator.noinit
                == android.hardware.radio.V1_6.OptionalOsAppId.hidl_discriminator.noinit
                ? null : new String(arrayListToPrimitiveArray(td.osAppId.value().osAppId));
                ? null : arrayListToPrimitiveArray(td.osAppId.value().osAppId);

        TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
        TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
        if (dnn != null) {
        if (dnn != null) {
            builder.setDataNetworkName(dnn);
            builder.setDataNetworkName(dnn);
        }
        }
        if (osAppId != null) {
        if (osAppId != null) {
            builder.setOsAppId(osAppId.getBytes());
            builder.setOsAppId(osAppId);
        }
        }
        return builder.build();
        return builder.build();
    }
    }


    private static TrafficDescriptor convertHalTrafficDescriptor(
    private static TrafficDescriptor convertHalTrafficDescriptor(
            android.hardware.radio.data.TrafficDescriptor td) {
            android.hardware.radio.data.TrafficDescriptor td) throws IllegalArgumentException {
        String dnn = td.dnn;
        String dnn = td.dnn;
        String osAppId = td.osAppId == null ? null : new String(td.osAppId.osAppId);
        byte[] osAppId = td.osAppId == null ? null : td.osAppId.osAppId;
        TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
        TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
        if (dnn != null) {
        if (dnn != null) {
            builder.setDataNetworkName(dnn);
            builder.setDataNetworkName(dnn);
        }
        }
        if (osAppId != null) {
        if (osAppId != null) {
            builder.setOsAppId(osAppId.getBytes());
            builder.setOsAppId(osAppId);
        }
        }
        return builder.build();
        return builder.build();
    }
    }
@@ -3703,7 +3723,17 @@ public class RILUtils {
    public static NetworkSlicingConfig convertHalSlicingConfig(
    public static NetworkSlicingConfig convertHalSlicingConfig(
            android.hardware.radio.V1_6.SlicingConfig sc) {
            android.hardware.radio.V1_6.SlicingConfig sc) {
        List<UrspRule> urspRules = sc.urspRules.stream().map(ur -> new UrspRule(ur.precedence,
        List<UrspRule> urspRules = sc.urspRules.stream().map(ur -> new UrspRule(ur.precedence,
                ur.trafficDescriptors.stream().map(RILUtils::convertHalTrafficDescriptor)
                ur.trafficDescriptors.stream()
                        .map(td -> {
                            try {
                                return convertHalTrafficDescriptor(td);
                            } catch (IllegalArgumentException e) {
                                loge("convertHalSlicingConfig: Failed to convert traffic descriptor"
                                        + ". e=" + e);
                                return null;
                            }
                        })
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList()),
                        .collect(Collectors.toList()),
                ur.routeSelectionDescriptor.stream().map(rsd -> new RouteSelectionDescriptor(
                ur.routeSelectionDescriptor.stream().map(rsd -> new RouteSelectionDescriptor(
                        rsd.precedence, rsd.sessionType.value(), rsd.sscMode.value(),
                        rsd.precedence, rsd.sessionType.value(), rsd.sscMode.value(),
@@ -3726,7 +3756,11 @@ public class RILUtils {
        for (android.hardware.radio.data.UrspRule ur : sc.urspRules) {
        for (android.hardware.radio.data.UrspRule ur : sc.urspRules) {
            List<TrafficDescriptor> tds = new ArrayList<>();
            List<TrafficDescriptor> tds = new ArrayList<>();
            for (android.hardware.radio.data.TrafficDescriptor td : ur.trafficDescriptors) {
            for (android.hardware.radio.data.TrafficDescriptor td : ur.trafficDescriptors) {
                try {
                    tds.add(convertHalTrafficDescriptor(td));
                    tds.add(convertHalTrafficDescriptor(td));
                } catch (IllegalArgumentException e) {
                    loge("convertHalTrafficDescriptor: " + e);
                }
            }
            }
            List<RouteSelectionDescriptor> rsds = new ArrayList<>();
            List<RouteSelectionDescriptor> rsds = new ArrayList<>();
            for (android.hardware.radio.data.RouteSelectionDescriptor rsd
            for (android.hardware.radio.data.RouteSelectionDescriptor rsd
@@ -4510,7 +4544,7 @@ public class RILUtils {


    /**
    /**
     * Convert List<UiccSlotMapping> list to SlotPortMapping[]
     * Convert List<UiccSlotMapping> list to SlotPortMapping[]
     * @param list List<UiccSlotMapping> of slots mapping
     * @param slotMapping List<UiccSlotMapping> of slots mapping
     * @return SlotPortMapping[] of slots mapping
     * @return SlotPortMapping[] of slots mapping
     */
     */
    public static android.hardware.radio.config.SlotPortMapping[] convertSimSlotsMapping(
    public static android.hardware.radio.config.SlotPortMapping[] convertSimSlotsMapping(
+2 −3
Original line number Original line Diff line number Diff line
@@ -696,10 +696,9 @@ public class AccessNetworksManager extends Handler {
    public @TransportType int getPreferredTransportByNetworkCapability(
    public @TransportType int getPreferredTransportByNetworkCapability(
            @NetCapability int networkCapability) {
            @NetCapability int networkCapability) {
        int apnType = DataUtils.networkCapabilityToApnType(networkCapability);
        int apnType = DataUtils.networkCapabilityToApnType(networkCapability);
        // For non-APN type capabilities, always route to WWAN.
        if (apnType == ApnSetting.TYPE_NONE) {
        if (apnType == ApnSetting.TYPE_NONE) {
            // The network capability can't be converted to APN type.
            return AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
            throw new IllegalArgumentException("Illegal network capability "
                    + DataUtils.networkCapabilityToString(networkCapability) + " provided.");
        }
        }
        return getPreferredTransport(apnType);
        return getPreferredTransport(apnType);
    }
    }
+33 −11
Original line number Original line Diff line number Diff line
@@ -67,6 +67,7 @@ import android.telephony.data.DataServiceCallback;
import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.QosBearerSession;
import android.telephony.data.QosBearerSession;
import android.telephony.data.TrafficDescriptor;
import android.telephony.data.TrafficDescriptor;
import android.telephony.data.TrafficDescriptor.OsAppId;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
@@ -93,6 +94,7 @@ import com.android.telephony.Rlog;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
@@ -440,6 +442,9 @@ public class DataNetwork extends StateMachine {
    /** The network capabilities of this data network. */
    /** The network capabilities of this data network. */
    private @NonNull NetworkCapabilities mNetworkCapabilities;
    private @NonNull NetworkCapabilities mNetworkCapabilities;


    /** The matched traffic descriptor returned from setup data call request. */
    private final @NonNull List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>();

    /** The link properties of this data network. */
    /** The link properties of this data network. */
    private @NonNull LinkProperties mLinkProperties;
    private @NonNull LinkProperties mLinkProperties;


@@ -1299,6 +1304,31 @@ public class DataNetwork extends StateMachine {
            }
            }
        }
        }


        // Extract network capabilities from the traffic descriptor.
        for (TrafficDescriptor trafficDescriptor : mTrafficDescriptors) {
            try {
                OsAppId osAppId = new OsAppId(trafficDescriptor.getOsAppId());
                if (!osAppId.getOsId().equals(OsAppId.ANDROID_OS_ID)) {
                    loge("Received non-Android OS id " + osAppId.getOsId());
                    continue;
                }
                int networkCapability = DataUtils.getNetworkCapabilityFromString(
                        osAppId.getAppId());
                if (networkCapability > 0) {
                    builder.addCapability(networkCapability);
                    // Enterprise is the only capability supporting differentiator.
                    if (networkCapability == NetworkCapabilities.NET_CAPABILITY_ENTERPRISE) {
                        builder.addEnterpriseId(osAppId.getDifferentiator());
                    }
                } else {
                    loge("Invalid app id " + osAppId.getAppId());
                }
            } catch (IllegalArgumentException e) {
                loge("Exception: " + e + ". Failed to create osAppId from "
                        + new BigInteger(1, trafficDescriptor.getOsAppId()).toString(16));
            }
        }

        // TODO: Support NET_CAPABILITY_NOT_METERED when non-restricted data is for unmetered use
        // TODO: Support NET_CAPABILITY_NOT_METERED when non-restricted data is for unmetered use
        if (!meteredApn) {
        if (!meteredApn) {
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
@@ -1383,17 +1413,6 @@ public class DataNetwork extends StateMachine {
        return mNetworkCapabilities;
        return mNetworkCapabilities;
    }
    }


    /**
     * Get the capabilities that can be translated to APN types.
     *
     * @return The capabilities that can be translated to APN types.
     */
    public @NonNull @NetCapability Set<Integer> getApnTypesCapabilities() {
        return Arrays.stream(mNetworkCapabilities.getCapabilities()).boxed()
                .filter(cap -> DataUtils.networkCapabilityToApnType(cap) != ApnSetting.TYPE_NONE)
                .collect(Collectors.toSet());
    }

    /**
    /**
     * @return The link properties of this data network.
     * @return The link properties of this data network.
     */
     */
@@ -1647,6 +1666,9 @@ public class DataNetwork extends StateMachine {


        mNetworkSliceInfo = response.getSliceInfo();
        mNetworkSliceInfo = response.getSliceInfo();


        mTrafficDescriptors.clear();
        mTrafficDescriptors.addAll(response.getTrafficDescriptors());

        mQosBearerSessions.clear();
        mQosBearerSessions.clear();
        mQosBearerSessions.addAll(response.getQosBearerSessions());
        mQosBearerSessions.addAll(response.getQosBearerSessions());
        if (mQosCallbackTracker != null) {
        if (mQosCallbackTracker != null) {
+5 −3
Original line number Original line Diff line number Diff line
@@ -1762,7 +1762,7 @@ public class DataNetworkController extends Handler {
        return new NetworkRequestList(mAllNetworkRequestList.stream()
        return new NetworkRequestList(mAllNetworkRequestList.stream()
                .filter(request -> request.getState()
                .filter(request -> request.getState()
                        == TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED)
                        == TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED)
                .filter(request -> dataProfile.canSatisfy(request.getCapabilities()))
                .filter(request -> request.canBeSatisfiedBy(dataProfile))
                .collect(Collectors.toList()));
                .collect(Collectors.toList()));
    }
    }


@@ -2507,13 +2507,15 @@ public class DataNetworkController extends Handler {
                    + TelephonyUtils.dataStateToString(mInternetDataNetworkState) + " to "
                    + TelephonyUtils.dataStateToString(mInternetDataNetworkState) + " to "
                    + TelephonyUtils.dataStateToString(dataNetworkState) + ".");
                    + TelephonyUtils.dataStateToString(dataNetworkState) + ".");
            // TODO: Create a new route to notify TelephonyRegistry.
            // TODO: Create a new route to notify TelephonyRegistry.
            if (dataNetworkState == TelephonyManager.DATA_CONNECTED) {
            if (dataNetworkState == TelephonyManager.DATA_CONNECTED
                    && mInternetDataNetworkState == TelephonyManager.DATA_DISCONNECTED) {
                mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                        () -> callback.onInternetDataNetworkConnected(
                        () -> callback.onInternetDataNetworkConnected(
                                allConnectedInternetDataNetworks.stream()
                                allConnectedInternetDataNetworks.stream()
                                        .map(DataNetwork::getDataProfile)
                                        .map(DataNetwork::getDataProfile)
                                        .collect(Collectors.toList()))));
                                        .collect(Collectors.toList()))));
            } else if (dataNetworkState == TelephonyManager.DATA_DISCONNECTED) {
            } else if (dataNetworkState == TelephonyManager.DATA_DISCONNECTED
                    && mInternetDataNetworkState == TelephonyManager.DATA_CONNECTED) {
                mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                        callback::onInternetDataNetworkDisconnected));
                        callback::onInternetDataNetworkDisconnected));
            } // TODO: Add suspended callback if needed.
            } // TODO: Add suspended callback if needed.
+139 −22
Original line number Original line Diff line number Diff line
@@ -30,7 +30,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.provider.Telephony;
import android.provider.Telephony;
import android.telephony.Annotation;
import android.telephony.Annotation;
import android.telephony.Annotation.NetCapability;
import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.NetworkType;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager;
@@ -43,7 +42,6 @@ import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.LocalLog;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
import com.android.telephony.Rlog;
import com.android.telephony.Rlog;
@@ -63,6 +61,8 @@ import java.util.stream.Collectors;
 * subscription.
 * subscription.
 */
 */
public class DataProfileManager extends Handler {
public class DataProfileManager extends Handler {
    private static final boolean VDBG = true;

    /** Event for data config updated. */
    /** Event for data config updated. */
    private static final int EVENT_DATA_CONFIG_UPDATED = 1;
    private static final int EVENT_DATA_CONFIG_UPDATED = 1;


@@ -217,7 +217,6 @@ public class DataProfileManager extends Handler {
                if (apn != null) {
                if (apn != null) {
                    DataProfile dataProfile = new DataProfile.Builder()
                    DataProfile dataProfile = new DataProfile.Builder()
                            .setApnSetting(apn)
                            .setApnSetting(apn)
                            // TODO: Support TD correctly once ENTERPRISE becomes an APN type.
                            .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null))
                            .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null))
                            .setPreferred(false)
                            .setPreferred(false)
                            .build();
                            .build();
@@ -332,6 +331,7 @@ public class DataProfileManager extends Handler {
                .orElse(null);
                .orElse(null);
        // Save the preferred data profile into database.
        // Save the preferred data profile into database.
        setPreferredDataProfile(dataProfile);
        setPreferredDataProfile(dataProfile);
        updateDataProfiles();
    }
    }


    /**
    /**
@@ -505,16 +505,98 @@ public class DataProfileManager extends Handler {
     */
     */
    public @Nullable DataProfile getDataProfileForNetworkRequest(
    public @Nullable DataProfile getDataProfileForNetworkRequest(
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
        ApnSetting apnSetting = null;
        if (networkRequest.hasAttribute(TelephonyNetworkRequest
                .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType);
        }

        TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder();
        if (networkRequest.hasAttribute(TelephonyNetworkRequest
                .CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN)) {
            if (apnSetting != null) {
                trafficDescriptorBuilder.setDataNetworkName(apnSetting.getApnName());
            }
        }

        if (networkRequest.hasAttribute(
                TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID)) {
            TrafficDescriptor.OsAppId osAppId = networkRequest.getOsAppId();
            if (osAppId != null) {
                trafficDescriptorBuilder.setOsAppId(osAppId.getBytes());
            }
        }

        TrafficDescriptor trafficDescriptor;
        try {
            trafficDescriptor = trafficDescriptorBuilder.build();
        } catch (IllegalArgumentException e) {
            // We reach here when both ApnSetting and trafficDescriptor are null.
            log("Unable to find a data profile for " + networkRequest);
            return null;
        }

        // Instead of building the data profile from APN setting and traffic descriptor on-the-fly,
        // find the existing one from mAllDataProfiles so the last-setup timestamp can be retained.
        // Only create a new one when it can't be found.
        for (DataProfile dataProfile : mAllDataProfiles) {
            if (Objects.equals(apnSetting, dataProfile.getApnSetting())
                    && trafficDescriptor.equals(dataProfile.getTrafficDescriptor())) {
                return dataProfile;
            }
        }

        // When reaching here, it means that we have a valid non-null traffic descriptor, but
        // could not find it in mAllDataProfiles. This could happen on the traffic descriptor
        // capable capabilities like ENTERPRISE.
        DataProfile.Builder profileBuilder = new DataProfile.Builder();
        if (apnSetting != null) {
            profileBuilder.setApnSetting(apnSetting);
        }

        // trafficDescriptor is always non-null when we reach here.
        profileBuilder.setTrafficDescriptor(trafficDescriptor);

        DataProfile dataProfile = profileBuilder.build();
        log("Added a new data profile " + dataProfile + " for " + networkRequest);
        mAllDataProfiles.add(dataProfile);
        return dataProfile;
    }

    /**
     * Get the APN setting for the network request.
     *
     * @param networkRequest The network request.
     * @param networkType The current data network type.
     * @return The APN setting. {@code null} if can't find any satisfiable data profile.
     */
    private @Nullable ApnSetting getApnSettingForNetworkRequest(
            @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) {
        if (!networkRequest.hasAttribute(
                TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
            return null;
        }

        // Filter out the data profile that can't satisfy the request.
        // Filter out the data profile that can't satisfy the request.
        // Preferred data profile should be returned in the top of the list.
        // Preferred data profile should be returned in the top of the list.
        List<DataProfile> dataProfiles = getDataProfilesForNetworkCapabilities(
        List<DataProfile> dataProfiles = mAllDataProfiles.stream()
                networkRequest.getCapabilities());
                .filter(networkRequest::canBeSatisfiedBy)
                // Put the preferred data profile at the top of the list, then the longest time
                // hasn't used data profile will be in the front so all the data profiles can be
                // tried.
                .sorted(Comparator.comparing((DataProfile dp) -> !dp.equals(mPreferredDataProfile))
                        .thenComparingLong(DataProfile::getLastSetupTimestamp))
                .collect(Collectors.toList());
        for (DataProfile dataProfile : dataProfiles) {
            logv("Satisfied profile: " + dataProfile + ", last setup="
                    + DataUtils.elapsedTimeToString(dataProfile.getLastSetupTimestamp()));
        }
        if (dataProfiles.size() == 0) {
        if (dataProfiles.size() == 0) {
            log("Can't find any data profile that can satisfy " + networkRequest);
            log("Can't find any data profile that can satisfy " + networkRequest);
            return null;
            return null;
        }
        }


        // Step 3: Check if the remaining data profiles can used in current data network type.
        // Check if the remaining data profiles can used in current data network type.
        dataProfiles = dataProfiles.stream()
        dataProfiles = dataProfiles.stream()
                .filter(dp -> dp.getApnSetting() != null
                .filter(dp -> dp.getApnSetting() != null
                        && dp.getApnSetting().canSupportNetworkType(networkType))
                        && dp.getApnSetting().canSupportNetworkType(networkType))
@@ -525,7 +607,7 @@ public class DataProfileManager extends Handler {
            return null;
            return null;
        }
        }


        // Step 4: Check if preferred data profile set id matches.
        // Check if preferred data profile set id matches.
        dataProfiles = dataProfiles.stream()
        dataProfiles = dataProfiles.stream()
                .filter(dp -> dp.getApnSetting() != null
                .filter(dp -> dp.getApnSetting() != null
                        && (dp.getApnSetting().getApnSetId()
                        && (dp.getApnSetting().getApnSetId()
@@ -538,26 +620,53 @@ public class DataProfileManager extends Handler {
            return null;
            return null;
        }
        }


        return dataProfiles.get(0);
        return dataProfiles.get(0).getApnSetting();
    }
    }


    /**
    /**
     * Get data profiles that can satisfy given network capabilities.
     * Generate a traffic-descriptor type data profile from a network request.
     *
     *
     * @param networkCapabilities The network capabilities.
     * @param networkRequest The network request.
     * @return data profiles that can satisfy given network capabilities.
     * @return The generated data profile. {@code null} if not available.
     */
     */
    @VisibleForTesting
    private @Nullable DataProfile getTrafficDescriptorTypeDataProfile(
    public @NonNull List<DataProfile> getDataProfilesForNetworkCapabilities(
            @NonNull TelephonyNetworkRequest networkRequest) {
            @NonNull @NetCapability int[] networkCapabilities) {
        if (!networkRequest.hasAttribute(
        return mAllDataProfiles.stream()
                TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID)) {
                .filter(dp -> dp.canSatisfy(networkCapabilities))
            return null;
        }

        // If the network request also contains APN-type capabilities (for example, enterprise
        // is also an APN-type capability, then we fill in the corresponding APN setting in
        // data profile as well.
        ApnSetting apnSetting = null;
        if (networkRequest.hasAttribute(
                TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
            // Put the preferred data profile at the top of the list, then the longest time
            // Put the preferred data profile at the top of the list, then the longest time
            // hasn't used data profile will be in the front so all the data profiles can be
            // hasn't used data profile will be in the front so all the data profiles can be
            // tried.
            // tried.
                .sorted(Comparator.comparing((DataProfile dp) -> !dp.equals(mPreferredDataProfile))
            apnSetting = mAllDataProfiles.stream()
                    .filter(dataProfile -> dataProfile.getApnSetting() != null)
                    .filter(networkRequest::canBeSatisfiedBy)
                    .min(Comparator.comparing(
                            (DataProfile dp) -> !dp.equals(mPreferredDataProfile))
                            .thenComparingLong(DataProfile::getLastSetupTimestamp))
                            .thenComparingLong(DataProfile::getLastSetupTimestamp))
                .collect(Collectors.toList());
                    .map(DataProfile::getApnSetting)
                    .orElse(null);
        }

        byte[] osAppId = networkRequest.getOsAppId() != null
                ? networkRequest.getOsAppId().getBytes() : null;
        DataProfile dataProfile = new DataProfile.Builder()
                .setApnSetting(apnSetting)
                .setTrafficDescriptor(new TrafficDescriptor(
                        apnSetting != null ? apnSetting.getApnName() : null,
                        osAppId))
                .build();
        if (!mAllDataProfiles.contains(dataProfile)) {
            mAllDataProfiles.add(dataProfile);
        }
        return dataProfile;
    }
    }


    /**
    /**
@@ -620,6 +729,14 @@ public class DataProfileManager extends Handler {
        Rlog.e(mLogTag, s);
        Rlog.e(mLogTag, s);
    }
    }


    /**
     * Log verbose messages.
     * @param s debug messages.
     */
    private void logv(@NonNull String s) {
        if (VDBG) Rlog.v(mLogTag, s);
    }

    /**
    /**
     * Log debug messages and also log into the local log.
     * Log debug messages and also log into the local log.
     * @param s debug messages
     * @param s debug messages
Loading