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

Commit 6dd82f23 authored by Jack Yu's avatar Jack Yu
Browse files

Moved DcNetworkAgent out of DataConnection

DcNetworkAgent is a large class so moved it out to a
separated file. No logic change.

Test: Manual + unit test
Bug: 130299990

Merged-In: Ic1d610c79f5a91a154bf2a427dd2ebd10249dca7
Change-Id: Ic1d610c79f5a91a154bf2a427dd2ebd10249dca7
(cherry picked from commit 3ef02277)
parent 8db85cb0
Loading
Loading
Loading
Loading
+0 −390
Original line number Diff line number Diff line
@@ -19,14 +19,11 @@ package com.android.internal.telephony.dataconnection;
import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;

import android.annotation.NonNull;
import android.app.PendingIntent;
import android.net.ConnectivityManager;
import android.net.KeepalivePacketData;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NattKeepalivePacketData;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
@@ -55,9 +52,7 @@ import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.DataServiceCallback;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Pair;
import android.util.SparseArray;
import android.util.StatsLog;
import android.util.TimeUtils;

@@ -2352,391 +2347,6 @@ public class DataConnection extends StateMachine {
    private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
                new DcDisconnectionErrorCreatingConnection();

    /**
     * This class represents a network agent which is communication channel between
     * {@link DataConnection} and {@link com.android.server.ConnectivityService}. The agent is
     * created when data connection enters {@link DcActiveState} until it exits that state.
     *
     * Note that in IWLAN handover scenario, this agent could be transferred to the new
     * {@link DataConnection} so for a short window of time this object might be accessed by two
     * different {@link DataConnection}. Thus each method in this class needs to be synchronized.
     */
    private static class DcNetworkAgent extends NetworkAgent {
        private String mTag;

        private Phone mPhone;

        private int mTransportType;

        private NetworkCapabilities mNetworkCapabilities;

        public final DcKeepaliveTracker keepaliveTracker = new DcKeepaliveTracker();

        private DataConnection mDataConnection;

        private final LocalLog mNetCapsLocalLog = new LocalLog(50);

        private static AtomicInteger sSerialNumber = new AtomicInteger(0);

        private DcNetworkAgent(DataConnection dc, String tag, Phone phone, NetworkInfo ni,
                               int score, NetworkMisc misc, int factorySerialNumber,
                               int transportType) {
            super(dc.getHandler().getLooper(), phone.getContext(), tag, ni,
                    dc.getNetworkCapabilities(), dc.getLinkProperties(), score, misc,
                    factorySerialNumber);
            mTag = tag;
            mPhone = phone;
            mNetworkCapabilities = dc.getNetworkCapabilities();
            mTransportType = transportType;
            mDataConnection = dc;
            logd(tag + " created for data connection " + dc.getName());
        }

        /**
         * Constructor
         *
         * @param dc The data connection owns this network agent.
         * @param phone The phone object.
         * @param ni Network info.
         * @param score Score of the data connection.
         * @param misc The miscellaneous information of the data connection.
         * @param factorySerialNumber Serial number of telephony network factory.
         * @param transportType The transport of the data connection.
         * @return The network agent
         */
        public static DcNetworkAgent createDcNetworkAgent(DataConnection dc, Phone phone,
                NetworkInfo ni, int score, NetworkMisc misc, int factorySerialNumber,
                int transportType) {
            // Use serial number only. Do not use transport type because it can be transferred to
            // a different transport.
            String tag = "DcNetworkAgent-" + sSerialNumber.incrementAndGet();
            return new DcNetworkAgent(dc, tag, phone, ni, score, misc, factorySerialNumber,
                    transportType);
        }

        /**
         * Set the data connection that owns this network agent.
         *
         * @param dc Data connection owning this network agent.
         * @param transportType Transport that this data connection is on.
         */
        public synchronized void acquireOwnership(@NonNull DataConnection dc,
                                                  @TransportType int transportType) {
            mDataConnection = dc;
            mTransportType = transportType;
            logd(dc.getName() + " acquired the ownership of this agent.");
        }

        /**
         * @return Data connection that owns this network agent.
         */
        public synchronized void releaseOwnership(DataConnection dc) {
            if (mDataConnection == null) {
                loge("releaseOwnership called on no-owner DcNetworkAgent!");
                return;
            } else if (mDataConnection != dc) {
                log("releaseOwnership: This agent belongs to "
                        + mDataConnection.getName() + ", ignored the request from " + dc.getName());
                return;
            }
            logd("Data connection " + mDataConnection.getName() + " released the ownership.");
            mDataConnection = null;
        }

        @Override
        protected synchronized void unwanted() {
            if (mDataConnection == null) {
                loge("Unwanted found called on no-owner DcNetworkAgent!");
                return;
            }

            logd("unwanted called. Now tear down the data connection "
                    + mDataConnection.getName());
            mDataConnection.tearDownAll(Phone.REASON_RELEASED_BY_CONNECTIVITY_SERVICE,
                    DcTracker.RELEASE_TYPE_DETACH, null);
        }

        @Override
        protected synchronized void pollLceData() {
            if (mDataConnection == null) {
                loge("pollLceData called on no-owner DcNetworkAgent!");
                return;
            }

            if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE     // active LCE service
                    && mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                mPhone.mCi.pullLceData(mDataConnection.obtainMessage(
                        EVENT_BW_REFRESH_RESPONSE));
            }
        }

        @Override
        protected synchronized void networkStatus(int status, String redirectUrl) {
            if (mDataConnection == null) {
                loge("networkStatus called on no-owner DcNetworkAgent!");
                return;
            }

            logd("validation status: " + status + " with redirection URL: " + redirectUrl);
            DcTracker dct = mPhone.getDcTracker(mTransportType);
            if (dct != null) {
                Message msg = dct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
                        status, 0, redirectUrl);
                msg.sendToTarget();
            }
        }

        public synchronized void sendNetworkCapabilities(NetworkCapabilities networkCapabilities,
                                                         DataConnection dc) {
            if (mDataConnection == null) {
                loge("sendNetworkCapabilities called on no-owner DcNetworkAgent!");
                return;
            } else if (mDataConnection != dc) {
                loge("sendNetworkCapabilities: This agent belongs to "
                        + mDataConnection.getName() + ", ignored the request from " + dc.getName());
                return;
            }

            if (!networkCapabilities.equals(mNetworkCapabilities)) {
                String logStr = "Changed from " + mNetworkCapabilities + " to "
                        + networkCapabilities + ", Data RAT="
                        + mPhone.getServiceState().getRilDataRadioTechnology()
                        + ", dc=" + mDataConnection.getName();
                logd(logStr);
                mNetCapsLocalLog.log(logStr);
                mNetworkCapabilities = networkCapabilities;
            }
            sendNetworkCapabilities(networkCapabilities);
        }

        public synchronized void sendLinkProperties(LinkProperties linkProperties,
                                                    DataConnection dc) {
            if (mDataConnection == null) {
                loge("sendLinkProperties called on no-owner DcNetworkAgent!");
                return;
            } else if (mDataConnection != dc) {
                loge("sendLinkProperties: This agent belongs to "
                        + mDataConnection.getName() + ", ignored the request from " + dc.getName());
                return;
            }
            sendLinkProperties(linkProperties);
        }

        public synchronized void sendNetworkScore(int score, DataConnection dc) {
            if (mDataConnection == null) {
                loge("sendNetworkScore called on no-owner DcNetworkAgent!");
                return;
            } else if (mDataConnection != dc) {
                loge("sendNetworkScore: This agent belongs to "
                        + mDataConnection.getName() + ", ignored the request from " + dc.getName());
                return;
            }
            sendNetworkScore(score);
        }

        public synchronized void sendNetworkInfo(NetworkInfo networkInfo, DataConnection dc) {
            if (mDataConnection == null) {
                loge("sendNetworkInfo called on no-owner DcNetworkAgent!");
                return;
            } else if (mDataConnection != dc) {
                loge("sendNetworkInfo: This agent belongs to "
                        + mDataConnection.getName() + ", ignored the request from " + dc.getName());
                return;
            }
            sendNetworkInfo(networkInfo);
        }

        @Override
        protected synchronized void startSocketKeepalive(Message msg) {
            if (mDataConnection == null) {
                loge("startSocketKeepalive called on no-owner DcNetworkAgent!");
                return;
            }

            if (msg.obj instanceof NattKeepalivePacketData) {
                mDataConnection.obtainMessage(EVENT_KEEPALIVE_START_REQUEST,
                        msg.arg1, msg.arg2, msg.obj).sendToTarget();
            } else {
                onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
            }
        }

        @Override
        protected synchronized void stopSocketKeepalive(Message msg) {
            if (mDataConnection == null) {
                loge("stopSocketKeepalive called on no-owner DcNetworkAgent!");
                return;
            }

            mDataConnection.obtainMessage(EVENT_KEEPALIVE_STOP_REQUEST,
                    msg.arg1, msg.arg2, msg.obj).sendToTarget();
        }

        @Override
        public String toString() {
            return "DcNetworkAgent:"
                    + " mDataConnection="
                    + ((mDataConnection != null) ? mDataConnection.getName() : null)
                    + " mTransportType="
                    + AccessNetworkConstants.transportTypeToString(mTransportType)
                    + " mNetworkCapabilities=" + mNetworkCapabilities;
        }

        /**
         * Dump the state of transport manager
         *
         * @param fd File descriptor
         * @param printWriter Print writer
         * @param args Arguments
         */
        public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
            IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
            pw.println(toString());
            pw.increaseIndent();
            pw.println("Net caps logs:");
            mNetCapsLocalLog.dump(fd, pw, args);
            pw.decreaseIndent();
        }

        /**
         * Log with debug level
         *
         * @param s is string log
         */
        private void logd(String s) {
            Rlog.d(mTag, s);
        }

        /**
         * Log with error level
         *
         * @param s is string log
         */
        private void loge(String s) {
            Rlog.e(mTag, s);
        }

        private class DcKeepaliveTracker {
            private class KeepaliveRecord {
                public int slotId;
                public int currentStatus;

                KeepaliveRecord(int slotId, int status) {
                    this.slotId = slotId;
                    this.currentStatus = status;
                }
            }

            private final SparseArray<KeepaliveRecord> mKeepalives = new SparseArray();

            int getHandleForSlot(int slotId) {
                for (int i = 0; i < mKeepalives.size(); i++) {
                    KeepaliveRecord kr = mKeepalives.valueAt(i);
                    if (kr.slotId == slotId) return mKeepalives.keyAt(i);
                }
                return -1;
            }

            int keepaliveStatusErrorToPacketKeepaliveError(int error) {
                switch(error) {
                    case KeepaliveStatus.ERROR_NONE:
                        return SocketKeepalive.SUCCESS;
                    case KeepaliveStatus.ERROR_UNSUPPORTED:
                        return SocketKeepalive.ERROR_UNSUPPORTED;
                    case KeepaliveStatus.ERROR_NO_RESOURCES:
                        return SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES;
                    case KeepaliveStatus.ERROR_UNKNOWN:
                    default:
                        return SocketKeepalive.ERROR_HARDWARE_ERROR;
                }
            }

            void handleKeepaliveStarted(final int slot, KeepaliveStatus ks) {
                switch (ks.statusCode) {
                    case KeepaliveStatus.STATUS_INACTIVE:
                        DcNetworkAgent.this.onSocketKeepaliveEvent(slot,
                                keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode));
                        break;
                    case KeepaliveStatus.STATUS_ACTIVE:
                        DcNetworkAgent.this.onSocketKeepaliveEvent(
                                slot, SocketKeepalive.SUCCESS);
                        // fall through to add record
                    case KeepaliveStatus.STATUS_PENDING:
                        logd("Adding keepalive handle="
                                + ks.sessionHandle + " slot = " + slot);
                        mKeepalives.put(ks.sessionHandle,
                                new KeepaliveRecord(
                                        slot, ks.statusCode));
                        break;
                    default:
                        logd("Invalid KeepaliveStatus Code: " + ks.statusCode);
                        break;
                }
            }

            void handleKeepaliveStatus(KeepaliveStatus ks) {
                final KeepaliveRecord kr;
                kr = mKeepalives.get(ks.sessionHandle);

                if (kr == null) {
                    // If there is no slot for the session handle, we received an event
                    // for a different data connection. This is not an error because the
                    // keepalive session events are broadcast to all listeners.
                    loge("Discarding keepalive event for different data connection:" + ks);
                    return;
                }
                // Switch on the current state, to see what we do with the status update
                switch (kr.currentStatus) {
                    case KeepaliveStatus.STATUS_INACTIVE:
                        logd("Inactive Keepalive received status!");
                        DcNetworkAgent.this.onSocketKeepaliveEvent(
                                kr.slotId, SocketKeepalive.ERROR_HARDWARE_ERROR);
                        break;
                    case KeepaliveStatus.STATUS_PENDING:
                        switch (ks.statusCode) {
                            case KeepaliveStatus.STATUS_INACTIVE:
                                DcNetworkAgent.this.onSocketKeepaliveEvent(kr.slotId,
                                        keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode));
                                kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE;
                                mKeepalives.remove(ks.sessionHandle);
                                break;
                            case KeepaliveStatus.STATUS_ACTIVE:
                                logd("Pending Keepalive received active status!");
                                kr.currentStatus = KeepaliveStatus.STATUS_ACTIVE;
                                DcNetworkAgent.this.onSocketKeepaliveEvent(
                                        kr.slotId, SocketKeepalive.SUCCESS);
                                break;
                            case KeepaliveStatus.STATUS_PENDING:
                                loge("Invalid unsolicied Keepalive Pending Status!");
                                break;
                            default:
                                loge("Invalid Keepalive Status received, " + ks.statusCode);
                        }
                        break;
                    case KeepaliveStatus.STATUS_ACTIVE:
                        switch (ks.statusCode) {
                            case KeepaliveStatus.STATUS_INACTIVE:
                                logd("Keepalive received stopped status!");
                                DcNetworkAgent.this.onSocketKeepaliveEvent(
                                        kr.slotId, SocketKeepalive.SUCCESS);
                                kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE;
                                mKeepalives.remove(ks.sessionHandle);
                                break;
                            case KeepaliveStatus.STATUS_PENDING:
                            case KeepaliveStatus.STATUS_ACTIVE:
                                loge("Active Keepalive received invalid status!");
                                break;
                            default:
                                loge("Invalid Keepalive Status received, " + ks.statusCode);
                        }
                        break;
                    default:
                        loge("Invalid Keepalive Status received, " + kr.currentStatus);
                }
            }
        }
    }

    /**
     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
     * Used for cellular networks that use Access Point Names (APN) such
+452 −0

File added.

Preview size limit exceeded, changes collapsed.

+0 −0

File mode changed from 100755 to 100644.