Thread hang on WifiManager.enableNetwork()
Asked Answered
M

1

6

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

Merissameristem answered 31/10, 2011 at 17:29 Comment(3)
Any luck on that? Got the same issue. Just found some info that perhaps connectNetwork should be used instead, but there is no official AIDL for that yet, so you would need to hack to it :(Joella
Yes, I had to do exactly that. I used reflection to access the "hidden" APIs (just for Honeycomb and later) and I have never had a problem since.Merissameristem
I have raised bug report.Incapacitate
F
1

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.

Forrest answered 2/7, 2012 at 19:10 Comment(1)
I am not sure if it is firmware issue as from what I know it happens on HTC Jetsream, Samsung Galaxy Tab 10.1, Asus RF101, Sony Tablet S and Motorola Xoom. It seems like a general bug in Honeycomb - I have found multiple reports in android issues db around wifiManager method synchronization. Sounds like Honeycomb cannot sync remove, add, enable and save from multiple threads. See issueIncapacitate

© 2022 - 2024 — McMap. All rights reserved.