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

Commit fa8f29db authored by Jack Yu's avatar Jack Yu Committed by Android (Google) Code Review
Browse files

Merge "Added handover support in the factory"

parents fa08cfc4 7aff3ba8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ public class AccessNetworksManager {
     */
    public static class QualifiedNetworks {
        public final @ApnType int apnType;
        // The qualified netowrks in preferred order. Each network is a AccessNetworkType.
        public final int[] qualifiedNetworks;
        public QualifiedNetworks(@ApnType int apnType, int[] qualifiedNetworks) {
            this.apnType = apnType;
+11 −13
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkRequest;
import android.os.Message;
import android.telephony.Rlog;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
@@ -413,15 +414,13 @@ public class ApnContext {
        }
    }

    public void requestNetwork(NetworkRequest networkRequest,
                               @RequestNetworkType int type, LocalLog log) {
    public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type,
                               Message onCompleteMsg, LocalLog log) {
        synchronized (mRefCountLock) {
            if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) {
                log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size());
            } else {
            mLocalLogs.add(log);
            mNetworkRequests.add(networkRequest);
                mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type);
            mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type,
                    onCompleteMsg);
            if (mDataConnection != null) {
                // New network request added. Should re-evaluate properties of
                // the data connection. For example, the score may change.
@@ -429,7 +428,6 @@ public class ApnContext {
            }
        }
    }
    }

    public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type,
                               LocalLog log) {
+77 −17
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import java.util.Set;
@@ -180,6 +181,12 @@ public class DcTracker extends Handler {
     */
    public static final int RELEASE_TYPE_HANDOVER = 3;

    /** The extras for request network completion message */
    static final String DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST = "extra_network_request";
    static final String DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE = "extra_transport_type";
    static final String DATA_COMPLETE_MSG_EXTRA_REQUEST_TYPE = "extra_request_type";
    static final String DATA_COMPLETE_MSG_EXTRA_SUCCESS = "extra_success";

    private final String mLogTag;

    public AtomicBoolean isCleanupRequired = new AtomicBoolean(false);
@@ -628,6 +635,13 @@ public class DcTracker extends Handler {

    private DataStallRecoveryHandler mDsRecoveryHandler;

    /**
     * Request network completion message map. Key is the APN type, value is the list of completion
     * messages to be sent. Using a list because there might be multiple network requests for
     * the same APN type.
     */
    private final Map<Integer, List<Message>> mRequestNetworkCompletionMsgs = new HashMap<>();

    //***** Constructor
    public DcTracker(Phone phone, int transportType) {
        super();
@@ -853,13 +867,13 @@ public class DcTracker extends Handler {
    }

    public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type,
                               LocalLog log) {
                               Message onCompleteMsg, LocalLog log) {
        final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
        final ApnContext apnContext = mApnContextsByType.get(apnType);
        log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext
                + ", type=" + requestTypeToString(type));
        if (apnContext != null) {
            apnContext.requestNetwork(networkRequest, type, log);
            apnContext.requestNetwork(networkRequest, type, onCompleteMsg, log);
        }
    }

@@ -2269,20 +2283,44 @@ public class DcTracker extends Handler {
        return null;
    }

    public void enableApn(@ApnSetting.ApnType int apnType, @RequestNetworkType int requestType) {
        sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType));
    private void addRequestNetworkCompleteMsg(Message onCompleteMsg,
                                              @ApnSetting.ApnType int apnType) {
        if (onCompleteMsg != null) {
            List<Message> messageList = mRequestNetworkCompletionMsgs.get(apnType);
            if (messageList == null) messageList = new ArrayList<>();
            messageList.add(onCompleteMsg);
            mRequestNetworkCompletionMsgs.put(apnType, messageList);
        }
    }

    private void sendRequestNetworkCompleteMsg(Message message, boolean success, int transport,
                                               @RequestNetworkType int requestType) {
        if (message == null) return;

        Bundle b = message.getData();
        b.putBoolean(DATA_COMPLETE_MSG_EXTRA_SUCCESS, success);
        b.putInt(DATA_COMPLETE_MSG_EXTRA_REQUEST_TYPE, requestType);
        b.putInt(DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE, transport);
        message.sendToTarget();
    }

    private void onEnableApn(@ApnSetting.ApnType int apnType, @RequestNetworkType int requestType) {
    public void enableApn(@ApnSetting.ApnType int apnType, @RequestNetworkType int requestType,
                          Message onCompleteMsg) {
        sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType,
                onCompleteMsg));
    }

    private void onEnableApn(@ApnSetting.ApnType int apnType, @RequestNetworkType int requestType,
                             Message onCompleteMsg) {
        ApnContext apnContext = mApnContextsByType.get(apnType);
        if (apnContext == null) {
            loge("onEnableApn(" + apnType + "): NO ApnContext");
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType, requestType);
            return;
        }

        boolean trySetup = false;
        String str = "onEnableApn: apnType=" + ApnSetting.getApnTypeString(apnType)
                + ", request type=" + requestType;
                + ", request type=" + requestTypeToString(requestType);
        if (DBG) log(str);
        apnContext.requestLog(str);

