美文网首页
Android之WIFI通信-P2P的discoverPeers

Android之WIFI通信-P2P的discoverPeers

作者: 锄禾豆 | 来源:发表于2022-02-19 21:44 被阅读0次

简单概况启动过程

1.
WifiP2pService --- > WifiP2pServiceImpl

2.WifiP2pServiceImp构造方法
    public WifiP2pServiceImpl(Context context) {
        mContext = context;

        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");

        mP2pSupported = mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_WIFI_DIRECT);

        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());

        mP2pStateMachine = new P2pStateMachine(TAG, wifiP2pThread.getLooper(), mP2pSupported);
        mP2pStateMachine.start();//状态机
    }

前言

7.1 源码
要看懂源码,就需要深入了解状态机(StateMachine)和双Handler通信(AsyncChannel)

案例
WifiP2pManager.discoverPeers
客户端:
1.看discoverPeers代码

    public void discoverPeers(Channel c, ActionListener listener) {
        checkChannel(c);//检测c是否存在,如果不存在,直接抛异常处理。这也说明了,channel首先被初始化的意义
        c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
    }
    
   private static void checkChannel(Channel c) {
        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
    }
    
    看wifi和蓝牙代码,必定涉及StateMachine,同时也会涉及Handler跨进程通信(AsyncChannel)

2.c.mAsyncChannel

mAsyncChannel是Handler跨进程通信的关键类。也就是说,三方应用和WifiP2pService服务进行跨进程通信的实现方式就是采用Handler。了解了这些,则明白为什么要initialize,并且要传入Looper对象

public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener)

3.c.putListener(listener)

这种回调方法的处理方式,确实给人眼前一亮

        private int putListener(Object listener) {//返回值为key
            if (listener == null) return INVALID_LISTENER_KEY;
            int key;
            synchronized (mListenerMapLock) {
                do {
                    key = mListenerKey++;
                } while (key == INVALID_LISTENER_KEY);
                mListenerMap.put(key, listener);//把listener放在map中。
            }
            return key;
        }
        //private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
也就是说,在Handler通信中,把listener转化成arg2发送出去

4.sticky broadcast的使用:
系统发送sticky 广播后,app才注册此广播,是否可以接收到广播?
答案:能。具体原理,我们这里不分析。

    private void sendP2pStateChangedBroadcast(boolean enabled) {
        logd(Debug.getCallers(5));
        final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        if (enabled) {
            intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
                    WifiP2pManager.WIFI_P2P_STATE_ENABLED);
        } else {
            intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
                    WifiP2pManager.WIFI_P2P_STATE_DISABLED);
        }
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }
    
    这也就是为什么,我们注册:WIFI_P2P_THIS_DEVICE_CHANGED_ACTION、WIFI_P2P_DISCOVERY_CHANGED_ACTION、WIFI_P2P_STATE_CHANGED_ACTION、WIFI_P2P_CONNECTION_CHANGED_ACTION,启动app之后,会立马接收到的原因

系统服务
1.WifiP2pServiceImpl

先要回答一个问题:WifiP2pServiceImpl中的状态机,在客户端调用之前,已经处于什么状态?
如果wifi是打开的,则处于InactiveState。
具体原因:
先说思路
1)WifiP2pServiceImpl和WifiStateMachine是有联动的,也是通过handler通信
a.WifiStateMachine中的mWifiP2pChannel为联动的变量
b.WifiStateMachine中的mP2pSupported为关键变量

2)WifiP2pServiceImpl和WifiMonitor是有联动的,在构造方法中
WifiP2pServiceImpl.P2pStateMachine构造方法中使用如下:
    mWifiMonitor.registerHandler(interfaceName,
        WifiMonitor.AP_STA_CONNECTED_EVENT, getHandler());

2.回到状态机

InactiveState没有处理消息DISCOVER_PEERS,传给了父状态P2pEnabledState,关注核心点:
                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();
                    if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {//调用jni。注意:通过WifiMonitor回复WifiMonitor.P2P_DEVICE_FOUND_EVENT
                        replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);//客户端调用的回调回复
                        sendP2pDiscoveryChangedBroadcast(true);//发送广播,开始扫描发现对等设备
                    } else {
                        replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
                                WifiP2pManager.ERROR);
                    }
                    break;


                case WifiMonitor.P2P_DEVICE_FOUND_EVENT://执行jni层,底层给的回复
                    WifiP2pDevice device = (WifiP2pDevice) message.obj;
                    if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
                    mPeers.updateSupplicantDetails(device);
                    sendPeersChangedBroadcast();//发送广播,带有扫描到的设备

总结

