(两百零一) 探讨p2p0的粘性

前言:在平常工作中,注意到关闭热点后,p2p0就自己起来了,而这是自己又没操作p2p相关的应用,这是为什么呢?

 

1.p2p0自启动流程

        // Check & re-enable P2P if needed.
        // P2P interface will be created if all of the below are true:
        // a) Wifi is enabled.
        // b) HAL (HIDL) interface is available.
        // c) There is atleast 1 client app which invoked initialize().
        private void checkAndReEnableP2p() {
            boolean isHalInterfaceAvailable = isHalInterfaceAvailable();
            Log.d(TAG, "Wifi enabled=" + mIsWifiEnabled + ", P2P Interface availability="
                    + isHalInterfaceAvailable + ", Number of clients="
                    + mDeathDataByBinder.size());
            if (mIsWifiEnabled && isHalInterfaceAvailable
                    && !mDeathDataByBinder.isEmpty()) {
                sendMessage(ENABLE_P2P);
            }
        }

WifiP2pServiceImpl中有个关键的方法叫做checkAndReEnableP2p,这个方法会在满足如下3个条件的时候将p2p创建出来

  • WiFi已打开
  • hal 接口是可获取的(即p2p0是可创建的)
  • 至少有一个app客户端调用了initialize,即有p2p请求

checkAndReEnableP2p在什么时候会被调用呢?

1)WiFi开启的时候

                // Register for wifi on/off broadcasts
                mContext.registerReceiver(new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        int wifistate = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                                WifiManager.WIFI_STATE_UNKNOWN);
                        if (wifistate == WifiManager.WIFI_STATE_ENABLED) {
                            mIsWifiEnabled = true;
                            checkAndReEnableP2p();
                        } else {
                            mIsWifiEnabled = false;
                            // Teardown P2P if it's up already.
                            sendMessage(DISABLE_P2P);
                        }
                        checkAndSendP2pStateChangedBroadcast();
                    }
                }, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));

2)p2p接口可创建的时候

                // Register for interface availability from HalDeviceManager
                mWifiNative.registerInterfaceAvailableListener((boolean isAvailable) -> {
                    mIsHalInterfaceAvailable = isAvailable;
                    if (isAvailable) {
                        checkAndReEnableP2p();
                    }
                    checkAndSendP2pStateChangedBroadcast();
                }, getHandler());

PS: android 在Q上修改了当gps为关的时候,WiFi直连开关为灰显状态,原因这边看到了:当gps关闭的时候,p2p会停止扫描

                // Register for location mode on/off broadcasts
                mContext.registerReceiver(new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        /* if location mode is off, ongoing discovery should be stopped.
                         * possible ongoing discovery:
                         * - peer discovery
                         * - service discovery
                         * - group joining scan in native service
                         */
                        if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
                            sendMessage(WifiP2pManager.STOP_DISCOVERY);
                        }
                    }
                }, new IntentFilter(LocationManager.MODE_CHANGED_ACTION));

 

2.何为p2p0可创建?

我们可以顺着下面的这个方法往下看

                // Register for interface availability from HalDeviceManager
                mWifiNative.registerInterfaceAvailableListener((boolean isAvailable) -> {
                    mIsHalInterfaceAvailable = isAvailable;
                    if (isAvailable) {
                        checkAndReEnableP2p();
                    }
                    checkAndSendP2pStateChangedBroadcast();
                }, getHandler());

这边通过WifiP2pNative创建了一个回调,当接口可获取性有变化的时候会通知到WifiP2pServiceImpl,然后由WifiP2pServiceImpl决定是否重新创建p2p,另外会发送一个p2p状态改变的广播出来。

        private void checkAndSendP2pStateChangedBroadcast() {
            boolean isHalInterfaceAvailable = isHalInterfaceAvailable();
            Log.d(TAG, "Wifi enabled=" + mIsWifiEnabled + ", P2P Interface availability="
                    + isHalInterfaceAvailable);
            sendP2pStateChangedBroadcast(mIsWifiEnabled && isHalInterfaceAvailable);
        }

        private void sendP2pStateChangedBroadcast(boolean enabled) {
            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);
        }

 

