(一百七十一) 探索softap和p2p interface优先级

1.先打开p2p后打开softap

softap的interface会将p2p的interface替换掉,适合于下面列出来的rule 4

HalDeviceManager

    /**
     * Returns true if we're allowed to delete the existing interface type for the requested
     * interface type.
     *
     * Rules - applies in order:
     *
     * General rules:
     * 1. No interface will be destroyed for a requested interface of the same type
     * 2. No interface will be destroyed if one of the requested interfaces already exists
     * 3. If there are >1 interface of an existing type, then it is ok to destroy that type
     *    interface
     *
     * Type-specific rules (but note that the general rules are appied first):
     * 4. Request for AP or STA will destroy any other interface
     * 5. Request for P2P will destroy NAN-only (but will destroy a second STA per #3)
     * 6. Request for NAN will not destroy any interface (but will destroy a second STA per #3)
     *
     * Note: the 'numNecessaryInterfaces' is used to specify how many interfaces would be needed to
     * be deleted. This is used to determine whether there are that many low priority interfaces
     * of the requested type to delete.
     */
    private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
            int requestedIfaceType, WifiIfaceInfo[][] currentIfaces, int numNecessaryInterfaces) {
        // rule 0: check for any low priority interfaces
        int numAvailableLowPriorityInterfaces = 0;
        for (InterfaceCacheEntry entry : mInterfaceInfoCache.values()) {
            if (entry.type == existingIfaceType && entry.isLowPriority) {
                numAvailableLowPriorityInterfaces++;
            }
        }
        if (numAvailableLowPriorityInterfaces >= numNecessaryInterfaces) {
            return true;
        }

        // rule 1
        if (existingIfaceType == requestedIfaceType) {
            return false;
        }

        // rule 2
        if (currentIfaces[requestedIfaceType].length != 0) {
            return false;
        }

        // rule 3
        if (currentIfaces[existingIfaceType].length > 1) {
            return true;
        }

        // rule 6
        if (requestedIfaceType == IfaceType.NAN) {
            return false;
        }

        // rule 5
        if (requestedIfaceType == IfaceType.P2P) {
            return existingIfaceType == IfaceType.NAN;
        }

        // rule 4, the requestIfaceType is either AP or STA
        return true;
    }

 

2.先打开softap后打开p2p

p2p打不开,因为softap优先级比较高,适用于上面的rule 5

 

3.softap关闭后p2p自动打开

原理在于interface destroy后会通知监听的listener

    /**
     * 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;
    }


    // 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;
    }

依次按优先级通知各个interface type对应的listener(只有在有可能创建的时候才会真正去通知)

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

        synchronized (mLock) {
            Map 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 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);
            }
        }
    }

看下哪些interface会注册监听器

    /**
     * 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);
    }

这边判断key是不是一样是判断listener是不是一个

    private abstract class ListenerProxy  {
        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) obj).mListener;
        }

主要有两个地方会调用这个监听器

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java#90

NAN

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pNative.java#162

P2P

主要看下P2P

    // 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);
        }
    }

    /**
     * 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);
        }
    }

http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java#744

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

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

原生逻辑会在WiFi打开p2p可得并且当前有p2p client的情况下将p2p打开

 

4.总结

总结下softap的优先级比p2p高,只有在关闭热点的情况下才能使用p2p相关功能。

原生p2p一直打开,不知道是处于什么考虑,热点打开的时候ap会替换掉p2p,p2p无法取代ap,但ap关闭后p2p会有条件开启。

你可能感兴趣的:(Wifi)