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

对着背影说爱祢 提交于 2020-01-22 22:04:00

前言:在平常工作中,注意到关闭热点后,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.总结

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!