2.1 WifiP2pNative

    /**
     * Register for an interface available callbacks from HalDeviceManager.
     *
     * @param listener callback to be invoked when the interface is available/not available.
     */
    public void registerInterfaceAvailableListener(
            @NonNull HalDeviceManager.InterfaceAvailableForRequestListener listener,
            Handler handler) {
        mInterfaceAvailableListener = new InterfaceAvailableListenerInternal(listener);
        // The interface available callbacks are cleared on every HAL stop, so need to
        // re-register these callbacks on every start.
        mHalDeviceManager.registerStatusListener(() -> {
            if (mHalDeviceManager.isStarted()) {
                Log.i(TAG, "Registering for interface available listener");
                mHalDeviceManager.registerInterfaceAvailableForRequestListener(
                        IfaceType.P2P, mInterfaceAvailableListener, handler);
            }
        }, handler);
        if (mHalDeviceManager.isStarted()) {
            mHalDeviceManager.registerInterfaceAvailableForRequestListener(
                    IfaceType.P2P, mInterfaceAvailableListener, handler);
        }
    }

这边把监听器包装了下

    // Internal callback registered to HalDeviceManager.
    private class InterfaceAvailableListenerInternal implements
            HalDeviceManager.InterfaceAvailableForRequestListener {
        private final HalDeviceManager.InterfaceAvailableForRequestListener mExternalListener;

        InterfaceAvailableListenerInternal(
                HalDeviceManager.InterfaceAvailableForRequestListener externalListener) {
            mExternalListener = externalListener;
        }

        @Override
        public void onAvailabilityChanged(boolean isAvailable) {
            Log.d(TAG, "P2P InterfaceAvailableListener " + isAvailable);
            // We need another level of abstraction here. When a P2P interface is created,
            // we should mask the availability change callback from WifiP2pService.
            // This is because when the P2P interface is created, we'll get a callback
            // indicating that we can no longer create a new P2P interface. We don't need to
            // propagate this internal state to WifiP2pServiceImpl.
            if (mIWifiP2pIface != null && !isAvailable) {
                Log.i(TAG, "Masking interface non-availability callback because "
                        + "we created a P2P iface");
                return;
            }
            mExternalListener.onAvailabilityChanged(isAvailable);
        }
    }

主要是为了当主动创建p2p的时候,回调不要往上报

 

2.2 HalDeviceManager

    /**
     * Register a listener to be called when an interface of the specified type could be requested.
     * No guarantees are provided (some other entity could request it first). The listener is
     * active from registration until unregistration - using
     * unregisterInterfaceAvailableForRequestListener().
     *
     * Only a single instance of a listener will be registered (even if the specified looper is
     * different).
     *
     * Note that if it is possible to create the specified interface type at registration time
     * then the callback will be triggered immediately.
     *
     * @param ifaceType The interface type (IfaceType) to be monitored.
     * @param listener Listener to call when an interface of the requested
     *                 type could be created
     * @param handler Handler on which to dispatch listener. Null implies the listener will be
     *                invoked synchronously from the context of the client which triggered the
     *                mode change.
     */
    public void registerInterfaceAvailableForRequestListener(int ifaceType,
            @NonNull InterfaceAvailableForRequestListener listener, @Nullable Handler handler) {
        if (VDBG) {
            Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType
                    + ", listener=" + listener + ", handler=" + handler);
        }

        synchronized (mLock) {
            InterfaceAvailableForRequestListenerProxy proxy =
                    new InterfaceAvailableForRequestListenerProxy(listener, handler);
            if (mInterfaceAvailableForRequestListeners.get(ifaceType).containsKey(proxy)) {
                if (VDBG) {
                    Log.d(TAG,
                            "registerInterfaceAvailableForRequestListener: dup listener skipped: "
                                    + listener);
                }
                return;
            }
            mInterfaceAvailableForRequestListeners.get(ifaceType).put(proxy, null);
        }

        WifiChipInfo[] chipInfos = getAllChipInfo();
        if (chipInfos == null) {
            Log.e(TAG,
                    "registerInterfaceAvailableForRequestListener: no chip info found - but "
                            + "possibly registered pre-started - ignoring");
            return;
        }
        dispatchAvailableForRequestListenersForType(ifaceType, chipInfos);
    }

