Wifi源码学习之wifi连接

wifi 连接,我们从 点击连接开始分析。

Wifi源码学习之wifi连接_第1张图片

Settings\src\com\android\settings\wifi\WifiSettings.java

首先看到 onActivityCreate() 方法中写了三个Listener。(看名字就知道是监听者模式)
而这一切似乎都和 这个 WifiManager.java 息息相关。

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    mConnectListener = new WifiManager.ActionListener() {
                               @Override
                               public void onSuccess() {
                               }
                               @Override
                               public void onFailure(int reason) {
                                   Activity activity = getActivity();
                                   if (activity != null) {
                                       Toast.makeText(activity,
                                            R.string.wifi_failed_connect_message,
                                            Toast.LENGTH_SHORT).show();
                                   }
                               }
                           };
    mSaveListener = new WifiManager.ActionListener() {
                            @Override
                            public void onSuccess() {
                            }
                            @Override
                            public void onFailure(int reason) {
                                Activity activity = getActivity();
                                if (activity != null) {
                                    Toast.makeText(activity,
                                        R.string.wifi_failed_save_message,
                                        Toast.LENGTH_SHORT).show();
                                }
                            }
                        };
    mForgetListener = new WifiManager.ActionListener() {
                               @Override
                               public void onSuccess() {
                               }
                               @Override
                               public void onFailure(int reason) {
                                   Activity activity = getActivity();
                                   if (activity != null) {
                                       Toast.makeText(activity,
                                           R.string.wifi_failed_forget_message,
                                           Toast.LENGTH_SHORT).show();
                                   }
                               }
                           };
......
}

我们再找找注册这些监听的地方:
发现有两种连接方式:

protected void connect(final WifiConfiguration config) {
    mWifiManager.connect(config, mConnectListener);
}

protected void connect(final int networkId) {
    mWifiManager.connect(networkId, mConnectListener);
}

在这儿被调用

@Override
public boolean onContextItemSelected(MenuItem item) {
    // 我们再找找这个 mSelectedAccessPoint  变量在哪儿赋值
    if (mSelectedAccessPoint == null) {
        return super.onContextItemSelected(item);
    }
    switch (item.getItemId()) {
   // 最终发现,连接的方法在这儿被调用。very good!
        case MENU_ID_CONNECT: {
            if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                connect(mSelectedAccessPoint.networkId);
            } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
                /** Bypass dialog for unsecured networks */
                mSelectedAccessPoint.generateOpenNetworkConfig();
                connect(mSelectedAccessPoint.getConfig());
            } else {
                showDialog(mSelectedAccessPoint, true);
            }
            return true;
        }
        case MENU_ID_FORGET: {
            forget();
            return true;
        }
        case MENU_ID_MODIFY: {
            showDialog(mSelectedAccessPoint, true);
            return true;
        }
        case MENU_ID_WRITE_NFC:
            showDialog(WRITE_NFC_DIALOG_ID);
            return true;
    }
    return super.onContextItemSelected(item);
}

最终发现,mSelectedAccessPoint 在这个方法中赋值

@Override
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
    if (preference instanceof AccessPoint) {
        // 这个变量就是指当前点击的 wifi
        mSelectedAccessPoint = (AccessPoint) preference;
        /** Bypass dialog for unsecured, unsaved, and inactive networks */
        if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
                mSelectedAccessPoint.networkId == INVALID_NETWORK_ID &&
                !mSelectedAccessPoint.isActive()) {
            mSelectedAccessPoint.generateOpenNetworkConfig();
            if (!savedNetworksExist) {
                savedNetworksExist = true;
                getActivity().invalidateOptionsMenu();
            }
            connect(mSelectedAccessPoint.getConfig());
        } else {
            showDialog(mSelectedAccessPoint, false);
        }
    } else {
        return super.onPreferenceTreeClick(screen, preference);
    }
    return true;
}

继续追踪 connect 方法:注释很多哈

/**
 * Connect to a network with the given configuration. The network also
 * gets added to the supplicant configuration.
 *
 * For a new network, this function is used instead of a
 * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
 * reconnect()
 *
 * @param config the set of variables that describe the configuration,
 *            contained in a {@link WifiConfiguration} object.
 * @param listener for callbacks on success or failure. Can be null.
 * @throws IllegalStateException if the WifiManager instance needs to be
 * initialized again
 *
 * @hide
 */
