Android8.0 WIFI ap Tethering 相關知識
阿新 • • 發佈:2019-01-27
開關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";