blob: cc095a0bb4a7829175313db13269d0f97347a6f3 [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
markchien62a625d2020-03-19 13:37:43 +0800174 /** @hide */
175 @Retention(RetentionPolicy.SOURCE)
176 @IntDef(value = {
177 TETHER_ERROR_NO_ERROR,
178 TETHER_ERROR_PROVISIONING_FAILED,
179 TETHER_ERROR_ENTITLEMENT_UNKNOWN,
180 })
181 public @interface EntitlementResult {
182 }
183
184 /** @hide */
185 @Retention(RetentionPolicy.SOURCE)
186 @IntDef(value = {
187 TETHER_ERROR_NO_ERROR,
188 TETHER_ERROR_UNKNOWN_IFACE,
189 TETHER_ERROR_SERVICE_UNAVAIL,
190 TETHER_ERROR_INTERNAL_ERROR,
191 TETHER_ERROR_TETHER_IFACE_ERROR,
192 TETHER_ERROR_ENABLE_FORWARDING_ERROR,
193 TETHER_ERROR_DISABLE_FORWARDING_ERROR,
194 TETHER_ERROR_IFACE_CFG_ERROR,
195 TETHER_ERROR_DHCPSERVER_ERROR,
196 })
197 public @interface TetheringIfaceError {
198 }
199
200 /** @hide */
201 @Retention(RetentionPolicy.SOURCE)
202 @IntDef(value = {
203 TETHER_ERROR_SERVICE_UNAVAIL,
204 TETHER_ERROR_INTERNAL_ERROR,
205 TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION,
206 TETHER_ERROR_UNKNOWN_TYPE,
207 })
208 public @interface StartTetheringError {
209 }
210
211 public static final int TETHER_ERROR_NO_ERROR = 0;
212 public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
213 public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
214 public static final int TETHER_ERROR_UNSUPPORTED = 3;
215 public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
216 public static final int TETHER_ERROR_INTERNAL_ERROR = 5;
markchien6d06f6d2019-12-16 20:15:20 +0800217 public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
218 public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
markchien62a625d2020-03-19 13:37:43 +0800219 public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8;
220 public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9;
221 public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
222 public static final int TETHER_ERROR_PROVISIONING_FAILED = 11;
223 public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
markchien75b6d7b2020-01-21 13:11:06 +0800224 public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
markchien6d06f6d2019-12-16 20:15:20 +0800225 public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
226 public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
markchien62a625d2020-03-19 13:37:43 +0800227 public static final int TETHER_ERROR_UNKNOWN_TYPE = 16;
markchien0df2ebc42019-09-30 14:40:57 +0800228
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +0000229 /** @hide */
230 @Retention(RetentionPolicy.SOURCE)
231 @IntDef(flag = false, value = {
232 TETHER_HARDWARE_OFFLOAD_STOPPED,
233 TETHER_HARDWARE_OFFLOAD_STARTED,
234 TETHER_HARDWARE_OFFLOAD_FAILED,
235 })
236 public @interface TetherOffloadStatus {
237 }
238
239 /** Tethering offload status is stopped. */
240 public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0;
241 /** Tethering offload status is started. */
242 public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1;
243 /** Fail to start tethering offload. */
244 public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2;
245
markchien0df2ebc42019-09-30 14:40:57 +0800246 /**
markchien6d06f6d2019-12-16 20:15:20 +0800247 * Create a TetheringManager object for interacting with the tethering service.
markchien75b6d7b2020-01-21 13:11:06 +0800248 *
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900249 * @param context Context for the manager.
250 * @param connectorSupplier Supplier for the manager connector; may return null while the
251 * service is not connected.
markchien75b6d7b2020-01-21 13:11:06 +0800252 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800253 */
markchien2c153702020-02-06 19:23:26 +0800254 @SystemApi(client = MODULE_LIBRARIES)
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900255 public TetheringManager(@NonNull final Context context,
256 @NonNull Supplier<IBinder> connectorSupplier) {
markchien6d06f6d2019-12-16 20:15:20 +0800257 mContext = context;
markchien6d06f6d2019-12-16 20:15:20 +0800258 mCallback = new TetheringCallbackInternal();
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900259 mConnectorSupplier = connectorSupplier;
markchien0df2ebc42019-09-30 14:40:57 +0800260
markchien6d06f6d2019-12-16 20:15:20 +0800261 final String pkgName = mContext.getOpPackageName();
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900262
263 final IBinder connector = mConnectorSupplier.get();
264 // If the connector is available on start, do not start a polling thread. This introduces
265 // differences in the thread that sends the oneway binder calls to the service between the
266 // first few seconds after boot and later, but it avoids always having differences between
267 // the first usage of TetheringManager from a process and subsequent usages (so the
268 // difference is only on boot). On boot binder calls may be queued until the service comes
269 // up and be sent from a worker thread; later, they are always sent from the caller thread.
270 // Considering that it's just oneway binder calls, and ordering is preserved, this seems
271 // better than inconsistent behavior persisting after boot.
272 if (connector != null) {
273 mConnector = ITetheringConnector.Stub.asInterface(connector);
274 } else {
275 startPollingForConnector();
276 }
277
markchien6d06f6d2019-12-16 20:15:20 +0800278 Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900279 getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
280 }
281
282 private void startPollingForConnector() {
283 new Thread(() -> {
284 while (true) {
285 try {
Amos Bianchi2fc17472020-02-13 15:54:45 -0800286 Thread.sleep(CONNECTOR_POLL_INTERVAL_MILLIS);
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900287 } catch (InterruptedException e) {
288 // Not much to do here, the system needs to wait for the connector
289 }
290
291 final IBinder connector = mConnectorSupplier.get();
292 if (connector != null) {
293 onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
294 return;
295 }
296 }
297 }).start();
298 }
299
300 private interface ConnectorConsumer {
301 void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
302 }
303
304 private void onTetheringConnected(ITetheringConnector connector) {
305 // Process the connector wait queue in order, including any items that are added
306 // while processing.
307 //
308 // 1. Copy the queue to a local variable under lock.
309 // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
310 // would block on the lock).
311 // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
312 // If not, set mConnector to non-null so future tasks are run immediately, not queued.
313 //
314 // For this to work, all calls to the tethering service must use getConnector(), which
315 // ensures that tasks are added to the queue with the lock held.
316 //
317 // Once mConnector is set to non-null, it will never be null again. If the network stack
318 // process crashes, no recovery is possible.
319 // TODO: evaluate whether it is possible to recover from network stack process crashes
320 // (though in most cases the system will have crashed when the network stack process
321 // crashes).
322 do {
323 final List<ConnectorConsumer> localWaitQueue;
324 synchronized (mConnectorWaitQueue) {
325 localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
326 mConnectorWaitQueue.clear();
327 }
328
329 // Allow more tasks to be added at the end without blocking while draining the queue.
330 for (ConnectorConsumer task : localWaitQueue) {
331 try {
332 task.onConnectorAvailable(connector);
333 } catch (RemoteException e) {
334 // Most likely the network stack process crashed, which is likely to crash the
335 // system. Keep processing other requests but report the error loudly.
336 Log.wtf(TAG, "Error processing request for the tethering connector", e);
337 }
338 }
339
340 synchronized (mConnectorWaitQueue) {
341 if (mConnectorWaitQueue.size() == 0) {
342 mConnector = connector;
343 return;
344 }
345 }
346 } while (true);
347 }
348
349 /**
350 * Asynchronously get the ITetheringConnector to execute some operation.
351 *
352 * <p>If the connector is already available, the operation will be executed on the caller's
353 * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
354 * limited to performing oneway binder calls to minimize differences due to threading.
355 */
356 private void getConnector(ConnectorConsumer consumer) {
357 final ITetheringConnector connector;
358 synchronized (mConnectorWaitQueue) {
359 connector = mConnector;
360 if (connector == null) {
361 mConnectorWaitQueue.add(consumer);
362 return;
363 }
364 }
365
markchien0df2ebc42019-09-30 14:40:57 +0800366 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900367 consumer.onConnectorAvailable(connector);
markchien0df2ebc42019-09-30 14:40:57 +0800368 } catch (RemoteException e) {
markchien6d06f6d2019-12-16 20:15:20 +0800369 throw new IllegalStateException(e);
markchien0df2ebc42019-09-30 14:40:57 +0800370 }
371 }
372
markchien6d06f6d2019-12-16 20:15:20 +0800373 private interface RequestHelper {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900374 void runRequest(ITetheringConnector connector, IIntResultListener listener);
markchien6d06f6d2019-12-16 20:15:20 +0800375 }
376
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900377 // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
378 // return results and perform operations synchronously.
379 // TODO: remove once there are no callers of these legacy methods.
markchien6d06f6d2019-12-16 20:15:20 +0800380 private class RequestDispatcher {
381 private final ConditionVariable mWaiting;
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900382 public volatile int mRemoteResult;
markchien6d06f6d2019-12-16 20:15:20 +0800383
384 private final IIntResultListener mListener = new IIntResultListener.Stub() {
385 @Override
386 public void onResult(final int resultCode) {
387 mRemoteResult = resultCode;
388 mWaiting.open();
389 }
390 };
391
392 RequestDispatcher() {
393 mWaiting = new ConditionVariable();
394 }
395
396 int waitForResult(final RequestHelper request) {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900397 getConnector(c -> request.runRequest(c, mListener));
markchien6d06f6d2019-12-16 20:15:20 +0800398 if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
399 throw new IllegalStateException("Callback timeout");
400 }
401
402 throwIfPermissionFailure(mRemoteResult);
403
404 return mRemoteResult;
405 }
406 }
407
408 private void throwIfPermissionFailure(final int errorCode) {
409 switch (errorCode) {
410 case TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION:
411 throw new SecurityException("No android.permission.TETHER_PRIVILEGED"
412 + " or android.permission.WRITE_SETTINGS permission");
413 case TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION:
414 throw new SecurityException(
415 "No android.permission.ACCESS_NETWORK_STATE permission");
416 }
417 }
418
419 private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900420 private volatile int mError = TETHER_ERROR_NO_ERROR;
markchien6d06f6d2019-12-16 20:15:20 +0800421 private final ConditionVariable mWaitForCallback = new ConditionVariable();
markchien0df2ebc42019-09-30 14:40:57 +0800422
423 @Override
markchien75b6d7b2020-01-21 13:11:06 +0800424 public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
425 mTetheringConfiguration = parcel.config;
426 mTetherStatesParcel = parcel.states;
markchien6d06f6d2019-12-16 20:15:20 +0800427 mWaitForCallback.open();
markchien0df2ebc42019-09-30 14:40:57 +0800428 }
429
430 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800431 public void onCallbackStopped(int errorCode) {
432 mError = errorCode;
433 mWaitForCallback.open();
434 }
435
436 @Override
437 public void onUpstreamChanged(Network network) { }
438
439 @Override
markchien0df2ebc42019-09-30 14:40:57 +0800440 public void onConfigurationChanged(TetheringConfigurationParcel config) {
441 mTetheringConfiguration = config;
442 }
443
444 @Override
445 public void onTetherStatesChanged(TetherStatesParcel states) {
446 mTetherStatesParcel = states;
447 }
448
Remi NGUYEN VAN43b0e5c2020-02-13 09:16:19 +0900449 @Override
450 public void onTetherClientsChanged(List<TetheredClient> clients) { }
451
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +0000452 @Override
453 public void onOffloadStatusChanged(int status) { }
454
markchien6d06f6d2019-12-16 20:15:20 +0800455 public void waitForStarted() {
456 mWaitForCallback.block(DEFAULT_TIMEOUT_MS);
457 throwIfPermissionFailure(mError);
markchien0df2ebc42019-09-30 14:40:57 +0800458 }
markchien0df2ebc42019-09-30 14:40:57 +0800459 }
460
461 /**
462 * Attempt to tether the named interface. This will setup a dhcp server
463 * on the interface, forward and NAT IP v4 packets and forward DNS requests
464 * to the best active upstream network interface. Note that if no upstream
465 * IP network interface is available, dhcp will still run and traffic will be
466 * allowed between the tethered devices and this device, though upstream net
467 * access will of course fail until an upstream network interface becomes
markchien6d06f6d2019-12-16 20:15:20 +0800468 * active.
markchien0df2ebc42019-09-30 14:40:57 +0800469 *
markchien6d06f6d2019-12-16 20:15:20 +0800470 * @deprecated The only usages is PanService. It uses this for legacy reasons
471 * and will migrate away as soon as possible.
markchien0df2ebc42019-09-30 14:40:57 +0800472 *
markchien6d06f6d2019-12-16 20:15:20 +0800473 * @param iface the interface name to tether.
474 * @return error a {@code TETHER_ERROR} value indicating success or failure type
markchien75b6d7b2020-01-21 13:11:06 +0800475 *
476 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800477 */
markchienb741c642019-11-27 21:20:33 +0800478 @Deprecated
markchien2c153702020-02-06 19:23:26 +0800479 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +0800480 public int tether(@NonNull final String iface) {
481 final String callerPkg = mContext.getOpPackageName();
482 Log.i(TAG, "tether caller:" + callerPkg);
483 final RequestDispatcher dispatcher = new RequestDispatcher();
484
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900485 return dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +0800486 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900487 connector.tether(iface, callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +0800488 } catch (RemoteException e) {
489 throw new IllegalStateException(e);
490 }
491 });
markchien0df2ebc42019-09-30 14:40:57 +0800492 }
493
494 /**
495 * Stop tethering the named interface.
496 *
markchien6d06f6d2019-12-16 20:15:20 +0800497 * @deprecated The only usages is PanService. It uses this for legacy reasons
498 * and will migrate away as soon as possible.
markchien75b6d7b2020-01-21 13:11:06 +0800499 *
500 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800501 */
markchienb741c642019-11-27 21:20:33 +0800502 @Deprecated
markchien2c153702020-02-06 19:23:26 +0800503 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +0800504 public int untether(@NonNull final String iface) {
505 final String callerPkg = mContext.getOpPackageName();
506 Log.i(TAG, "untether caller:" + callerPkg);
507
508 final RequestDispatcher dispatcher = new RequestDispatcher();
509
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900510 return dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +0800511 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900512 connector.untether(iface, callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +0800513 } catch (RemoteException e) {
514 throw new IllegalStateException(e);
515 }
516 });
markchien0df2ebc42019-09-30 14:40:57 +0800517 }
518
519 /**
markchien6d06f6d2019-12-16 20:15:20 +0800520 * Attempt to both alter the mode of USB and Tethering of USB.
markchien0df2ebc42019-09-30 14:40:57 +0800521 *
markchien6d06f6d2019-12-16 20:15:20 +0800522 * @deprecated New client should not use this API anymore. All clients should use
523 * #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
524 * used and an entitlement check is needed, downstream USB tethering will be enabled but will
525 * not have any upstream.
markchien75b6d7b2020-01-21 13:11:06 +0800526 *
527 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800528 */
markchienb741c642019-11-27 21:20:33 +0800529 @Deprecated
markchien2c153702020-02-06 19:23:26 +0800530 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +0800531 public int setUsbTethering(final boolean enable) {
532 final String callerPkg = mContext.getOpPackageName();
533 Log.i(TAG, "setUsbTethering caller:" + callerPkg);
534
535 final RequestDispatcher dispatcher = new RequestDispatcher();
536
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900537 return dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +0800538 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900539 connector.setUsbTethering(enable, callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +0800540 } catch (RemoteException e) {
541 throw new IllegalStateException(e);
542 }
543 });
markchien0df2ebc42019-09-30 14:40:57 +0800544 }
545
546 /**
markchien06889172020-01-20 19:31:56 +0800547 * Use with {@link #startTethering} to specify additional parameters when starting tethering.
548 */
549 public static class TetheringRequest {
550 /** A configuration set for TetheringRequest. */
551 private final TetheringRequestParcel mRequestParcel;
552
553 private TetheringRequest(final TetheringRequestParcel request) {
554 mRequestParcel = request;
555 }
556
557 /** Builder used to create TetheringRequest. */
558 public static class Builder {
559 private final TetheringRequestParcel mBuilderParcel;
560
561 /** Default constructor of Builder. */
markchien62a625d2020-03-19 13:37:43 +0800562 public Builder(@TetheringType final int type) {
markchien06889172020-01-20 19:31:56 +0800563 mBuilderParcel = new TetheringRequestParcel();
564 mBuilderParcel.tetheringType = type;
565 mBuilderParcel.localIPv4Address = null;
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000566 mBuilderParcel.staticClientAddress = null;
markchien06889172020-01-20 19:31:56 +0800567 mBuilderParcel.exemptFromEntitlementCheck = false;
568 mBuilderParcel.showProvisioningUi = true;
569 }
570
571 /**
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000572 * Configure tethering with static IPv4 assignment.
markchien06889172020-01-20 19:31:56 +0800573 *
Treehugger Robot86d212b2020-03-30 04:23:55 +0000574 * A DHCP server will be started, but will only be able to offer the client address.
575 * The two addresses must be in the same prefix.
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000576 *
577 * @param localIPv4Address The preferred local IPv4 link address to use.
578 * @param clientAddress The static client address.
markchien06889172020-01-20 19:31:56 +0800579 */
580 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
581 @NonNull
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000582 public Builder setStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address,
583 @NonNull final LinkAddress clientAddress) {
584 Objects.requireNonNull(localIPv4Address);
585 Objects.requireNonNull(clientAddress);
Treehugger Robot86d212b2020-03-30 04:23:55 +0000586 if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) {
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000587 throw new IllegalArgumentException("Invalid server or client addresses");
588 }
589
markchien06889172020-01-20 19:31:56 +0800590 mBuilderParcel.localIPv4Address = localIPv4Address;
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000591 mBuilderParcel.staticClientAddress = clientAddress;
markchien06889172020-01-20 19:31:56 +0800592 return this;
593 }
594
595 /** Start tethering without entitlement checks. */
596 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
597 @NonNull
598 public Builder setExemptFromEntitlementCheck(boolean exempt) {
599 mBuilderParcel.exemptFromEntitlementCheck = exempt;
600 return this;
601 }
602
markchien62a625d2020-03-19 13:37:43 +0800603 /**
604 * If an entitlement check is needed, sets whether to show the entitlement UI or to
605 * perform a silent entitlement check. By default, the entitlement UI is shown.
606 */
markchien06889172020-01-20 19:31:56 +0800607 @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
608 @NonNull
markchien62a625d2020-03-19 13:37:43 +0800609 public Builder setShouldShowEntitlementUi(boolean showUi) {
610 mBuilderParcel.showProvisioningUi = showUi;
markchien06889172020-01-20 19:31:56 +0800611 return this;
612 }
613
614 /** Build {@link TetheringRequest] with the currently set configuration. */
615 @NonNull
616 public TetheringRequest build() {
617 return new TetheringRequest(mBuilderParcel);
618 }
junyulai25d64392020-03-23 10:47:42 +0800619 }
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000620
junyulai25d64392020-03-23 10:47:42 +0800621 /**
622 * Get the local IPv4 address, if one was configured with
623 * {@link Builder#setStaticIpv4Addresses}.
624 */
625 @Nullable
626 public LinkAddress getLocalIpv4Address() {
627 return mRequestParcel.localIPv4Address;
628 }
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000629
junyulai25d64392020-03-23 10:47:42 +0800630 /**
631 * Get the static IPv4 address of the client, if one was configured with
632 * {@link Builder#setStaticIpv4Addresses}.
633 */
634 @Nullable
635 public LinkAddress getClientStaticIpv4Address() {
636 return mRequestParcel.staticClientAddress;
637 }
markchien62a625d2020-03-19 13:37:43 +0800638
junyulai25d64392020-03-23 10:47:42 +0800639 /** Get tethering type. */
640 @TetheringType
641 public int getTetheringType() {
642 return mRequestParcel.tetheringType;
643 }
markchien62a625d2020-03-19 13:37:43 +0800644
junyulai25d64392020-03-23 10:47:42 +0800645 /** Check if exempt from entitlement check. */
646 public boolean isExemptFromEntitlementCheck() {
647 return mRequestParcel.exemptFromEntitlementCheck;
648 }
markchien62a625d2020-03-19 13:37:43 +0800649
junyulai25d64392020-03-23 10:47:42 +0800650 /** Check if show entitlement ui. */
651 public boolean getShouldShowEntitlementUi() {
652 return mRequestParcel.showProvisioningUi;
markchien06889172020-01-20 19:31:56 +0800653 }
654
655 /**
Treehugger Robot86d212b2020-03-30 04:23:55 +0000656 * Check whether the two addresses are ipv4 and in the same prefix.
657 * @hide
658 */
659 public static boolean checkStaticAddressConfiguration(
660 @NonNull final LinkAddress localIPv4Address,
661 @NonNull final LinkAddress clientAddress) {
662 return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength()
663 && localIPv4Address.isIpv4() && clientAddress.isIpv4()
664 && new IpPrefix(localIPv4Address.toString()).equals(
665 new IpPrefix(clientAddress.toString()));
666 }
667
668 /**
markchien06889172020-01-20 19:31:56 +0800669 * Get a TetheringRequestParcel from the configuration
670 * @hide
671 */
672 public TetheringRequestParcel getParcel() {
673 return mRequestParcel;
674 }
675
676 /** String of TetheringRequest detail. */
677 public String toString() {
678 return "TetheringRequest [ type= " + mRequestParcel.tetheringType
679 + ", localIPv4Address= " + mRequestParcel.localIPv4Address
Automerger Merge Worker37a22752020-03-17 16:59:57 +0000680 + ", staticClientAddress= " + mRequestParcel.staticClientAddress
markchien06889172020-01-20 19:31:56 +0800681 + ", exemptFromEntitlementCheck= "
682 + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
683 + mRequestParcel.showProvisioningUi + " ]";
684 }
685 }
686
687 /**
688 * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
689 */
markchien62a625d2020-03-19 13:37:43 +0800690 public interface StartTetheringCallback {
markchien06889172020-01-20 19:31:56 +0800691 /**
692 * Called when tethering has been successfully started.
693 */
markchien62a625d2020-03-19 13:37:43 +0800694 default void onTetheringStarted() {}
markchien06889172020-01-20 19:31:56 +0800695
696 /**
697 * Called when starting tethering failed.
698 *
markchien62a625d2020-03-19 13:37:43 +0800699 * @param error The error that caused the failure.
markchien06889172020-01-20 19:31:56 +0800700 */
markchien62a625d2020-03-19 13:37:43 +0800701 default void onTetheringFailed(@StartTetheringError final int error) {}
markchien06889172020-01-20 19:31:56 +0800702 }
703
704 /**
markchien0df2ebc42019-09-30 14:40:57 +0800705 * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
706 * fails, stopTethering will be called automatically.
markchien06889172020-01-20 19:31:56 +0800707 *
708 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
709 * fail if a tethering entitlement check is required.
710 *
711 * @param request a {@link TetheringRequest} which can specify the preferred configuration.
712 * @param executor {@link Executor} to specify the thread upon which the callback of
713 * TetheringRequest will be invoked.
714 * @param callback A callback that will be called to indicate the success status of the
715 * tethering start request.
markchien0df2ebc42019-09-30 14:40:57 +0800716 */
markchien06889172020-01-20 19:31:56 +0800717 @RequiresPermission(anyOf = {
718 android.Manifest.permission.TETHER_PRIVILEGED,
719 android.Manifest.permission.WRITE_SETTINGS
720 })
721 public void startTethering(@NonNull final TetheringRequest request,
722 @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
markchien6d06f6d2019-12-16 20:15:20 +0800723 final String callerPkg = mContext.getOpPackageName();
724 Log.i(TAG, "startTethering caller:" + callerPkg);
725
markchien06889172020-01-20 19:31:56 +0800726 final IIntResultListener listener = new IIntResultListener.Stub() {
727 @Override
728 public void onResult(final int resultCode) {
729 executor.execute(() -> {
730 if (resultCode == TETHER_ERROR_NO_ERROR) {
731 callback.onTetheringStarted();
732 } else {
733 callback.onTetheringFailed(resultCode);
734 }
735 });
736 }
737 };
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900738 getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
markchien0df2ebc42019-09-30 14:40:57 +0800739 }
740
741 /**
markchien06889172020-01-20 19:31:56 +0800742 * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
743 * fails, stopTethering will be called automatically.
744 *
745 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
746 * fail if a tethering entitlement check is required.
747 *
748 * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
749 * @param executor {@link Executor} to specify the thread upon which the callback of
750 * TetheringRequest will be invoked.
markchien11ee8132020-03-19 21:04:04 +0800751 * @hide
markchien06889172020-01-20 19:31:56 +0800752 */
753 @RequiresPermission(anyOf = {
754 android.Manifest.permission.TETHER_PRIVILEGED,
755 android.Manifest.permission.WRITE_SETTINGS
756 })
markchien11ee8132020-03-19 21:04:04 +0800757 @SystemApi(client = MODULE_LIBRARIES)
markchien06889172020-01-20 19:31:56 +0800758 public void startTethering(int type, @NonNull final Executor executor,
759 @NonNull final StartTetheringCallback callback) {
760 startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
761 }
762
763 /**
markchien0df2ebc42019-09-30 14:40:57 +0800764 * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
765 * applicable.
markchien06889172020-01-20 19:31:56 +0800766 *
767 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
768 * fail if a tethering entitlement check is required.
markchien0df2ebc42019-09-30 14:40:57 +0800769 */
markchien06889172020-01-20 19:31:56 +0800770 @RequiresPermission(anyOf = {
771 android.Manifest.permission.TETHER_PRIVILEGED,
772 android.Manifest.permission.WRITE_SETTINGS
773 })
markchien62a625d2020-03-19 13:37:43 +0800774 public void stopTethering(@TetheringType final int type) {
markchien6d06f6d2019-12-16 20:15:20 +0800775 final String callerPkg = mContext.getOpPackageName();
776 Log.i(TAG, "stopTethering caller:" + callerPkg);
777
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900778 getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
779 @Override
780 public void onResult(int resultCode) {
781 // TODO: provide an API to obtain result
782 // This has never been possible as stopTethering has always been void and never
783 // taken a callback object. The only indication that callers have is if the call
784 // results in a TETHER_STATE_CHANGE broadcast.
markchien6d06f6d2019-12-16 20:15:20 +0800785 }
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900786 }));
markchien0df2ebc42019-09-30 14:40:57 +0800787 }
788
789 /**
markchien75b6d7b2020-01-21 13:11:06 +0800790 * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
791 * entitlement succeeded.
792 */
793 public interface OnTetheringEntitlementResultListener {
794 /**
795 * Called to notify entitlement result.
796 *
797 * @param resultCode an int value of entitlement result. It may be one of
798 * {@link #TETHER_ERROR_NO_ERROR},
markchien62a625d2020-03-19 13:37:43 +0800799 * {@link #TETHER_ERROR_PROVISIONING_FAILED}, or
markchien75b6d7b2020-01-21 13:11:06 +0800800 * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
801 */
markchien62a625d2020-03-19 13:37:43 +0800802 void onTetheringEntitlementResult(@EntitlementResult int result);
markchien75b6d7b2020-01-21 13:11:06 +0800803 }
804
805 /**
markchien0df2ebc42019-09-30 14:40:57 +0800806 * Request the latest value of the tethering entitlement check.
807 *
markchien75b6d7b2020-01-21 13:11:06 +0800808 * <p>This method will only return the latest entitlement result if it is available. If no
809 * cached entitlement result is available, and {@code showEntitlementUi} is false,
810 * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is
811 * true, entitlement will be run.
812 *
markchien06889172020-01-20 19:31:56 +0800813 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
814 * fail if a tethering entitlement check is required.
815 *
markchien75b6d7b2020-01-21 13:11:06 +0800816 * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
markchien62a625d2020-03-19 13:37:43 +0800817 * @param showEntitlementUi a boolean indicating whether to check result for the UI-based
818 * entitlement check or the silent entitlement check.
markchien75b6d7b2020-01-21 13:11:06 +0800819 * @param executor the executor on which callback will be invoked.
820 * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
821 * notify the caller of the result of entitlement check. The listener may be called zero
822 * or one time.
823 */
markchien06889172020-01-20 19:31:56 +0800824 @RequiresPermission(anyOf = {
825 android.Manifest.permission.TETHER_PRIVILEGED,
826 android.Manifest.permission.WRITE_SETTINGS
827 })
markchien62a625d2020-03-19 13:37:43 +0800828 public void requestLatestTetheringEntitlementResult(@TetheringType int type,
829 boolean showEntitlementUi,
markchien75b6d7b2020-01-21 13:11:06 +0800830 @NonNull Executor executor,
831 @NonNull final OnTetheringEntitlementResultListener listener) {
832 if (listener == null) {
833 throw new IllegalArgumentException(
834 "OnTetheringEntitlementResultListener cannot be null.");
835 }
836
837 ResultReceiver wrappedListener = new ResultReceiver(null /* handler */) {
838 @Override
839 protected void onReceiveResult(int resultCode, Bundle resultData) {
840 executor.execute(() -> {
841 listener.onTetheringEntitlementResult(resultCode);
842 });
843 }
844 };
845
846 requestLatestTetheringEntitlementResult(type, wrappedListener,
847 showEntitlementUi);
848 }
849
850 /**
851 * Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
852 * with ConnectivityManager#getLatestTetheringEntitlementResult
853 *
854 * {@hide}
markchien0df2ebc42019-09-30 14:40:57 +0800855 */
856 // TODO: improve the usage of ResultReceiver, b/145096122
markchien2c153702020-02-06 19:23:26 +0800857 @SystemApi(client = MODULE_LIBRARIES)
markchien62a625d2020-03-19 13:37:43 +0800858 public void requestLatestTetheringEntitlementResult(@TetheringType final int type,
markchien6d06f6d2019-12-16 20:15:20 +0800859 @NonNull final ResultReceiver receiver, final boolean showEntitlementUi) {
860 final String callerPkg = mContext.getOpPackageName();
861 Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
862
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +0900863 getConnector(c -> c.requestLatestTetheringEntitlementResult(
864 type, receiver, showEntitlementUi, callerPkg));
markchien0df2ebc42019-09-30 14:40:57 +0800865 }
866
867 /**
markchien75b6d7b2020-01-21 13:11:06 +0800868 * Callback for use with {@link registerTetheringEventCallback} to find out tethering
869 * upstream status.
870 */
markchien62a625d2020-03-19 13:37:43 +0800871 public interface TetheringEventCallback {
markchien75b6d7b2020-01-21 13:11:06 +0800872 /**
873 * Called when tethering supported status changed.
874 *
875 * <p>This will be called immediately after the callback is registered, and may be called
876 * multiple times later upon changes.
877 *
878 * <p>Tethering may be disabled via system properties, device configuration, or device
879 * policy restrictions.
880 *
881 * @param supported The new supported status
882 */
markchien62a625d2020-03-19 13:37:43 +0800883 default void onTetheringSupported(boolean supported) {}
markchien75b6d7b2020-01-21 13:11:06 +0800884
885 /**
886 * Called when tethering upstream changed.
887 *
888 * <p>This will be called immediately after the callback is registered, and may be called
889 * multiple times later upon changes.
890 *
891 * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
892 * have any upstream.
893 */
markchien62a625d2020-03-19 13:37:43 +0800894 default void onUpstreamChanged(@Nullable Network network) {}
markchien75b6d7b2020-01-21 13:11:06 +0800895
896 /**
897 * Called when there was a change in tethering interface regular expressions.
898 *
899 * <p>This will be called immediately after the callback is registered, and may be called
900 * multiple times later upon changes.
901 * @param reg The new regular expressions.
markchien62a625d2020-03-19 13:37:43 +0800902 *
903 * @hide
markchien75b6d7b2020-01-21 13:11:06 +0800904 */
markchien62a625d2020-03-19 13:37:43 +0800905 @SystemApi(client = MODULE_LIBRARIES)
906 default void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
markchien75b6d7b2020-01-21 13:11:06 +0800907
908 /**
markchien62a625d2020-03-19 13:37:43 +0800909 * Called when there was a change in the list of tetherable interfaces. Tetherable
910 * interface means this interface is available and can be used for tethering.
markchien75b6d7b2020-01-21 13:11:06 +0800911 *
912 * <p>This will be called immediately after the callback is registered, and may be called
913 * multiple times later upon changes.
markchien62a625d2020-03-19 13:37:43 +0800914 * @param interfaces The list of tetherable interface names.
markchien75b6d7b2020-01-21 13:11:06 +0800915 */
markchien62a625d2020-03-19 13:37:43 +0800916 default void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
markchien75b6d7b2020-01-21 13:11:06 +0800917
918 /**
919 * Called when there was a change in the list of tethered interfaces.
920 *
921 * <p>This will be called immediately after the callback is registered, and may be called
922 * multiple times later upon changes.
markchien62a625d2020-03-19 13:37:43 +0800923 * @param interfaces The list of 0 or more String of currently tethered interface names.
markchien75b6d7b2020-01-21 13:11:06 +0800924 */
markchien62a625d2020-03-19 13:37:43 +0800925 default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
markchien75b6d7b2020-01-21 13:11:06 +0800926
927 /**
928 * Called when an error occurred configuring tethering.
929 *
930 * <p>This will be called immediately after the callback is registered if the latest status
931 * on the interface is an error, and may be called multiple times later upon changes.
932 * @param ifName Name of the interface.
933 * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
934 */
markchien62a625d2020-03-19 13:37:43 +0800935 default void onError(@NonNull String ifName, @TetheringIfaceError int error) {}
Remi NGUYEN VANbfc910c2020-01-20 21:26:34 +0900936
937 /**
938 * Called when the list of tethered clients changes.
939 *
940 * <p>This callback provides best-effort information on connected clients based on state
941 * known to the system, however the list cannot be completely accurate (and should not be
942 * used for security purposes). For example, clients behind a bridge and using static IP
943 * assignments are not visible to the tethering device; or even when using DHCP, such
944 * clients may still be reported by this callback after disconnection as the system cannot
945 * determine if they are still connected.
946 * @param clients The new set of tethered clients; the collection is not ordered.
947 */
markchien62a625d2020-03-19 13:37:43 +0800948 default void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +0000949
950 /**
951 * Called when tethering offload status changes.
952 *
953 * <p>This will be called immediately after the callback is registered.
954 * @param status The offload status.
955 */
markchien62a625d2020-03-19 13:37:43 +0800956 default void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
markchien75b6d7b2020-01-21 13:11:06 +0800957 }
958
959 /**
960 * Regular expressions used to identify tethering interfaces.
markchien62a625d2020-03-19 13:37:43 +0800961 * @hide
markchien75b6d7b2020-01-21 13:11:06 +0800962 */
markchien62a625d2020-03-19 13:37:43 +0800963 @SystemApi(client = MODULE_LIBRARIES)
markchien75b6d7b2020-01-21 13:11:06 +0800964 public static class TetheringInterfaceRegexps {
965 private final String[] mTetherableBluetoothRegexs;
966 private final String[] mTetherableUsbRegexs;
967 private final String[] mTetherableWifiRegexs;
968
markchien62a625d2020-03-19 13:37:43 +0800969 /** @hide */
markchien75b6d7b2020-01-21 13:11:06 +0800970 public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
971 @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
972 mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
973 mTetherableUsbRegexs = tetherableUsbRegexs.clone();
974 mTetherableWifiRegexs = tetherableWifiRegexs.clone();
975 }
976
977 @NonNull
978 public List<String> getTetherableBluetoothRegexs() {
979 return Collections.unmodifiableList(Arrays.asList(mTetherableBluetoothRegexs));
980 }
981
982 @NonNull
983 public List<String> getTetherableUsbRegexs() {
984 return Collections.unmodifiableList(Arrays.asList(mTetherableUsbRegexs));
985 }
986
987 @NonNull
988 public List<String> getTetherableWifiRegexs() {
989 return Collections.unmodifiableList(Arrays.asList(mTetherableWifiRegexs));
990 }
991
992 @Override
993 public int hashCode() {
994 return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
995 mTetherableWifiRegexs);
996 }
997
998 @Override
999 public boolean equals(@Nullable Object obj) {
1000 if (!(obj instanceof TetheringInterfaceRegexps)) return false;
1001 final TetheringInterfaceRegexps other = (TetheringInterfaceRegexps) obj;
1002 return Arrays.equals(mTetherableBluetoothRegexs, other.mTetherableBluetoothRegexs)
1003 && Arrays.equals(mTetherableUsbRegexs, other.mTetherableUsbRegexs)
1004 && Arrays.equals(mTetherableWifiRegexs, other.mTetherableWifiRegexs);
1005 }
1006 }
1007
1008 /**
markchien6d06f6d2019-12-16 20:15:20 +08001009 * Start listening to tethering change events. Any new added callback will receive the last
1010 * tethering status right away. If callback is registered,
markchien75b6d7b2020-01-21 13:11:06 +08001011 * {@link TetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
markchien6d06f6d2019-12-16 20:15:20 +08001012 * has no upstream or disabled, the argument of callback will be null. The same callback object
1013 * cannot be registered twice.
markchien0df2ebc42019-09-30 14:40:57 +08001014 *
markchien6d06f6d2019-12-16 20:15:20 +08001015 * @param executor the executor on which callback will be invoked.
1016 * @param callback the callback to be called when tethering has change events.
markchien0df2ebc42019-09-30 14:40:57 +08001017 */
markchien06889172020-01-20 19:31:56 +08001018 @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
markchien6d06f6d2019-12-16 20:15:20 +08001019 public void registerTetheringEventCallback(@NonNull Executor executor,
markchien75b6d7b2020-01-21 13:11:06 +08001020 @NonNull TetheringEventCallback callback) {
markchien6d06f6d2019-12-16 20:15:20 +08001021 final String callerPkg = mContext.getOpPackageName();
1022 Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg);
1023
1024 synchronized (mTetheringEventCallbacks) {
markchien75b6d7b2020-01-21 13:11:06 +08001025 if (mTetheringEventCallbacks.containsKey(callback)) {
markchien6d06f6d2019-12-16 20:15:20 +08001026 throw new IllegalArgumentException("callback was already registered.");
1027 }
1028 final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
markchien75b6d7b2020-01-21 13:11:06 +08001029 // Only accessed with a lock on this object
1030 private final HashMap<String, Integer> mErrorStates = new HashMap<>();
1031 private String[] mLastTetherableInterfaces = null;
1032 private String[] mLastTetheredInterfaces = null;
1033
markchien6d06f6d2019-12-16 20:15:20 +08001034 @Override
1035 public void onUpstreamChanged(Network network) throws RemoteException {
1036 executor.execute(() -> {
1037 callback.onUpstreamChanged(network);
1038 });
1039 }
1040
markchien75b6d7b2020-01-21 13:11:06 +08001041 private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
1042 for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
1043 final String iface = newStates.erroredIfaceList[i];
1044 final Integer lastError = mErrorStates.get(iface);
1045 final int newError = newStates.lastErrorList[i];
1046 if (newError != TETHER_ERROR_NO_ERROR
1047 && !Objects.equals(lastError, newError)) {
1048 callback.onError(iface, newError);
1049 }
1050 mErrorStates.put(iface, newError);
1051 }
1052 }
1053
1054 private synchronized void maybeSendTetherableIfacesChangedCallback(
1055 final TetherStatesParcel newStates) {
1056 if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
1057 mLastTetherableInterfaces = newStates.availableList.clone();
1058 callback.onTetherableInterfacesChanged(
1059 Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
1060 }
1061
1062 private synchronized void maybeSendTetheredIfacesChangedCallback(
1063 final TetherStatesParcel newStates) {
1064 if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
1065 mLastTetheredInterfaces = newStates.tetheredList.clone();
1066 callback.onTetheredInterfacesChanged(
1067 Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
1068 }
1069
1070 // Called immediately after the callbacks are registered.
markchien6d06f6d2019-12-16 20:15:20 +08001071 @Override
markchien75b6d7b2020-01-21 13:11:06 +08001072 public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
markchien6d06f6d2019-12-16 20:15:20 +08001073 executor.execute(() -> {
markchien75b6d7b2020-01-21 13:11:06 +08001074 callback.onTetheringSupported(parcel.tetheringSupported);
1075 callback.onUpstreamChanged(parcel.upstreamNetwork);
1076 sendErrorCallbacks(parcel.states);
1077 sendRegexpsChanged(parcel.config);
1078 maybeSendTetherableIfacesChangedCallback(parcel.states);
1079 maybeSendTetheredIfacesChangedCallback(parcel.states);
Remi NGUYEN VAN43b0e5c2020-02-13 09:16:19 +09001080 callback.onClientsChanged(parcel.tetheredClients);
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +00001081 callback.onOffloadStatusChanged(parcel.offloadStatus);
markchien6d06f6d2019-12-16 20:15:20 +08001082 });
1083 }
1084
1085 @Override
1086 public void onCallbackStopped(int errorCode) {
1087 executor.execute(() -> {
1088 throwIfPermissionFailure(errorCode);
1089 });
1090 }
1091
markchien75b6d7b2020-01-21 13:11:06 +08001092 private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
1093 callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
1094 parcel.tetherableBluetoothRegexs,
1095 parcel.tetherableUsbRegexs,
1096 parcel.tetherableWifiRegexs));
1097 }
markchien6d06f6d2019-12-16 20:15:20 +08001098
1099 @Override
markchien75b6d7b2020-01-21 13:11:06 +08001100 public void onConfigurationChanged(TetheringConfigurationParcel config) {
1101 executor.execute(() -> sendRegexpsChanged(config));
1102 }
1103
1104 @Override
1105 public void onTetherStatesChanged(TetherStatesParcel states) {
1106 executor.execute(() -> {
1107 sendErrorCallbacks(states);
1108 maybeSendTetherableIfacesChangedCallback(states);
1109 maybeSendTetheredIfacesChangedCallback(states);
1110 });
1111 }
Remi NGUYEN VAN43b0e5c2020-02-13 09:16:19 +09001112
1113 @Override
1114 public void onTetherClientsChanged(final List<TetheredClient> clients) {
1115 executor.execute(() -> callback.onClientsChanged(clients));
1116 }
Automerger Merge Workerc22ab7b2020-03-09 04:07:07 +00001117
1118 @Override
1119 public void onOffloadStatusChanged(final int status) {
1120 executor.execute(() -> callback.onOffloadStatusChanged(status));
1121 }
markchien6d06f6d2019-12-16 20:15:20 +08001122 };
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001123 getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
markchien6d06f6d2019-12-16 20:15:20 +08001124 mTetheringEventCallbacks.put(callback, remoteCallback);
1125 }
markchien0df2ebc42019-09-30 14:40:57 +08001126 }
1127
1128 /**
markchien6d06f6d2019-12-16 20:15:20 +08001129 * Remove tethering event callback previously registered with
1130 * {@link #registerTetheringEventCallback}.
markchien0df2ebc42019-09-30 14:40:57 +08001131 *
markchien6d06f6d2019-12-16 20:15:20 +08001132 * @param callback previously registered callback.
markchien0df2ebc42019-09-30 14:40:57 +08001133 */
markchien06889172020-01-20 19:31:56 +08001134 @RequiresPermission(anyOf = {
1135 Manifest.permission.TETHER_PRIVILEGED,
1136 Manifest.permission.ACCESS_NETWORK_STATE
1137 })
markchien75b6d7b2020-01-21 13:11:06 +08001138 public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) {
markchien6d06f6d2019-12-16 20:15:20 +08001139 final String callerPkg = mContext.getOpPackageName();
1140 Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg);
1141
1142 synchronized (mTetheringEventCallbacks) {
1143 ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback);
1144 if (remoteCallback == null) {
1145 throw new IllegalArgumentException("callback was not registered.");
1146 }
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001147
1148 getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
markchien6d06f6d2019-12-16 20:15:20 +08001149 }
markchien0df2ebc42019-09-30 14:40:57 +08001150 }
1151
1152 /**
1153 * Get a more detailed error code after a Tethering or Untethering
1154 * request asynchronously failed.
1155 *
markchien6d06f6d2019-12-16 20:15:20 +08001156 * @param iface The name of the interface of interest
1157 * @return error The error code of the last error tethering or untethering the named
1158 * interface
markchien75b6d7b2020-01-21 13:11:06 +08001159 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001160 */
markchien2c153702020-02-06 19:23:26 +08001161 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +08001162 public int getLastTetherError(@NonNull final String iface) {
1163 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001164 if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
1165
1166 int i = 0;
1167 for (String errored : mTetherStatesParcel.erroredIfaceList) {
1168 if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
1169
1170 i++;
1171 }
1172 return TETHER_ERROR_NO_ERROR;
1173 }
1174
1175 /**
1176 * Get the list of regular expressions that define any tetherable
1177 * USB network interfaces. If USB tethering is not supported by the
1178 * device, this list should be empty.
1179 *
markchien6d06f6d2019-12-16 20:15:20 +08001180 * @return an array of 0 or more regular expression Strings defining
1181 * what interfaces are considered tetherable usb interfaces.
markchien75b6d7b2020-01-21 13:11:06 +08001182 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001183 */
markchien2c153702020-02-06 19:23:26 +08001184 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001185 public @NonNull String[] getTetherableUsbRegexs() {
markchien6d06f6d2019-12-16 20:15:20 +08001186 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001187 return mTetheringConfiguration.tetherableUsbRegexs;
1188 }
1189
1190 /**
1191 * Get the list of regular expressions that define any tetherable
1192 * Wifi network interfaces. If Wifi tethering is not supported by the
1193 * device, this list should be empty.
1194 *
markchien6d06f6d2019-12-16 20:15:20 +08001195 * @return an array of 0 or more regular expression Strings defining
1196 * what interfaces are considered tetherable wifi interfaces.
markchien75b6d7b2020-01-21 13:11:06 +08001197 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001198 */
markchien2c153702020-02-06 19:23:26 +08001199 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001200 public @NonNull String[] getTetherableWifiRegexs() {
markchien6d06f6d2019-12-16 20:15:20 +08001201 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001202 return mTetheringConfiguration.tetherableWifiRegexs;
1203 }
1204
1205 /**
1206 * Get the list of regular expressions that define any tetherable
1207 * Bluetooth network interfaces. If Bluetooth tethering is not supported by the
1208 * device, this list should be empty.
1209 *
markchien6d06f6d2019-12-16 20:15:20 +08001210 * @return an array of 0 or more regular expression Strings defining
1211 * what interfaces are considered tetherable bluetooth interfaces.
markchien75b6d7b2020-01-21 13:11:06 +08001212 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001213 */
markchien2c153702020-02-06 19:23:26 +08001214 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001215 public @NonNull String[] getTetherableBluetoothRegexs() {
markchien6d06f6d2019-12-16 20:15:20 +08001216 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001217 return mTetheringConfiguration.tetherableBluetoothRegexs;
1218 }
1219
1220 /**
1221 * Get the set of tetherable, available interfaces. This list is limited by
1222 * device configuration and current interface existence.
1223 *
markchien6d06f6d2019-12-16 20:15:20 +08001224 * @return an array of 0 or more Strings of tetherable interface names.
markchien75b6d7b2020-01-21 13:11:06 +08001225 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001226 */
markchien2c153702020-02-06 19:23:26 +08001227 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001228 public @NonNull String[] getTetherableIfaces() {
markchien6d06f6d2019-12-16 20:15:20 +08001229 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001230 if (mTetherStatesParcel == null) return new String[0];
markchien6d06f6d2019-12-16 20:15:20 +08001231
markchien0df2ebc42019-09-30 14:40:57 +08001232 return mTetherStatesParcel.availableList;
1233 }
1234
1235 /**
1236 * Get the set of tethered interfaces.
1237 *
markchien6d06f6d2019-12-16 20:15:20 +08001238 * @return an array of 0 or more String of currently tethered interface names.
markchien75b6d7b2020-01-21 13:11:06 +08001239 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001240 */
markchien2c153702020-02-06 19:23:26 +08001241 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001242 public @NonNull String[] getTetheredIfaces() {
markchien6d06f6d2019-12-16 20:15:20 +08001243 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001244 if (mTetherStatesParcel == null) return new String[0];
markchien6d06f6d2019-12-16 20:15:20 +08001245
markchien0df2ebc42019-09-30 14:40:57 +08001246 return mTetherStatesParcel.tetheredList;
1247 }
1248
1249 /**
1250 * Get the set of interface names which attempted to tether but
markchien6d06f6d2019-12-16 20:15:20 +08001251 * failed. Re-attempting to tether may cause them to reset to the Tethered
1252 * state. Alternatively, causing the interface to be destroyed and recreated
1253 * may cause them to reset to the available state.
markchien9e44cde2019-12-25 19:40:32 +08001254 * {@link TetheringManager#getLastTetherError} can be used to get more
markchien6d06f6d2019-12-16 20:15:20 +08001255 * information on the cause of the errors.
markchien0df2ebc42019-09-30 14:40:57 +08001256 *
markchien6d06f6d2019-12-16 20:15:20 +08001257 * @return an array of 0 or more String indicating the interface names
1258 * which failed to tether.
markchien75b6d7b2020-01-21 13:11:06 +08001259 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001260 */
markchien2c153702020-02-06 19:23:26 +08001261 @SystemApi(client = MODULE_LIBRARIES)
markchien0df2ebc42019-09-30 14:40:57 +08001262 public @NonNull String[] getTetheringErroredIfaces() {
markchien6d06f6d2019-12-16 20:15:20 +08001263 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001264 if (mTetherStatesParcel == null) return new String[0];
markchien6d06f6d2019-12-16 20:15:20 +08001265
markchien0df2ebc42019-09-30 14:40:57 +08001266 return mTetherStatesParcel.erroredIfaceList;
1267 }
1268
1269 /**
1270 * Get the set of tethered dhcp ranges.
1271 *
markchienb741c642019-11-27 21:20:33 +08001272 * @deprecated This API just return the default value which is not used in DhcpServer.
markchien75b6d7b2020-01-21 13:11:06 +08001273 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001274 */
markchienb741c642019-11-27 21:20:33 +08001275 @Deprecated
markchien0df2ebc42019-09-30 14:40:57 +08001276 public @NonNull String[] getTetheredDhcpRanges() {
markchien6d06f6d2019-12-16 20:15:20 +08001277 mCallback.waitForStarted();
markchien0df2ebc42019-09-30 14:40:57 +08001278 return mTetheringConfiguration.legacyDhcpRanges;
1279 }
1280
1281 /**
markchien6d06f6d2019-12-16 20:15:20 +08001282 * Check if the device allows for tethering. It may be disabled via
1283 * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
1284 * due to device configuration.
markchien0df2ebc42019-09-30 14:40:57 +08001285 *
markchien6d06f6d2019-12-16 20:15:20 +08001286 * @return a boolean - {@code true} indicating Tethering is supported.
markchien75b6d7b2020-01-21 13:11:06 +08001287 * @hide
markchien0df2ebc42019-09-30 14:40:57 +08001288 */
markchien2c153702020-02-06 19:23:26 +08001289 @SystemApi(client = MODULE_LIBRARIES)
markchien6d06f6d2019-12-16 20:15:20 +08001290 public boolean isTetheringSupported() {
1291 final String callerPkg = mContext.getOpPackageName();
markchien0df2ebc42019-09-30 14:40:57 +08001292
Automerger Merge Workerfcf74d12020-03-03 12:51:02 +00001293 return isTetheringSupported(callerPkg);
1294 }
1295
1296 /**
1297 * Check if the device allows for tethering. It may be disabled via {@code ro.tether.denied}
1298 * system property, Settings.TETHER_SUPPORTED or due to device configuration. This is useful
1299 * for system components that query this API on behalf of an app. In particular, Bluetooth
1300 * has @UnsupportedAppUsage calls that will let apps turn on bluetooth tethering if they have
1301 * the right permissions, but such an app needs to know whether it can (permissions as well
1302 * as support from the device) turn on tethering in the first place to show the appropriate UI.
1303 *
1304 * @param callerPkg The caller package name, if it is not matching the calling uid,
1305 * SecurityException would be thrown.
1306 * @return a boolean - {@code true} indicating Tethering is supported.
1307 * @hide
1308 */
1309 @SystemApi(client = MODULE_LIBRARIES)
1310 public boolean isTetheringSupported(@NonNull final String callerPkg) {
1311
markchien6d06f6d2019-12-16 20:15:20 +08001312 final RequestDispatcher dispatcher = new RequestDispatcher();
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001313 final int ret = dispatcher.waitForResult((connector, listener) -> {
markchien6d06f6d2019-12-16 20:15:20 +08001314 try {
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001315 connector.isTetheringSupported(callerPkg, listener);
markchien6d06f6d2019-12-16 20:15:20 +08001316 } catch (RemoteException e) {
1317 throw new IllegalStateException(e);
1318 }
1319 });
1320
1321 return ret == TETHER_ERROR_NO_ERROR;
markchien0df2ebc42019-09-30 14:40:57 +08001322 }
1323
1324 /**
markchien6d06f6d2019-12-16 20:15:20 +08001325 * Stop all active tethering.
markchien06889172020-01-20 19:31:56 +08001326 *
1327 * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
1328 * fail if a tethering entitlement check is required.
markchien0df2ebc42019-09-30 14:40:57 +08001329 */
markchien06889172020-01-20 19:31:56 +08001330 @RequiresPermission(anyOf = {
1331 android.Manifest.permission.TETHER_PRIVILEGED,
1332 android.Manifest.permission.WRITE_SETTINGS
1333 })
markchien6d06f6d2019-12-16 20:15:20 +08001334 public void stopAllTethering() {
1335 final String callerPkg = mContext.getOpPackageName();
1336 Log.i(TAG, "stopAllTethering caller:" + callerPkg);
markchien0df2ebc42019-09-30 14:40:57 +08001337
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001338 getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
1339 @Override
1340 public void onResult(int resultCode) {
1341 // TODO: add an API parameter to send result to caller.
1342 // This has never been possible as stopAllTethering has always been void and never
1343 // taken a callback object. The only indication that callers have is if the call
1344 // results in a TETHER_STATE_CHANGE broadcast.
markchien6d06f6d2019-12-16 20:15:20 +08001345 }
Remi NGUYEN VAN24b7b6a2020-01-27 17:26:14 +09001346 }));
markchien0df2ebc42019-09-30 14:40:57 +08001347 }
1348}