public void connect(WifiConfiguration config, ActionListener listener) {
    if (config == null) throw new IllegalArgumentException("config cannot be null");
    validateChannel();
    // Use INVALID_NETWORK_ID for arg1 when passing a config object
    // arg1 is used to pass network id when the network already exists
    sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
            putListener(listener), config);
}

/**
 * Connect to a network with the given networkId.
 *
 * This function is used instead of a enableNetwork(), saveConfiguration() and
 * reconnect()
 *
 * @param networkId the network id identifiying the network in the
 *                supplicant configuration list
 * @param listener for callbacks on success or failure. Can be null.
 * @throws IllegalStateException if the WifiManager instance needs to be
 * initialized again
 * @hide
 */
public void connect(int networkId, ActionListener listener) {
    if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
    validateChannel();
    sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
}

继续追踪;原来 sAsyncChannel 是在这儿被创建的。

private void init() {
    synchronized (sThreadRefLock) {
        if (++sThreadRefCount == 1) {
            Messenger messenger = getWifiServiceMessenger();
            if (messenger == null) {
                sAsyncChannel = null;
                return;
            }
            sHandlerThread = new HandlerThread("WifiManager");
   // 就是在这儿
            sAsyncChannel = new AsyncChannel();
            sConnected = new CountDownLatch(1);
            sHandlerThread.start();
            Handler handler = new ServiceHandler(sHandlerThread.getLooper());
            // 这个connect 方法就是初始化的作用
            sAsyncChannel.connect(mContext, handler, messenger);
            try {
                sConnected.await();
            } catch (InterruptedException e) {
                Log.e(TAG, "interrupted wait at init");
            }
        }
    }
}

然后我们回头看 它的 sendMessage() 方法到底干了什么。

frameworks\base\core\java\com\android\internal\util\AsyncChannel.java

public void sendMessage(int what, int arg1, int mListener, Object obj) {
    Message msg = Message.obtain();
    msg.what = what;
    msg.arg1 = arg1;
    // 我们的监听
    msg.mListener= mListener;
    msg.obj = obj;
    sendMessage(msg);
}

继续吧。

/**
 * Send a message to the destination handler.
 *
 * @param msg
 */
public void sendMessage(Message msg) {
    msg.replyTo = mSrcMessenger;
    try {
        mDstMessenger.send(msg);
    } catch (RemoteException e) {
        replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
    }
}

找找这个 mDstMessenger 是从哪儿来的?
connected 方法,是不是很熟悉。刚刚在我们的 init()方法中。

public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
    if (DBG) log("connected srcHandler to the dstMessenger  E");
    // Initialize source fields
    mSrcContext = srcContext;
    mSrcHandler = srcHandler;
    mSrcMessenger = new Messenger(mSrcHandler);
    // Initialize destination fields
    mDstMessenger = dstMessenger;
    if (DBG) log("connected srcHandler to the dstMessenger X");
}
private void init() {
    synchronized (sThreadRefLock) {
        if (++sThreadRefCount == 1) {
   // 最终发现
            Messenger messenger = getWifiServiceMessenger();
再往下看看吧!
public Messenger getWifiServiceMessenger() {
    try {
        return mService.getWifiServiceMessenger();
    } catch (RemoteException e) {
        return null;
    } catch (SecurityException e) {
        return null;
    }
}

追踪 mService.在这儿赋值。

public WifiManager(Context context, IWifiManager service) {
    mContext = context;
    mService = service;
    init();
}

找找 WifiManager 初始化的地方:

frameworks\base\core\java\android\app\ContextImpl.java

Binder 进程间通信,咱就不再深究了。wifi 毕竟最终还是和硬件交互。
registerService(WIFI_SERVICE, new ServiceFetcher() {
        public Object createService(ContextImpl ctx) {
            IBinder b = ServiceManager.getService(WIFI_SERVICE);
            IWifiManager service = IWifiManager.Stub.asInterface(b);
            return new WifiManager(ctx.getOuterContext(), service);
        }});

连接成功,失败都是在回调中处理。其它的好像也没有什么了。

你可能感兴趣的:(android系统开发)