这边又包了一层代理,然后放到特定的SparseArray里去

    private class InterfaceAvailableForRequestListenerProxy extends
            ListenerProxy<InterfaceAvailableForRequestListener> {
        InterfaceAvailableForRequestListenerProxy(
                InterfaceAvailableForRequestListener destroyedListener, Handler handler) {
            super(destroyedListener, handler, "InterfaceAvailableForRequestListenerProxy");
        }

        @Override
        protected void actionWithArg(boolean isAvailable) {
            mListener.onAvailabilityChanged(isAvailable);
        }
    }

    private abstract class ListenerProxy<LISTENER>  {
        protected LISTENER mListener;
        private Handler mHandler;

        // override equals & hash to make sure that the container HashSet is unique with respect to
        // the contained listener
        @Override
        public boolean equals(Object obj) {
            return mListener == ((ListenerProxy<LISTENER>) obj).mListener;
        }

        @Override
        public int hashCode() {
            return mListener.hashCode();
        }

        void trigger() {
            if (mHandler != null) {
                mHandler.post(() -> {
                    action();
                });
            } else {
                action();
            }
        }

        void triggerWithArg(boolean arg) {
            if (mHandler != null) {
                mHandler.post(() -> {
                    actionWithArg(arg);
                });
            } else {
                actionWithArg(arg);
            }
        }

        protected void action() {}
        protected void actionWithArg(boolean arg) {}

        ListenerProxy(LISTENER listener, Handler handler, String tag) {
            mListener = listener;
            mHandler = handler;
        }
    }

这里写了两个点,一个是相同的listener只能注册一次,和handler没关系,另外如果是指定传递handler进来,那边可以指定在对应handler里执行回调。

注册回调后会立刻触发一次interface可创建性检查,如果当前可创建性与当前已保存状态不一致,触发回调

    private void dispatchAvailableForRequestListenersForType(int ifaceType,
            WifiChipInfo[] chipInfos) {
        if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListenersForType: ifaceType=" + ifaceType);

        synchronized (mLock) {
            Map<InterfaceAvailableForRequestListenerProxy, Boolean> listeners =
                    mInterfaceAvailableForRequestListeners.get(ifaceType);

            if (listeners.size() == 0) {
                return;
            }

            boolean isAvailable = isItPossibleToCreateIface(chipInfos, ifaceType);

            if (VDBG) {
                Log.d(TAG, "Interface available for: ifaceType=" + ifaceType + " = " + isAvailable);
            }
            for (Map.Entry<InterfaceAvailableForRequestListenerProxy, Boolean> listenerEntry :
                    listeners.entrySet()) {
                if (listenerEntry.getValue() == null || listenerEntry.getValue() != isAvailable) {
                    if (VDBG) {
                        Log.d(TAG, "Interface available listener dispatched: ifaceType=" + ifaceType
                                + ", listener=" + listenerEntry.getKey());
                    }
                    listenerEntry.getKey().triggerWithArg(isAvailable);
                }
                listenerEntry.setValue(isAvailable);
            }
        }
    }

另外就是在有接口创建或者摧毁的时候按优先级进行轮询通知,p2p算优先级比较低

    // dispatch all available for request listeners of the specified type AND clean-out the list:
    // listeners are called once at most!
    private boolean dispatchAvailableForRequestListeners() {
        if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListeners");

        synchronized (mLock) {
            WifiChipInfo[] chipInfos = getAllChipInfo();
            if (chipInfos == null) {
                Log.e(TAG, "dispatchAvailableForRequestListeners: no chip info found");
                stopWifi(); // major error: shutting down
                return false;
            }
            if (VDBG) {
                Log.d(TAG, "dispatchAvailableForRequestListeners: chipInfos="
                        + Arrays.deepToString(chipInfos));
            }

            for (int ifaceType : IFACE_TYPES_BY_PRIORITY) {
                dispatchAvailableForRequestListenersForType(ifaceType, chipInfos);
            }
        }

        return true;
    }

    /* This "PRIORITY" is not for deciding interface elimination (that is controlled by
     * allowedToDeleteIfaceTypeForRequestedType. This priority is used for:
     * - Comparing 2 configuration options
     * - Order of dispatch of available for request listeners
     */
    private static final int[] IFACE_TYPES_BY_PRIORITY =
            {IfaceType.AP, IfaceType.STA, IfaceType.P2P, IfaceType.NAN};

