/frameworks/base/core/java/android/net/ConnectivityManager.java
2481 public void startTethering(int type, boolean showProvisioningUi,
2482 final OnStartTetheringCallback callback) {
2483 startTethering(type, showProvisioningUi, callback, null);
2484 }
2486 /**
2487 * Runs tether provisioning for the given type if needed and then starts tethering if
2488 * the check succeeds. If no carrier provisioning is required for tethering, tethering is
2489 * enabled immediately. If provisioning fails, tethering will not be enabled. It also
2490 * schedules tether provisioning re-checks if appropriate.
2491 *
2492 * @param type The type of tethering to start. Must be one of
2493 * {@link ConnectivityManager.TETHERING_WIFI},
2494 * {@link ConnectivityManager.TETHERING_USB}, or
2495 * {@link ConnectivityManager.TETHERING_BLUETOOTH}.
2496 * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
2497 * is one. This should be true the first time this function is called and also any time
2498 * the user can see this UI. It gives users information from their carrier about the
2499 * check failing and how they can sign up for tethering if possible.
2500 * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
2501 * of the result of trying to tether.
2502 * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
2503 *
2504 * @deprecated Use {@link TetheringManager#startTethering} instead.
2505 * @hide
2506 */
2507 @SystemApi
2508 @Deprecated
2509 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
2510 public void startTethering(int type, boolean showProvisioningUi,
2511 final OnStartTetheringCallback callback, Handler handler) {
2512 Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
2513
2514 final Executor executor = new Executor() {
2515 @Override
2516 public void execute(Runnable command) {
2517 if (handler == null) {
2518 command.run();
2519 } else {
2520 handler.post(command);
2521 }
2522 }
2523 };
2524
2525 final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
2526 @Override
2527 public void onTetheringStarted() {
2528 callback.onTetheringStarted();
2529 }
2530
2531 @Override
2532 public void onTetheringFailed(final int error) {
2533 callback.onTetheringFailed();
2534 }
2535 };
2536
2537 final TetheringRequest request = new TetheringRequest.Builder(type)
2538 .setShouldShowEntitlementUi(showProvisioningUi).build();
2539
2540 mTetheringManager.startTethering(request, executor, tetheringCallback);
2541 }
/frameworks/base/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
712 /**
713 * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
714 * fails, stopTethering will be called automatically.
715 *
716 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
717 * fail if a tethering entitlement check is required.
718 *
719 * @param request a {@link TetheringRequest} which can specify the preferred configuration.
720 * @param executor {@link Executor} to specify the thread upon which the callback of
721 * TetheringRequest will be invoked.
722 * @param callback A callback that will be called to indicate the success status of the
723 * tethering start request.
724 */
725 @RequiresPermission(anyOf = {
726 android.Manifest.permission.TETHER_PRIVILEGED,
727 android.Manifest.permission.WRITE_SETTINGS
728 })
729 public void startTethering(@NonNull final TetheringRequest request,
730 @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
731 final String callerPkg = mContext.getOpPackageName();
732 Log.i(TAG, "startTethering caller:" + callerPkg);
733
734 final IIntResultListener listener = new IIntResultListener.Stub() {
735 @Override
736 public void onResult(final int resultCode) {
737 executor.execute(() -> {
738 if (resultCode == TETHER_ERROR_NO_ERROR) {
739 callback.onTetheringStarted();
740 } else {
741 callback.onTetheringFailed(resultCode);
742 }
743 });
744 }
745 };
746 getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
747 }
/**
* Attempt to both alter the mode of USB and Tethering of USB.
*
* @deprecated New client should not use this API anymore. All clients should use
* #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
* not have any upstream.
*
* {@hide}
*/
@Deprecated
@SystemApi(client = MODULE_LIBRARIES)
public int setUsbTethering(final boolean enable) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "setUsbTethering caller:" + callerPkg);
final RequestDispatcher dispatcher = new RequestDispatcher();
return dispatcher.waitForResult((connector, listener) -> {
try {
connector.setUsbTethering(enable, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
});
}
/frameworks/base/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
private static class TetheringConnector extends ITetheringConnector.Stub {
@Override
public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) {
if (checkAndNotifyCommonError(callerPkg, listener)) return;
try {
listener.onResult(mTethering.setUsbTethering(enable));
} catch (RemoteException e) { }
}
/frameworks/base/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
1288 int setUsbTethering(boolean enable) {
1289 if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
1290 UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
1291 if (usbManager == null) {
1292 mLog.e("setUsbTethering: failed to get UsbManager!");
1293 return TETHER_ERROR_SERVICE_UNAVAIL;
1294 }
1295
1296 synchronized (mPublicSync) {
1297 usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
1298 : UsbManager.FUNCTION_NONE);
1299 }
1300 return TETHER_ERROR_NO_ERROR;
1301 }
/frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
992 @Override
993 public void startTethering(String[] dhcpRange) {
994 startTetheringWithConfiguration(true, dhcpRange);
995 }
996
997 @Override
998 public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
999 NetworkStack.checkNetworkStackPermission(mContext);
1000 try {
1001 NetdUtils.tetherStart(mNetdService, usingLegacyDnsProxy, dhcpRange);
1002 } catch (RemoteException | ServiceSpecificException e) {
1003 throw new IllegalStateException(e);
1004 }
1005 }
/packages/modules/NetworkStack/common/moduleutils/src/android/net/shared/NetdUtils.java
41 /** Start tethering. */
42 public static void tetherStart(final INetd netd, final boolean usingLegacyDnsProxy,
43 final String[] dhcpRange) throws RemoteException, ServiceSpecificException {
44 final TetherConfigParcel config = new TetherConfigParcel();
45 config.usingLegacyDnsProxy = usingLegacyDnsProxy;
46 config.dhcpRanges = dhcpRange;
47 netd.tetherStartWithConfiguration(config);
48 }
/system/netd/server/NetdNativeService.cpp
931 binder::Status NetdNativeService::tetherStartWithConfiguration(const TetherConfigParcel& config) {
932 NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
933 if (config.dhcpRanges.size() % 2 == 1) {
934 return statusFromErrcode(-EINVAL);
935 }
936 // TODO: Pass TetherConfigParcel directly.
937 int res = gCtls->tetherCtrl.startTethering(config.usingLegacyDnsProxy, config.dhcpRanges);
938 return statusFromErrcode(res);
939 }
/system/netd/server/TetherController.cpp
int TetherController::startTethering(bool usingLegacyDnsProxy,
const std::vector<std::string>& dhcpRanges) {
struct in_addr v4_addr;
for (const auto& dhcpRange : dhcpRanges) {
if (!inet_aton(dhcpRange.c_str(), &v4_addr)) {
return -EINVAL;
}
}
auto dhcp_ranges = toCstrVec(dhcpRanges);
return startTethering(usingLegacyDnsProxy, dhcp_ranges.size(), dhcp_ranges.data());
}
int TetherController::startTethering(bool usingLegacyDnsProxy, int num_addrs, char** dhcp_ranges) {
if (!usingLegacyDnsProxy && num_addrs == 0) {
// Both DHCP and DnsProxy are disabled, we don't need to start dnsmasq
configureForTethering(true);
mIsTetheringStarted = true;
return 0;
}
if (mIsTetheringStarted) {
ALOGE("Tethering already started");
errno = EBUSY;
return -errno;
}
ALOGD("Starting tethering services");
unique_fd pipeRead, pipeWrite;
if (!Pipe(&pipeRead, &pipeWrite, O_CLOEXEC)) {
int res = errno;
ALOGE("pipe2() failed (%s)", strerror(errno));
return -res;
}
// Set parameters
Fwmark fwmark;
fwmark.netId = NetworkController::LOCAL_NET_ID;
fwmark.explicitlySelected = true;
fwmark.protectedFromVpn = true;
fwmark.permission = PERMISSION_SYSTEM;
char markStr[UINT32_HEX_STRLEN];
snprintf(markStr, sizeof(markStr), "0x%x", fwmark.intValue);
std::vector<const std::string> argVector = {
"/system/bin/dnsmasq",
"--keep-in-foreground",
"--no-resolv",
"--no-poll",
"--dhcp-authoritative",
// TODO: pipe through metered status from ConnService
"--dhcp-option-force=43,ANDROID_METERED",
"--pid-file",
"--listen-mark",
markStr,
"--user",
kDnsmasqUsername,
};
if (!usingLegacyDnsProxy) {
argVector.push_back("--port=0");
}
// DHCP server will be disabled if num_addrs == 0 and no --dhcp-range is passed.
for (int addrIndex = 0; addrIndex < num_addrs; addrIndex += 2) {
argVector.push_back(StringPrintf("--dhcp-range=%s,%s,1h", dhcp_ranges[addrIndex],
dhcp_ranges[addrIndex + 1]));
}
std::vector<char*> args(argVector.size() + 1);
for (unsigned i = 0; i < argVector.size(); i++) {
args[i] = (char*)argVector[i].c_str();
}
/*
* TODO: Create a monitoring thread to handle and restart
* the daemon if it exits prematurely
*/
// Note that don't modify any memory between vfork and execv.
// Changing state of file descriptors would be fine. See posix_spawn_file_actions_add*
// dup2 creates fd without CLOEXEC, dnsmasq will receive commands through the
// duplicated fd.
posix_spawn_file_actions_t fa;
int res = posix_spawn_file_actions_init(&fa);
if (res) {
ALOGE("posix_spawn_file_actions_init failed (%s)", strerror(res));
return -res;
}
const android::base::ScopeGuard faGuard = [&] { posix_spawn_file_actions_destroy(&fa); };
res = posix_spawn_file_actions_adddup2(&fa, pipeRead.get(), STDIN_FILENO);
if (res) {
ALOGE("posix_spawn_file_actions_adddup2 failed (%s)", strerror(res));
return -res;
}
posix_spawnattr_t attr;
res = posix_spawnattr_init(&attr);
if (res) {
ALOGE("posix_spawnattr_init failed (%s)", strerror(res));
return -res;
}
const android::base::ScopeGuard attrGuard = [&] { posix_spawnattr_destroy(&attr); };
res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK);
if (res) {
ALOGE("posix_spawnattr_setflags failed (%s)", strerror(res));
return -res;
}
pid_t pid;
res = posix_spawn(&pid, args[0], &fa, &attr, &args[0], nullptr);
if (res) {
ALOGE("posix_spawn failed (%s)", strerror(res));
return -res;
}
mDaemonPid = pid;
mDaemonFd = pipeWrite.release();
configureForTethering(true);
mIsTetheringStarted = true;
applyDnsInterfaces();
ALOGD("Tethering services running");
return 0;
}
int TetherController::stopTethering() {
configureForTethering(false);
if (!mIsTetheringStarted) {
ALOGE("Tethering already stopped");
return 0;
}
mIsTetheringStarted = false;
// dnsmasq is not started
if (mDaemonPid == 0) {
return 0;
}
ALOGD("Stopping tethering services");
kill(mDaemonPid, SIGTERM);
waitpid(mDaemonPid, nullptr, 0);
mDaemonPid = 0;
close(mDaemonFd);
mDaemonFd = -1;
mDnsmasqState.clear();
ALOGD("Tethering services stopped");
return 0;
}
bool TetherController::isTetheringStarted() {
return mIsTetheringStarted;
}