2011-10-31 14 views
6

Sto vedendo il mio thread chiamante si blocca nel codice nativo quando chiama WifiManager.enableNetwork(). Finora, sono stato in grado di riprodurre questo blocco sul tablet Motorola Xoom con Android 3.2.1. Ho provato su diversi altri telefoni e tablet (tutti in esecuzione Froyo o Gingerbread) e non ho visto il problema. Lo Xoom è l'unico dispositivo dual-core che devo testare (e ho riprodotto il problema su 2 diversi Xooms), quindi mi sento come se stessi inciampando su alcuni requisiti di threading Android molto sottili quando si interfaccia con WifiManager. L'analisi dello stack in cui il mio thread chiamante si blocca è:Thread si blocca su WifiManager.enableNetwork()

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 

La mia applicazione sta tentando di connettersi a un noto punto di accesso Wi-Fi, eseguire alcuni test, poi ri-collegare il dispositivo al suo punto di accesso originale (se era in precedenza collegato). Prima di stabilire la connessione, abbiamo già verificato che il Wi-Fi è abilitato e abbiamo eseguito una scansione per verificare che il nostro SSID del punto di accesso sia stato trovato. Questo codice per stabilire la connessione è in esecuzione in un AsyncTask e simile a questa:

... 
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); 
     } 
    }    
} 
... 

Questo codice è stato basato sul impostazioni WiFi codice del menu nel codice open source Android Gingerbread. C'è qualcosa nel chiamare WifiManager.enableNetwork() che mi manca? Deve essere eseguito su un thread particolare? Ho provato a garantire che enableNetwork() venga chiamato sul thread dell'interfaccia utente (spostando la logica sul ricevitore broadcast). Questo sembrava aiutare un po ', ma ero ancora in grado di riprodurre il blocco. Forse questo è qualcosa di specifico per Honeycomb? Al momento, questi 2 Xoom sono gli unici dispositivi Honeycomb che ho a disposizione per il test, quindi sono gli unici punti di dati che ho.

G

+0

Che fortuna? Ho lo stesso problema Ho appena trovato alcune informazioni che forse dovrebbero essere usate connectNetwork, ma non c'è ancora AIDL ufficiale, quindi dovresti hackerarlo :( – pprzemek

+0

Sì, ho dovuto fare esattamente questo. Ho usato il reflection per accedere al "nascosto" "API (solo per Honeycomb e versioni successive) e da allora non ho mai avuto un problema. –

+0

Ho sollevato [bug report] (http://code.google.com/p/android/issues/detail?id=34070). –

risposta

1

Questo è davvero un problema di firmware specifico per 3. * (a quanto pare).

Ho visto accadere questo su un Asus Transformer TF101 e Sony Tablet S (entrambi con 3. *, che era qualche tempo fa).

A partire dalla 3.0, ci sono nuove API per la connessione a WiFi, che non richiedono l'uso di enableNetwork in batch (per abilitare tutte le reti tranne quella corrente).

Altro su queste API, quello che ho potuto raccogliere dal codice sorgente di 4,0:

  • Essi sono contrassegnati con "@hide"
  • Essi sono utilizzati da l'applicazione Impostazioni
  • non sono ancora documentate come del 4,1
  • Hanno cambiato un po 'tra il 3 * e 4 * runtime

mia raccomandazione è di cercare di utilizzare tali API via riflessione. Poiché vengono utilizzati dall'app Impostazioni, funzionano.

+0

Non sono sicuro che si tratti di un problema firmware come da quello che so succede su HTC Jetsream, Samsung Galaxy Tab 10.1, Asus RF101, Sony Tablet S e Motorola Xoom. Sembra un bug generale in Honeycomb - Ho trovato più report nei problemi Android db intorno alla sincronizzazione del metodo wifiManager.Sembra che Honeycomb non possa sincronizzare rimuovere, aggiungere, abilitare e salvare da più thread. Vedi [issue] (http://code.google.com/p/android/issues/detail?id=34070) –