本文为《深入理解Android Wi-Fi、NFC和GPS卷》读书笔记,Android源码为Android 5.1
主要特点就是无底线的粘贴源码
android-5.1/frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pService.java
public WifiP2pService(Context context) {
super(context);
mImpl = new WifiP2pServiceImpl(context);
}
android-5.1/frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
public WifiP2pServiceImpl(Context context) {
mContext = context;
//STOPSHIP: get this from native side
mInterface = "p2p0";//P2P使用的虚拟网络接口设备名为p2p0
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
//判断系统是否支持WiFi-Direct功能
mP2pSupported = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_DIRECT);
//获取PrimaryDeviceType,默认值是 10-0050F204-5
//10是Category ID,代表Telephone
//0050F204是WFA的OUI,最后一个5是Sub Category ID,在Telephone大类里边,它代表支持Dual Mode的Smartphone(规范中定义为Smart phone-Dual mode)
mThisDevice.primaryDeviceType = mContext.getResources().getString(
com.android.internal.R.string.config_wifi_p2p_device_type);
HandlerThread wifiP2pThread = new HandlerThread("WifiP2pService");
wifiP2pThread.start();
mClientHandler = new ClientHandler(wifiP2pThread.getLooper());
//WifiP2pService主要工作也是由状态机来完成的,即下面的这个P2pStateMachine
mP2pStateMachine = new P2pStateMachine(TAG, wifiP2pThread.getLooper(), mP2pSupported);
mP2pStateMachine.start();
}
P2pStateMachine 是 WifiP2pServiceImpl 定义的内部类,构造函数如下:
P2pStateMachine(String name, Looper looper, boolean p2pSupported) {
super(name, looper);
addState(mDefaultState);//为状态机添加状态,一共15个状态
addState(mP2pNotSupportedState, mDefaultState);
addState(mP2pDisablingState, mDefaultState);
addState(mP2pDisabledState, mDefaultState);
addState(mP2pEnablingState, mDefaultState);
addState(mP2pEnabledState, mDefaultState);
addState(mInactiveState, mP2pEnabledState);
addState(mGroupCreatingState, mP2pEnabledState);
addState(mUserAuthorizingInviteRequestState, mGroupCreatingState);
addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState);
addState(mProvisionDiscoveryState, mGroupCreatingState);
addState(mGroupNegotiationState, mGroupCreatingState);
addState(mFrequencyConflictState, mGroupCreatingState);
addState(mGroupCreatedState, mP2pEnabledState);
addState(mUserAuthorizingJoinState, mGroupCreatedState);
addState(mOngoingGroupRemovalState, mGroupCreatedState);
if (p2pSupported) {
setInitialState(mP2pDisabledState);//初始状态为P2pDisableState
} else {
setInitialState(mP2pNotSupportedState);
}
setLogRecSize(50);
setLogOnlyTransitions(true);
}
在Android平台中,如果用户打开Wi-Fi功能,P2pStateMachine就会收到第一个消息 CMD_ENABLE_P2P。该消息是WiFiStateMachine进入DriverStartedState 后, 在其EA中借助 mWifiP2pChannel向P2pStateMachine发送的。
class P2pDisabledState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiStateMachine.CMD_ENABLE_P2P:
try {
mNwService.setInterfaceUp(mInterface);
} catch (RemoteException re) {
loge("Unable to change interface settings: " + re);
} catch (IllegalStateException ie) {
loge("Unable to change interface settings: " + ie);
}
//启动WifiMonitor,它将通过wpa_ctl连接上wpa_supplicant
mWifiMonitor.startMonitoring();
//转入P2pEnablingState,其EA未做有益于的事情
transitionTo(mP2pEnablingState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
处理完 CMD_ENABLE_P2P消息后,P2pStateMachine将创建一个WiFiMonitor用于接收来自 wpa_supplicant 的消息,同时状态机转入P2pEnablingState。
class P2pEnablingState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiMonitor.SUP_CONNECTION_EVENT:
if (DBG) logd("P2p socket connection successful");
transitionTo(mInactiveState);//转入InactiveState
break;
case WifiMonitor.SUP_DISCONNECTION_EVENT:
loge("P2p socket connection failed");
transitionTo(mP2pDisabledState);
break;
case WifiStateMachine.CMD_ENABLE_P2P:
case WifiStateMachine.CMD_DISABLE_P2P_REQ:
deferMessage(message);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
当状态机转入InactiveState后,首先执行的是其负状态 P2pEnabledState 的EA,然后才是InactiveState自己的EA。由于 InactiveState的EA仅打印了一句日志输出,故此处仅介绍 P2pEnabledState 的EA:
class P2pEnabledState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
//发送WIFI_P2P_STATE_CHANGED_ACTION广播并设置 EXTRA_WIFI_STATE 状态为 WIFI_P2P_STATE_ENABLED
sendP2pStateChangedBroadcast(true);
mNetworkInfo.setIsAvailable(true);
//发送WIFI_P2P_CONNECTION_CHANGED_ACTION广播,它将携带WifiP2pInfo和NetworkInfo消息。
//注意,下面这个函数还会向WiFiStateMachine发送P2P_CONNECTION_CHANGED消息。
sendP2pConnectionChangedBroadcast();
initializeP2pSettings();//初始化P2P的一些设置
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiMonitor.SUP_DISCONNECTION_EVENT:
loge("Unexpected loss of p2p socket connection");
transitionTo(mP2pDisabledState);
break;
case WifiStateMachine.CMD_ENABLE_P2P:
//Nothing to do
break;
case WifiStateMachine.CMD_DISABLE_P2P_REQ:
if (mPeers.clear()) {
sendPeersChangedBroadcast();
}
if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
mWifiMonitor.stopMonitoring();
transitionTo(mP2pDisablingState);
break;
case WifiP2pManager.SET_DEVICE_NAME:
{
WifiP2pDevice d = (WifiP2pDevice) message.obj;
if (d != null && setAndPersistDeviceName(d.deviceName)) {
if (DBG) logd("set device name " + d.deviceName);
replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
WifiP2pManager.ERROR);
}
break;
}
case WifiP2pManager.SET_WFD_INFO:
{
WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
if (d != null && setWfdInfo(d)) {
replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
WifiP2pManager.ERROR);
}
break;
}
case BLOCK_DISCOVERY:
boolean blocked = (message.arg1 == ENABLED ? true : false);
if (mDiscoveryBlocked == blocked) break;
mDiscoveryBlocked = blocked;
if (blocked && mDiscoveryStarted) {
mWifiNative.p2pStopFind();
mDiscoveryPostponed = true;
}
if (!blocked && mDiscoveryPostponed) {
mDiscoveryPostponed = false;
mWifiNative.p2pFind(DISCOVER_TIMEOUT_S);
}
if (blocked) {
try {
StateMachine m = (StateMachine)message.obj;
m.sendMessage(message.arg2);
} catch (Exception e) {
loge("unable to send BLOCK_DISCOVERY response: " + e);
}
}
break;
case WifiP2pManager.DISCOVER_PEERS:
if (mDiscoveryBlocked) {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.BUSY);
break;
}
// do not send service discovery request while normal find operation.
clearSupplicantServiceRequest();//先取消Service Discovery请求
//发送P2P_FIND 超时时间给WPAS, DISCOVER_TIMEOUT_S 值为120秒
if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
发送 WIFI_P2P_DISCOVERY_CHANGED_ACTION广播以通知P2P Device Discovery已启动
sendP2pDiscoveryChangedBroadcast(true);
} else {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.ERROR);
}
break;
case WifiMonitor.P2P_FIND_STOPPED_EVENT:
sendP2pDiscoveryChangedBroadcast(false);
break;
case WifiP2pManager.STOP_DISCOVERY:
if (mWifiNative.p2pStopFind()) {
replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
WifiP2pManager.ERROR);
}
break;
case WifiP2pManager.DISCOVER_SERVICES:
if (mDiscoveryBlocked) {
replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
WifiP2pManager.BUSY);
break;
}
if (DBG) logd(getName() + " discover services");
if (!updateSupplicantServiceRequest()) {
replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
WifiP2pManager.NO_SERVICE_REQUESTS);
break;
}
if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
WifiP2pManager.ERROR);
}
break;
case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
//WifiMonitor根据WPAS反馈的信息构建一个WifiP2pDevice对象
WifiP2pDevice device = (WifiP2pDevice) message.obj;
//如果搜索到的这个P2P Device是自己(根据Device Address来判断),则不处理它
if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
//mPeers执行一个WifiP2pDeviceList对象。如果之前已存储了此Device的信息,更新这些信息,否则将添加一个新的WifiP2pDevice对象
mPeers.updateSupplicantDetails(device);
sendPeersChangedBroadcast();//发送 WIFI_P2P_PEERS_CHANGED_ACTION 广播
break;
case WifiMonitor.P2P_DEVICE_LOST_EVENT:
device = (WifiP2pDevice) message.obj;
// Gets current details for the one removed
device = mPeers.remove(device.deviceAddress);
if (device != null) {
sendPeersChangedBroadcast();
}
break;
case WifiP2pManager.ADD_LOCAL_SERVICE:
if (DBG) logd(getName() + " add service");
WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
if (addLocalService(message.replyTo, servInfo)) {
replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED);
}
break;
case WifiP2pManager.REMOVE_LOCAL_SERVICE:
if (DBG) logd(getName() + " remove service");
servInfo = (WifiP2pServiceInfo)message.obj;
removeLocalService(message.replyTo, servInfo);
replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED);
break;
case WifiP2pManager.CLEAR_LOCAL_SERVICES:
if (DBG) logd(getName() + " clear service");
clearLocalServices(message.replyTo);
replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED);
break;
case WifiP2pManager.ADD_SERVICE_REQUEST:
if (DBG) logd(getName() + " add service request");
if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) {
replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED);
break;
}
replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED);
break;
case WifiP2pManager.REMOVE_SERVICE_REQUEST:
if (DBG) logd(getName() + " remove service request");
removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj);
replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED);
break;
case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
if (DBG) logd(getName() + " clear service request");
clearServiceRequests(message.replyTo);
replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
break;
case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
if (DBG) logd(getName() + " receive service response");
List sdRespList =
(List) message.obj;
for (WifiP2pServiceResponse resp : sdRespList) {
WifiP2pDevice dev =
mPeers.get(resp.getSrcDevice().deviceAddress);
resp.setSrcDevice(dev);
sendServiceResponse(resp);
}
break;
case WifiP2pManager.DELETE_PERSISTENT_GROUP:
if (DBG) logd(getName() + " delete persistent group");
mGroups.remove(message.arg1);
replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
break;
case SET_MIRACAST_MODE:
mWifiNative.setMiracastMode(message.arg1);
break;
case WifiP2pManager.START_LISTEN:
if (DBG) logd(getName() + " start listen mode");
mWifiNative.p2pFlush();
if (mWifiNative.p2pExtListen(true, 500, 500)) {
replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
}
break;
case WifiP2pManager.STOP_LISTEN:
if (DBG) logd(getName() + " stop listen mode");
if (mWifiNative.p2pExtListen(false, 0, 0)) {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
}
mWifiNative.p2pFlush();
break;
case WifiP2pManager.SET_CHANNEL:
Bundle p2pChannels = (Bundle) message.obj;
int lc = p2pChannels.getInt("lc", 0);
int oc = p2pChannels.getInt("oc", 0);
if (DBG) logd(getName() + " set listen and operating channel");
if (mWifiNative.p2pSetChannel(lc, oc)) {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
}
break;
case SET_COUNTRY_CODE:
String countryCode = (String) message.obj;
countryCode = countryCode.toUpperCase(Locale.ROOT);
if (mLastSetCountryCode == null ||
countryCode.equals(mLastSetCountryCode) == false) {
if (mWifiNative.setCountryCode(countryCode)) {
mLastSetCountryCode = countryCode;
}
}
break;
case WifiP2pManager.GET_HANDOVER_REQUEST:
Bundle requestBundle = new Bundle();
requestBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE,
mWifiNative.getNfcHandoverRequest());
replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE,
requestBundle);
break;
case WifiP2pManager.GET_HANDOVER_SELECT:
Bundle selectBundle = new Bundle();
selectBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE,
mWifiNative.getNfcHandoverSelect());
replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE,
selectBundle);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
@Override
public void exit() {
sendP2pDiscoveryChangedBroadcast(false);
sendP2pStateChangedBroadcast(false);
mNetworkInfo.setIsAvailable(false);
mLastSetCountryCode = null;
}
}
private void initializeP2pSettings() {
//发送SET persistent_reconnect 1给WPAS,该命令对应如下一种应用场景
//当发现一个Persistent Group时,如果 persistent_reconnect 为1,则可利用之前保存的配置信息自动重连,重新连接时无需用户参与。如果 persistent_reconnect 为0,则需要提醒用户,让用户来决定是否加入此persistent group。
mWifiNative.setPersistentReconnect(true);
//获取P2P设备名称,先从数据库中查询 wifi_p2p_device_name 字段的值,如果数据库中没有设置该字段,则取数据库中 android_id 字段值的前4个字符并在其前面加上 Android_ 字符串以组成P2P设备名。以Galaxy Note 2为例,数据库文件是 /data/data/com.android.providers.settings/database/settings.db,所查询的表名为secure, wifi_p2p_device_name字段取值为 Android_4aa9, android_id 字段取值为 4aa9213016889423
mThisDevice.deviceName = getPersistedDeviceName();//mThisDevice指向一个WifiP2pDevice对象
//将P2P设备名保存到WPAS中
mWifiNative.setDeviceName(mThisDevice.deviceName);
//设置P2P网络SSID的后缀。如果本设备能扮演GO,则它创建的Group对应的SSID后缀就是此处设置的后缀名
mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
//设置Primary DeviceType
mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
// Supplicant defaults to using virtual display with display
// which refers to a remote display. Use physical_display
//设置支持的WSC设置方法
mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
// STA has higher priority over P2P
//设置STA连接的优先级高于P2P连接
mWifiNative.setConcurrencyPriority("sta");
//从WPAS获取P2P Device Address
mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
//更新自己的状态,并发送 WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 消息
updateThisDevice(WifiP2pDevice.AVAILABLE);
if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);
mClientInfoList.clear();
//清空WPAS中保存peer P2P Device和Service信息
mWifiNative.p2pFlush();
mWifiNative.p2pServiceFlush();
mServiceTransactionId = 0;
mServiceDiscReqId = null;
String countryCode = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.WIFI_COUNTRY_CODE);
if (countryCode != null && !countryCode.isEmpty()) {
mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode);
}
//WPAS会保存 persistent Group 消息,而 P2pStateMachine 也会保存一些信息,下面这个函数将根据WPAS中的信息来更新P2pStateMachine 中保存的 Group 信息。 P2pStateMachine 通过一个名为 mGroups的成员变量(类型为WifiP2PGroupList)来保存所有的Group信息
updatePersistentNetworks(RELOAD);
}
至此P2pStateMachine就算初始化完毕,接下来的工作就是处理用户发起的操作。
class InactiveState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
mSavedPeerConfig.invalidate();
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiP2pManager.CONNECT:
if (DBG) logd(getName() + " sending connect");
//WifiP2pSettings将设置一个WifiP2pConfig对象以告诉 P2pStateMachine该连接哪一个 P2P Device
WifiP2pConfig config = (WifiP2pConfig) message.obj;
if (isConfigInvalid(config)) {
loge("Dropping connect requeset " + config);
replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
break;
}
mAutonomousGroup = false;
mWifiNative.p2pStopFind();
if (reinvokePersistentGroup(config)) {
transitionTo(mGroupNegotiationState);
} else {
transitionTo(mProvisionDiscoveryState);
}
mSavedPeerConfig = config;
mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
sendPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
break;
case WifiP2pManager.STOP_DISCOVERY:
if (mWifiNative.p2pStopFind()) {
// When discovery stops in inactive state, flush to clear
// state peer data
mWifiNative.p2pFlush();
mServiceDiscReqId = null;
replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
WifiP2pManager.ERROR);
}
break;
case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
config = (WifiP2pConfig) message.obj;
if (isConfigInvalid(config)) {
loge("Dropping GO neg request " + config);
break;
}
mSavedPeerConfig = config;
mAutonomousGroup = false;
mJoinExistingGroup = false;
transitionTo(mUserAuthorizingNegotiationRequestState);
break;
case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
WifiP2pGroup group = (WifiP2pGroup) message.obj;
WifiP2pDevice owner = group.getOwner();
if (owner == null) {
loge("Ignored invitation from null owner");
break;
}
config = new WifiP2pConfig();
config.deviceAddress = group.getOwner().deviceAddress;
if (isConfigInvalid(config)) {
loge("Dropping invitation request " + config);
break;
}
mSavedPeerConfig = config;
//Check if we have the owner in peer list and use appropriate
//wps method. Default is to use PBC.
if ((owner = mPeers.get(owner.deviceAddress)) != null) {
if (owner.wpsPbcSupported()) {
mSavedPeerConfig.wps.setup = WpsInfo.PBC;
} else if (owner.wpsKeypadSupported()) {
mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
} else if (owner.wpsDisplaySupported()) {
mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
}
}
mAutonomousGroup = false;
mJoinExistingGroup = true;
transitionTo(mUserAuthorizingInviteRequestState);
break;
case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
//We let the supplicant handle the provision discovery response
//and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
//Handling provision discovery and issuing a p2p_connect before
//group negotiation comes through causes issues
break;
case WifiP2pManager.CREATE_GROUP:
mAutonomousGroup = true;
int netId = message.arg1;
boolean ret = false;
if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
// check if the go persistent group is present.
netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
if (netId != -1) {
ret = mWifiNative.p2pGroupAdd(netId);
} else {
ret = mWifiNative.p2pGroupAdd(true);
}
} else {
ret = mWifiNative.p2pGroupAdd(false);
}
if (ret) {
replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
transitionTo(mGroupNegotiationState);
} else {
replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
WifiP2pManager.ERROR);
// remain at this state.
}
break;
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
if (DBG) logd(getName() + " group started");
// We hit this scenario when a persistent group is reinvoked
if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
mAutonomousGroup = false;
deferMessage(message);
transitionTo(mGroupNegotiationState);//转入GroupCreatedState
} else {
loge("Unexpected group creation, remove " + mGroup);
mWifiNative.p2pGroupRemove(mGroup.getInterface());
}
break;
case WifiP2pManager.START_LISTEN:
if (DBG) logd(getName() + " start listen mode");
mWifiNative.p2pFlush();
if (mWifiNative.p2pExtListen(true, 500, 500)) {
replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
}
break;
case WifiP2pManager.STOP_LISTEN:
if (DBG) logd(getName() + " stop listen mode");
if (mWifiNative.p2pExtListen(false, 0, 0)) {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
}
mWifiNative.p2pFlush();
break;
case WifiP2pManager.SET_CHANNEL:
Bundle p2pChannels = (Bundle) message.obj;
int lc = p2pChannels.getInt("lc", 0);
int oc = p2pChannels.getInt("oc", 0);
if (DBG) logd(getName() + " set listen and operating channel");
if (mWifiNative.p2pSetChannel(lc, oc)) {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
}
break;
case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER:
String handoverSelect = null;
if (message.obj != null) {
handoverSelect = ((Bundle) message.obj)
.getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
}
if (handoverSelect != null
&& mWifiNative.initiatorReportNfcHandover(handoverSelect)) {
replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
transitionTo(mGroupCreatingState);
} else {
replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
}
break;
case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER:
String handoverRequest = null;
if (message.obj != null) {
handoverRequest = ((Bundle) message.obj)
.getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
}
if (handoverRequest != null
&& mWifiNative.responderReportNfcHandover(handoverRequest)) {
replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
transitionTo(mGroupCreatingState);
} else {
replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
}
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
class ProvisionDiscoveryState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
//触发本机设备向对端设备发送 Provision Discovery Request帧
mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
WifiP2pProvDiscEvent provDisc;
WifiP2pDevice device;
switch (message.what) {
case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
provDisc = (WifiP2pProvDiscEvent) message.obj;
device = provDisc.device;
if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
if (DBG) logd("Found a match " + mSavedPeerConfig);
//下面这个函数将调用WifiNative的P2pConnect函数,此函数将触发WPAS发送GON Request帧。接收端设备收到该帧后,将弹出提示框以提醒用户
p2pConnectWithPinDisplay(mSavedPeerConfig);
//转入GroupNegotiationState
transitionTo(mGroupNegotiationState);
}
break;
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
provDisc = (WifiP2pProvDiscEvent) message.obj;
device = provDisc.device;
if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) {
if (DBG) logd("Found a match " + mSavedPeerConfig);
/* we already have the pin */
if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) {
p2pConnectWithPinDisplay(mSavedPeerConfig);
transitionTo(mGroupNegotiationState);
} else {
mJoinExistingGroup = false;
transitionTo(mUserAuthorizingNegotiationRequestState);
}
}
break;
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
provDisc = (WifiP2pProvDiscEvent) message.obj;
device = provDisc.device;
if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) {
if (DBG) logd("Found a match " + mSavedPeerConfig);
mSavedPeerConfig.wps.pin = provDisc.pin;
p2pConnectWithPinDisplay(mSavedPeerConfig);
notifyInvitationSent(provDisc.pin, device.deviceAddress);
transitionTo(mGroupNegotiationState);
}
break;
case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
loge("provision discovery failed");
handleGroupCreationFailure();
transitionTo(mInactiveState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
注意,由于WSC配置方法为PBC,所以对端设备的P2pStateMachine将收到一个P2P_PROV_DISC_PBC_REQ_EVENT 消息。当对端设备处理完毕后,将收到一个 P2P_PROV_DISC_PBC_RSP_EVENT消息。马上来看 P2P_PROV_DISC_PBC_RSP_EVENT 消息的处理流程,见上面代码中的"case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:"
class GroupCreatedState extends State {
@Override
public void enter() {
if (DBG) logd(getName());
// Once connected, peer config details are invalid
mSavedPeerConfig.invalidate();
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
updateThisDevice(WifiP2pDevice.CONNECTED);//连接成功
//DHCP server has already been started if I am a group owner
if (mGroup.isGroupOwner()) {
//SERVER_ADDRESS为192.168.49.1,该地址也被设置到Dhcp Server中
//另外,P2pStateMachine由一个名为mWifiP2pInfo的成员变量,其类型为 WifiP2pInfo,
//下面这个函数也将GO的IP地址保存到mWifiP2pInfo中
setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
}
// In case of a negotiation group, connection changed is sent
// after a client joins. For autonomous, send now
if (mAutonomousGroup) {
sendP2pConnectionChangedBroadcast();
}
}
@Override
public boolean processMessage(Message message) {
if (DBG) logd(getName() + message.toString());
switch (message.what) {
case WifiMonitor.AP_STA_CONNECTED_EVENT://该消息表示一个P2P Client关联上本机GO
WifiP2pDevice device = (WifiP2pDevice) message.obj;
String deviceAddress = device.deviceAddress;
// Clear timeout that was set when group was started.
mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
if (deviceAddress != null) {
if (mPeers.get(deviceAddress) != null) {
mGroup.addClient(mPeers.get(deviceAddress));//添加一个P2P Client
} else {
mGroup.addClient(deviceAddress);
}
mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
if (DBG) logd(getName() + " ap sta connected");
sendPeersChangedBroadcast();
} else {
loge("Connect on null device address, ignore");
}
sendP2pConnectionChangedBroadcast();
break;
case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
device = (WifiP2pDevice) message.obj;
deviceAddress = device.deviceAddress;
if (deviceAddress != null) {
mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
if (mGroup.removeClient(deviceAddress)) {
if (DBG) logd("Removed client " + deviceAddress);
if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
logd("Client list empty, remove non-persistent p2p group");
mWifiNative.p2pGroupRemove(mGroup.getInterface());
// We end up sending connection changed broadcast
// when this happens at exit()
} else {
// Notify when a client disconnects from group
sendP2pConnectionChangedBroadcast();
}
} else {
if (DBG) logd("Failed to remove client " + deviceAddress);
for (WifiP2pDevice c : mGroup.getClientList()) {
if (DBG) logd("client " + c.deviceAddress);
}
}
sendPeersChangedBroadcast();
if (DBG) logd(getName() + " ap sta disconnected");
} else {
loge("Disconnect on unknown device: " + device);
}
break;
case DhcpStateMachine.CMD_POST_DHCP_ACTION:
DhcpResults dhcpResults = (DhcpResults) message.obj;
if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&
dhcpResults != null) {
if (DBG) logd("DhcpResults: " + dhcpResults);
setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress);
sendP2pConnectionChangedBroadcast();
//Turn on power save on client
mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
try {
String iface = mGroup.getInterface();
mNwService.addInterfaceToLocalNetwork(iface,
dhcpResults.getRoutes(iface));
} catch (RemoteException e) {
loge("Failed to add iface to local network " + e);
}
} else {
loge("DHCP failed");
mWifiNative.p2pGroupRemove(mGroup.getInterface());
}
break;
case WifiP2pManager.REMOVE_GROUP:
if (DBG) logd(getName() + " remove group");
if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
transitionTo(mOngoingGroupRemovalState);
replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
} else {
handleGroupRemoved();
transitionTo(mInactiveState);
replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
WifiP2pManager.ERROR);
}
break;
/* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
* handling since supplicant actually tries to reconnect after a temporary
* disconnect until group idle time out. Eventually, a group removal event
* will come when group has been removed.
*
* When there are connectivity issues during temporary disconnect, the application
* will also just remove the group.
*
* Treating network disconnection as group removal causes race conditions since
* supplicant would still maintain the group at that stage.
*/
case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
if (DBG) logd(getName() + " group removed");
handleGroupRemoved();
transitionTo(mInactiveState);
break;
case WifiMonitor.P2P_DEVICE_LOST_EVENT:
device = (WifiP2pDevice) message.obj;
//Device loss for a connected device indicates it is not in discovery any more
if (mGroup.contains(device)) {
if (DBG) logd("Add device to lost list " + device);
mPeersLostDuringConnection.updateSupplicantDetails(device);
return HANDLED;
}
// Do the regular device lost handling
return NOT_HANDLED;
case WifiStateMachine.CMD_DISABLE_P2P_REQ:
sendMessage(WifiP2pManager.REMOVE_GROUP);
deferMessage(message);
break;
// This allows any client to join the GO during the
// WPS window
case WifiP2pManager.START_WPS:
WpsInfo wps = (WpsInfo) message.obj;
if (wps == null) {
replyToMessage(message, WifiP2pManager.START_WPS_FAILED);
break;
}
boolean ret = true;
if (wps.setup == WpsInfo.PBC) {
ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null);
} else {
if (wps.pin == null) {
String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
try {
Integer.parseInt(pin);
notifyInvitationSent(pin, "any");
} catch (NumberFormatException ignore) {
ret = false;
}
} else {
ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
wps.pin);
}
}
replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED :
WifiP2pManager.START_WPS_FAILED);
break;
case WifiP2pManager.CONNECT:
WifiP2pConfig config = (WifiP2pConfig) message.obj;
if (isConfigInvalid(config)) {
loge("Dropping connect requeset " + config);
replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
break;
}
logd("Inviting device : " + config.deviceAddress);
mSavedPeerConfig = config;
if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
sendPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
} else {
replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
WifiP2pManager.ERROR);
}
// TODO: figure out updating the status to declined when invitation is rejected
break;
case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
P2pStatus status = (P2pStatus)message.obj;
if (status == P2pStatus.SUCCESS) {
// invocation was succeeded.
break;
}
loge("Invitation result " + status);
if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
// target device has already removed the credential.
// So, remove this credential accordingly.
int netId = mGroup.getNetworkId();
if (netId >= 0) {
if (DBG) logd("Remove unknown client from the list");
if (!removeClientFromList(netId,
mSavedPeerConfig.deviceAddress, false)) {
// not found the client on the list
loge("Already removed the client, ignore");
break;
}
// try invitation.
sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
}
}
break;
case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
mSavedPeerConfig = new WifiP2pConfig();
mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
} else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
mSavedPeerConfig.wps.pin = provDisc.pin;
} else {
mSavedPeerConfig.wps.setup = WpsInfo.PBC;
}
transitionTo(mUserAuthorizingJoinState);
break;
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
loge("Duplicate group creation event notice, ignore");
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
public void exit() {
updateThisDevice(WifiP2pDevice.AVAILABLE);
resetWifiP2pInfo();
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
sendP2pConnectionChangedBroadcast();
}
}
当对端P2P设备成功关联到本机后,WifiMonitor又将发送一个名为 AP_STA_CONNECTED_EVENT 的消息,见代码"case WifiMonitor.AP_STA_CONNECTED_EVENT:"