创建

    private IWifiIface createIface(int ifaceType, boolean lowPriority,
            InterfaceDestroyedListener destroyedListener, Handler handler) {
        if (mDbg) {
            Log.d(TAG, "createIface: ifaceType=" + ifaceType + ", lowPriority=" + lowPriority);
        }

        synchronized (mLock) {
            WifiChipInfo[] chipInfos = getAllChipInfo();
            if (chipInfos == null) {
                Log.e(TAG, "createIface: no chip info found");
                stopWifi(); // major error: shutting down
                return null;
            }

            if (!validateInterfaceCache(chipInfos)) {
                Log.e(TAG, "createIface: local cache is invalid!");
                stopWifi(); // major error: shutting down
                return null;
            }

            IWifiIface iface = createIfaceIfPossible(chipInfos, ifaceType, lowPriority,
                    destroyedListener, handler);
            if (iface != null) { // means that some configuration has changed
                if (!dispatchAvailableForRequestListeners()) {
                    return null; // catastrophic failure - shut down
                }
            }

            return iface;
        }
    }

摧毁

    /**
     * Removes (releases/destroys) the given interface. Will trigger any registered
     * InterfaceDestroyedListeners and possibly some InterfaceAvailableForRequestListeners if we
     * can potentially create some other interfaces as a result of removing this interface.
     */
    public boolean removeIface(IWifiIface iface) {
        boolean success = removeIfaceInternal(iface);
        dispatchAvailableForRequestListeners();
        return success;
    }

 

3.总结

 

 

 

虚拟以太网是指在真实的互联网中,通过软件方法在数据链路层实现一个 按以太网原理工作的虚拟网络。在虚拟网络中可以透明地运行所有应用程 序,支持各种第三层网络协议,如IP,IPv6,IPX等,可以进行普通的文件 共享以及ERP、VoIP等待应用。 特点: . 配置极其简单。 . 树形结构,可以从任一个节点接入,可谓一点接入,全网通行。 . 配合握手服务器(可由任一节点充当),可以实现两个节点间 直接点对点 通讯,无需 中转 !! . 3DES 数据加密 用途: . 创建企业虚拟网 . 创建专题虚拟网,你可以作为虚拟网的树根,然后把所有志同道合的人连接在一起, 形成一个独具特色的 “虚拟以太网社区”。 简单地说,任何人都可以用VE建立自己的虚拟Internet世界。 使用说明: 1. 双击virtualether.exe运行,程序会自动安装驱动程序va.sys,成功后会弹出设置界面。 2.设置方法。virtual ethernet的设置包括本地(local),远端(remote)和代理(proxy)。  . local设置,本端作为虚拟HUB接受连接:  . 设置本端的连接监听端口,即虚拟HUB的连接端口。  . 设置本端的连接密码,当远端连接过来时,需要进行密码验证。 . 设置点对点通讯的握手服务器域名/IP,及其端口。 . 如果本端想做握手服务器,可以设置一个本地的UDP端口。 注:只有本端想做虚拟HUB时才需要正确设置。    remote设置,本端作为虚拟网卡向虚拟HUB发起连接:  . 远端虚拟HUB的IP或域名(当然可以是动态域名)  . 远端虚拟HUB的密码,即远端在 local 设置中的密码 . 远端虚拟HUB的连接端口,即远端在 local 设置中监听端口 注:1.只有本端想与虚拟HUB连接时才需要正确设置。 2.如果想连接到自己的虚拟HUB,则选择“connect to my local virtual HUB”。 Proxy设置,如果你机器通过代理上网,如HTTP代理,Socket代理,就需要根据你的 代理情况进行设置。(这个功能可以穿透firewall,网管要小心啦) 如果你的上网方式是通过 http 代理,则可能需要把将要连接的虚拟HUM的监听端口设置成443才可以。 两个客户端之间发生通讯时,如果已经配置握手服务器,软件会自动尝试建立点对点通道
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值