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

Commit e492bd80 authored by Jack Yu's avatar Jack Yu Committed by Gerrit Code Review
Browse files

Merge "Moved DcNetworkAgent out of DataConnection"

parents d8add796 6dd82f23
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.