Table of Contents
Android internal arche - Wifi
GUI
WifiSettings.java
Backend code for wifi_settings.xml.
public class WifiSettings extends PreferenceActivity implements DialogInterface.OnClickListener {
WifiEnabler mWifiEnabler;
...
Oncreate(...) {
mWifiEnabler = new WifiEnabler(this,
(CheckBoxPreference) findPreference("enable_wifi"));
}
WifiEnabler.java
public class WifiEnabler implements Preference.OnPreferenceChangeListener...
private final WifiManager mWifiManager;
private final BroadcastReceiver mReceiver
...
public WifiEnabler(Context context, CheckBoxPreference checkBox) {
mContext = context;
mCheckBox = checkBox;
mOriginalSummary = checkBox.getSummary();
checkBox.setPersistent(false);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
// The order matters! We really should not depend on this. :(
mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
}
...
public boolean onPreferenceChange(Preference preference, Object value) {
boolean enable = (Boolean) value;
// Show toast message if Wi-Fi is not allowed in airplane mode
if (enable && !WirelessSettings
.isRadioAllowed(mContext, Settings.System.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode,
Toast.LENGTH_SHORT).show();
return false;
}
/**
* Disable tethering if enabling Wifi
*/
int wifiApState = mWifiManager.getWifiApState();
if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
mWifiManager.setWifiApEnabled(null, false);
}
if (mWifiManager.setWifiEnabled(enable)) {
mCheckBox.setEnabled(false);
} else {
mCheckBox.setSummary(R.string.wifi_error);
}
// Don't update UI to opposite state until we're sure
return false;
}
mReceiver receives WIFI events and triggers corresponding actions in mWifiManager.
Constructor WifiEnabler(..) registers interess for Wifi events (mIntentFilter). If Wifi button changes state onPreferenceChange() is called. mWifiManager.setWifiEnabled(enable) is called if wifi checkbox is enabled.
Frameworks
$cm7rom2_src/frameworks/base/wifi/java/android/net/wifi
WifiManager.java
public class WifiManager {
IWifiManager mService;
...
public WifiManager(IWifiManager service, Handler handler) {
mService = service;
mHandler = handler;
}
...
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(enabled);
} catch (RemoteException e) {
return false;
}
}
WifiManager is the facade to various wifi framework functions. It is created by calling mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);. The IWifiManager service and Handler handler instances is probably injected after the call. service maybe an instance of WifiService.
IWifiManager.java
Stub class generated from IWifiManager.aidl. Implementation of Android aidl a kind of IPC. More info: http://developer.android.com/guide/developing/tools/aidl.html.
public interface IWifiManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.net.wifi.IWifiManager
{
private static final java.lang.String DESCRIPTOR = "android.net.wifi.IWifiManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an android.net.wifi.IWifiManager interface,
* generating a proxy if needed.
*/
public static android.net.wifi.IWifiManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
...
}
WifiService.java
$cm7rom2_src/frameworks/base/services/java/com/android/server/WifiService.java
An extension of IWifiManager.aidl$Stub. Note from IWifiManager.java above Stub extends Binder and implements IWifiManager interface. It is returned when a client binds to the service.
public class WifiService extends IWifiManager.Stub {
...
WifiService(Context context, WifiStateTracker tracker) {
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
nwService = INetworkManagementService.Stub.asInterface(b);
...
HandlerThread wifiThread = new HandlerThread("WifiService");
wifiThread.start();
mWifiHandler = new WifiHandler(wifiThread.getLooper());
...
}
public boolean setWifiEnabled(boolean enable) {
enforceChangePermission();
if (mWifiHandler == null) return false;
synchronized (mWifiHandler) {
// caller may not have WAKE_LOCK permission - it's not required here
long ident = Binder.clearCallingIdentity();
sWakeLock.acquire();
Binder.restoreCallingIdentity(ident);
mLastEnableUid = Binder.getCallingUid();
// set a flag if the user is enabling Wifi while in airplane mode
mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable());
sendEnableMessage(enable, true, Binder.getCallingUid());
}
return true;
}
...
private void sendEnableMessage(boolean enable, boolean persist, int uid) {
Message msg = Message.obtain(mWifiHandler,
(enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
(persist ? 1 : 0), uid);
msg.sendToTarget();
}
...
private void setWifiEnabledState(int wifiState, int uid) {
final int previousWifiState = mWifiStateTracker.getWifiState();
long ident = Binder.clearCallingIdentity();
try {
if (wifiState == WIFI_STATE_ENABLED) {
mBatteryStats.noteWifiOn();
} else if (wifiState == WIFI_STATE_DISABLED) {
mBatteryStats.noteWifiOff();
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
}
// Update state
mWifiStateTracker.setWifiState(wifiState);
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
mContext.sendStickyBroadcast(intent);
}
...
/**
* Handler that allows posting to the WifiThread.
*/
private class WifiHandler extends Handler {
public WifiHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ENABLE_WIFI:
setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
if (mWifiWatchdogService == null) {
mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
}
sWakeLock.release();
break;
...
}
}
}
}
Connecting to service
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
nwService = INetworkManagementService.Stub.asInterface(b);
ServiceManager.getService() returns an IBinder to the service. This IBinder is also the service Stub itself.
Handling messages
WifiService uses Android's Handler mechanism to interact with WifiNative. See also http://developer.android.com/reference/android/os/Handler.html. A message is sent to WifiHandler to trigger an operation on wifi. WifiHandler is an inner class WifiService$WifiHandler. When an message is sent to WifiHandler e.g: MESSAGEENABLEWIFI, setWifiEnabledBlocking and setWifiEnabledState, methods of WifiService are called. setWifiEnabledBlocking starts the procedure with state WIFISTATEENABLING and requests WifiStateTracker.loadDriver() first, which inturn requests WifiNative.loadDriver(). Eventually insidesetWifiEnabledState WifiStateTracker.setWifiState(wifiState) is called, which just set the internal private final AtomicInteger mWifiState to ENABLED and broadcasts the new state.
WifiStateTracker
Note the class comment:
/**
* Track the state of Wifi connectivity. All event handling is done here,
* and all changes in connectivity state are initiated here.
*
* @hide
*/
public class WifiStateTracker extends NetworkStateTracker {
...
private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_UNKNOWN);
...
/**
* Load the driver and firmware
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean loadDriver() {
return WifiNative.loadDriver();
}
...
public void setWifiState(int wifiState) {
mWifiState.set(wifiState);
}
...
...
}
ConnectivityService.java - initializing WifiService
public class ConnectivityService extends IConnectivityManager.Stub {
private static final boolean DBG = false;
...
private ConnectivityService(Context context) {
...
/*
* Create the network state trackers for Wi-Fi and mobile
* data. Maybe this could be done with a factory class,
* but it's not clear that it's worth it, given that
* the number of different network types is not going
* to change very often.
*/
boolean noMobileData = !getMobileDataEnabled();
for (int netType : mPriorityList) {
switch (mNetAttributes[netType].mRadio) {
case ConnectivityManager.TYPE_WIFI:
if (DBG) Slog.v(TAG, "Starting Wifi Service.");
WifiStateTracker wst = new WifiStateTracker(context, mHandler);
WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
wifiService.startWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring();
break;
case ConnectivityManager.TYPE_MOBILE:
...
}
....
ServiceManager.java
...
WifiService(Context context, WifiStateTracker tracker) {
mContext = context;
mWifiStateTracker = tracker;
mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
nwService = INetworkManagementService.Stub.asInterface(b);
...
ServiceManager provide a facility to connect to system services. ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE) return a Binder to a certain service. This Binder is by definition the Stub implementation of IPC (aidl) client.
SystemServer.java
class ServerThread extends Thread {
private static final String TAG = "SystemServer";
...
try {
Slog.i(TAG, "Connectivity Service");
connectivity = ConnectivityService.getInstance(context);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Connectivity Service", e);
}
...
}
public class SystemServer
{
private static final String TAG = "SystemServer";
public static final int FACTORY_TEST_OFF = 0;
public static final int FACTORY_TEST_LOW_LEVEL = 1;
public static final int FACTORY_TEST_HIGH_LEVEL = 2;
static Timer timer;
static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr
// The earliest supported time. We pick one day into 1970, to
// give any timezone code room without going into negative time.
private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;
/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);
public static void main(String[] args) {
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
...
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
...
}
