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

Commit 64a09341 authored by Wink Saville's avatar Wink Saville Committed by Android (Google) Code Review
Browse files

Merge "Fix handling of unsol_data_state_change with PDP sharing scenario" into honeycomb-LTE

parents aef70d3f e303d7b3
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -89,6 +89,11 @@ public class ApnContext {
    }

    public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
        if (dcac != null) {
            dcac.addApnContext(this);
        } else {
            if (mDataConnectionAc != null) mDataConnectionAc.removeApnContext(this);
        }
        mDataConnectionAc = dcac;
    }

+36 −0
Original line number Diff line number Diff line
@@ -24,12 +24,18 @@ import android.net.LinkProperties;
import android.net.ProxyProperties;
import android.os.Message;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * AsyncChannel to a DataConnection
 */
public class DataConnectionAc extends AsyncChannel {
    private static final boolean DBG = false;
    private String mLogTag;
    private List<ApnContext> mApnList = null;

    public DataConnection dataConnection;

@@ -85,6 +91,7 @@ public class DataConnectionAc extends AsyncChannel {
    public DataConnectionAc(DataConnection dc, String logTag) {
        dataConnection = dc;
        mLogTag = logTag;
        mApnList = Collections.synchronizedList(new ArrayList<ApnContext>());
    }

    /**
@@ -371,6 +378,35 @@ public class DataConnectionAc extends AsyncChannel {
        }
    }

    /**
     * Add ApnContext association.
     *
     * @param ApnContext to associate
     */
    public void addApnContext(ApnContext apnContext) {
        if (!mApnList.contains(apnContext)) {
            mApnList.add(apnContext);
        }
    }

    /**
     * Remove ApnContext associateion.
     *
     * @param ApnContext to dissociate
     */
    public void removeApnContext(ApnContext apnContext) {
        mApnList.remove(apnContext);
    }

    /**
     * Retrieve collection of ApnContext currently associated with the DataConnectionAc.
     *
     * @return Collection of ApnContext
     */
    public Collection<ApnContext> getApnList() {
        return mApnList;
    }

    private void log(String s) {
        android.util.Log.d(mLogTag, "DataConnectionAc " + s);
    }
+124 −67
Original line number Diff line number Diff line
@@ -68,7 +68,9 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

@@ -968,6 +970,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
        }
    }

    /**
     * @param cid Connection id provided from RIL.
     * @return DataConnectionAc associated with specified cid.
     */
    private DataConnectionAc findDataConnectionAcByCid(int cid) {
        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
            if (dcac.getCidSync() == cid) {
                return dcac;
            }
        }
        return null;
    }

    /**
     * @param dcacs Collection of DataConnectionAc reported from RIL.
     * @return List of ApnContext whihc is connected, but does not present in
     *         data connection list reported from RIL.
     */
    private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
        if (dcacs == null) return null;

        ArrayList<ApnContext> list = new ArrayList<ApnContext>();
        for (ApnContext apnContext : mApnContexts.values()) {
            if (apnContext.getState() == State.CONNECTED) {
                boolean found = false;
                for (DataConnectionAc dcac : dcacs) {
                    if (dcac == apnContext.getDataConnectionAc()) {
                        // ApnContext holds the ref to dcac present in data call list.
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    // ApnContext does not have dcan reorted in data call list.
                    if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" +
                                 apnContext.toString() + ")");
                    list.add(apnContext);
                }
            }
        }
        return list;
    }

    /**
     * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST
     * or RIL_UNSOL_DATA_CALL_LIST_CHANGED
@@ -985,44 +1030,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
            if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
            return;
        }
        if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());

        // Create a hash map to store the dataCallState of each call id
        // Create a hash map to store the dataCallState of each DataConnectionAc
        // TODO: Depends on how frequent the DATA_CALL_LIST got updated,
        //       may cache response to reduce comparison.
        HashMap<Integer, DataCallState> response;
        response = new HashMap<Integer, DataCallState>();
        if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
        for (DataCallState dc : dataCallStates) {
            response.put(dc.cid, dc);
            if (DBG) log("onDataStateChanged(ar): " + dc.cid + ": " + dc.toString());
        HashMap<DataCallState, DataConnectionAc> response;
        response = new HashMap<DataCallState, DataConnectionAc>();
        for (DataCallState dataCallState : dataCallStates) {
            DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);

            if (dcac != null) response.put(dataCallState, dcac);
        }

        // For each connected apn, check if there is a matched active
        // data call state, which has the same link properties.
        if (DBG) log("    ApnContext size=" + mApnContexts.values().size());
        for (ApnContext apnContext : mApnContexts.values()) {
            if (DBG){
                log("onDataStateChanged(ar): " + apnContext.toString());
                if (apnContext.getDataConnection() != null) {
                    log("onDataStateChanged(ar): " +  apnContext.getDataConnection().toString());
        // step1: Find a list of "connected" APN which does not have reference to
        //        calls listed in the Data Call List.
        List<ApnContext> apnsToClear = findApnContextToClean(response.values());

        // step2: Check status of each calls in Data Call List.
        //        Collect list of ApnContext associated with the data call if the link
        //        has to be cleared.
        for (DataCallState newState : dataCallStates) {
            DataConnectionAc dcac = response.get(newState);

            // no associated DataConnection found. Ignore.
            if (dcac == null) continue;

            Collection<ApnContext> apns = dcac.getApnList();

            // filter out ApnContext with "Connected" state.
            ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
            for (ApnContext apnContext : apns) {
                if ((apnContext != null) &&
                    (apnContext.getState() == State.CONNECTED)) {
                    connectedApns.add(apnContext);
                }
            }
            DataConnectionAc dcac = apnContext.getDataConnectionAc();
            if (dcac == null) {

            // No "Connected" ApnContext associated with this CID. Ignore.
            if (connectedApns.isEmpty()) {
                continue;
            }
            int connectionId = dcac.getCidSync();

            if (apnContext.getState() == State.CONNECTED) {
                // The way things are supposed to work, the PDP list
                // should not contain the CID after it disconnects.
                // However, the way things really work, sometimes the PDP
                // context is still listed with active = false, which
                // makes it hard to distinguish an activating context from
                // an activated-and-then de-activated one.
                if (response.containsKey(connectionId)) {
                    DataCallState newState = response.get(connectionId);
                    if (DBG) log("onDataStateChanged(ar): Found ConnId=" + connectionId
            if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
                            + " newState=" + newState.toString());
            if (newState.active != 0) {
                boolean resetConnection;
@@ -1032,9 +1082,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                    resetConnection = false;
                    break;
                case CHANGED:
                            if (DBG) log("onDataStateChanged(ar): Found and changed, notify");
                    for (ApnContext apnContext : connectedApns) {
                        if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" +
                                     apnContext.toString() + ")");
                        mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
                                                    apnContext.getApnType());
                    }
                    // Temporary hack, at this time a transition from CDMA -> Global
                    // fails so we'll hope for the best and not reset the connection.
                    // @see bug/4455071
@@ -1057,19 +1110,23 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                }
                if (resetConnection == false) continue;
            }
                }

            if (DBG) log("onDataStateChanged(ar): reset connection.");

            apnsToClear.addAll(connectedApns);
        }

        // step3: Clear apn connection if applicable.
        if (!apnsToClear.isEmpty()) {
            // Add an event log when the network drops PDP
            int cid = getCellLocationId();
            EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
                                TelephonyManager.getDefault().getNetworkType());
        }

        for (ApnContext apnContext : apnsToClear) {
            cleanUpConnection(true, apnContext);
        }
        }

        if (DBG) log("onDataStateChanged(ar): X");
    }