Loading telephony/java/com/android/internal/telephony/ApnContext.java +2 −16 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.util.Log; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; Loading Loading @@ -49,8 +47,6 @@ public class ApnContext { String mReason; PendingIntent mReconnectIntent; /** * user/app requested connection on this APN */ Loading Loading @@ -90,9 +86,9 @@ public class ApnContext { public synchronized void setDataConnectionAc(DataConnectionAc dcac) { if (dcac != null) { dcac.addApnContext(this); dcac.addApnContextSync(this); } else { if (mDataConnectionAc != null) mDataConnectionAc.removeApnContext(this); if (mDataConnectionAc != null) mDataConnectionAc.removeApnContextSync(this); } mDataConnectionAc = dcac; } Loading Loading @@ -169,16 +165,6 @@ public class ApnContext { return mReason; } public synchronized void setReconnectIntent(PendingIntent intent) { if (DBG) log("set ReconnectIntent for type " + mApnType); mReconnectIntent = intent; } public synchronized PendingIntent getReconnectIntent() { return mReconnectIntent; } public boolean isReady() { return mDataEnabled.get() && mDependencyMet.get(); } Loading telephony/java/com/android/internal/telephony/DataConnection.java +42 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import android.app.PendingIntent; import android.net.LinkAddress; import android.net.LinkCapabilities; import android.net.LinkProperties; Loading @@ -35,8 +36,10 @@ import android.os.Parcelable; import android.os.SystemProperties; import android.text.TextUtils; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** Loading Loading @@ -68,6 +71,8 @@ public abstract class DataConnection extends StateMachine { protected static int mCount; protected AsyncChannel mAc; private List<ApnContext> mApnList = null; PendingIntent mReconnectIntent = null; /** * Used internally for saving connecting parameters. Loading Loading @@ -250,6 +255,8 @@ public abstract class DataConnection extends StateMachine { addState(mDisconnectingState, mDefaultState); addState(mDisconnectingErrorCreatingConnection, mDefaultState); setInitialState(mInactiveState); mApnList = new ArrayList<ApnContext>(); if (DBG) log("DataConnection constructor X"); } Loading Loading @@ -662,7 +669,41 @@ public abstract class DataConnection extends StateMachine { mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount); break; } case DataConnectionAc.REQ_ADD_APNCONTEXT: { ApnContext apnContext = (ApnContext) msg.obj; if (VDBG) log("REQ_ADD_APNCONTEXT apn=" + apnContext.getApnType()); if (!mApnList.contains(apnContext)) { mApnList.add(apnContext); } mAc.replyToMessage(msg, DataConnectionAc.RSP_ADD_APNCONTEXT); break; } case DataConnectionAc.REQ_REMOVE_APNCONTEXT: { ApnContext apnContext = (ApnContext) msg.obj; if (VDBG) log("REQ_REMOVE_APNCONTEXT apn=" + apnContext.getApnType()); mApnList.remove(apnContext); mAc.replyToMessage(msg, DataConnectionAc.RSP_REMOVE_APNCONTEXT); break; } case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: { if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size()); mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST, new ArrayList(mApnList)); break; } case DataConnectionAc.REQ_SET_RECONNECT_INTENT: { PendingIntent intent = (PendingIntent) msg.obj; if (VDBG) log("REQ_SET_RECONNECT_INTENT"); mReconnectIntent = intent; mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_RECONNECT_INTENT); break; } case DataConnectionAc.REQ_GET_RECONNECT_INTENT: { if (VDBG) log("REQ_GET_RECONNECT_INTENT"); mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_RECONNECT_INTENT, mReconnectIntent); break; } case EVENT_CONNECT: if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); ConnectionParams cp = (ConnectionParams) msg.obj; Loading telephony/java/com/android/internal/telephony/DataConnectionAc.java +140 −13 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.telephony; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import android.app.PendingIntent; import android.net.LinkCapabilities; import android.net.LinkProperties; import android.net.ProxyProperties; Loading @@ -26,8 +27,6 @@ import android.os.Message; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * AsyncChannel to a DataConnection Loading @@ -35,7 +34,6 @@ import java.util.List; public class DataConnectionAc extends AsyncChannel { private static final boolean DBG = false; private String mLogTag; private List<ApnContext> mApnList = null; public DataConnection dataConnection; Loading Loading @@ -68,6 +66,21 @@ public class DataConnectionAc extends AsyncChannel { public static final int REQ_GET_REFCOUNT = BASE + 16; public static final int RSP_GET_REFCOUNT = BASE + 17; public static final int REQ_ADD_APNCONTEXT = BASE + 18; public static final int RSP_ADD_APNCONTEXT = BASE + 19; public static final int REQ_REMOVE_APNCONTEXT = BASE + 20; public static final int RSP_REMOVE_APNCONTEXT = BASE + 21; public static final int REQ_GET_APNCONTEXT_LIST = BASE + 22; public static final int RSP_GET_APNCONTEXT_LIST = BASE + 23; public static final int REQ_SET_RECONNECT_INTENT = BASE + 24; public static final int RSP_SET_RECONNECT_INTENT = BASE + 25; public static final int REQ_GET_RECONNECT_INTENT = BASE + 26; public static final int RSP_GET_RECONNECT_INTENT = BASE + 27; /** * enum used to notify action taken or necessary to be * taken after the link property is changed. Loading @@ -91,7 +104,6 @@ public class DataConnectionAc extends AsyncChannel { public DataConnectionAc(DataConnection dc, String logTag) { dataConnection = dc; mLogTag = logTag; mApnList = Collections.synchronizedList(new ArrayList<ApnContext>()); } /** Loading Loading @@ -379,32 +391,147 @@ public class DataConnectionAc extends AsyncChannel { } /** * Add ApnContext association. * Request to add ApnContext association. * Response RSP_ADD_APNCONTEXT when complete. */ public void reqAddApnContext(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_ADD_APNCONTEXT, apnContext); if (DBG) log("reqAddApnContext"); } /** * Add ApnContext association synchronoulsy. * * @param ApnContext to associate */ public void addApnContext(ApnContext apnContext) { if (!mApnList.contains(apnContext)) { mApnList.add(apnContext); public void addApnContextSync(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_ADD_APNCONTEXT, apnContext); if ((response != null) && (response.what == RSP_ADD_APNCONTEXT)) { if (DBG) log("addApnContext ok"); } else { log("addApnContext error response=" + response); } } /** * Request to remove ApnContext association. * Response RSP_REMOVE_APNCONTEXT when complete. */ public void reqRemomveApnContext(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_REMOVE_APNCONTEXT, apnContext); if (DBG) log("reqRemomveApnContext"); } /** * Remove ApnContext associateion. * * @param ApnContext to dissociate */ public void removeApnContext(ApnContext apnContext) { mApnList.remove(apnContext); public void removeApnContextSync(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_REMOVE_APNCONTEXT, apnContext); if ((response != null) && (response.what == RSP_REMOVE_APNCONTEXT)) { if (DBG) log("removeApnContext ok"); } else { log("removeApnContext error response=" + response); } } /** * Request to retrive ApnContext List associated with DC. * Response RSP_GET_APNCONTEXT_LIST when complete. */ public void reqGetApnList(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_GET_APNCONTEXT_LIST); if (DBG) log("reqGetApnList"); } /** * Retrieve Collection of ApnContext from the response message. * * @param Message sent from DC in response to REQ_GET_APNCONTEXT_LIST. * @return Collection of ApnContext */ public Collection<ApnContext> rspApnList(Message response) { Collection<ApnContext> retVal = (Collection<ApnContext>)response.obj; if (retVal == null) retVal = new ArrayList<ApnContext>(); return retVal; } /** * Retrieve collection of ApnContext currently associated with the DataConnectionAc. * Retrieve collection of ApnContext currently associated with * the DataConnectionA synchronously. * * @return Collection of ApnContext */ public Collection<ApnContext> getApnList() { return mApnList; public Collection<ApnContext> getApnListSync() { Message response = sendMessageSynchronously(REQ_GET_APNCONTEXT_LIST); if ((response != null) && (response.what == RSP_GET_APNCONTEXT_LIST)) { if (DBG) log("getApnList ok"); return rspApnList(response); } else { log("getApnList error response=" + response); // return dummy list with no entry return new ArrayList<ApnContext>(); } } /** * Request to set Pending ReconnectIntent to DC. * Response RSP_SET_RECONNECT_INTENT when complete. */ public void reqSetReconnectIntent(PendingIntent intent) { Message response = sendMessageSynchronously(REQ_SET_RECONNECT_INTENT, intent); if (DBG) log("reqSetReconnectIntent"); } /** * Set pending reconnect intent to DC synchronously. * * @param PendingIntent to set. */ public void setReconnectIntentSync(PendingIntent intent) { Message response = sendMessageSynchronously(REQ_SET_RECONNECT_INTENT, intent); if ((response != null) && (response.what == RSP_SET_RECONNECT_INTENT)) { if (DBG) log("setReconnectIntent ok"); } else { log("setReconnectIntent error response=" + response); } } /** * Request to get Pending ReconnectIntent to DC. * Response RSP_GET_RECONNECT_INTENT when complete. */ public void reqGetReconnectIntent() { Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT); if (DBG) log("reqGetReconnectIntent"); } /** * Retrieve reconnect intent from response message from DC. * * @param Message which contains the reconnect intent. * @return PendingIntent from the response. */ public PendingIntent rspReconnectIntent(Message response) { PendingIntent retVal = (PendingIntent) response.obj; return retVal; } /** * Retrieve reconnect intent currently set in DC synchronously. * * @return PendingIntent reconnect intent current ly set in DC */ public PendingIntent getReconnectIntentSync() { Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT); if ((response != null) && (response.what == RSP_GET_RECONNECT_INTENT)) { if (DBG) log("getReconnectIntent ok"); return rspReconnectIntent(response); } else { log("getReconnectIntent error response=" + response); return null; } } private void log(String s) { Loading telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +121 −66 Original line number Diff line number Diff line Loading @@ -125,15 +125,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) log("GPRS reconnect alarm. Previous state was " + mState); String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE); ApnContext apnContext = mApnContexts.get(type); if (apnContext != null) { int connectionId = intent.getIntExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, -1); DataConnectionAc dcac= mDataConnectionAsyncChannels.get(connectionId); if (dcac != null) { for (ApnContext apnContext : dcac.getApnListSync()) { apnContext.setReason(reason); if (apnContext.getState() == State.FAILED) { apnContext.setState(State.IDLE); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext)); } // Alram had expired. Clear pending intent recorded on the DataConnection. dcac.setReconnectIntentSync(null); } } /** Watches for changes to the APN db. */ Loading Loading @@ -591,17 +597,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private void setupDataOnReadyApns(String reason) { // Stop reconnect alarms on all data connections pending // retry. Reset ApnContext state to IDLE. for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { if (dcac.getReconnectIntentSync() != null) { cancelReconnectAlarm(dcac); if (dcac.dataConnection != null) { dcac.dataConnection.resetRetryCount(); } Collection<ApnContext> apnList = dcac.getApnListSync(); for (ApnContext apnContext : apnList) { apnContext.setState(State.IDLE); } } } // Only check for default APN state for (ApnContext apnContext : mApnContexts.values()) { if (apnContext.isReady()) { if (apnContext.getState() == State.FAILED) { cleanApnContextBeforeRestart(apnContext); if (apnContext.getDataConnection() != null) { apnContext.getDataConnection().resetRetryCount(); } } // Do not start ApnContext in SCANNING state // FAILED state must be reset to IDLE by now if (apnContext.getState() == State.IDLE) { apnContext.setReason(reason); trySetupData(apnContext); Loading Loading @@ -751,53 +765,70 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) { log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason()); } if (tearDown && cleanApnContextBeforeRestart(apnContext)) { // if the request is tearDown and ApnContext does not hold an active connection, // we're ok to return here. return; } DataConnectionAc dcac = apnContext.getDataConnectionAc(); if (tearDown && (dcac != null)) { if (tearDown) { boolean isConnected = (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED); if (!isConnected) { // The request is tearDown and but ApnContext is not connected. // If apnContext is not enabled anymore, break the linkage to the DCAC/DC. apnContext.setState(State.IDLE); if (!apnContext.isReady()) { apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); } } else { // Connection is still there. Try to clean up. if (dcac != null) { if (apnContext.getState() != State.DISCONNECTING) { if (DBG) log("cleanUpConnection: tearing down"); Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext); apnContext.getDataConnection().tearDown(apnContext.getReason(), msg); apnContext.setState(State.DISCONNECTING); } else { // apn is connected but no reference to dcac. // Should not be happen, but reset the state in case. apnContext.setState(State.IDLE); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); } } } } else { // force clean up the data connection. if (dcac != null) dcac.resetSync(); apnContext.setState(State.IDLE); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); } // make sure reconnection alarm is cleaned up if there is no ApnContext // associated to the connection. if (dcac != null) { Collection<ApnContext> apnList = dcac.getApnListSync(); if (apnList.isEmpty()) { cancelReconnectAlarm(dcac); } } } /** * @param APNContext to clean * @return true if ApnContext is not connected anymore. * false if ApnContext still holds a connection. * Cancels the alarm associated with DCAC. * * @param DataConnectionAc on which the alarm should be stopped. */ private boolean cleanApnContextBeforeRestart(ApnContext apnContext) { if (apnContext == null) return true; private void cancelReconnectAlarm(DataConnectionAc dcac) { if (dcac == null) return; // Clear the reconnect alarm, if set. if (apnContext.getReconnectIntent() != null) { PendingIntent intent = dcac.getReconnectIntentSync(); if (intent != null) { AlarmManager am = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); am.cancel(apnContext.getReconnectIntent()); apnContext.setReconnectIntent(null); } if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) { if (DBG) log("cleanUpConnection: state= " + apnContext.getState()); return true; am.cancel(intent); dcac.setReconnectIntentSync(null); } if (apnContext.getState() == State.FAILED) { apnContext.setState(State.IDLE); return true; } return false; } /** Loading Loading @@ -936,17 +967,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { configureRetry(dc, apnContext.getApnType()); } apnContext.setDataConnectionAc(dcac); apnContext.setApnSetting(apn); apnContext.setDataConnection(dc); } apnContext.setApnSetting(apn); apnContext.setState(State.INITING); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); // If reconnect alarm is active on this DataConnection, wait for the alarm being // fired so that we don't disruppt data retry pattern engaged. if (apnContext.getDataConnectionAc().getReconnectIntentSync() != null) { if (DBG) log("setupData: data reconnection pending"); apnContext.setState(State.FAILED); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); return true; } Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = apnContext; dc.bringUp(msg, apn); apnContext.setState(State.INITING); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); if (DBG) log("setupData: initing!"); return true; } Loading Loading @@ -1063,13 +1103,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // no associated DataConnection found. Ignore. if (dcac == null) continue; Collection<ApnContext> apns = dcac.getApnList(); Collection<ApnContext> apns = dcac.getApnListSync(); // filter out ApnContext with "Connected" state. ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>(); for (ApnContext apnContext : apns) { if ((apnContext != null) && (apnContext.getState() == State.CONNECTED)) { if (apnContext.getState() == State.CONNECTED) { connectedApns.add(apnContext); } } Loading Loading @@ -1449,21 +1488,28 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { + (delay / 1000) + "s"); } DataConnectionAc dcac = apnContext.getDataConnectionAc(); if ((dcac == null) || (dcac.dataConnection == null)) { // should not happen, but just in case. loge("null dcac or dc."); return; } AlarmManager am = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); // TODO : Register the receiver only once maybe in baseclass. IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM + '.'+apnContext.getApnType()); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType()); Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' + dcac.dataConnection.getDataConnectionId()); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason()); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType()); apnContext.setReconnectIntent(PendingIntent.getBroadcast ( mPhone.getContext(), 0, intent, 0)); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, dcac.dataConnection.getDataConnectionId()); PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, intent, 0); dcac.setReconnectIntentSync(alarmIntent); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, apnContext.getReconnectIntent()); SystemClock.elapsedRealtime() + delay, alarmIntent); } Loading Loading @@ -1768,9 +1814,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } apnContext.setState(State.IDLE); apnContext.setApnSetting(null); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); Loading @@ -1779,6 +1822,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (!isConnected()) { if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { // Radio will be turned off. No need to retry data setup apnContext.setApnSetting(null); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); return; } } Loading @@ -1790,6 +1836,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // we're not tying up the RIL command channel. // This also helps in any external dependency to turn off the context. startAlarmForReconnect(APN_DELAY_MILLIS, apnContext); } else { apnContext.setApnSetting(null); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); } } Loading Loading @@ -1915,6 +1965,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { " status=" + status); } // install reconnect intent filter for this data connection. IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM + '.' + id); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); if (DBG) log("createDataConnection() X id=" + id); return conn; } Loading Loading
telephony/java/com/android/internal/telephony/ApnContext.java +2 −16 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.util.Log; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; Loading Loading @@ -49,8 +47,6 @@ public class ApnContext { String mReason; PendingIntent mReconnectIntent; /** * user/app requested connection on this APN */ Loading Loading @@ -90,9 +86,9 @@ public class ApnContext { public synchronized void setDataConnectionAc(DataConnectionAc dcac) { if (dcac != null) { dcac.addApnContext(this); dcac.addApnContextSync(this); } else { if (mDataConnectionAc != null) mDataConnectionAc.removeApnContext(this); if (mDataConnectionAc != null) mDataConnectionAc.removeApnContextSync(this); } mDataConnectionAc = dcac; } Loading Loading @@ -169,16 +165,6 @@ public class ApnContext { return mReason; } public synchronized void setReconnectIntent(PendingIntent intent) { if (DBG) log("set ReconnectIntent for type " + mApnType); mReconnectIntent = intent; } public synchronized PendingIntent getReconnectIntent() { return mReconnectIntent; } public boolean isReady() { return mDataEnabled.get() && mDependencyMet.get(); } Loading
telephony/java/com/android/internal/telephony/DataConnection.java +42 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import android.app.PendingIntent; import android.net.LinkAddress; import android.net.LinkCapabilities; import android.net.LinkProperties; Loading @@ -35,8 +36,10 @@ import android.os.Parcelable; import android.os.SystemProperties; import android.text.TextUtils; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** Loading Loading @@ -68,6 +71,8 @@ public abstract class DataConnection extends StateMachine { protected static int mCount; protected AsyncChannel mAc; private List<ApnContext> mApnList = null; PendingIntent mReconnectIntent = null; /** * Used internally for saving connecting parameters. Loading Loading @@ -250,6 +255,8 @@ public abstract class DataConnection extends StateMachine { addState(mDisconnectingState, mDefaultState); addState(mDisconnectingErrorCreatingConnection, mDefaultState); setInitialState(mInactiveState); mApnList = new ArrayList<ApnContext>(); if (DBG) log("DataConnection constructor X"); } Loading Loading @@ -662,7 +669,41 @@ public abstract class DataConnection extends StateMachine { mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount); break; } case DataConnectionAc.REQ_ADD_APNCONTEXT: { ApnContext apnContext = (ApnContext) msg.obj; if (VDBG) log("REQ_ADD_APNCONTEXT apn=" + apnContext.getApnType()); if (!mApnList.contains(apnContext)) { mApnList.add(apnContext); } mAc.replyToMessage(msg, DataConnectionAc.RSP_ADD_APNCONTEXT); break; } case DataConnectionAc.REQ_REMOVE_APNCONTEXT: { ApnContext apnContext = (ApnContext) msg.obj; if (VDBG) log("REQ_REMOVE_APNCONTEXT apn=" + apnContext.getApnType()); mApnList.remove(apnContext); mAc.replyToMessage(msg, DataConnectionAc.RSP_REMOVE_APNCONTEXT); break; } case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: { if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size()); mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST, new ArrayList(mApnList)); break; } case DataConnectionAc.REQ_SET_RECONNECT_INTENT: { PendingIntent intent = (PendingIntent) msg.obj; if (VDBG) log("REQ_SET_RECONNECT_INTENT"); mReconnectIntent = intent; mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_RECONNECT_INTENT); break; } case DataConnectionAc.REQ_GET_RECONNECT_INTENT: { if (VDBG) log("REQ_GET_RECONNECT_INTENT"); mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_RECONNECT_INTENT, mReconnectIntent); break; } case EVENT_CONNECT: if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); ConnectionParams cp = (ConnectionParams) msg.obj; Loading
telephony/java/com/android/internal/telephony/DataConnectionAc.java +140 −13 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.telephony; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import android.app.PendingIntent; import android.net.LinkCapabilities; import android.net.LinkProperties; import android.net.ProxyProperties; Loading @@ -26,8 +27,6 @@ import android.os.Message; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * AsyncChannel to a DataConnection Loading @@ -35,7 +34,6 @@ import java.util.List; public class DataConnectionAc extends AsyncChannel { private static final boolean DBG = false; private String mLogTag; private List<ApnContext> mApnList = null; public DataConnection dataConnection; Loading Loading @@ -68,6 +66,21 @@ public class DataConnectionAc extends AsyncChannel { public static final int REQ_GET_REFCOUNT = BASE + 16; public static final int RSP_GET_REFCOUNT = BASE + 17; public static final int REQ_ADD_APNCONTEXT = BASE + 18; public static final int RSP_ADD_APNCONTEXT = BASE + 19; public static final int REQ_REMOVE_APNCONTEXT = BASE + 20; public static final int RSP_REMOVE_APNCONTEXT = BASE + 21; public static final int REQ_GET_APNCONTEXT_LIST = BASE + 22; public static final int RSP_GET_APNCONTEXT_LIST = BASE + 23; public static final int REQ_SET_RECONNECT_INTENT = BASE + 24; public static final int RSP_SET_RECONNECT_INTENT = BASE + 25; public static final int REQ_GET_RECONNECT_INTENT = BASE + 26; public static final int RSP_GET_RECONNECT_INTENT = BASE + 27; /** * enum used to notify action taken or necessary to be * taken after the link property is changed. Loading @@ -91,7 +104,6 @@ public class DataConnectionAc extends AsyncChannel { public DataConnectionAc(DataConnection dc, String logTag) { dataConnection = dc; mLogTag = logTag; mApnList = Collections.synchronizedList(new ArrayList<ApnContext>()); } /** Loading Loading @@ -379,32 +391,147 @@ public class DataConnectionAc extends AsyncChannel { } /** * Add ApnContext association. * Request to add ApnContext association. * Response RSP_ADD_APNCONTEXT when complete. */ public void reqAddApnContext(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_ADD_APNCONTEXT, apnContext); if (DBG) log("reqAddApnContext"); } /** * Add ApnContext association synchronoulsy. * * @param ApnContext to associate */ public void addApnContext(ApnContext apnContext) { if (!mApnList.contains(apnContext)) { mApnList.add(apnContext); public void addApnContextSync(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_ADD_APNCONTEXT, apnContext); if ((response != null) && (response.what == RSP_ADD_APNCONTEXT)) { if (DBG) log("addApnContext ok"); } else { log("addApnContext error response=" + response); } } /** * Request to remove ApnContext association. * Response RSP_REMOVE_APNCONTEXT when complete. */ public void reqRemomveApnContext(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_REMOVE_APNCONTEXT, apnContext); if (DBG) log("reqRemomveApnContext"); } /** * Remove ApnContext associateion. * * @param ApnContext to dissociate */ public void removeApnContext(ApnContext apnContext) { mApnList.remove(apnContext); public void removeApnContextSync(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_REMOVE_APNCONTEXT, apnContext); if ((response != null) && (response.what == RSP_REMOVE_APNCONTEXT)) { if (DBG) log("removeApnContext ok"); } else { log("removeApnContext error response=" + response); } } /** * Request to retrive ApnContext List associated with DC. * Response RSP_GET_APNCONTEXT_LIST when complete. */ public void reqGetApnList(ApnContext apnContext) { Message response = sendMessageSynchronously(REQ_GET_APNCONTEXT_LIST); if (DBG) log("reqGetApnList"); } /** * Retrieve Collection of ApnContext from the response message. * * @param Message sent from DC in response to REQ_GET_APNCONTEXT_LIST. * @return Collection of ApnContext */ public Collection<ApnContext> rspApnList(Message response) { Collection<ApnContext> retVal = (Collection<ApnContext>)response.obj; if (retVal == null) retVal = new ArrayList<ApnContext>(); return retVal; } /** * Retrieve collection of ApnContext currently associated with the DataConnectionAc. * Retrieve collection of ApnContext currently associated with * the DataConnectionA synchronously. * * @return Collection of ApnContext */ public Collection<ApnContext> getApnList() { return mApnList; public Collection<ApnContext> getApnListSync() { Message response = sendMessageSynchronously(REQ_GET_APNCONTEXT_LIST); if ((response != null) && (response.what == RSP_GET_APNCONTEXT_LIST)) { if (DBG) log("getApnList ok"); return rspApnList(response); } else { log("getApnList error response=" + response); // return dummy list with no entry return new ArrayList<ApnContext>(); } } /** * Request to set Pending ReconnectIntent to DC. * Response RSP_SET_RECONNECT_INTENT when complete. */ public void reqSetReconnectIntent(PendingIntent intent) { Message response = sendMessageSynchronously(REQ_SET_RECONNECT_INTENT, intent); if (DBG) log("reqSetReconnectIntent"); } /** * Set pending reconnect intent to DC synchronously. * * @param PendingIntent to set. */ public void setReconnectIntentSync(PendingIntent intent) { Message response = sendMessageSynchronously(REQ_SET_RECONNECT_INTENT, intent); if ((response != null) && (response.what == RSP_SET_RECONNECT_INTENT)) { if (DBG) log("setReconnectIntent ok"); } else { log("setReconnectIntent error response=" + response); } } /** * Request to get Pending ReconnectIntent to DC. * Response RSP_GET_RECONNECT_INTENT when complete. */ public void reqGetReconnectIntent() { Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT); if (DBG) log("reqGetReconnectIntent"); } /** * Retrieve reconnect intent from response message from DC. * * @param Message which contains the reconnect intent. * @return PendingIntent from the response. */ public PendingIntent rspReconnectIntent(Message response) { PendingIntent retVal = (PendingIntent) response.obj; return retVal; } /** * Retrieve reconnect intent currently set in DC synchronously. * * @return PendingIntent reconnect intent current ly set in DC */ public PendingIntent getReconnectIntentSync() { Message response = sendMessageSynchronously(REQ_GET_RECONNECT_INTENT); if ((response != null) && (response.what == RSP_GET_RECONNECT_INTENT)) { if (DBG) log("getReconnectIntent ok"); return rspReconnectIntent(response); } else { log("getReconnectIntent error response=" + response); return null; } } private void log(String s) { Loading
telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +121 −66 Original line number Diff line number Diff line Loading @@ -125,15 +125,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) log("GPRS reconnect alarm. Previous state was " + mState); String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE); ApnContext apnContext = mApnContexts.get(type); if (apnContext != null) { int connectionId = intent.getIntExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, -1); DataConnectionAc dcac= mDataConnectionAsyncChannels.get(connectionId); if (dcac != null) { for (ApnContext apnContext : dcac.getApnListSync()) { apnContext.setReason(reason); if (apnContext.getState() == State.FAILED) { apnContext.setState(State.IDLE); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext)); } // Alram had expired. Clear pending intent recorded on the DataConnection. dcac.setReconnectIntentSync(null); } } /** Watches for changes to the APN db. */ Loading Loading @@ -591,17 +597,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private void setupDataOnReadyApns(String reason) { // Stop reconnect alarms on all data connections pending // retry. Reset ApnContext state to IDLE. for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { if (dcac.getReconnectIntentSync() != null) { cancelReconnectAlarm(dcac); if (dcac.dataConnection != null) { dcac.dataConnection.resetRetryCount(); } Collection<ApnContext> apnList = dcac.getApnListSync(); for (ApnContext apnContext : apnList) { apnContext.setState(State.IDLE); } } } // Only check for default APN state for (ApnContext apnContext : mApnContexts.values()) { if (apnContext.isReady()) { if (apnContext.getState() == State.FAILED) { cleanApnContextBeforeRestart(apnContext); if (apnContext.getDataConnection() != null) { apnContext.getDataConnection().resetRetryCount(); } } // Do not start ApnContext in SCANNING state // FAILED state must be reset to IDLE by now if (apnContext.getState() == State.IDLE) { apnContext.setReason(reason); trySetupData(apnContext); Loading Loading @@ -751,53 +765,70 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) { log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason()); } if (tearDown && cleanApnContextBeforeRestart(apnContext)) { // if the request is tearDown and ApnContext does not hold an active connection, // we're ok to return here. return; } DataConnectionAc dcac = apnContext.getDataConnectionAc(); if (tearDown && (dcac != null)) { if (tearDown) { boolean isConnected = (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED); if (!isConnected) { // The request is tearDown and but ApnContext is not connected. // If apnContext is not enabled anymore, break the linkage to the DCAC/DC. apnContext.setState(State.IDLE); if (!apnContext.isReady()) { apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); } } else { // Connection is still there. Try to clean up. if (dcac != null) { if (apnContext.getState() != State.DISCONNECTING) { if (DBG) log("cleanUpConnection: tearing down"); Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext); apnContext.getDataConnection().tearDown(apnContext.getReason(), msg); apnContext.setState(State.DISCONNECTING); } else { // apn is connected but no reference to dcac. // Should not be happen, but reset the state in case. apnContext.setState(State.IDLE); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); } } } } else { // force clean up the data connection. if (dcac != null) dcac.resetSync(); apnContext.setState(State.IDLE); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); } // make sure reconnection alarm is cleaned up if there is no ApnContext // associated to the connection. if (dcac != null) { Collection<ApnContext> apnList = dcac.getApnListSync(); if (apnList.isEmpty()) { cancelReconnectAlarm(dcac); } } } /** * @param APNContext to clean * @return true if ApnContext is not connected anymore. * false if ApnContext still holds a connection. * Cancels the alarm associated with DCAC. * * @param DataConnectionAc on which the alarm should be stopped. */ private boolean cleanApnContextBeforeRestart(ApnContext apnContext) { if (apnContext == null) return true; private void cancelReconnectAlarm(DataConnectionAc dcac) { if (dcac == null) return; // Clear the reconnect alarm, if set. if (apnContext.getReconnectIntent() != null) { PendingIntent intent = dcac.getReconnectIntentSync(); if (intent != null) { AlarmManager am = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); am.cancel(apnContext.getReconnectIntent()); apnContext.setReconnectIntent(null); } if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) { if (DBG) log("cleanUpConnection: state= " + apnContext.getState()); return true; am.cancel(intent); dcac.setReconnectIntentSync(null); } if (apnContext.getState() == State.FAILED) { apnContext.setState(State.IDLE); return true; } return false; } /** Loading Loading @@ -936,17 +967,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { configureRetry(dc, apnContext.getApnType()); } apnContext.setDataConnectionAc(dcac); apnContext.setApnSetting(apn); apnContext.setDataConnection(dc); } apnContext.setApnSetting(apn); apnContext.setState(State.INITING); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); // If reconnect alarm is active on this DataConnection, wait for the alarm being // fired so that we don't disruppt data retry pattern engaged. if (apnContext.getDataConnectionAc().getReconnectIntentSync() != null) { if (DBG) log("setupData: data reconnection pending"); apnContext.setState(State.FAILED); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); return true; } Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = apnContext; dc.bringUp(msg, apn); apnContext.setState(State.INITING); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); if (DBG) log("setupData: initing!"); return true; } Loading Loading @@ -1063,13 +1103,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // no associated DataConnection found. Ignore. if (dcac == null) continue; Collection<ApnContext> apns = dcac.getApnList(); Collection<ApnContext> apns = dcac.getApnListSync(); // filter out ApnContext with "Connected" state. ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>(); for (ApnContext apnContext : apns) { if ((apnContext != null) && (apnContext.getState() == State.CONNECTED)) { if (apnContext.getState() == State.CONNECTED) { connectedApns.add(apnContext); } } Loading Loading @@ -1449,21 +1488,28 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { + (delay / 1000) + "s"); } DataConnectionAc dcac = apnContext.getDataConnectionAc(); if ((dcac == null) || (dcac.dataConnection == null)) { // should not happen, but just in case. loge("null dcac or dc."); return; } AlarmManager am = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); // TODO : Register the receiver only once maybe in baseclass. IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM + '.'+apnContext.getApnType()); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType()); Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' + dcac.dataConnection.getDataConnectionId()); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason()); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnContext.getApnType()); apnContext.setReconnectIntent(PendingIntent.getBroadcast ( mPhone.getContext(), 0, intent, 0)); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, dcac.dataConnection.getDataConnectionId()); PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, intent, 0); dcac.setReconnectIntentSync(alarmIntent); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, apnContext.getReconnectIntent()); SystemClock.elapsedRealtime() + delay, alarmIntent); } Loading Loading @@ -1768,9 +1814,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } apnContext.setState(State.IDLE); apnContext.setApnSetting(null); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); Loading @@ -1779,6 +1822,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (!isConnected()) { if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { // Radio will be turned off. No need to retry data setup apnContext.setApnSetting(null); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); return; } } Loading @@ -1790,6 +1836,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // we're not tying up the RIL command channel. // This also helps in any external dependency to turn off the context. startAlarmForReconnect(APN_DELAY_MILLIS, apnContext); } else { apnContext.setApnSetting(null); apnContext.setDataConnection(null); apnContext.setDataConnectionAc(null); } } Loading Loading @@ -1915,6 +1965,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { " status=" + status); } // install reconnect intent filter for this data connection. IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM + '.' + id); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); if (DBG) log("createDataConnection() X id=" + id); return conn; } Loading