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

Commit 7aff3ba8 authored by Jack Yu's avatar Jack Yu
Browse files

Added handover support in the factory

Test: Manual
Bug: 73659459

Change-Id: Ie94ae1b0b2139d01578024f7217f22edf975ce9d
parent f32edd1b
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