Fix network-feature timeout code.

Track requests independently with seperate timers.  Clean up on expiration
by just stopping that particular request, not immediately restoring the default.

bug: 2127590
This commit is contained in:
Robert Greenwalt
2009-09-27 17:27:04 -07:00
parent 149d5ac149
commit affc3a1c31

View File

@@ -439,6 +439,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return tracker != null && tracker.setRadio(turnOn); return tracker != null && tracker.setRadio(turnOn);
} }
/**
* Used to notice when the calling process dies so we can self-expire
*
* Also used to know if the process has cleaned up after itself when
* our auto-expire timer goes off. The timer has a link to an object.
*
*/
private class FeatureUser implements IBinder.DeathRecipient { private class FeatureUser implements IBinder.DeathRecipient {
int mNetworkType; int mNetworkType;
String mFeature; String mFeature;
@@ -453,6 +460,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mBinder = binder; mBinder = binder;
mPid = getCallingPid(); mPid = getCallingPid();
mUid = getCallingUid(); mUid = getCallingUid();
try { try {
mBinder.linkToDeath(this, 0); mBinder.linkToDeath(this, 0);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -467,11 +475,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public void binderDied() { public void binderDied() {
Log.d(TAG, "ConnectivityService FeatureUser binderDied(" + Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
mNetworkType + ", " + mFeature + ", " + mBinder); mNetworkType + ", " + mFeature + ", " + mBinder);
stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid); stopUsingNetworkFeature(this, false);
} }
public void expire() {
Log.d(TAG, "ConnectivityService FeatureUser expire(" +
mNetworkType + ", " + mFeature + ", " + mBinder);
stopUsingNetworkFeature(this, false);
}
} }
// javadoc from interface
public int startUsingNetworkFeature(int networkType, String feature, public int startUsingNetworkFeature(int networkType, String feature,
IBinder binder) { IBinder binder) {
if (DBG) { if (DBG) {
@@ -483,9 +497,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return Phone.APN_REQUEST_FAILED; return Phone.APN_REQUEST_FAILED;
} }
synchronized (mFeatureUsers) { FeatureUser f = new FeatureUser(networkType, feature, binder);
mFeatureUsers.add(new FeatureUser(networkType, feature, binder));
}
// TODO - move this into the MobileDataStateTracker // TODO - move this into the MobileDataStateTracker
int usedNetworkType = networkType; int usedNetworkType = networkType;
@@ -513,10 +525,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return Phone.APN_TYPE_NOT_AVAILABLE; return Phone.APN_TYPE_NOT_AVAILABLE;
} }
if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { synchronized(this) {
// this gets used for per-pid dns when connected mFeatureUsers.add(f);
mNetRequestersPids[usedNetworkType].add(currentPid); if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
// this gets used for per-pid dns when connected
mNetRequestersPids[usedNetworkType].add(currentPid);
}
} }
mHandler.sendMessageDelayed(mHandler.obtainMessage(
NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
f), getRestoreDefaultNetworkDelay());
if ((ni.isConnectedOrConnecting() == true) && if ((ni.isConnectedOrConnecting() == true) &&
!network.isTeardownRequested()) { !network.isTeardownRequested()) {
@@ -533,22 +552,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// check if the radio in play can make another contact // check if the radio in play can make another contact
// assume if cannot for now // assume if cannot for now
// since we have to drop the default on this radio, setup
// an automatic event to switch back
if(mHandler.hasMessages(NetworkStateTracker.
EVENT_RESTORE_DEFAULT_NETWORK, radio) ||
radio.getNetworkInfo().isConnectedOrConnecting()) {
mHandler.removeMessages(NetworkStateTracker.
EVENT_RESTORE_DEFAULT_NETWORK,
radio);
mHandler.sendMessageDelayed(mHandler.obtainMessage(
NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
radio), getRestoreDefaultNetworkDelay());
}
if (DBG) Log.d(TAG, "reconnecting to special network"); if (DBG) Log.d(TAG, "reconnecting to special network");
network.reconnect(); network.reconnect();
return Phone.APN_REQUEST_STARTED; return Phone.APN_REQUEST_STARTED;
} else { } else {
synchronized(this) {
mFeatureUsers.add(f);
}
mHandler.sendMessageDelayed(mHandler.obtainMessage(
NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
f), getRestoreDefaultNetworkDelay());
return network.startUsingNetworkFeature(feature, return network.startUsingNetworkFeature(feature,
getCallingPid(), getCallingUid()); getCallingPid(), getCallingUid());
} }
@@ -556,13 +570,43 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return Phone.APN_TYPE_NOT_AVAILABLE; return Phone.APN_TYPE_NOT_AVAILABLE;
} }
// javadoc from interface
public int stopUsingNetworkFeature(int networkType, String feature) { public int stopUsingNetworkFeature(int networkType, String feature) {
return stopUsingNetworkFeature(networkType, feature, getCallingPid(), int pid = getCallingPid();
getCallingUid()); int uid = getCallingUid();
FeatureUser u = null;
boolean found = false;
synchronized(this) {
for (int i = 0; i < mFeatureUsers.size() ; i++) {
u = (FeatureUser)mFeatureUsers.get(i);
if (uid == u.mUid && pid == u.mPid &&
networkType == u.mNetworkType &&
TextUtils.equals(feature, u.mFeature)) {
found = true;
break;
}
}
}
if (found && u != null) {
// stop regardless of how many other time this proc had called start
return stopUsingNetworkFeature(u, true);
} else {
// none found!
return 1;
}
} }
private int stopUsingNetworkFeature(int networkType, String feature, private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
int pid, int uid) { int networkType = u.mNetworkType;
String feature = u.mFeature;
int pid = u.mPid;
int uid = u.mUid;
NetworkStateTracker tracker = null;
boolean callTeardown = false; // used to carry our decision outside of sync block
if (DBG) { if (DBG) {
Log.d(TAG, "stopUsingNetworkFeature for net " + networkType + Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
": " + feature); ": " + feature);
@@ -572,55 +616,65 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return -1; return -1;
} }
synchronized (mFeatureUsers) { // need to link the mFeatureUsers list with the mNetRequestersPids state in this
for (int i=0; i < mFeatureUsers.size(); i++) { // sync block
FeatureUser u = (FeatureUser)mFeatureUsers.get(i); synchronized(this) {
if (uid == u.mUid && pid == u.mPid && // check if this process still has an outstanding start request
networkType == u.mNetworkType && if (!mFeatureUsers.contains(u)) {
TextUtils.equals(feature, u.mFeature)) {
u.unlinkDeathRecipient();
mFeatureUsers.remove(i);
break;
}
}
}
// TODO - move to MobileDataStateTracker
int usedNetworkType = networkType;
if (networkType == ConnectivityManager.TYPE_MOBILE) {
if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
}
}
NetworkStateTracker tracker = mNetTrackers[usedNetworkType];
if(usedNetworkType != networkType) {
Integer currentPid = new Integer(pid);
if (mNetRequestersPids[usedNetworkType].remove(currentPid)) {
reassessPidDns(pid, true);
}
if (mNetRequestersPids[usedNetworkType].size() != 0) {
if (DBG) Log.d(TAG, "not tearing down special network - " +
"others still using it");
return 1; return 1;
} }
u.unlinkDeathRecipient();
tracker.teardown(); mFeatureUsers.remove(mFeatureUsers.indexOf(u));
NetworkStateTracker radio = mNetTrackers[networkType]; // If we care about duplicate requests, check for that here.
// Check if we want to revert to the default //
if (mHandler.hasMessages(NetworkStateTracker. // This is done to support the extension of a request - the app
EVENT_RESTORE_DEFAULT_NETWORK, radio)) { // can request we start the network feature again and renew the
mHandler.removeMessages(NetworkStateTracker. // auto-shutoff delay. Normal "stop" calls from the app though
EVENT_RESTORE_DEFAULT_NETWORK, radio); // do not pay attention to duplicate requests - in effect the
radio.reconnect(); // API does not refcount and a single stop will counter multiple starts.
if (ignoreDups == false) {
for (int i = 0; i < mFeatureUsers.size() ; i++) {
FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
if (x.mUid == u.mUid && x.mPid == u.mPid &&
x.mNetworkType == u.mNetworkType &&
TextUtils.equals(x.mFeature, u.mFeature)) {
return 1;
}
}
} }
// TODO - move to MobileDataStateTracker
int usedNetworkType = networkType;
if (networkType == ConnectivityManager.TYPE_MOBILE) {
if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
}
}
tracker = mNetTrackers[usedNetworkType];
if(usedNetworkType != networkType) {
Integer currentPid = new Integer(pid);
reassessPidDns(pid, true);
mNetRequestersPids[usedNetworkType].remove(currentPid);
if (mNetRequestersPids[usedNetworkType].size() != 0) {
if (DBG) Log.d(TAG, "not tearing down special network - " +
"others still using it");
return 1;
}
callTeardown = true;
}
}
if (callTeardown) {
tracker.teardown();
return 1; return 1;
} else { } else {
// do it the old fashioned way
return tracker.stopUsingNetworkFeature(feature, pid, uid); return tracker.stopUsingNetworkFeature(feature, pid, uid);
} }
} }
@@ -1231,17 +1285,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// fill me in // fill me in
break; break;
case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK: case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
for (NetworkStateTracker net : mNetTrackers) { FeatureUser u = (FeatureUser)msg.obj;
NetworkInfo i = net.getNetworkInfo(); u.expire();
if (i.isConnected() &&
!mNetAttributes[i.getType()].isDefault()) {
if (DBG) {
Log.d(TAG, "tearing down " + i +
" to restore the default network");
}
teardown(net);
}
}
break; break;
} }
} }