@@ -2292,6 +2330,7 @@ public class DcTracker extends Handler {
            str = "onEnableApn: dependency is not met.";
            if (DBG) log(str);
            apnContext.requestLog(str);
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType, requestType);
            return;
        }

@@ -2299,11 +2338,22 @@ public class DcTracker extends Handler {
            DctConstants.State state = apnContext.getState();
            switch(state) {
                case CONNECTING:
                    if (DBG) log("onEnableApn: 'CONNECTING' so return");
                    apnContext.requestLog("onEnableApn state=CONNECTING, so return");
                    addRequestNetworkCompleteMsg(onCompleteMsg, apnType);
                    return;
                case CONNECTED:
                    if (DBG) log("onEnableApn: 'CONNECTED' so return");
                    apnContext.requestLog("onEnableApn state=CONNECTED, so return");

                    sendRequestNetworkCompleteMsg(onCompleteMsg, true, mTransportType,
                            requestType);
                    return;
                case DISCONNECTING:
                    // We're "READY" and active so just return
                    if (DBG) log("onEnableApn: 'ready' so return");
                    apnContext.requestLog("onEnableApn state=" + state + ", so return");
                    if (DBG) log("onEnableApn: 'DISCONNECTING' so return");
                    apnContext.requestLog("onEnableApn state=DISCONNECTING, so return");
                    sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType,
                            requestType);
                    return;
                case IDLE:
                    // fall through: this is unexpected but if it happens cleanup and try setup
@@ -2311,7 +2361,6 @@ public class DcTracker extends Handler {
                case RETRYING:
                    // We're "READY" but not active so disconnect (cleanup = true) and
                    // connect (trySetup = true) to be sure we retry the connection.
                    trySetup = true;
                    apnContext.setReason(Phone.REASON_DATA_ENABLED);
                    break;
            }
@@ -2324,12 +2373,14 @@ public class DcTracker extends Handler {
            if (apnContext.getState() == DctConstants.State.FAILED) {
                apnContext.setState(DctConstants.State.IDLE);
            }
            trySetup = true;
        }
        apnContext.setEnabled(true);
        if (trySetup) {
        apnContext.resetErrorCodeRetries();
            trySetupData(apnContext, requestType);
        if (trySetupData(apnContext, requestType)) {
            addRequestNetworkCompleteMsg(onCompleteMsg, apnType);
        } else {
            sendRequestNetworkCompleteMsg(onCompleteMsg, false, mTransportType,
                    requestType);
        }
    }

@@ -2347,7 +2398,7 @@ public class DcTracker extends Handler {

        boolean cleanup = false;
        String str = "onDisableApn: apnType=" + ApnSetting.getApnTypeString(apnType)
                + ", release type=" + releaseType;
                + ", release type=" + releaseTypeToString(releaseType);
        if (DBG) log(str);
        apnContext.requestLog(str);

@@ -2672,6 +2723,15 @@ public class DcTracker extends Handler {
     */
    private void onDataSetupComplete(ApnContext apnContext, boolean success, int cause,
                                     @RequestNetworkType int requestType) {
        int apnType = ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType());
        List<Message> messageList = mRequestNetworkCompletionMsgs.get(apnType);
        if (messageList != null) {
            for (Message msg : messageList) {
                sendRequestNetworkCompleteMsg(msg, success, mTransportType, requestType);
            }
            messageList.clear();
        }

        if (success) {
            DataConnection dataConnection = apnContext.getDataConnection();

@@ -3512,7 +3572,7 @@ public class DcTracker extends Handler {
                break;

            case DctConstants.EVENT_ENABLE_APN:
                onEnableApn(msg.arg1, msg.arg2);
                onEnableApn(msg.arg1, msg.arg2, (Message) msg.obj);
                break;

            case DctConstants.EVENT_DISABLE_APN:
+130 −41
Original line number Diff line number Diff line
@@ -22,10 +22,15 @@ import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkRequest;
import android.net.StringNetworkSpecifier;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.Rlog;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
import android.util.LocalLog;

import com.android.internal.telephony.Phone;
@@ -33,6 +38,8 @@ import com.android.internal.telephony.PhoneSwitcher;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.SubscriptionMonitor;
import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType;
import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType;
import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams;
import com.android.internal.util.IndentingPrintWriter;

import java.io.FileDescriptor;
@@ -55,8 +62,9 @@ public class TelephonyNetworkFactory extends NetworkFactory {
    private final SubscriptionMonitor mSubscriptionMonitor;
    private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE);

    // Key: network request. Value: whether it's applied to DcTracker.
    private final Map<NetworkRequest, Boolean> mNetworkRequests = new HashMap<>();
    // Key: network request. Value: the transport of DcTracker it applies to,
    // TransportType.INVALID if not applied.
    private final Map<NetworkRequest, Integer> mNetworkRequests = new HashMap<>();

    private final Phone mPhone;

@@ -71,6 +79,8 @@ public class TelephonyNetworkFactory extends NetworkFactory {
    private static final int EVENT_SUBSCRIPTION_CHANGED             = 2;
    private static final int EVENT_NETWORK_REQUEST                  = 3;
    private static final int EVENT_NETWORK_RELEASE                  = 4;
    private static final int EVENT_DATA_HANDOVER_NEEDED             = 5;
    private static final int EVENT_DATA_HANDOVER_COMPLETED          = 6;

    public TelephonyNetworkFactory(SubscriptionMonitor subscriptionMonitor, Looper looper,
                                   Phone phone) {
@@ -91,6 +101,8 @@ public class TelephonyNetworkFactory extends NetworkFactory {

        mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH,
                null);
        mTransportManager.registerForHandoverNeededEvent(mInternalHandler,
                EVENT_DATA_HANDOVER_NEEDED);

        mSubscriptionId = INVALID_SUBSCRIPTION_ID;
        mSubscriptionMonitor.registerForSubscriptionChanged(mPhone.getPhoneId(), mInternalHandler,
@@ -148,6 +160,26 @@ public class TelephonyNetworkFactory extends NetworkFactory {
                    onReleaseNetworkFor(msg);
                    break;
                }
                case EVENT_DATA_HANDOVER_NEEDED: {
                    AsyncResult ar = (AsyncResult) msg.obj;
                    HandoverParams handoverParams = (HandoverParams) ar.result;
                    onDataHandoverNeeded(handoverParams.apnType, handoverParams.targetTransport);
                    break;
                }
                case EVENT_DATA_HANDOVER_COMPLETED: {
                    Bundle bundle = msg.getData();
                    int requestType = bundle.getInt(DcTracker.DATA_COMPLETE_MSG_EXTRA_REQUEST_TYPE);
                    if (requestType == DcTracker.REQUEST_TYPE_HANDOVER) {
                        NetworkRequest nr = bundle.getParcelable(
                                DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST);
                        boolean success = bundle.getBoolean(
                                DcTracker.DATA_COMPLETE_MSG_EXTRA_SUCCESS);
                        int transport = bundle.getInt(
                                DcTracker.DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE);
                        onDataHandoverSetupCompleted(nr, success, transport);
                    }
                    break;
                }
            }
        }
    }
@@ -157,38 +189,24 @@ public class TelephonyNetworkFactory extends NetworkFactory {
        return mTransportManager.getCurrentTransport(apnType);
    }

    private void requestNetworkInternal(NetworkRequest networkRequest) {
        int transportType = getTransportTypeFromNetworkRequest(networkRequest);
        if (mPhone.getDcTracker(transportType) != null) {
            // TODO: Handover logic will be added later. For now always normal request.
            mPhone.getDcTracker(transportType).requestNetwork(networkRequest,
                    DcTracker.REQUEST_TYPE_NORMAL, mLocalLog);
    private void requestNetworkInternal(NetworkRequest networkRequest,
                                        @RequestNetworkType int requestType,
                                        int transport, Message onCompleteMsg) {
        if (mPhone.getDcTracker(transport) != null) {
            mPhone.getDcTracker(transport).requestNetwork(networkRequest, requestType,
                    onCompleteMsg, mLocalLog);
        }
    }

    private void releaseNetworkInternal(NetworkRequest networkRequest,
                                        @ReleaseNetworkType int releaseType) {
        int transportType = getTransportTypeFromNetworkRequest(networkRequest);
        if (mPhone.getDcTracker(transportType) != null) {
            // TODO: Handover logic will be added later. For now always normal or detach request.
            mPhone.getDcTracker(transportType).releaseNetwork(networkRequest, releaseType,
                                        @ReleaseNetworkType int releaseType,
                                        int transport) {
        if (mPhone.getDcTracker(transport) != null) {
            mPhone.getDcTracker(transport).releaseNetwork(networkRequest, releaseType,
                    mLocalLog);
        }
    }

    private void applyRequestsOnActivePhoneSwitch(NetworkRequest networkRequest, int action) {
        if (action == ACTION_NO_OP) return;

        String logStr = "onActivePhoneSwitch: " + ((action == ACTION_REQUEST)
                ? "Requesting" : "Releasing") + " network request " + networkRequest;
        mLocalLog.log(logStr);
        if (action == ACTION_REQUEST) {
            requestNetworkInternal(networkRequest);
        } else if (action == ACTION_RELEASE) {
            releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_DETACH);
        }
    }

    private static int getAction(boolean wasActive, boolean isActive) {
        if (!wasActive && isActive) {
            return ACTION_REQUEST;
@@ -201,15 +219,30 @@ public class TelephonyNetworkFactory extends NetworkFactory {

    // apply or revoke requests if our active-ness changes
    private void onActivePhoneSwitch() {
        for (HashMap.Entry<NetworkRequest, Boolean> entry : mNetworkRequests.entrySet()) {
        for (HashMap.Entry<NetworkRequest, Integer> entry : mNetworkRequests.entrySet()) {
            NetworkRequest networkRequest = entry.getKey();
            boolean applied = entry.getValue();
            boolean applied = entry.getValue() != TransportType.INVALID;

            boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest(
                    networkRequest, mPhone.getPhoneId());

            applyRequestsOnActivePhoneSwitch(networkRequest, getAction(applied, shouldApply));
            mNetworkRequests.put(networkRequest, shouldApply);
            int action = getAction(applied, shouldApply);
            if (action == ACTION_NO_OP) continue;

            String logStr = "onActivePhoneSwitch: " + ((action == ACTION_REQUEST)
                    ? "Requesting" : "Releasing") + " network request " + networkRequest;
            mLocalLog.log(logStr);
            int transportType = getTransportTypeFromNetworkRequest(networkRequest);
            if (action == ACTION_REQUEST) {
                requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL,
                        getTransportTypeFromNetworkRequest(networkRequest), null);
            } else if (action == ACTION_RELEASE) {
                int transport = getTransportTypeFromNetworkRequest(networkRequest);
                releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_DETACH, transport);
            }

            mNetworkRequests.put(networkRequest,
                    shouldApply ? transportType : TransportType.INVALID);
        }
    }

@@ -237,14 +270,16 @@ public class TelephonyNetworkFactory extends NetworkFactory {
        boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest(
                networkRequest, mPhone.getPhoneId());

        mNetworkRequests.put(networkRequest, shouldApply);
        mNetworkRequests.put(networkRequest, shouldApply
                ? getTransportTypeFromNetworkRequest(networkRequest) : TransportType.INVALID);

        String s = "onNeedNetworkFor " + networkRequest + " shouldApply " + shouldApply;
        log(s);
        mLocalLog.log(s);

        if (shouldApply) {
            requestNetworkInternal(networkRequest);
            requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL,
                    getTransportTypeFromNetworkRequest(networkRequest), null);
        }
    }

@@ -257,7 +292,7 @@ public class TelephonyNetworkFactory extends NetworkFactory {

    private void onReleaseNetworkFor(Message msg) {
        NetworkRequest networkRequest = (NetworkRequest)msg.obj;
        boolean applied = mNetworkRequests.get(networkRequest);
        boolean applied = mNetworkRequests.get(networkRequest) != TransportType.INVALID;

        mNetworkRequests.remove(networkRequest);

@@ -266,7 +301,60 @@ public class TelephonyNetworkFactory extends NetworkFactory {
        mLocalLog.log(s);

        if (applied) {
            releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL);
            int transport = getTransportTypeFromNetworkRequest(networkRequest);
            releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, transport);
        }
    }

    private void onDataHandoverNeeded(@ApnType int apnType, int targetTransport) {
        log("onDataHandoverNeeded: apnType=" + ApnSetting.getApnTypeString(apnType)
                + ", target transport=" + TransportType.toString(targetTransport));
        if (mTransportManager.getCurrentTransport(apnType) == targetTransport) {
            log("apnType " + ApnSetting.getApnTypeString(apnType) + " is already on "
                    + TransportType.toString(targetTransport));
            return;
        }

        for (HashMap.Entry<NetworkRequest, Integer> entry : mNetworkRequests.entrySet()) {
            NetworkRequest networkRequest = entry.getKey();
            int currentTransport = entry.getValue();
            boolean applied = currentTransport != TransportType.INVALID;
            if (ApnContext.getApnTypeFromNetworkRequest(networkRequest) == apnType
                    && applied
                    && currentTransport != targetTransport) {
                Message onCompleteMsg = mInternalHandler.obtainMessage(
                        EVENT_DATA_HANDOVER_COMPLETED);
                onCompleteMsg.getData().putParcelable(
                        DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST, networkRequest);
                requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_HANDOVER,
                        targetTransport, onCompleteMsg);
            }
        }
    }

    private void onDataHandoverSetupCompleted(NetworkRequest networkRequest, boolean success,
                                              int targetTransport) {
        log("onDataHandoverSetupCompleted: " + networkRequest + ", success=" + success
                + ", targetTransport=" + TransportType.toString(targetTransport));

        // At this point, handover setup has been completed on the target transport. If succeeded,
        // we can release the data connection on the original transport. If failed, then we also
        // need to remove the network request from the targeting transport.

        if (success) {
            // Handover setup succeeded on targeting transport. Now we can release the network
            // request on the original transport.
            int originTransport = (targetTransport == TransportType.WWAN)
                    ? TransportType.WLAN : TransportType.WWAN;
            int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
            releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_HANDOVER,
                    originTransport);
            mNetworkRequests.put(networkRequest, targetTransport);
            // Switch the current transport to the new one.
            mTransportManager.setCurrentTransport(apnType, targetTransport);
        } else {
            // If handover failed, we need to remove the request on the targeting transport.
            releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, targetTransport);
        }
    }

@@ -278,10 +366,11 @@ public class TelephonyNetworkFactory extends NetworkFactory {
        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
        pw.println("Network Requests:");
        pw.increaseIndent();
        for (HashMap.Entry<NetworkRequest, Boolean> entry : mNetworkRequests.entrySet()) {
        for (HashMap.Entry<NetworkRequest, Integer> entry : mNetworkRequests.entrySet()) {
            NetworkRequest nr = entry.getKey();
            boolean applied = entry.getValue();
            pw.println((applied ? "Applied: " : "Not applied: ") + nr);
            int transport = entry.getValue();
            pw.println(nr + (transport != TransportType.INVALID
                    ? (" applied on " + transport) : " not applied"));
        }
        mLocalLog.dump(fd, pw, args);
        pw.decreaseIndent();
+121 −15

File changed.

Preview size limit exceeded, changes collapsed.

Loading