Make upstream tether list threadsafe

Outsiders asking for this list may cause the list to change on another thread.
Fixing general synchronization issues.

bug:5531630
Change-Id: I7a3ee0bba3db40f45bcb0159491942fa4cf38c37
This commit is contained in:
Robert Greenwalt
2011-11-03 16:01:40 -07:00
parent 7311bd4b70
commit b445362bd6

View File

@ -81,6 +81,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private String[] mTetherableBluetoothRegexs; private String[] mTetherableBluetoothRegexs;
private Collection<Integer> mUpstreamIfaceTypes; private Collection<Integer> mUpstreamIfaceTypes;
// used to synchronize public access to members
private Object mPublicSync;
private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE); private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI); private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN); private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);
@ -135,6 +138,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mConnService = connService; mConnService = connService;
mLooper = looper; mLooper = looper;
mPublicSync = new Object();
mIfaces = new HashMap<String, TetherInterfaceSM>(); mIfaces = new HashMap<String, TetherInterfaceSM>();
// make our own thread so we don't anr the system // make our own thread so we don't anr the system
@ -172,18 +177,25 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
} }
void updateConfiguration() { void updateConfiguration() {
mTetherableUsbRegexs = mContext.getResources().getStringArray( String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
com.android.internal.R.array.config_tether_usb_regexs); com.android.internal.R.array.config_tether_usb_regexs);
mTetherableWifiRegexs = mContext.getResources().getStringArray( String[] tetherableWifiRegexs = mContext.getResources().getStringArray(
com.android.internal.R.array.config_tether_wifi_regexs); com.android.internal.R.array.config_tether_wifi_regexs);
mTetherableBluetoothRegexs = mContext.getResources().getStringArray( String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray(
com.android.internal.R.array.config_tether_bluetooth_regexs); com.android.internal.R.array.config_tether_bluetooth_regexs);
int ifaceTypes[] = mContext.getResources().getIntArray( int ifaceTypes[] = mContext.getResources().getIntArray(
com.android.internal.R.array.config_tether_upstream_types); com.android.internal.R.array.config_tether_upstream_types);
mUpstreamIfaceTypes = new ArrayList(); Collection<Integer> upstreamIfaceTypes = new ArrayList();
for (int i : ifaceTypes) { for (int i : ifaceTypes) {
mUpstreamIfaceTypes.add(new Integer(i)); upstreamIfaceTypes.add(new Integer(i));
}
synchronized (mPublicSync) {
mTetherableUsbRegexs = tetherableUsbRegexs;
mTetherableWifiRegexs = tetherableWifiRegexs;
mTetherableBluetoothRegexs = tetherableBluetoothRegexs;
mUpstreamIfaceTypes = upstreamIfaceTypes;
} }
// check if the upstream type list needs to be modified due to secure-settings // check if the upstream type list needs to be modified due to secure-settings
@ -194,17 +206,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up); if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
boolean found = false; boolean found = false;
boolean usb = false; boolean usb = false;
if (isWifi(iface)) { synchronized (mPublicSync) {
found = true; if (isWifi(iface)) {
} else if (isUsb(iface)) { found = true;
found = true; } else if (isUsb(iface)) {
usb = true; found = true;
} else if (isBluetooth(iface)) { usb = true;
found = true; } else if (isBluetooth(iface)) {
} found = true;
if (found == false) return; }
if (found == false) return;
synchronized (mIfaces) {
TetherInterfaceSM sm = mIfaces.get(iface); TetherInterfaceSM sm = mIfaces.get(iface);
if (up) { if (up) {
if (sm == null) { if (sm == null) {
@ -231,46 +243,52 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
} }
private boolean isUsb(String iface) { private boolean isUsb(String iface) {
for (String regex : mTetherableUsbRegexs) { synchronized (mPublicSync) {
if (iface.matches(regex)) return true; for (String regex : mTetherableUsbRegexs) {
if (iface.matches(regex)) return true;
}
return false;
} }
return false;
} }
public boolean isWifi(String iface) { public boolean isWifi(String iface) {
for (String regex : mTetherableWifiRegexs) { synchronized (mPublicSync) {
if (iface.matches(regex)) return true; for (String regex : mTetherableWifiRegexs) {
if (iface.matches(regex)) return true;
}
return false;
} }
return false;
} }
public boolean isBluetooth(String iface) { public boolean isBluetooth(String iface) {
for (String regex : mTetherableBluetoothRegexs) { synchronized (mPublicSync) {
if (iface.matches(regex)) return true; for (String regex : mTetherableBluetoothRegexs) {
if (iface.matches(regex)) return true;
}
return false;
} }
return false;
} }
public void interfaceAdded(String iface) { public void interfaceAdded(String iface) {
if (VDBG) Log.d(TAG, "interfaceAdded " + iface); if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
boolean found = false; boolean found = false;
boolean usb = false; boolean usb = false;
if (isWifi(iface)) { synchronized (mPublicSync) {
found = true; if (isWifi(iface)) {
} found = true;
if (isUsb(iface)) { }
found = true; if (isUsb(iface)) {
usb = true; found = true;
} usb = true;
if (isBluetooth(iface)) { }
found = true; if (isBluetooth(iface)) {
} found = true;
if (found == false) { }
if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring"); if (found == false) {
return; if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
} return;
}
synchronized (mIfaces) {
TetherInterfaceSM sm = mIfaces.get(iface); TetherInterfaceSM sm = mIfaces.get(iface);
if (sm != null) { if (sm != null) {
if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring"); if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
@ -285,7 +303,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public void interfaceRemoved(String iface) { public void interfaceRemoved(String iface) {
if (VDBG) Log.d(TAG, "interfaceRemoved " + iface); if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
synchronized (mIfaces) { synchronized (mPublicSync) {
TetherInterfaceSM sm = mIfaces.get(iface); TetherInterfaceSM sm = mIfaces.get(iface);
if (sm == null) { if (sm == null) {
if (VDBG) { if (VDBG) {
@ -303,7 +321,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public int tether(String iface) { public int tether(String iface) {
if (DBG) Log.d(TAG, "Tethering " + iface); if (DBG) Log.d(TAG, "Tethering " + iface);
TetherInterfaceSM sm = null; TetherInterfaceSM sm = null;
synchronized (mIfaces) { synchronized (mPublicSync) {
sm = mIfaces.get(iface); sm = mIfaces.get(iface);
} }
if (sm == null) { if (sm == null) {
@ -321,7 +339,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public int untether(String iface) { public int untether(String iface) {
if (DBG) Log.d(TAG, "Untethering " + iface); if (DBG) Log.d(TAG, "Untethering " + iface);
TetherInterfaceSM sm = null; TetherInterfaceSM sm = null;
synchronized (mIfaces) { synchronized (mPublicSync) {
sm = mIfaces.get(iface); sm = mIfaces.get(iface);
} }
if (sm == null) { if (sm == null) {
@ -338,16 +356,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public int getLastTetherError(String iface) { public int getLastTetherError(String iface) {
TetherInterfaceSM sm = null; TetherInterfaceSM sm = null;
synchronized (mIfaces) { synchronized (mPublicSync) {
sm = mIfaces.get(iface); sm = mIfaces.get(iface);
if (sm == null) {
Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
", ignoring");
return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
return sm.getLastError();
} }
if (sm == null) {
Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + ", ignoring");
return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
}
return sm.getLastError();
} }
// TODO - move all private methods used only by the state machine into the state machine
// to clarify what needs synchronized protection.
private void sendTetherStateChangedBroadcast() { private void sendTetherStateChangedBroadcast() {
try { try {
if (!mConnService.isTetheringSupported()) return; if (!mConnService.isTetheringSupported()) return;
@ -363,7 +384,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
boolean usbTethered = false; boolean usbTethered = false;
boolean bluetoothTethered = false; boolean bluetoothTethered = false;
synchronized (mIfaces) { synchronized (mPublicSync) {
Set ifaces = mIfaces.keySet(); Set ifaces = mIfaces.keySet();
for (Object iface : ifaces) { for (Object iface : ifaces) {
TetherInterfaceSM sm = mIfaces.get(iface); TetherInterfaceSM sm = mIfaces.get(iface);
@ -469,7 +490,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public void onReceive(Context content, Intent intent) { public void onReceive(Context content, Intent intent) {
String action = intent.getAction(); String action = intent.getAction();
if (action.equals(UsbManager.ACTION_USB_STATE)) { if (action.equals(UsbManager.ACTION_USB_STATE)) {
synchronized (Tethering.this) { synchronized (Tethering.this.mPublicSync) {
boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false); boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false); mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
// start tethering if we have a request pending // start tethering if we have a request pending
@ -545,6 +566,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return true; return true;
} }
// TODO - return copies so people can't tamper
public String[] getTetherableUsbRegexs() { public String[] getTetherableUsbRegexs() {
return mTetherableUsbRegexs; return mTetherableUsbRegexs;
} }
@ -561,7 +583,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")"); if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE); UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
synchronized (this) { synchronized (mPublicSync) {
if (enable) { if (enable) {
if (mRndisEnabled) { if (mRndisEnabled) {
tetherUsb(true); tetherUsb(true);
@ -581,11 +603,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
} }
public int[] getUpstreamIfaceTypes() { public int[] getUpstreamIfaceTypes() {
updateConfiguration(); int values[];
int values[] = new int[mUpstreamIfaceTypes.size()]; synchronized (mPublicSync) {
Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator(); updateConfiguration();
for (int i=0; i < mUpstreamIfaceTypes.size(); i++) { values = new int[mUpstreamIfaceTypes.size()];
values[i] = iterator.next(); Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
values[i] = iterator.next();
}
} }
return values; return values;
} }
@ -593,43 +618,46 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public void checkDunRequired() { public void checkDunRequired() {
int secureSetting = Settings.Secure.getInt(mContext.getContentResolver(), int secureSetting = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.TETHER_DUN_REQUIRED, 2); Settings.Secure.TETHER_DUN_REQUIRED, 2);
// 2 = not set, 0 = DUN not required, 1 = DUN required synchronized (mPublicSync) {
if (secureSetting != 2) { // 2 = not set, 0 = DUN not required, 1 = DUN required
int requiredApn = (secureSetting == 1 ? if (secureSetting != 2) {
ConnectivityManager.TYPE_MOBILE_DUN : int requiredApn = (secureSetting == 1 ?
ConnectivityManager.TYPE_MOBILE_HIPRI); ConnectivityManager.TYPE_MOBILE_DUN :
if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) { ConnectivityManager.TYPE_MOBILE_HIPRI);
while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) { if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
mUpstreamIfaceTypes.remove(MOBILE_TYPE); while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
} mUpstreamIfaceTypes.remove(MOBILE_TYPE);
while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) { }
mUpstreamIfaceTypes.remove(HIPRI_TYPE); while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
} mUpstreamIfaceTypes.remove(HIPRI_TYPE);
if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) { }
mUpstreamIfaceTypes.add(DUN_TYPE); if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
} mUpstreamIfaceTypes.add(DUN_TYPE);
} else { }
while (mUpstreamIfaceTypes.contains(DUN_TYPE)) { } else {
mUpstreamIfaceTypes.remove(DUN_TYPE); while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
} mUpstreamIfaceTypes.remove(DUN_TYPE);
if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) { }
mUpstreamIfaceTypes.add(MOBILE_TYPE); if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
} mUpstreamIfaceTypes.add(MOBILE_TYPE);
if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) { }
mUpstreamIfaceTypes.add(HIPRI_TYPE); if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
mUpstreamIfaceTypes.add(HIPRI_TYPE);
}
} }
} }
} if (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
if (mUpstreamIfaceTypes.contains(DUN_TYPE)) { mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN;
mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN; } else {
} else { mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI;
mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI; }
} }
} }
// TODO review API - maybe return ArrayList<String> here and below?
public String[] getTetheredIfaces() { public String[] getTetheredIfaces() {
ArrayList<String> list = new ArrayList<String>(); ArrayList<String> list = new ArrayList<String>();
synchronized (mIfaces) { synchronized (mPublicSync) {
Set keys = mIfaces.keySet(); Set keys = mIfaces.keySet();
for (Object key : keys) { for (Object key : keys) {
TetherInterfaceSM sm = mIfaces.get(key); TetherInterfaceSM sm = mIfaces.get(key);
@ -647,7 +675,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public String[] getTetheredIfacePairs() { public String[] getTetheredIfacePairs() {
final ArrayList<String> list = Lists.newArrayList(); final ArrayList<String> list = Lists.newArrayList();
synchronized (mIfaces) { synchronized (mPublicSync) {
for (TetherInterfaceSM sm : mIfaces.values()) { for (TetherInterfaceSM sm : mIfaces.values()) {
if (sm.isTethered()) { if (sm.isTethered()) {
list.add(sm.mMyUpstreamIfaceName); list.add(sm.mMyUpstreamIfaceName);
@ -660,7 +688,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public String[] getTetherableIfaces() { public String[] getTetherableIfaces() {
ArrayList<String> list = new ArrayList<String>(); ArrayList<String> list = new ArrayList<String>();
synchronized (mIfaces) { synchronized (mPublicSync) {
Set keys = mIfaces.keySet(); Set keys = mIfaces.keySet();
for (Object key : keys) { for (Object key : keys) {
TetherInterfaceSM sm = mIfaces.get(key); TetherInterfaceSM sm = mIfaces.get(key);
@ -678,7 +706,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public String[] getErroredIfaces() { public String[] getErroredIfaces() {
ArrayList<String> list = new ArrayList<String>(); ArrayList<String> list = new ArrayList<String>();
synchronized (mIfaces) { synchronized (mPublicSync) {
Set keys = mIfaces.keySet(); Set keys = mIfaces.keySet();
for (Object key : keys) { for (Object key : keys) {
TetherInterfaceSM sm = mIfaces.get(key); TetherInterfaceSM sm = mIfaces.get(key);
@ -777,43 +805,54 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return res; return res;
} }
public synchronized int getLastError() { public int getLastError() {
return mLastError; synchronized (Tethering.this.mPublicSync) {
return mLastError;
}
} }
private synchronized void setLastError(int error) { private void setLastError(int error) {
mLastError = error; synchronized (Tethering.this.mPublicSync) {
mLastError = error;
if (isErrored()) { if (isErrored()) {
if (mUsb) { if (mUsb) {
// note everything's been unwound by this point so nothing to do on // note everything's been unwound by this point so nothing to do on
// further error.. // further error..
Tethering.this.configureUsbIface(false); Tethering.this.configureUsbIface(false);
}
} }
} }
} }
// synchronized between this getter and the following setter public boolean isAvailable() {
public synchronized boolean isAvailable() { synchronized (Tethering.this.mPublicSync) {
return mAvailable; return mAvailable;
}
} }
private synchronized void setAvailable(boolean available) { private void setAvailable(boolean available) {
mAvailable = available; synchronized (Tethering.this.mPublicSync) {
mAvailable = available;
}
} }
// synchronized between this getter and the following setter public boolean isTethered() {
public synchronized boolean isTethered() { synchronized (Tethering.this.mPublicSync) {
return mTethered; return mTethered;
}
} }
private synchronized void setTethered(boolean tethered) { private void setTethered(boolean tethered) {
mTethered = tethered; synchronized (Tethering.this.mPublicSync) {
mTethered = tethered;
}
} }
// synchronized between this getter and the following setter public boolean isErrored() {
public synchronized boolean isErrored() { synchronized (Tethering.this.mPublicSync) {
return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR); return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
}
} }
class InitialState extends State { class InitialState extends State {
@ -922,7 +961,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
sendTetherStateChangedBroadcast(); sendTetherStateChangedBroadcast();
} }
void cleanupUpstream() { private void cleanupUpstream() {
if (mMyUpstreamIfaceName != null) { if (mMyUpstreamIfaceName != null) {
// note that we don't care about errors here. // note that we don't care about errors here.
// sometimes interfaces are gone before we get // sometimes interfaces are gone before we get
@ -1237,21 +1276,23 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
updateConfiguration(); updateConfiguration();
if (VDBG) { synchronized (mPublicSync) {
Log.d(TAG, "chooseUpstreamType has upstream iface types:"); if (VDBG) {
for (Integer netType : mUpstreamIfaceTypes) { Log.d(TAG, "chooseUpstreamType has upstream iface types:");
Log.d(TAG, " " + netType); for (Integer netType : mUpstreamIfaceTypes) {
Log.d(TAG, " " + netType);
}
} }
}
for (Integer netType : mUpstreamIfaceTypes) { for (Integer netType : mUpstreamIfaceTypes) {
NetworkInfo info = null; NetworkInfo info = null;
try { try {
info = mConnService.getNetworkInfo(netType.intValue()); info = mConnService.getNetworkInfo(netType.intValue());
} catch (RemoteException e) { } } catch (RemoteException e) { }
if ((info != null) && info.isConnected()) { if ((info != null) && info.isConnected()) {
upType = netType.intValue(); upType = netType.intValue();
break; break;
}
} }
} }
@ -1479,14 +1520,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return; return;
} }
pw.println("mUpstreamIfaceTypes: "); synchronized (mPublicSync) {
for (Integer netType : mUpstreamIfaceTypes) { pw.println("mUpstreamIfaceTypes: ");
pw.println(" " + netType); for (Integer netType : mUpstreamIfaceTypes) {
} pw.println(" " + netType);
}
pw.println(); pw.println();
pw.println("Tether state:"); pw.println("Tether state:");
synchronized (mIfaces) {
for (Object o : mIfaces.values()) { for (Object o : mIfaces.values()) {
pw.println(" "+o.toString()); pw.println(" "+o.toString());
} }