Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread hang on WifiManager.enableNetwork()

I am seeing my calling thread hang in native code when calling WifiManager.enableNetwork(). So far, I have only been able to reproduce this hang on the Motorola Xoom tablet running Android 3.2.1. I have tested on several other phones and tablets (all running either Froyo or Gingerbread) and have not seen the problem. The Xoom is the only dual-core device I have to test (and I have reproduced the issue on 2 different Xooms), so I feel like I'm stumbling onto some very subtle Android threading requirements when interfacing with WifiManager. The stack trace where my calling thread hangs is:

    BinderProxy.transact(int, Parcel, Parcel, int) line: not available [native method]
    IWifiManager$Stub$Proxy.enableNetwork(int, boolean) line: 513
    WifiManager.enableNetwork(int, boolean) line: 587

My application is attempting to connect to a known wifi access point, perform some tests, then re-connect the device to its original access point (if it was previously connected). Prior to establishing the connection, we have already verified that wifi is enabled and we have performed a scan to verify that our access point SSID is found. This code to establish the connection is running in an AsyncTask and looks something like this:

... 
private WifiManager mWifiManager;
private List<WifiConfiguration> mConfiguredNets = new ArrayList<WifiConfiguration>();
private Object mConnectMonitor = new Object();
private NetworkInfo.State mNetworkState = State.UNKNOWN;

private final BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context inContext, final Intent inIntent) {
        final String action = inIntent.getAction();
        if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            NetworkInfo ni =
                (NetworkInfo)inIntent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            State state = ni.getState();
            if (state == State.CONNECTED) {
                synchronized (mConnectMonitor) {
                    mNetworkState = state;
                    mConnectMonitor.notify();
                }   
            }   
        }   
    }
};  

public void runninInAsyncTask(Context activityContext, int networkID) {

    mWifiManager = (WifiManager)activityContext.getSystemService(Context.WIFI_SERVICE);

    // Register our broadcast receiver to get network state change events
    IntentFilter ifilter = new IntentFilter();
    ifilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    activityContext.registerReceiver(mConnectionStateReceiver, ifilter);

    // Get a list of our currently configured networks so we can re-enable
    // them after connecting to the desired network
    mConfiguredNets = mWifiManager.getConfiguredNetworks();

    // Enable our network and disable all others
    mWifiManager.enableNetwork(networkId, true);

    // Start the reconnection process to connect to our desired  network
    synchronized (mConnectMonitor) {
        mWifiManager.reconnect();
        mConnectMonitor.wait(60000);
        if (mNetworkState != State.CONNECTED) {
            Log.e(TAG, "Problems connecting to desired network!");
        }
        else {
            Log.e(TAG, "Successfully connected to desired network!");
        }
    }               

    // Re-enable all of our previously configured networks
    for (WifiConfiguration wifiConfig : mConfiguredNets)
    {               
        if (wifiConfig.status != Status.ENABLED) {
            mWifiManager.enableNetwork(wifiConfig.networkId, false);
        }
    }               
}
...

This code was based on the Wifi settings menu code in the Android Gingerbread open source code. Is there anything about calling WifiManager.enableNetwork() that I am missing? Does it have to be run on a particular thread? I have tried ensuring that enableNetwork() is called on the UI thread (by moving the logic to the broadcast receiver). This seemed to help a little bit, but I still was able to reproduce the hang. Maybe this is something specific to Honeycomb? Right now, these 2 Xooms are the only Honeycomb devices I have available for testing, so they are the only data-points I have.

G

like image 246
Greg R Avatar asked Oct 31 '11 17:10

Greg R


1 Answers

This is indeed a firmware issue specific to 3.* (it seems).

I've seen this happen on an Asus Transformer TF101, and Sony Tablet S (both with 3.*, that was some time ago).

Starting with 3.0, there are new APIs for connecting to WiFi, which do not require using enableNetwork in batches (to enable all networks but the current one).

More on those APIs, what I could gather from 4.0 source code:

  • They are marked with "@hide"
  • They are used by the Settings app
  • They are still not documented as of 4.1
  • They changed somewhat between the 3.* and 4.* runtime

My recommendation is to try and use those APIs via reflection. Since they are used by the Settings app, they work.

like image 151
Kostya Vasilyev Avatar answered Oct 13 '22 00:10

Kostya Vasilyev