====== 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 =====
$cm7_rom_2_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 ====
$cm7_rom_2_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: ''MESSAGE_ENABLE_WIFI'', ''setWifiEnabledBlocking'' and ''setWifiEnabledState'', methods of ''WifiService'' are called. ''setWifiEnabledBlocking'' starts the procedure with state ''WIFI_STATE_ENABLING'' and requests ''WifiStateTracker.loadDriver()'' first, which inturn requests WifiNative.loadDriver(). Eventually inside''setWifiEnabledState'' ''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();
}
...
}
===== Diagrams =====
{{:programming:android:android_wifi_framework.png?200|}}