1.discoverPeers(Channel c, ActionListener listener)的回调仅仅是判断是否jni执行成功
2.执行成功,涉及需要进一步扫描设备,所以通过广播把数据报告出来,而不是通过回调
总之,回调的是执行状态,结果通过广播通知

案例
connect

android.net.wifi.p2p.PEERS_CHANGED
android.net.wifi.p2p.DISCOVERY_STATE_CHANGE
android.net.wifi.p2p.PEERS_CHANGED
android.net.wifi.p2p.THIS_DEVICE_CHANGED
android.net.wifi.p2p.CONNECTION_STATE_CHANGE
android.net.wifi.p2p.PEERS_CHANGED

额外发现

1.日志格式
        if (DBG) log("halfConnectSync srcHandler to the dstMessenger  E");

        // We are connected
        connected(srcContext, srcHandler, dstMessenger);

        if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
        
        为什么用E X
        想一下execute这个单词
        
2.WifiP2pServiceImp和WifiStateMachine关联?
两者之间也通过双handler通信

05-19 13:12:35.216   414   414 I WifiP2pService: Registering wifip2p
05-19 13:12:35.216   414   486 D WifiP2pService: P2pDisabledState
05-19 13:12:35.243   414   486 D WifiP2pService: P2pDisabledState what 69633
05-19 13:12:35.243   414   486 D WifiP2pService: DefaultState what 69633
05-19 13:12:35.243   414   486 D WifiP2pService: P2pDisabledState what 69632
05-19 13:12:35.243   414   486 D WifiP2pService: DefaultState what 69632
05-19 13:12:35.243   414   486 D WifiP2pService: Full connection with WifiStateMachine established
05-19 13:12:38.160   414   486 D WifiP2pService: P2pDisabledState what 131203 //CMD_ENABLE_P2P
05-19 13:12:38.177   414   486 E WifiP2pService: Unable to change interface settings: java.lang.IllegalStateException: command '25 interface setcfg p2p0 0.0.0.0 0 up' failed with '400 25 Failed to clear address (No such device)'
05-19 13:12:38.177   414   486 D WifiP2pService: P2pEnablingState
05-19 13:12:38.177   414   486 D WifiP2pService: P2pEnablingState what 147457  //SUP_CONNECTION_EVENT
05-19 13:12:38.177   414   486 D WifiP2pService: P2p socket connection successful

问题

1.mWifiP2pManager.listen用来做什么?

2.mWifiP2pManager.createGroup 怎么使用?

3.mWifiP2pManager.setDeviceName  是否可以默认? -- 可以,更改SettingsProvider即可

    private String getPersistedDeviceName() {
        String deviceName = Settings.Global.getString(mContext.getContentResolver(),
                Settings.Global.WIFI_P2P_DEVICE_NAME);
        if (deviceName == null) {
            /* We use the 4 digits of the ANDROID_ID to have a friendly
             * default that has low likelihood of collision with a peer */
            String id = Settings.Secure.getString(mContext.getContentResolver(),
                    Settings.Secure.ANDROID_ID);
            return "Android_" + id.substring(0,4);
        }
        return deviceName;
    }

    private boolean setAndPersistDeviceName(String devName) {
        if (devName == null) return false;

        if (!mWifiNative.setDeviceName(devName)) {
            loge("Failed to set device name " + devName);
            return false;
        }

        mThisDevice.deviceName = devName;
        mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);

        Settings.Global.putString(mContext.getContentResolver(),
                Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
        sendThisDeviceChangedBroadcast();
        return true;
    }
    
    第一次初始化
    private void initializeP2pSettings() {
        mWifiNative.setPersistentReconnect(true);
        mThisDevice.deviceName = getPersistedDeviceName();//初始化
        mWifiNative.setDeviceName(mThisDevice.deviceName);//设置1
        // DIRECT-XY-DEVICENAME (XY is randomly generated)
        mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);//设置2
        mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
        // Supplicant defaults to using virtual display with display
        // which refers to a remote display. Use physical_display
        mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
        // STA has higher priority over P2P
        mWifiNative.setConcurrencyPriority("sta");

        mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
        updateThisDevice(WifiP2pDevice.AVAILABLE);//广播更新状态
        if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);

        mClientInfoList.clear();
        mWifiNative.p2pFlush();
        mWifiNative.p2pServiceFlush();
        mServiceTransactionId = 0;
        mServiceDiscReqId = null;

        updatePersistentNetworks(RELOAD);
    }

相关文章

网友评论

      本文标题:Android之WIFI通信-P2P的discoverPeers

      本文链接:https://www.haomeiwen.com/subject/yzwqkrtx.html