blob: f472d563c4773a39f265e2b6ae1f1f3738610a82 [file] [log] [blame]
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -07001/*
2 * Copyright (C) 2014 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 */
16
17package android.net;
18
James Mattis407ea1d2021-12-14 18:23:30 -080019import android.annotation.CallbackExecutor;
Lorenzo Colitti19b8b882020-01-24 19:29:17 +090020import android.annotation.NonNull;
James Mattis407ea1d2021-12-14 18:23:30 -080021import android.annotation.Nullable;
Remi NGUYEN VAN11f39242020-03-09 13:56:18 +090022import android.annotation.RequiresPermission;
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +090023import android.annotation.SystemApi;
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060024import android.annotation.SystemService;
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +090025import android.annotation.TestApi;
Artur Satayev164c7562019-12-10 17:47:52 +000026import android.compat.annotation.UnsupportedAppUsage;
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070027import android.content.Context;
Mathew Inwoodfe2fed72020-11-04 09:29:36 +000028import android.os.Build;
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070029import android.os.RemoteException;
30
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +090031import com.android.internal.annotations.GuardedBy;
32import com.android.internal.os.BackgroundThread;
33
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090034import java.util.ArrayList;
Lorenzo Colitti19b8b882020-01-24 19:29:17 +090035import java.util.Objects;
markchienc8e7d752020-02-26 20:54:55 +080036import java.util.concurrent.Executor;
James Mattis407ea1d2021-12-14 18:23:30 -080037import java.util.function.BiConsumer;
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090038
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070039/**
40 * A class representing the IP configuration of the Ethernet network.
41 *
42 * @hide
43 */
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +090044@SystemApi
Jeff Sharkeyad1cebe2017-06-02 17:36:26 -060045@SystemService(Context.ETHERNET_SERVICE)
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070046public class EthernetManager {
47 private static final String TAG = "EthernetManager";
48
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070049 private final IEthernetManager mService;
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +090050 @GuardedBy("mListeners")
51 private final ArrayList<ListenerInfo> mListeners = new ArrayList<>();
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090052 private final IEthernetServiceListener.Stub mServiceListener =
53 new IEthernetServiceListener.Stub() {
54 @Override
Pavel Maltsev50ec1f32017-10-31 15:34:16 -070055 public void onAvailabilityChanged(String iface, boolean isAvailable) {
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +090056 synchronized (mListeners) {
57 for (ListenerInfo li : mListeners) {
58 li.executor.execute(() ->
59 li.listener.onAvailabilityChanged(iface, isAvailable));
60 }
61 }
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090062 }
63 };
64
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +090065 private static class ListenerInfo {
66 @NonNull
67 public final Executor executor;
68 @NonNull
69 public final Listener listener;
70
71 private ListenerInfo(@NonNull Executor executor, @NonNull Listener listener) {
72 this.executor = executor;
73 this.listener = listener;
74 }
75 }
76
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090077 /**
78 * A listener interface to receive notification on changes in Ethernet.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +090079 * @hide
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090080 */
81 public interface Listener {
82 /**
83 * Called when Ethernet port's availability is changed.
Pavel Maltsev50ec1f32017-10-31 15:34:16 -070084 * @param iface Ethernet interface name
85 * @param isAvailable {@code true} if Ethernet port exists.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +090086 * @hide
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090087 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +000088 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Pavel Maltsev50ec1f32017-10-31 15:34:16 -070089 void onAvailabilityChanged(String iface, boolean isAvailable);
Jaewan Kim32b3f2c2014-10-20 12:04:13 +090090 }
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070091
92 /**
93 * Create a new EthernetManager instance.
94 * Applications will almost always want to use
95 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
96 * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +090097 * @hide
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -070098 */
99 public EthernetManager(Context context, IEthernetManager service) {
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700100 mService = service;
101 }
102
103 /**
Lorenzo Colitti56e4e582014-05-22 11:51:27 -0700104 * Get Ethernet configuration.
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700105 * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900106 * @hide
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700107 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000108 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700109 public IpConfiguration getConfiguration(String iface) {
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700110 try {
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700111 return mService.getConfiguration(iface);
Jeff Sharkeyf7138282016-03-01 19:27:23 -0700112 } catch (RemoteException e) {
113 throw e.rethrowFromSystemServer();
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700114 }
115 }
116
117 /**
Lorenzo Colitti56e4e582014-05-22 11:51:27 -0700118 * Set Ethernet configuration.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900119 * @hide
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700120 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000121 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700122 public void setConfiguration(String iface, IpConfiguration config) {
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700123 try {
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700124 mService.setConfiguration(iface, config);
Jeff Sharkeyf7138282016-03-01 19:27:23 -0700125 } catch (RemoteException e) {
126 throw e.rethrowFromSystemServer();
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900127 }
128 }
129
130 /**
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700131 * Indicates whether the system currently has one or more Ethernet interfaces.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900132 * @hide
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900133 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000134 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900135 public boolean isAvailable() {
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700136 return getAvailableInterfaces().length > 0;
137 }
138
139 /**
140 * Indicates whether the system has given interface.
141 *
142 * @param iface Ethernet interface name
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900143 * @hide
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700144 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000145 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700146 public boolean isAvailable(String iface) {
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900147 try {
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700148 return mService.isAvailable(iface);
Jeff Sharkeyf7138282016-03-01 19:27:23 -0700149 } catch (RemoteException e) {
150 throw e.rethrowFromSystemServer();
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900151 }
152 }
153
154 /**
155 * Adds a listener.
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +0900156 *
157 * Consider using {@link #addListener(Listener, Executor)} instead: this method uses a default
158 * executor that may have higher latency than a provided executor.
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900159 * @param listener A {@link Listener} to add.
160 * @throws IllegalArgumentException If the listener is null.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900161 * @hide
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900162 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000163 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +0900164 public void addListener(@NonNull Listener listener) {
165 addListener(listener, BackgroundThread.getExecutor());
166 }
167
168 /**
169 * Adds a listener.
170 * @param listener A {@link Listener} to add.
171 * @param executor Executor to run callbacks on.
172 * @throws IllegalArgumentException If the listener or executor is null.
173 * @hide
174 */
175 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
176 public void addListener(@NonNull Listener listener, @NonNull Executor executor) {
177 if (listener == null || executor == null) {
178 throw new NullPointerException("listener and executor must not be null");
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900179 }
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +0900180 synchronized (mListeners) {
181 mListeners.add(new ListenerInfo(executor, listener));
182 if (mListeners.size() == 1) {
183 try {
184 mService.addListener(mServiceListener);
185 } catch (RemoteException e) {
186 throw e.rethrowFromSystemServer();
187 }
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900188 }
189 }
190 }
191
192 /**
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700193 * Returns an array of available Ethernet interface names.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900194 * @hide
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700195 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000196 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Pavel Maltsev50ec1f32017-10-31 15:34:16 -0700197 public String[] getAvailableInterfaces() {
198 try {
199 return mService.getAvailableInterfaces();
200 } catch (RemoteException e) {
201 throw e.rethrowAsRuntimeException();
202 }
203 }
204
205 /**
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900206 * Removes a listener.
207 * @param listener A {@link Listener} to remove.
208 * @throws IllegalArgumentException If the listener is null.
Remi NGUYEN VAN199d6852020-01-24 22:57:09 +0900209 * @hide
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900210 */
Mathew Inwoodfe2fed72020-11-04 09:29:36 +0000211 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +0900212 public void removeListener(@NonNull Listener listener) {
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900213 if (listener == null) {
214 throw new IllegalArgumentException("listener must not be null");
215 }
Remi NGUYEN VAN55838a82020-12-03 17:58:49 +0900216 synchronized (mListeners) {
217 mListeners.removeIf(l -> l.listener == listener);
218 if (mListeners.isEmpty()) {
219 try {
220 mService.removeListener(mServiceListener);
221 } catch (RemoteException e) {
222 throw e.rethrowFromSystemServer();
223 }
Jaewan Kim32b3f2c2014-10-20 12:04:13 +0900224 }
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700225 }
226 }
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900227
228 /**
Lorenzo Colitti013187d2020-03-17 00:16:13 +0900229 * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface}
230 * as Ethernet interfaces. The effects of this method apply to any test interfaces that are
231 * already present on the system.
232 * @hide
233 */
234 @TestApi
235 public void setIncludeTestInterfaces(boolean include) {
236 try {
237 mService.setIncludeTestInterfaces(include);
238 } catch (RemoteException e) {
239 throw e.rethrowFromSystemServer();
240 }
241 }
242
243 /**
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900244 * A request for a tethered interface.
245 */
246 public static class TetheredInterfaceRequest {
247 private final IEthernetManager mService;
248 private final ITetheredInterfaceCallback mCb;
249
250 private TetheredInterfaceRequest(@NonNull IEthernetManager service,
251 @NonNull ITetheredInterfaceCallback cb) {
252 this.mService = service;
253 this.mCb = cb;
254 }
255
256 /**
257 * Release the request, causing the interface to revert back from tethering mode if there
258 * is no other requestor.
259 */
260 public void release() {
261 try {
262 mService.releaseTetheredInterface(mCb);
263 } catch (RemoteException e) {
264 e.rethrowFromSystemServer();
265 }
266 }
267 }
268
269 /**
270 * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}.
271 */
272 public interface TetheredInterfaceCallback {
273 /**
274 * Called when the tethered interface is available.
275 * @param iface The name of the interface.
276 */
277 void onAvailable(@NonNull String iface);
278
279 /**
280 * Called when the tethered interface is now unavailable.
281 */
282 void onUnavailable();
283 }
284
285 /**
286 * Request a tethered interface in tethering mode.
287 *
288 * <p>When this method is called and there is at least one ethernet interface available, the
289 * system will designate one to act as a tethered interface. If there is already a tethered
290 * interface, the existing interface will be used.
291 * @param callback A callback to be called once the request has been fulfilled.
292 */
Remi NGUYEN VAN11f39242020-03-09 13:56:18 +0900293 @RequiresPermission(anyOf = {
294 android.Manifest.permission.NETWORK_STACK,
295 android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
296 })
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900297 @NonNull
markchienc8e7d752020-02-26 20:54:55 +0800298 public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor,
299 @NonNull final TetheredInterfaceCallback callback) {
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900300 Objects.requireNonNull(callback, "Callback must be non-null");
markchienc8e7d752020-02-26 20:54:55 +0800301 Objects.requireNonNull(executor, "Executor must be non-null");
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900302 final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
303 @Override
304 public void onAvailable(String iface) {
markchienc8e7d752020-02-26 20:54:55 +0800305 executor.execute(() -> callback.onAvailable(iface));
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900306 }
307
308 @Override
309 public void onUnavailable() {
markchienc8e7d752020-02-26 20:54:55 +0800310 executor.execute(() -> callback.onUnavailable());
Lorenzo Colitti19b8b882020-01-24 19:29:17 +0900311 }
312 };
313
314 try {
315 mService.requestTetheredInterface(cbInternal);
316 } catch (RemoteException e) {
317 throw e.rethrowFromSystemServer();
318 }
319 return new TetheredInterfaceRequest(mService, cbInternal);
320 }
James Mattis407ea1d2021-12-14 18:23:30 -0800321
322 private static final class InternalNetworkManagementListener
James Mattis1ecadfa2022-01-28 13:42:38 -0800323 extends IEthernetNetworkManagementListener.Stub {
James Mattis407ea1d2021-12-14 18:23:30 -0800324 @NonNull
325 private final Executor mExecutor;
326 @NonNull
James Mattis1ecadfa2022-01-28 13:42:38 -0800327 private final BiConsumer<Network, EthernetNetworkManagementException> mListener;
James Mattis407ea1d2021-12-14 18:23:30 -0800328
329 InternalNetworkManagementListener(
330 @NonNull final Executor executor,
James Mattis1ecadfa2022-01-28 13:42:38 -0800331 @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) {
James Mattis407ea1d2021-12-14 18:23:30 -0800332 Objects.requireNonNull(executor, "Pass a non-null executor");
333 Objects.requireNonNull(listener, "Pass a non-null listener");
334 mExecutor = executor;
335 mListener = listener;
336 }
337
338 @Override
339 public void onComplete(
340 @Nullable final Network network,
James Mattis1ecadfa2022-01-28 13:42:38 -0800341 @Nullable final EthernetNetworkManagementException e) {
James Mattis407ea1d2021-12-14 18:23:30 -0800342 mExecutor.execute(() -> mListener.accept(network, e));
343 }
344 }
345
346 private InternalNetworkManagementListener getInternalNetworkManagementListener(
347 @Nullable final Executor executor,
James Mattis1ecadfa2022-01-28 13:42:38 -0800348 @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) {
James Mattis407ea1d2021-12-14 18:23:30 -0800349 if (null != listener) {
350 Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
351 }
352 final InternalNetworkManagementListener proxy;
353 if (null == listener) {
354 proxy = null;
355 } else {
356 proxy = new InternalNetworkManagementListener(executor, listener);
357 }
358 return proxy;
359 }
360
361 private void updateConfiguration(
362 @NonNull String iface,
James Mattis1ecadfa2022-01-28 13:42:38 -0800363 @NonNull EthernetNetworkUpdateRequest request,
James Mattis407ea1d2021-12-14 18:23:30 -0800364 @Nullable @CallbackExecutor Executor executor,
James Mattis1ecadfa2022-01-28 13:42:38 -0800365 @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
James Mattis407ea1d2021-12-14 18:23:30 -0800366 final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
367 executor, listener);
368 try {
369 mService.updateConfiguration(iface, request, proxy);
370 } catch (RemoteException e) {
371 throw e.rethrowFromSystemServer();
372 }
373 }
374
375 private void connectNetwork(
376 @NonNull String iface,
377 @Nullable @CallbackExecutor Executor executor,
James Mattis1ecadfa2022-01-28 13:42:38 -0800378 @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
James Mattis407ea1d2021-12-14 18:23:30 -0800379 final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
380 executor, listener);
381 try {
382 mService.connectNetwork(iface, proxy);
383 } catch (RemoteException e) {
384 throw e.rethrowFromSystemServer();
385 }
386 }
387
388 private void disconnectNetwork(
389 @NonNull String iface,
390 @Nullable @CallbackExecutor Executor executor,
James Mattis1ecadfa2022-01-28 13:42:38 -0800391 @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
James Mattis407ea1d2021-12-14 18:23:30 -0800392 final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
393 executor, listener);
394 try {
395 mService.disconnectNetwork(iface, proxy);
396 } catch (RemoteException e) {
397 throw e.rethrowFromSystemServer();
398 }
399 }
Lorenzo Colitti2edad7a2014-05-21 16:23:43 -0700400}