blob: 4f053cb65c38f9bc2c9ec9a5a5b547ef0cb7690f [file] [log] [blame]
markchien0df2ebc42019-09-30 14:40:57 +08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.net;
17
markchien2c153702020-02-06 19:23:26 +080018import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
19
markchien06889172020-01-20 19:31:56 +080020import android.Manifest;
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +000021import android.annotation.IntDef;
markchien0df2ebc42019-09-30 14:40:57 +080022import android.annotation.NonNull;
markchien75b6d7b2020-01-21 13:11:06 +080023import android.annotation.Nullable;
24import android.annotation.RequiresPermission;
25import android.annotation.SystemApi;
26import android.annotation.TestApi;
markchien6d06f6d2019-12-16 20:15:20 +080027import android.content.Context;
markchien75b6d7b2020-01-21 13:11:06 +080028import android.os.Bundle;
markchien0df2ebc42019-09-30 14:40:57 +080029import android.os.ConditionVariable;
30import android.os.IBinder;
markchien0df2ebc42019-09-30 14:40:57 +080031import android.os.RemoteException;
32import android.os.ResultReceiver;
markchien6d06f6d2019-12-16 20:15:20 +080033import android.util.ArrayMap;
34import android.util.Log;
markchien0df2ebc42019-09-30 14:40:57 +080035
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +090036import com.android.internal.annotations.GuardedBy;
37
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +000038import java.lang.annotation.Retention;
39import java.lang.annotation.RetentionPolicy;
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +090040import java.util.ArrayList;
markchien75b6d7b2020-01-21 13:11:06 +080041import java.util.Arrays;
Remi NGUYEN VANbfc910c2020-01-20 21:26:34 +090042import java.util.Collection;
markchien75b6d7b2020-01-21 13:11:06 +080043import java.util.Collections;
44import java.util.HashMap;
45import java.util.List;
46import java.util.Objects;
markchien6d06f6d2019-12-16 20:15:20 +080047import java.util.concurrent.Executor;
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +090048import java.util.function.Supplier;
markchien0df2ebc42019-09-30 14:40:57 +080049
50/**
markchien6d06f6d2019-12-16 20:15:20 +080051 * This class provides the APIs to control the tethering service.
52 * <p> The primary responsibilities of this class are to provide the APIs for applications to
53 * start tethering, stop tethering, query configuration and query status.
54 *
markchien0df2ebc42019-09-30 14:40:57 +080055 * @hide
56 */
markchien75b6d7b2020-01-21 13:11:06 +080057@SystemApi
markchien2c153702020-02-06 19:23:26 +080058@SystemApi(client = MODULE_LIBRARIES)
markchien75b6d7b2020-01-21 13:11:06 +080059@TestApi
markchien0df2ebc42019-09-30 14:40:57 +080060public class TetheringManager {
61 private static final String TAG = TetheringManager.class.getSimpleName();
markchien6d06f6d2019-12-16 20:15:20 +080062 private static final int DEFAULT_TIMEOUT_MS = 60_000;
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +090063 private static final long CONNECTOR_POLL_INTERVAL_MILLIS = 200L;
markchien0df2ebc42019-09-30 14:40:57 +080064
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +090065 @GuardedBy("mConnectorWaitQueue")
66 @Nullable
67 private ITetheringConnector mConnector;
68 @GuardedBy("mConnectorWaitQueue")
69 @NonNull
70 private final List<ConnectorConsumer> mConnectorWaitQueue = new ArrayList<>();
71 private final Supplier<IBinder> mConnectorSupplier;
markchien0df2ebc42019-09-30 14:40:57 +080072
markchien6d06f6d2019-12-16 20:15:20 +080073 private final TetheringCallbackInternal mCallback;
74 private final Context mContext;
markchien75b6d7b2020-01-21 13:11:06 +080075 private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
markchien6d06f6d2019-12-16 20:15:20 +080076 mTetheringEventCallbacks = new ArrayMap<>();
77
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +090078 private volatile TetheringConfigurationParcel mTetheringConfiguration;
79 private volatile TetherStatesParcel mTetherStatesParcel;
markchien0df2ebc42019-09-30 14:40:57 +080080
markchien9e44cde2019-12-25 19:40:32 +080081 /**
82 * Broadcast Action: A tetherable connection has come or gone.
83 * Uses {@code TetheringManager.EXTRA_AVAILABLE_TETHER},
84 * {@code TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY},
85 * {@code TetheringManager.EXTRA_ACTIVE_TETHER}, and
86 * {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate
87 * the current state of tethering. Each include a list of
88 * interface names in that state (may be empty).
89 */
90 public static final String ACTION_TETHER_STATE_CHANGED =
91 "android.net.conn.TETHER_STATE_CHANGED";
92
93 /**
94 * gives a String[] listing all the interfaces configured for
95 * tethering and currently available for tethering.
96 */
97 public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
98
99 /**
100 * gives a String[] listing all the interfaces currently in local-only
101 * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
102 */
markchien75b6d7b2020-01-21 13:11:06 +0800103 public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
markchien9e44cde2019-12-25 19:40:32 +0800104
105 /**
106 * gives a String[] listing all the interfaces currently tethered
107 * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
108 */
109 public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
110
111 /**
112 * gives a String[] listing all the interfaces we tried to tether and
113 * failed. Use {@link #getLastTetherError} to find the error code
114 * for any interfaces listed here.
115 */
116 public static final String EXTRA_ERRORED_TETHER = "erroredArray";
117
markchien62a625d2020-03-19 13:37:43 +0800118 /** @hide */
119 @Retention(RetentionPolicy.SOURCE)
120 @IntDef(flag = false, value = {
121 TETHERING_WIFI,
122 TETHERING_USB,
123 TETHERING_BLUETOOTH,
124 TETHERING_WIFI_P2P,
125 TETHERING_NCM,
126 TETHERING_ETHERNET,
127 })
128 public @interface TetheringType {
129 }
130
markchien9e44cde2019-12-25 19:40:32 +0800131 /**
132 * Invalid tethering type.
133 * @see #startTethering.
134 */
135 public static final int TETHERING_INVALID = -1;
136
137 /**
138 * Wifi tethering type.
139 * @see #startTethering.
140 */
141 public static final int TETHERING_WIFI = 0;
142
143 /**
144 * USB tethering type.
145 * @see #startTethering.
146 */
147 public static final int TETHERING_USB = 1;
148
149 /**
150 * Bluetooth tethering type.
151 * @see #startTethering.
152 */
153 public static final int TETHERING_BLUETOOTH = 2;
154
155 /**
156 * Wifi P2p tethering type.
157 * Wifi P2p tethering is set through events automatically, and don't
158 * need to start from #startTethering.
159 */
160 public static final int TETHERING_WIFI_P2P = 3;
161
Milim Lee58527ba2019-10-17 05:02:33 +0900162 /**
163 * Ncm local tethering type.
164 * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
165 */
166 public static final int TETHERING_NCM = 4;
167
Remi NGUYEN VANf2f3f3e2020-01-24 22:57:09 +0900168 /**
169 * Ethernet tethering type.
170 * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
171 */
172 public static final int TETHERING_ETHERNET = 5;
173
Dedy Lansky04bef3c2019-11-21 00:36:14 +0200174 /**
175 * WIGIG tethering type. Use a separate type to prevent
176 * conflicts with TETHERING_WIFI
177 * This type is only used internally by the tethering module
178 * @hide
179 */
180 public static final int TETHERING_WIGIG = 6;
181
markchien62a625d2020-03-19 13:37:43 +0800182 /** @hide */
183 @Retention(RetentionPolicy.SOURCE)
184 @IntDef(value = {
185 TETHER_ERROR_NO_ERROR,
186 TETHER_ERROR_PROVISIONING_FAILED,
187 TETHER_ERROR_ENTITLEMENT_UNKNOWN,
188 })
189 public @interface EntitlementResult {
190 }
191
192 /** @hide */
193 @Retention(RetentionPolicy.SOURCE)
194 @IntDef(value = {
195 TETHER_ERROR_NO_ERROR,
196 TETHER_ERROR_UNKNOWN_IFACE,
197 TETHER_ERROR_SERVICE_UNAVAIL,
198 TETHER_ERROR_INTERNAL_ERROR,
199 TETHER_ERROR_TETHER_IFACE_ERROR,
200 TETHER_ERROR_ENABLE_FORWARDING_ERROR,
201 TETHER_ERROR_DISABLE_FORWARDING_ERROR,
202 TETHER_ERROR_IFACE_CFG_ERROR,
203 TETHER_ERROR_DHCPSERVER_ERROR,
204 })
205 public @interface TetheringIfaceError {
206 }
207
208 /** @hide */
209 @Retention(RetentionPolicy.SOURCE)
210 @IntDef(value = {
211 TETHER_ERROR_SERVICE_UNAVAIL,
212 TETHER_ERROR_INTERNAL_ERROR,
213 TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION,
214 TETHER_ERROR_UNKNOWN_TYPE,
215 })
216 public @interface StartTetheringError {
217 }
218
219 public static final int TETHER_ERROR_NO_ERROR = 0;
220 public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
221 public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
222 public static final int TETHER_ERROR_UNSUPPORTED = 3;
223 public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
224 public static final int TETHER_ERROR_INTERNAL_ERROR = 5;
markchien6d06f6d2019-12-16 20:15:20 +0800225 public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
226 public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
markchien62a625d2020-03-19 13:37:43 +0800227 public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8;
228 public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9;
229 public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
230 public static final int TETHER_ERROR_PROVISIONING_FAILED = 11;
231 public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
markchien75b6d7b2020-01-21 13:11:06 +0800232 public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
markchien6d06f6d2019-12-16 20:15:20 +0800233 public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
234 public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
markchien62a625d2020-03-19 13:37:43 +0800235 public static final int TETHER_ERROR_UNKNOWN_TYPE = 16;
markchien0df2ebc42019-09-30 14:40:57 +0800236
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +0000237 /** @hide */
238 @Retention(RetentionPolicy.SOURCE)
239 @IntDef(flag = false, value = {
240 TETHER_HARDWARE_OFFLOAD_STOPPED,
241 TETHER_HARDWARE_OFFLOAD_STARTED,
242 TETHER_HARDWARE_OFFLOAD_FAILED,
243 })
244 public @interface TetherOffloadStatus {
245 }
246
247 /** Tethering offload status is stopped. */
248 public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0;
249 /** Tethering offload status is started. */
250 public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1;
251 /** Fail to start tethering offload. */
252 public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2;
253
markchien0df2ebc42019-09-30 14:40:57 +0800254 /**
markchien6d06f6d2019-12-16 20:15:20 +0800255 * Create a TetheringManager object for interacting with the tethering service.
markchien75b6d7b2020-01-21 13:11:06 +0800256 *
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900257 * @param context Context for the manager.
258 * @param connectorSupplier Supplier for the manager connector; may return null while the
259 * service is not connected.
markchien75b6d7b2020-01-21 13:11:06 +0800260 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800261 */
markchien2c153702020-02-06 19:23:26 +0800262 @SystemApi(client = MODULE_LIBRARIES)
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900263 public TetheringManager(@NonNull final Context context,
264 @NonNull Supplier<IBinder> connectorSupplier) {
markchien6d06f6d2019-12-16 20:15:20 +0800265 mContext = context;
markchien6d06f6d2019-12-16 20:15:20 +0800266 mCallback = new TetheringCallbackInternal();
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900267 mConnectorSupplier = connectorSupplier;
markchien0df2ebc42019-09-30 14:40:57 +0800268
markchien6d06f6d2019-12-16 20:15:20 +0800269 final String pkgName = mContext.getOpPackageName();
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900270
271 final IBinder connector = mConnectorSupplier.get();
272 // If the connector is available on start, do not start a polling thread. This introduces
273 // differences in the thread that sends the oneway binder calls to the service between the
274 // first few seconds after boot and later, but it avoids always having differences between
275 // the first usage of TetheringManager from a process and subsequent usages (so the
276 // difference is only on boot). On boot binder calls may be queued until the service comes
277 // up and be sent from a worker thread; later, they are always sent from the caller thread.
278 // Considering that it's just oneway binder calls, and ordering is preserved, this seems
279 // better than inconsistent behavior persisting after boot.
280 if (connector != null) {
281 mConnector = ITetheringConnector.Stub.asInterface(connector);
282 } else {
283 startPollingForConnector();
284 }
285
markchien6d06f6d2019-12-16 20:15:20 +0800286 Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900287 getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
288 }
289
290 private void startPollingForConnector() {
291 new Thread(() -> {
292 while (true) {
293 try {
Amos Bianchi2fc17472020-02-13 15:54:45 -0800294 Thread.sleep(CONNECTOR_POLL_INTERVAL_MILLIS);
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900295 } catch (InterruptedException e) {
296 // Not much to do here, the system needs to wait for the connector
297 }
298
299 final IBinder connector = mConnectorSupplier.get();
300 if (connector != null) {
301 onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
302 return;
303 }
304 }
305 }).start();
306 }
307
308 private interface ConnectorConsumer {
309 void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
310 }
311
312 private void onTetheringConnected(ITetheringConnector connector) {
313 // Process the connector wait queue in order, including any items that are added
314 // while processing.
315 //
316 // 1. Copy the queue to a local variable under lock.
317 // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
318 // would block on the lock).
319 // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
320 // If not, set mConnector to non-null so future tasks are run immediately, not queued.
321 //
322 // For this to work, all calls to the tethering service must use getConnector(), which
323 // ensures that tasks are added to the queue with the lock held.
324 //
325 // Once mConnector is set to non-null, it will never be null again. If the network stack
326 // process crashes, no recovery is possible.
327 // TODO: evaluate whether it is possible to recover from network stack process crashes
328 // (though in most cases the system will have crashed when the network stack process
329 // crashes).
330 do {
331 final List<ConnectorConsumer> localWaitQueue;
332 synchronized (mConnectorWaitQueue) {
333 localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
334 mConnectorWaitQueue.clear();
335 }
336
337 // Allow more tasks to be added at the end without blocking while draining the queue.
338 for (ConnectorConsumer task : localWaitQueue) {
339 try {
340 task.onConnectorAvailable(connector);
341 } catch (RemoteException e) {
342 // Most likely the network stack process crashed, which is likely to crash the
343 // system. Keep processing other requests but report the error loudly.
344 Log.wtf(TAG, "Error processing request for the tethering connector", e);
345 }
346 }
347
348 synchronized (mConnectorWaitQueue) {
349 if (mConnectorWaitQueue.size() == 0) {
350 mConnector = connector;
351 return;
352 }
353 }
354 } while (true);
355 }
356
357 /**
358 * Asynchronously get the ITetheringConnector to execute some operation.
359 *
360 * <p>If the connector is already available, the operation will be executed on the caller's
361 * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
362 * limited to performing oneway binder calls to minimize differences due to threading.
363 */
364 private void getConnector(ConnectorConsumer consumer) {
365 final ITetheringConnector connector;
366 synchronized (mConnectorWaitQueue) {
367 connector = mConnector;
368 if (connector == null) {
369 mConnectorWaitQueue.add(consumer);
370 return;
371 }
372 }
373
markchien0df2ebc42019-09-30 14:40:57 +0800374 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900375 consumer.onConnectorAvailable(connector);
markchien0df2ebc42019-09-30 14:40:57 +0800376 } catch (RemoteException e) {
markchien6d06f6d2019-12-16 20:15:20 +0800377 throw new IllegalStateException(e);
markchien0df2ebc42019-09-30 14:40:57 +0800378 }
379 }
380
markchien6d06f6d2019-12-16 20:15:20 +0800381 private interface RequestHelper {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900382 void runRequest(ITetheringConnector connector, IIntResultListener listener);
markchien6d06f6d2019-12-16 20:15:20 +0800383 }
384
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900385 // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
386 // return results and perform operations synchronously.
387 // TODO: remove once there are no callers of these legacy methods.
markchien6d06f6d2019-12-16 20:15:20 +0800388 private class RequestDispatcher {
389 private final ConditionVariable mWaiting;
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900390 public volatile int mRemoteResult;
markchien6d06f6d2019-12-16 20:15:20 +0800391
392 private final IIntResultListener mListener = new IIntResultListener.Stub() {
393 @Override
394 public void onResult(final int resultCode) {
395 mRemoteResult = resultCode;
396 mWaiting.open();
397 }
398 };
399
400 RequestDispatcher() {
401 mWaiting = new ConditionVariable();
402 }
403
404 int waitForResult(final RequestHelper request) {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900405 getConnector(c -> request.runRequest(c, mListener));
markchien6d06f6d2019-12-16 20:15:20 +0800406 if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
407 throw new IllegalStateException("Callback timeout");
408 }
409
410 throwIfPermissionFailure(mRemoteResult);
411
412 return mRemoteResult;
413 }
414 }
415
416 private void throwIfPermissionFailure(final int errorCode) {
417 switch (errorCode) {
418 case TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION:
419 throw new SecurityException("No android.permission.TETHER_PRIVILEGED"
420 + " or android.permission.WRITE_SETTINGS permission");
421 case TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION:
422 throw new SecurityException(
423 "No android.permission.ACCESS_NETWORK_STATE permission");
424 }
425 }
426
427 private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900428 private volatile int mError = TETHER_ERROR_NO_ERROR;
markchien6d06f6d2019-12-16 20:15:20 +0800429 private final ConditionVariable mWaitForCallback = new ConditionVariable();
markchien0df2ebc42019-09-30 14:40:57 +0800430
431 @Override
markchien75b6d7b2020-01-21 13:11:06 +0800432 public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
433 mTetheringConfiguration = parcel.config;
434 mTetherStatesParcel = parcel.states;
markchien6d06f6d2019-12-16 20:15:20 +0800435 mWaitForCallback.open();
markchien0df2ebc42019-09-30 14:40:57 +0800436 }
437
438 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800439 public void onCallbackStopped(int errorCode) {
440 mError = errorCode;
441 mWaitForCallback.open();
442 }
443
444 @Override
445 public void onUpstreamChanged(Network network) { }
446
447 @Override
markchien0df2ebc42019-09-30 14:40:57 +0800448 public void onConfigurationChanged(TetheringConfigurationParcel config) {
449 mTetheringConfiguration = config;
450 }
451
452 @Override
453 public void onTetherStatesChanged(TetherStatesParcel states) {
454 mTetherStatesParcel = states;
455 }
456
Remi NGUYEN VAN43b0e5c2020-02-13 09:16:19 +0900457 @Override
458 public void onTetherClientsChanged(List<TetheredClient> clients) { }
459
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +0000460 @Override
461 public void onOffloadStatusChanged(int status) { }
462
markchien6d06f6d2019-12-16 20:15:20 +0800463 public void waitForStarted() {
464 mWaitForCallback.block(DEFAULT_TIMEOUT_MS);
465 throwIfPermissionFailure(mError);
markchien0df2ebc42019-09-30 14:40:57 +0800466 }
markchien0df2ebc42019-09-30 14:40:57 +0800467 }
468
469 /**
470 * Attempt to tether the named interface. This will setup a dhcp server
471 * on the interface, forward and NAT IP v4 packets and forward DNS requests
472 * to the best active upstream network interface. Note that if no upstream
473 * IP network interface is available, dhcp will still run and traffic will be
474 * allowed between the tethered devices and this device, though upstream net
475 * access will of course fail until an upstream network interface becomes
markchien6d06f6d2019-12-16 20:15:20 +0800476 * active.
markchien0df2ebc42019-09-30 14:40:57 +0800477 *
markchien6d06f6d2019-12-16 20:15:20 +0800478 * @deprecated The only usages is PanService. It uses this for legacy reasons
479 * and will migrate away as soon as possible.
markchien0df2ebc42019-09-30 14:40:57 +0800480 *
markchien6d06f6d2019-12-16 20:15:20 +0800481 * @param iface the interface name to tether.
482 * @return error a {@code TETHER_ERROR} value indicating success or failure type
markchien75b6d7b2020-01-21 13:11:06 +0800483 *
484 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800485 */
markchienb741c642019-11-27 21:20:33 +0800486 @Deprecated
markchien2c153702020-02-06 19:23:26 +0800487 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +0800488 public int tether(@NonNull final String iface) {
489 final String callerPkg = mContext.getOpPackageName();
490 Log.i(TAG, "tether caller:" + callerPkg);
491 final RequestDispatcher dispatcher = new RequestDispatcher();
492
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900493 return dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +0800494 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900495 connector.tether(iface, callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +0800496 } catch (RemoteException e) {
497 throw new IllegalStateException(e);
498 }
499 });
markchien0df2ebc42019-09-30 14:40:57 +0800500 }
501
502 /**
503 * Stop tethering the named interface.
504 *
markchien6d06f6d2019-12-16 20:15:20 +0800505 * @deprecated The only usages is PanService. It uses this for legacy reasons
506 * and will migrate away as soon as possible.
markchien75b6d7b2020-01-21 13:11:06 +0800507 *
508 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800509 */
markchienb741c642019-11-27 21:20:33 +0800510 @Deprecated
markchien2c153702020-02-06 19:23:26 +0800511 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +0800512 public int untether(@NonNull final String iface) {
513 final String callerPkg = mContext.getOpPackageName();
514 Log.i(TAG, "untether caller:" + callerPkg);
515
516 final RequestDispatcher dispatcher = new RequestDispatcher();
517
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900518 return dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +0800519 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900520 connector.untether(iface, callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +0800521 } catch (RemoteException e) {
522 throw new IllegalStateException(e);
523 }
524 });
markchien0df2ebc42019-09-30 14:40:57 +0800525 }
526
527 /**
markchien6d06f6d2019-12-16 20:15:20 +0800528 * Attempt to both alter the mode of USB and Tethering of USB.
markchien0df2ebc42019-09-30 14:40:57 +0800529 *
markchien6d06f6d2019-12-16 20:15:20 +0800530 * @deprecated New client should not use this API anymore. All clients should use
531 * #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
532 * used and an entitlement check is needed, downstream USB tethering will be enabled but will
533 * not have any upstream.
markchien75b6d7b2020-01-21 13:11:06 +0800534 *
535 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800536 */
markchienb741c642019-11-27 21:20:33 +0800537 @Deprecated
markchien2c153702020-02-06 19:23:26 +0800538 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +0800539 public int setUsbTethering(final boolean enable) {
540 final String callerPkg = mContext.getOpPackageName();
541 Log.i(TAG, "setUsbTethering caller:" + callerPkg);
542
543 final RequestDispatcher dispatcher = new RequestDispatcher();
544
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900545 return dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +0800546 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900547 connector.setUsbTethering(enable, callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +0800548 } catch (RemoteException e) {
549 throw new IllegalStateException(e);
550 }
551 });
markchien0df2ebc42019-09-30 14:40:57 +0800552 }
553
554 /**
markchien06889172020-01-20 19:31:56 +0800555 * Use with {@link #startTethering} to specify additional parameters when starting tethering.
556 */
557 public static class TetheringRequest {
558 /** A configuration set for TetheringRequest. */
559 private final TetheringRequestParcel mRequestParcel;
560
561 private TetheringRequest(final TetheringRequestParcel request) {
562 mRequestParcel = request;
563 }
564
565 /** Builder used to create TetheringRequest. */
566 public static class Builder {
567 private final TetheringRequestParcel mBuilderParcel;
568
569 /** Default constructor of Builder. */
markchien62a625d2020-03-19 13:37:43 +0800570 public Builder(@TetheringType final int type) {
markchien06889172020-01-20 19:31:56 +0800571 mBuilderParcel = new TetheringRequestParcel();
572 mBuilderParcel.tetheringType = type;
573 mBuilderParcel.localIPv4Address = null;
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000574 mBuilderParcel.staticClientAddress = null;
markchien06889172020-01-20 19:31:56 +0800575 mBuilderParcel.exemptFromEntitlementCheck = false;
576 mBuilderParcel.showProvisioningUi = true;
577 }
578
579 /**
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000580 * Configure tethering with static IPv4 assignment.
markchien06889172020-01-20 19:31:56 +0800581 *
Treehugger Robot86d212b2020-03-30 04:23:55 +0000582 * A DHCP server will be started, but will only be able to offer the client address.
583 * The two addresses must be in the same prefix.
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000584 *
585 * @param localIPv4Address The preferred local IPv4 link address to use.
586 * @param clientAddress The static client address.
markchien06889172020-01-20 19:31:56 +0800587 */
588 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
589 @NonNull
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000590 public Builder setStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address,
591 @NonNull final LinkAddress clientAddress) {
592 Objects.requireNonNull(localIPv4Address);
593 Objects.requireNonNull(clientAddress);
Treehugger Robot86d212b2020-03-30 04:23:55 +0000594 if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) {
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000595 throw new IllegalArgumentException("Invalid server or client addresses");
596 }
597
markchien06889172020-01-20 19:31:56 +0800598 mBuilderParcel.localIPv4Address = localIPv4Address;
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000599 mBuilderParcel.staticClientAddress = clientAddress;
markchien06889172020-01-20 19:31:56 +0800600 return this;
601 }
602
603 /** Start tethering without entitlement checks. */
604 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
605 @NonNull
606 public Builder setExemptFromEntitlementCheck(boolean exempt) {
607 mBuilderParcel.exemptFromEntitlementCheck = exempt;
608 return this;
609 }
610
markchien62a625d2020-03-19 13:37:43 +0800611 /**
612 * If an entitlement check is needed, sets whether to show the entitlement UI or to
613 * perform a silent entitlement check. By default, the entitlement UI is shown.
614 */
markchien06889172020-01-20 19:31:56 +0800615 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
616 @NonNull
markchien62a625d2020-03-19 13:37:43 +0800617 public Builder setShouldShowEntitlementUi(boolean showUi) {
618 mBuilderParcel.showProvisioningUi = showUi;
markchien06889172020-01-20 19:31:56 +0800619 return this;
620 }
621
622 /** Build {@link TetheringRequest] with the currently set configuration. */
623 @NonNull
624 public TetheringRequest build() {
625 return new TetheringRequest(mBuilderParcel);
626 }
junyulai25d64392020-03-23 10:47:42 +0800627 }
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000628
junyulai25d64392020-03-23 10:47:42 +0800629 /**
630 * Get the local IPv4 address, if one was configured with
631 * {@link Builder#setStaticIpv4Addresses}.
632 */
633 @Nullable
634 public LinkAddress getLocalIpv4Address() {
635 return mRequestParcel.localIPv4Address;
636 }
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000637
junyulai25d64392020-03-23 10:47:42 +0800638 /**
639 * Get the static IPv4 address of the client, if one was configured with
640 * {@link Builder#setStaticIpv4Addresses}.
641 */
642 @Nullable
643 public LinkAddress getClientStaticIpv4Address() {
644 return mRequestParcel.staticClientAddress;
645 }
markchien62a625d2020-03-19 13:37:43 +0800646
junyulai25d64392020-03-23 10:47:42 +0800647 /** Get tethering type. */
648 @TetheringType
649 public int getTetheringType() {
650 return mRequestParcel.tetheringType;
651 }
markchien62a625d2020-03-19 13:37:43 +0800652
junyulai25d64392020-03-23 10:47:42 +0800653 /** Check if exempt from entitlement check. */
654 public boolean isExemptFromEntitlementCheck() {
655 return mRequestParcel.exemptFromEntitlementCheck;
656 }
markchien62a625d2020-03-19 13:37:43 +0800657
junyulai25d64392020-03-23 10:47:42 +0800658 /** Check if show entitlement ui. */
659 public boolean getShouldShowEntitlementUi() {
660 return mRequestParcel.showProvisioningUi;
markchien06889172020-01-20 19:31:56 +0800661 }
662
663 /**
Treehugger Robot86d212b2020-03-30 04:23:55 +0000664 * Check whether the two addresses are ipv4 and in the same prefix.
665 * @hide
666 */
667 public static boolean checkStaticAddressConfiguration(
668 @NonNull final LinkAddress localIPv4Address,
669 @NonNull final LinkAddress clientAddress) {
670 return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength()
671 && localIPv4Address.isIpv4() && clientAddress.isIpv4()
672 && new IpPrefix(localIPv4Address.toString()).equals(
673 new IpPrefix(clientAddress.toString()));
674 }
675
676 /**
markchien06889172020-01-20 19:31:56 +0800677 * Get a TetheringRequestParcel from the configuration
678 * @hide
679 */
680 public TetheringRequestParcel getParcel() {
681 return mRequestParcel;
682 }
683
684 /** String of TetheringRequest detail. */
685 public String toString() {
686 return "TetheringRequest [ type= " + mRequestParcel.tetheringType
687 + ", localIPv4Address= " + mRequestParcel.localIPv4Address
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000688 + ", staticClientAddress= " + mRequestParcel.staticClientAddress
markchien06889172020-01-20 19:31:56 +0800689 + ", exemptFromEntitlementCheck= "
690 + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
691 + mRequestParcel.showProvisioningUi + " ]";
692 }
693 }
694
695 /**
696 * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
697 */
markchien62a625d2020-03-19 13:37:43 +0800698 public interface StartTetheringCallback {
markchien06889172020-01-20 19:31:56 +0800699 /**
700 * Called when tethering has been successfully started.
701 */
markchien62a625d2020-03-19 13:37:43 +0800702 default void onTetheringStarted() {}
markchien06889172020-01-20 19:31:56 +0800703
704 /**
705 * Called when starting tethering failed.
706 *
markchien62a625d2020-03-19 13:37:43 +0800707 * @param error The error that caused the failure.
markchien06889172020-01-20 19:31:56 +0800708 */
markchien62a625d2020-03-19 13:37:43 +0800709 default void onTetheringFailed(@StartTetheringError final int error) {}
markchien06889172020-01-20 19:31:56 +0800710 }
711
712 /**
markchien0df2ebc42019-09-30 14:40:57 +0800713 * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
714 * fails, stopTethering will be called automatically.
markchien06889172020-01-20 19:31:56 +0800715 *
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.
markchien0df2ebc42019-09-30 14:40:57 +0800724 */
markchien06889172020-01-20 19:31:56 +0800725 @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) {
markchien6d06f6d2019-12-16 20:15:20 +0800731 final String callerPkg = mContext.getOpPackageName();
732 Log.i(TAG, "startTethering caller:" + callerPkg);
733
markchien06889172020-01-20 19:31:56 +0800734 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 };
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900746 getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
markchien0df2ebc42019-09-30 14:40:57 +0800747 }
748
749 /**
markchien06889172020-01-20 19:31:56 +0800750 * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
751 * fails, stopTethering will be called automatically.
752 *
753 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
754 * fail if a tethering entitlement check is required.
755 *
756 * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
757 * @param executor {@link Executor} to specify the thread upon which the callback of
758 * TetheringRequest will be invoked.
markchien11ee8132020-03-19 21:04:04 +0800759 * @hide
markchien06889172020-01-20 19:31:56 +0800760 */
761 @RequiresPermission(anyOf = {
762 android.Manifest.permission.TETHER_PRIVILEGED,
763 android.Manifest.permission.WRITE_SETTINGS
764 })
markchien11ee8132020-03-19 21:04:04 +0800765 @SystemApi(client = MODULE_LIBRARIES)
markchien06889172020-01-20 19:31:56 +0800766 public void startTethering(int type, @NonNull final Executor executor,
767 @NonNull final StartTetheringCallback callback) {
768 startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
769 }
770
771 /**
markchien0df2ebc42019-09-30 14:40:57 +0800772 * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
773 * applicable.
markchien06889172020-01-20 19:31:56 +0800774 *
775 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
776 * fail if a tethering entitlement check is required.
markchien0df2ebc42019-09-30 14:40:57 +0800777 */
markchien06889172020-01-20 19:31:56 +0800778 @RequiresPermission(anyOf = {
779 android.Manifest.permission.TETHER_PRIVILEGED,
780 android.Manifest.permission.WRITE_SETTINGS
781 })
markchien62a625d2020-03-19 13:37:43 +0800782 public void stopTethering(@TetheringType final int type) {
markchien6d06f6d2019-12-16 20:15:20 +0800783 final String callerPkg = mContext.getOpPackageName();
784 Log.i(TAG, "stopTethering caller:" + callerPkg);
785
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900786 getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
787 @Override
788 public void onResult(int resultCode) {
789 // TODO: provide an API to obtain result
790 // This has never been possible as stopTethering has always been void and never
791 // taken a callback object. The only indication that callers have is if the call
792 // results in a TETHER_STATE_CHANGE broadcast.
markchien6d06f6d2019-12-16 20:15:20 +0800793 }
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900794 }));
markchien0df2ebc42019-09-30 14:40:57 +0800795 }
796
797 /**
markchien75b6d7b2020-01-21 13:11:06 +0800798 * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
799 * entitlement succeeded.
800 */
801 public interface OnTetheringEntitlementResultListener {
802 /**
803 * Called to notify entitlement result.
804 *
805 * @param resultCode an int value of entitlement result. It may be one of
806 * {@link #TETHER_ERROR_NO_ERROR},
markchien62a625d2020-03-19 13:37:43 +0800807 * {@link #TETHER_ERROR_PROVISIONING_FAILED}, or
markchien75b6d7b2020-01-21 13:11:06 +0800808 * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
809 */
markchien62a625d2020-03-19 13:37:43 +0800810 void onTetheringEntitlementResult(@EntitlementResult int result);
markchien75b6d7b2020-01-21 13:11:06 +0800811 }
812
813 /**
markchien0df2ebc42019-09-30 14:40:57 +0800814 * Request the latest value of the tethering entitlement check.
815 *
markchien75b6d7b2020-01-21 13:11:06 +0800816 * <p>This method will only return the latest entitlement result if it is available. If no
817 * cached entitlement result is available, and {@code showEntitlementUi} is false,
818 * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is
819 * true, entitlement will be run.
820 *
markchien06889172020-01-20 19:31:56 +0800821 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
822 * fail if a tethering entitlement check is required.
823 *
markchien75b6d7b2020-01-21 13:11:06 +0800824 * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
markchien62a625d2020-03-19 13:37:43 +0800825 * @param showEntitlementUi a boolean indicating whether to check result for the UI-based
826 * entitlement check or the silent entitlement check.
markchien75b6d7b2020-01-21 13:11:06 +0800827 * @param executor the executor on which callback will be invoked.
828 * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
829 * notify the caller of the result of entitlement check. The listener may be called zero
830 * or one time.
831 */
markchien06889172020-01-20 19:31:56 +0800832 @RequiresPermission(anyOf = {
833 android.Manifest.permission.TETHER_PRIVILEGED,
834 android.Manifest.permission.WRITE_SETTINGS
835 })
markchien62a625d2020-03-19 13:37:43 +0800836 public void requestLatestTetheringEntitlementResult(@TetheringType int type,
837 boolean showEntitlementUi,
markchien75b6d7b2020-01-21 13:11:06 +0800838 @NonNull Executor executor,
839 @NonNull final OnTetheringEntitlementResultListener listener) {
840 if (listener == null) {
841 throw new IllegalArgumentException(
842 "OnTetheringEntitlementResultListener cannot be null.");
843 }
844
845 ResultReceiver wrappedListener = new ResultReceiver(null /* handler */) {
846 @Override
847 protected void onReceiveResult(int resultCode, Bundle resultData) {
848 executor.execute(() -> {
849 listener.onTetheringEntitlementResult(resultCode);
850 });
851 }
852 };
853
854 requestLatestTetheringEntitlementResult(type, wrappedListener,
855 showEntitlementUi);
856 }
857
858 /**
859 * Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
860 * with ConnectivityManager#getLatestTetheringEntitlementResult
861 *
862 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800863 */
864 // TODO: improve the usage of ResultReceiver, b/145096122
markchien2c153702020-02-06 19:23:26 +0800865 @SystemApi(client = MODULE_LIBRARIES)
markchien62a625d2020-03-19 13:37:43 +0800866 public void requestLatestTetheringEntitlementResult(@TetheringType final int type,
markchien6d06f6d2019-12-16 20:15:20 +0800867 @NonNull final ResultReceiver receiver, final boolean showEntitlementUi) {
868 final String callerPkg = mContext.getOpPackageName();
869 Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
870
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900871 getConnector(c -> c.requestLatestTetheringEntitlementResult(
872 type, receiver, showEntitlementUi, callerPkg));
markchien0df2ebc42019-09-30 14:40:57 +0800873 }
874
875 /**
markchien75b6d7b2020-01-21 13:11:06 +0800876 * Callback for use with {@link registerTetheringEventCallback} to find out tethering
877 * upstream status.
878 */
markchien62a625d2020-03-19 13:37:43 +0800879 public interface TetheringEventCallback {
markchien75b6d7b2020-01-21 13:11:06 +0800880 /**
881 * Called when tethering supported status changed.
882 *
883 * <p>This will be called immediately after the callback is registered, and may be called
884 * multiple times later upon changes.
885 *
886 * <p>Tethering may be disabled via system properties, device configuration, or device
887 * policy restrictions.
888 *
889 * @param supported The new supported status
890 */
markchien62a625d2020-03-19 13:37:43 +0800891 default void onTetheringSupported(boolean supported) {}
markchien75b6d7b2020-01-21 13:11:06 +0800892
893 /**
894 * Called when tethering upstream changed.
895 *
896 * <p>This will be called immediately after the callback is registered, and may be called
897 * multiple times later upon changes.
898 *
899 * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
900 * have any upstream.
901 */
markchien62a625d2020-03-19 13:37:43 +0800902 default void onUpstreamChanged(@Nullable Network network) {}
markchien75b6d7b2020-01-21 13:11:06 +0800903
904 /**
905 * Called when there was a change in tethering interface regular expressions.
906 *
907 * <p>This will be called immediately after the callback is registered, and may be called
908 * multiple times later upon changes.
909 * @param reg The new regular expressions.
markchien62a625d2020-03-19 13:37:43 +0800910 *
911 * @hide
markchien75b6d7b2020-01-21 13:11:06 +0800912 */
markchien62a625d2020-03-19 13:37:43 +0800913 @SystemApi(client = MODULE_LIBRARIES)
914 default void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
markchien75b6d7b2020-01-21 13:11:06 +0800915
916 /**
markchien62a625d2020-03-19 13:37:43 +0800917 * Called when there was a change in the list of tetherable interfaces. Tetherable
918 * interface means this interface is available and can be used for tethering.
markchien75b6d7b2020-01-21 13:11:06 +0800919 *
920 * <p>This will be called immediately after the callback is registered, and may be called
921 * multiple times later upon changes.
markchien62a625d2020-03-19 13:37:43 +0800922 * @param interfaces The list of tetherable interface names.
markchien75b6d7b2020-01-21 13:11:06 +0800923 */
markchien62a625d2020-03-19 13:37:43 +0800924 default void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
markchien75b6d7b2020-01-21 13:11:06 +0800925
926 /**
927 * Called when there was a change in the list of tethered interfaces.
928 *
929 * <p>This will be called immediately after the callback is registered, and may be called
930 * multiple times later upon changes.
markchien62a625d2020-03-19 13:37:43 +0800931 * @param interfaces The list of 0 or more String of currently tethered interface names.
markchien75b6d7b2020-01-21 13:11:06 +0800932 */
markchien62a625d2020-03-19 13:37:43 +0800933 default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
markchien75b6d7b2020-01-21 13:11:06 +0800934
935 /**
936 * Called when an error occurred configuring tethering.
937 *
938 * <p>This will be called immediately after the callback is registered if the latest status
939 * on the interface is an error, and may be called multiple times later upon changes.
940 * @param ifName Name of the interface.
941 * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
942 */
markchien62a625d2020-03-19 13:37:43 +0800943 default void onError(@NonNull String ifName, @TetheringIfaceError int error) {}
Remi NGUYEN VANbfc910c2020-01-20 21:26:34 +0900944
945 /**
946 * Called when the list of tethered clients changes.
947 *
948 * <p>This callback provides best-effort information on connected clients based on state
949 * known to the system, however the list cannot be completely accurate (and should not be
950 * used for security purposes). For example, clients behind a bridge and using static IP
951 * assignments are not visible to the tethering device; or even when using DHCP, such
952 * clients may still be reported by this callback after disconnection as the system cannot
953 * determine if they are still connected.
954 * @param clients The new set of tethered clients; the collection is not ordered.
955 */
markchien62a625d2020-03-19 13:37:43 +0800956 default void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +0000957
958 /**
959 * Called when tethering offload status changes.
960 *
961 * <p>This will be called immediately after the callback is registered.
962 * @param status The offload status.
963 */
markchien62a625d2020-03-19 13:37:43 +0800964 default void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
markchien75b6d7b2020-01-21 13:11:06 +0800965 }
966
967 /**
968 * Regular expressions used to identify tethering interfaces.
markchien62a625d2020-03-19 13:37:43 +0800969 * @hide
markchien75b6d7b2020-01-21 13:11:06 +0800970 */
markchien62a625d2020-03-19 13:37:43 +0800971 @SystemApi(client = MODULE_LIBRARIES)
markchien75b6d7b2020-01-21 13:11:06 +0800972 public static class TetheringInterfaceRegexps {
973 private final String[] mTetherableBluetoothRegexs;
974 private final String[] mTetherableUsbRegexs;
975 private final String[] mTetherableWifiRegexs;
976
markchien62a625d2020-03-19 13:37:43 +0800977 /** @hide */
markchien75b6d7b2020-01-21 13:11:06 +0800978 public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
979 @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
980 mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
981 mTetherableUsbRegexs = tetherableUsbRegexs.clone();
982 mTetherableWifiRegexs = tetherableWifiRegexs.clone();
983 }
984
985 @NonNull
986 public List<String> getTetherableBluetoothRegexs() {
987 return Collections.unmodifiableList(Arrays.asList(mTetherableBluetoothRegexs));
988 }
989
990 @NonNull
991 public List<String> getTetherableUsbRegexs() {
992 return Collections.unmodifiableList(Arrays.asList(mTetherableUsbRegexs));
993 }
994
995 @NonNull
996 public List<String> getTetherableWifiRegexs() {
997 return Collections.unmodifiableList(Arrays.asList(mTetherableWifiRegexs));
998 }
999
1000 @Override
1001 public int hashCode() {
1002 return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
1003 mTetherableWifiRegexs);
1004 }
1005
1006 @Override
1007 public boolean equals(@Nullable Object obj) {
1008 if (!(obj instanceof TetheringInterfaceRegexps)) return false;
1009 final TetheringInterfaceRegexps other = (TetheringInterfaceRegexps) obj;
1010 return Arrays.equals(mTetherableBluetoothRegexs, other.mTetherableBluetoothRegexs)
1011 && Arrays.equals(mTetherableUsbRegexs, other.mTetherableUsbRegexs)
1012 && Arrays.equals(mTetherableWifiRegexs, other.mTetherableWifiRegexs);
1013 }
1014 }
1015
1016 /**
markchien6d06f6d2019-12-16 20:15:20 +08001017 * Start listening to tethering change events. Any new added callback will receive the last
1018 * tethering status right away. If callback is registered,
markchien75b6d7b2020-01-21 13:11:06 +08001019 * {@link TetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
markchien6d06f6d2019-12-16 20:15:20 +08001020 * has no upstream or disabled, the argument of callback will be null. The same callback object
1021 * cannot be registered twice.
markchien0df2ebc42019-09-30 14:40:57 +08001022 *
markchien6d06f6d2019-12-16 20:15:20 +08001023 * @param executor the executor on which callback will be invoked.
1024 * @param callback the callback to be called when tethering has change events.
markchien0df2ebc42019-09-30 14:40:57 +08001025 */
markchien06889172020-01-20 19:31:56 +08001026 @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
markchien6d06f6d2019-12-16 20:15:20 +08001027 public void registerTetheringEventCallback(@NonNull Executor executor,
markchien75b6d7b2020-01-21 13:11:06 +08001028 @NonNull TetheringEventCallback callback) {
markchien6d06f6d2019-12-16 20:15:20 +08001029 final String callerPkg = mContext.getOpPackageName();
1030 Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg);
1031
1032 synchronized (mTetheringEventCallbacks) {
markchien75b6d7b2020-01-21 13:11:06 +08001033 if (mTetheringEventCallbacks.containsKey(callback)) {
markchien6d06f6d2019-12-16 20:15:20 +08001034 throw new IllegalArgumentException("callback was already registered.");
1035 }
1036 final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
markchien75b6d7b2020-01-21 13:11:06 +08001037 // Only accessed with a lock on this object
1038 private final HashMap<String, Integer> mErrorStates = new HashMap<>();
1039 private String[] mLastTetherableInterfaces = null;
1040 private String[] mLastTetheredInterfaces = null;
1041
markchien6d06f6d2019-12-16 20:15:20 +08001042 @Override
1043 public void onUpstreamChanged(Network network) throws RemoteException {
1044 executor.execute(() -> {
1045 callback.onUpstreamChanged(network);
1046 });
1047 }
1048
markchien75b6d7b2020-01-21 13:11:06 +08001049 private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
1050 for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
1051 final String iface = newStates.erroredIfaceList[i];
1052 final Integer lastError = mErrorStates.get(iface);
1053 final int newError = newStates.lastErrorList[i];
1054 if (newError != TETHER_ERROR_NO_ERROR
1055 && !Objects.equals(lastError, newError)) {
1056 callback.onError(iface, newError);
1057 }
1058 mErrorStates.put(iface, newError);
1059 }
1060 }
1061
1062 private synchronized void maybeSendTetherableIfacesChangedCallback(
1063 final TetherStatesParcel newStates) {
1064 if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
1065 mLastTetherableInterfaces = newStates.availableList.clone();
1066 callback.onTetherableInterfacesChanged(
1067 Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
1068 }
1069
1070 private synchronized void maybeSendTetheredIfacesChangedCallback(
1071 final TetherStatesParcel newStates) {
1072 if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
1073 mLastTetheredInterfaces = newStates.tetheredList.clone();
1074 callback.onTetheredInterfacesChanged(
1075 Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
1076 }
1077
1078 // Called immediately after the callbacks are registered.
markchien6d06f6d2019-12-16 20:15:20 +08001079 @Override
markchien75b6d7b2020-01-21 13:11:06 +08001080 public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
markchien6d06f6d2019-12-16 20:15:20 +08001081 executor.execute(() -> {
markchien75b6d7b2020-01-21 13:11:06 +08001082 callback.onTetheringSupported(parcel.tetheringSupported);
1083 callback.onUpstreamChanged(parcel.upstreamNetwork);
1084 sendErrorCallbacks(parcel.states);
1085 sendRegexpsChanged(parcel.config);
1086 maybeSendTetherableIfacesChangedCallback(parcel.states);
1087 maybeSendTetheredIfacesChangedCallback(parcel.states);
Remi NGUYEN VAN43b0e5c2020-02-13 09:16:19 +09001088 callback.onClientsChanged(parcel.tetheredClients);
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +00001089 callback.onOffloadStatusChanged(parcel.offloadStatus);
markchien6d06f6d2019-12-16 20:15:20 +08001090 });
1091 }
1092
1093 @Override
1094 public void onCallbackStopped(int errorCode) {
1095 executor.execute(() -> {
1096 throwIfPermissionFailure(errorCode);
1097 });
1098 }
1099
markchien75b6d7b2020-01-21 13:11:06 +08001100 private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
1101 callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
1102 parcel.tetherableBluetoothRegexs,
1103 parcel.tetherableUsbRegexs,
1104 parcel.tetherableWifiRegexs));
1105 }
markchien6d06f6d2019-12-16 20:15:20 +08001106
1107 @Override
markchien75b6d7b2020-01-21 13:11:06 +08001108 public void onConfigurationChanged(TetheringConfigurationParcel config) {
1109 executor.execute(() -> sendRegexpsChanged(config));
1110 }
1111
1112 @Override
1113 public void onTetherStatesChanged(TetherStatesParcel states) {
1114 executor.execute(() -> {
1115 sendErrorCallbacks(states);
1116 maybeSendTetherableIfacesChangedCallback(states);
1117 maybeSendTetheredIfacesChangedCallback(states);
1118 });
1119 }
Remi NGUYEN VAN43b0e5c2020-02-13 09:16:19 +09001120
1121 @Override
1122 public void onTetherClientsChanged(final List<TetheredClient> clients) {
1123 executor.execute(() -> callback.onClientsChanged(clients));
1124 }
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +00001125
1126 @Override
1127 public void onOffloadStatusChanged(final int status) {
1128 executor.execute(() -> callback.onOffloadStatusChanged(status));
1129 }
markchien6d06f6d2019-12-16 20:15:20 +08001130 };
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001131 getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
markchien6d06f6d2019-12-16 20:15:20 +08001132 mTetheringEventCallbacks.put(callback, remoteCallback);
1133 }
markchien0df2ebc42019-09-30 14:40:57 +08001134 }
1135
1136 /**
markchien6d06f6d2019-12-16 20:15:20 +08001137 * Remove tethering event callback previously registered with
1138 * {@link #registerTetheringEventCallback}.
markchien0df2ebc42019-09-30 14:40:57 +08001139 *
markchien6d06f6d2019-12-16 20:15:20 +08001140 * @param callback previously registered callback.
markchien0df2ebc42019-09-30 14:40:57 +08001141 */
markchien06889172020-01-20 19:31:56 +08001142 @RequiresPermission(anyOf = {
1143 Manifest.permission.TETHER_PRIVILEGED,
1144 Manifest.permission.ACCESS_NETWORK_STATE
1145 })
markchien75b6d7b2020-01-21 13:11:06 +08001146 public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) {
markchien6d06f6d2019-12-16 20:15:20 +08001147 final String callerPkg = mContext.getOpPackageName();
1148 Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg);
1149
1150 synchronized (mTetheringEventCallbacks) {
1151 ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback);
1152 if (remoteCallback == null) {
1153 throw new IllegalArgumentException("callback was not registered.");
1154 }
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001155
1156 getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
markchien6d06f6d2019-12-16 20:15:20 +08001157 }
markchien0df2ebc42019-09-30 14:40:57 +08001158 }
1159
1160 /**
1161 * Get a more detailed error code after a Tethering or Untethering
1162 * request asynchronously failed.
1163 *
markchien6d06f6d2019-12-16 20:15:20 +08001164 * @param iface The name of the interface of interest
1165 * @return error The error code of the last error tethering or untethering the named
1166 * interface
markchien75b6d7b2020-01-21 13:11:06 +08001167 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001168 */
markchien2c153702020-02-06 19:23:26 +08001169 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +08001170 public int getLastTetherError(@NonNull final String iface) {
1171 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001172 if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
1173
1174 int i = 0;
1175 for (String errored : mTetherStatesParcel.erroredIfaceList) {
1176 if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
1177
1178 i++;
1179 }
1180 return TETHER_ERROR_NO_ERROR;
1181 }
1182
1183 /**
1184 * Get the list of regular expressions that define any tetherable
1185 * USB network interfaces. If USB tethering is not supported by the
1186 * device, this list should be empty.
1187 *
markchien6d06f6d2019-12-16 20:15:20 +08001188 * @return an array of 0 or more regular expression Strings defining
1189 * what interfaces are considered tetherable usb interfaces.
markchien75b6d7b2020-01-21 13:11:06 +08001190 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001191 */
markchien2c153702020-02-06 19:23:26 +08001192 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001193 public @NonNull String[] getTetherableUsbRegexs() {
markchien6d06f6d2019-12-16 20:15:20 +08001194 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001195 return mTetheringConfiguration.tetherableUsbRegexs;
1196 }
1197
1198 /**
1199 * Get the list of regular expressions that define any tetherable
1200 * Wifi network interfaces. If Wifi tethering is not supported by the
1201 * device, this list should be empty.
1202 *
markchien6d06f6d2019-12-16 20:15:20 +08001203 * @return an array of 0 or more regular expression Strings defining
1204 * what interfaces are considered tetherable wifi interfaces.
markchien75b6d7b2020-01-21 13:11:06 +08001205 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001206 */
markchien2c153702020-02-06 19:23:26 +08001207 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001208 public @NonNull String[] getTetherableWifiRegexs() {
markchien6d06f6d2019-12-16 20:15:20 +08001209 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001210 return mTetheringConfiguration.tetherableWifiRegexs;
1211 }
1212
1213 /**
1214 * Get the list of regular expressions that define any tetherable
1215 * Bluetooth network interfaces. If Bluetooth tethering is not supported by the
1216 * device, this list should be empty.
1217 *
markchien6d06f6d2019-12-16 20:15:20 +08001218 * @return an array of 0 or more regular expression Strings defining
1219 * what interfaces are considered tetherable bluetooth interfaces.
markchien75b6d7b2020-01-21 13:11:06 +08001220 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001221 */
markchien2c153702020-02-06 19:23:26 +08001222 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001223 public @NonNull String[] getTetherableBluetoothRegexs() {
markchien6d06f6d2019-12-16 20:15:20 +08001224 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001225 return mTetheringConfiguration.tetherableBluetoothRegexs;
1226 }
1227
1228 /**
1229 * Get the set of tetherable, available interfaces. This list is limited by
1230 * device configuration and current interface existence.
1231 *
markchien6d06f6d2019-12-16 20:15:20 +08001232 * @return an array of 0 or more Strings of tetherable interface names.
markchien75b6d7b2020-01-21 13:11:06 +08001233 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001234 */
markchien2c153702020-02-06 19:23:26 +08001235 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001236 public @NonNull String[] getTetherableIfaces() {
markchien6d06f6d2019-12-16 20:15:20 +08001237 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001238 if (mTetherStatesParcel == null) return new String[0];
markchien6d06f6d2019-12-16 20:15:20 +08001239
markchien0df2ebc42019-09-30 14:40:57 +08001240 return mTetherStatesParcel.availableList;
1241 }
1242
1243 /**
1244 * Get the set of tethered interfaces.
1245 *
markchien6d06f6d2019-12-16 20:15:20 +08001246 * @return an array of 0 or more String of currently tethered interface names.
markchien75b6d7b2020-01-21 13:11:06 +08001247 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001248 */
markchien2c153702020-02-06 19:23:26 +08001249 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001250 public @NonNull String[] getTetheredIfaces() {
markchien6d06f6d2019-12-16 20:15:20 +08001251 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001252 if (mTetherStatesParcel == null) return new String[0];
markchien6d06f6d2019-12-16 20:15:20 +08001253
markchien0df2ebc42019-09-30 14:40:57 +08001254 return mTetherStatesParcel.tetheredList;
1255 }
1256
1257 /**
1258 * Get the set of interface names which attempted to tether but
markchien6d06f6d2019-12-16 20:15:20 +08001259 * failed. Re-attempting to tether may cause them to reset to the Tethered
1260 * state. Alternatively, causing the interface to be destroyed and recreated
1261 * may cause them to reset to the available state.
markchien9e44cde2019-12-25 19:40:32 +08001262 * {@link TetheringManager#getLastTetherError} can be used to get more
markchien6d06f6d2019-12-16 20:15:20 +08001263 * information on the cause of the errors.
markchien0df2ebc42019-09-30 14:40:57 +08001264 *
markchien6d06f6d2019-12-16 20:15:20 +08001265 * @return an array of 0 or more String indicating the interface names
1266 * which failed to tether.
markchien75b6d7b2020-01-21 13:11:06 +08001267 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001268 */
markchien2c153702020-02-06 19:23:26 +08001269 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001270 public @NonNull String[] getTetheringErroredIfaces() {
markchien6d06f6d2019-12-16 20:15:20 +08001271 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001272 if (mTetherStatesParcel == null) return new String[0];
markchien6d06f6d2019-12-16 20:15:20 +08001273
markchien0df2ebc42019-09-30 14:40:57 +08001274 return mTetherStatesParcel.erroredIfaceList;
1275 }
1276
1277 /**
1278 * Get the set of tethered dhcp ranges.
1279 *
markchienb741c642019-11-27 21:20:33 +08001280 * @deprecated This API just return the default value which is not used in DhcpServer.
markchien75b6d7b2020-01-21 13:11:06 +08001281 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001282 */
markchienb741c642019-11-27 21:20:33 +08001283 @Deprecated
markchien0df2ebc42019-09-30 14:40:57 +08001284 public @NonNull String[] getTetheredDhcpRanges() {
markchien6d06f6d2019-12-16 20:15:20 +08001285 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001286 return mTetheringConfiguration.legacyDhcpRanges;
1287 }
1288
1289 /**
markchien6d06f6d2019-12-16 20:15:20 +08001290 * Check if the device allows for tethering. It may be disabled via
1291 * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
1292 * due to device configuration.
markchien0df2ebc42019-09-30 14:40:57 +08001293 *
markchien6d06f6d2019-12-16 20:15:20 +08001294 * @return a boolean - {@code true} indicating Tethering is supported.
markchien75b6d7b2020-01-21 13:11:06 +08001295 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001296 */
markchien2c153702020-02-06 19:23:26 +08001297 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +08001298 public boolean isTetheringSupported() {
1299 final String callerPkg = mContext.getOpPackageName();
markchien0df2ebc42019-09-30 14:40:57 +08001300
Automerger Merge Workerfcf74d12020-03-03 12:51:02 +00001301 return isTetheringSupported(callerPkg);
1302 }
1303
1304 /**
1305 * Check if the device allows for tethering. It may be disabled via {@code ro.tether.denied}
1306 * system property, Settings.TETHER_SUPPORTED or due to device configuration. This is useful
1307 * for system components that query this API on behalf of an app. In particular, Bluetooth
1308 * has @UnsupportedAppUsage calls that will let apps turn on bluetooth tethering if they have
1309 * the right permissions, but such an app needs to know whether it can (permissions as well
1310 * as support from the device) turn on tethering in the first place to show the appropriate UI.
1311 *
1312 * @param callerPkg The caller package name, if it is not matching the calling uid,
1313 * SecurityException would be thrown.
1314 * @return a boolean - {@code true} indicating Tethering is supported.
1315 * @hide
1316 */
1317 @SystemApi(client = MODULE_LIBRARIES)
1318 public boolean isTetheringSupported(@NonNull final String callerPkg) {
1319
markchien6d06f6d2019-12-16 20:15:20 +08001320 final RequestDispatcher dispatcher = new RequestDispatcher();
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001321 final int ret = dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +08001322 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001323 connector.isTetheringSupported(callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +08001324 } catch (RemoteException e) {
1325 throw new IllegalStateException(e);
1326 }
1327 });
1328
1329 return ret == TETHER_ERROR_NO_ERROR;
markchien0df2ebc42019-09-30 14:40:57 +08001330 }
1331
1332 /**
markchien6d06f6d2019-12-16 20:15:20 +08001333 * Stop all active tethering.
markchien06889172020-01-20 19:31:56 +08001334 *
1335 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
1336 * fail if a tethering entitlement check is required.
markchien0df2ebc42019-09-30 14:40:57 +08001337 */
markchien06889172020-01-20 19:31:56 +08001338 @RequiresPermission(anyOf = {
1339 android.Manifest.permission.TETHER_PRIVILEGED,
1340 android.Manifest.permission.WRITE_SETTINGS
1341 })
markchien6d06f6d2019-12-16 20:15:20 +08001342 public void stopAllTethering() {
1343 final String callerPkg = mContext.getOpPackageName();
1344 Log.i(TAG, "stopAllTethering caller:" + callerPkg);
markchien0df2ebc42019-09-30 14:40:57 +08001345
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001346 getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
1347 @Override
1348 public void onResult(int resultCode) {
1349 // TODO: add an API parameter to send result to caller.
1350 // This has never been possible as stopAllTethering has always been void and never
1351 // taken a callback object. The only indication that callers have is if the call
1352 // results in a TETHER_STATE_CHANGE broadcast.
markchien6d06f6d2019-12-16 20:15:20 +08001353 }
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001354 }));
markchien0df2ebc42019-09-30 14:40:57 +08001355 }
1356}