1. 程式人生 > >Android8.0 WIFI ap Tethering 相關知識

Android8.0 WIFI ap Tethering 相關知識

開關wifi ap的程式碼在frameworks/base/core/java/android/net/ConnectivityManager.java中。

    /**
     * Runs tether provisioning for the given type if needed and then starts tethering if
     * the check succeeds. If no carrier provisioning is required for tethering, tethering is
     * enabled immediately. If provisioning fails, tethering will not
be enabled. It also * schedules tether provisioning re-checks if appropriate. * * @param type The type of tethering to start. Must be one of * {@link ConnectivityManager.TETHERING_WIFI}, * {@link ConnectivityManager.TETHERING_USB}, or * {@link ConnectivityManager.TETHERING_BLUETOOTH}. * @param
showProvisioningUi a boolean indicating to show the provisioning app UI if there * is one. This should be true the first time this function is called and also any time * the user can see this UI. It gives users information from their carrier about the * check failing and
how they can sign up for tethering if possible. * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller * of the result of trying to tether. * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int type, boolean showProvisioningUi, final OnStartTetheringCallback callback, Handler handler) { checkNotNull(callback, "OnStartTetheringCallback cannot be null."); ResultReceiver wrappedCallback = new ResultReceiver(handler) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == TETHER_ERROR_NO_ERROR) { callback.onTetheringStarted(); } else { callback.onTetheringFailed(); } } }; try { mService.startTethering(type, wrappedCallback, showProvisioningUi); } catch (RemoteException e) { Log.e(TAG, "Exception trying to start tethering.", e); wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null); } } /** * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if * applicable. * * @param type The type of tethering to stop. Must be one of * {@link ConnectivityManager.TETHERING_WIFI}, * {@link ConnectivityManager.TETHERING_USB}, or * {@link ConnectivityManager.TETHERING_BLUETOOTH}. * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int type) { try { mService.stopTethering(type); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

這裡最終呼叫了mService.startTethering這是個介面,最終實現的地方在frameworks/base/services/core/java/com/android/server/ConnectivityManagerService.java

    @Override
    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
        ConnectivityManager.enforceTetherChangePermission(mContext);
        if (!isTetheringSupported()) {
            receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
            return;
        }
        mTethering.startTethering(type, receiver, showProvisioningUi);
    }

    @Override
    public void stopTethering(int type) {
        ConnectivityManager.enforceTetherChangePermission(mContext);
        mTethering.stopTethering(type);
    }

然後呼叫frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java

    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
        if (!isTetherProvisioningRequired()) {
            enableTetheringInternal(type, true, receiver);
            return;
        }

        if (showProvisioningUi) {
            runUiTetherProvisioningAndEnable(type, receiver);
        } else {
            runSilentTetherProvisioningAndEnable(type, receiver);
        }
    }

    public void stopTethering(int type) {
        enableTetheringInternal(type, false, null);
        if (isTetherProvisioningRequired()) {
            cancelTetherProvisioningRechecks(type);
        }
    }

接著走

    private int setWifiTethering(final boolean enable) {
        int rval = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mPublicSync) {
                mWifiTetherRequested = enable;
                final WifiManager mgr = getWifiManager();
                if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
                    (!enable && mgr.stopSoftAp())) {
                    rval = ConnectivityManager.TETHER_ERROR_NO_ERROR;
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return rval;
    }

然後走frameworks/base/wifi/java/android/net/wifi/WifiManager.java

    /**
     * Start SoftAp mode with the specified configuration.
     * Note that starting in access point mode disables station
     * mode operation
     * @param wifiConfig SSID, security and channel details as
     *        part of WifiConfiguration
     * @return {@code true} if the operation succeeds, {@code false} otherwise
     *
     * @hide
     */
    public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
        try {
            return mService.startSoftAp(wifiConfig);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Stop SoftAp mode.
     * Note that stopping softap mode will restore the previous wifi mode.
     * @return {@code true} if the operation succeeds, {@code false} otherwise
     *
     * @hide
     */
    public boolean stopSoftAp() {
        try {
            return mService.stopSoftAp();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

mService.startSoftAp這個介面實現的地方在frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

    /**
     * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
     * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
     * @return {@code true} if softap start was triggered
     * @throws SecurityException if the caller does not have permission to start softap
     */
    @Override
    public boolean startSoftAp(WifiConfiguration wifiConfig) {
        // NETWORK_STACK is a signature only permission.
        enforceNetworkStackPermission();

        mLog.trace("startSoftAp uid=%").c(Binder.getCallingUid()).flush();

        synchronized (mLocalOnlyHotspotRequests) {
            // If a tethering request comes in while we have LOHS running (or requested), call stop
            // for softap mode and restart softap with the tethering config.
            if (!mLocalOnlyHotspotRequests.isEmpty()) {
                stopSoftApInternal();
            }

            return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
        }
    }

    /**
     * Internal method to start softap mode. Callers of this method should have already checked
     * proper permissions beyond the NetworkStack permission.
     */
    private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
        mLog.trace("startSoftApInternal uid=% mode=%")
                .c(Binder.getCallingUid()).c(mode).flush();

        // This will internally check for DUAL_BAND and take action.
        startDualSapMode(true);

        // null wifiConfig is a meaningful input for CMD_SET_AP
        if (wifiConfig == null || isValid(wifiConfig)) {
            SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
            mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
            return true;
        }
        Slog.e(TAG, "Invalid WifiConfiguration");
        return false;
    }

mWifiController繼承了StateMachine。

/**
 * WifiController is the class used to manage on/off state of WifiStateMachine for various operating
 * modes (normal, airplane, wifi hotspot, etc.).
 */

WiFi ap 相關的設定都是在frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiApConfigStore.java

這個配置了能不能同時開啟ap和wifi。

    private static final String mConcurrencyCfgTemplateFile =
            "/vendor/etc/wifi/wifi_concurrency_cfg.txt";