1 /* 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 17 package android.net; 18 19 import android.annotation.NonNull; 20 import android.annotation.RequiresPermission; 21 import android.annotation.SystemApi; 22 import android.annotation.SystemService; 23 import android.annotation.TestApi; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.Context; 26 import android.os.Handler; 27 import android.os.Message; 28 import android.os.RemoteException; 29 30 import java.util.ArrayList; 31 import java.util.Objects; 32 import java.util.concurrent.Executor; 33 34 /** 35 * A class representing the IP configuration of the Ethernet network. 36 * 37 * @hide 38 */ 39 @SystemApi 40 @TestApi 41 @SystemService(Context.ETHERNET_SERVICE) 42 public class EthernetManager { 43 private static final String TAG = "EthernetManager"; 44 private static final int MSG_AVAILABILITY_CHANGED = 1000; 45 46 private final Context mContext; 47 private final IEthernetManager mService; 48 private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { 49 @Override 50 public void handleMessage(Message msg) { 51 if (msg.what == MSG_AVAILABILITY_CHANGED) { 52 boolean isAvailable = (msg.arg1 == 1); 53 for (Listener listener : mListeners) { 54 listener.onAvailabilityChanged((String) msg.obj, isAvailable); 55 } 56 } 57 } 58 }; 59 private final ArrayList<Listener> mListeners = new ArrayList<>(); 60 private final IEthernetServiceListener.Stub mServiceListener = 61 new IEthernetServiceListener.Stub() { 62 @Override 63 public void onAvailabilityChanged(String iface, boolean isAvailable) { 64 mHandler.obtainMessage( 65 MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, iface).sendToTarget(); 66 } 67 }; 68 69 /** 70 * A listener interface to receive notification on changes in Ethernet. 71 * @hide 72 */ 73 public interface Listener { 74 /** 75 * Called when Ethernet port's availability is changed. 76 * @param iface Ethernet interface name 77 * @param isAvailable {@code true} if Ethernet port exists. 78 * @hide 79 */ 80 @UnsupportedAppUsage onAvailabilityChanged(String iface, boolean isAvailable)81 void onAvailabilityChanged(String iface, boolean isAvailable); 82 } 83 84 /** 85 * Create a new EthernetManager instance. 86 * Applications will almost always want to use 87 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve 88 * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. 89 * @hide 90 */ EthernetManager(Context context, IEthernetManager service)91 public EthernetManager(Context context, IEthernetManager service) { 92 mContext = context; 93 mService = service; 94 } 95 96 /** 97 * Get Ethernet configuration. 98 * @return the Ethernet Configuration, contained in {@link IpConfiguration}. 99 * @hide 100 */ 101 @UnsupportedAppUsage getConfiguration(String iface)102 public IpConfiguration getConfiguration(String iface) { 103 try { 104 return mService.getConfiguration(iface); 105 } catch (RemoteException e) { 106 throw e.rethrowFromSystemServer(); 107 } 108 } 109 110 /** 111 * Set Ethernet configuration. 112 * @hide 113 */ 114 @UnsupportedAppUsage setConfiguration(String iface, IpConfiguration config)115 public void setConfiguration(String iface, IpConfiguration config) { 116 try { 117 mService.setConfiguration(iface, config); 118 } catch (RemoteException e) { 119 throw e.rethrowFromSystemServer(); 120 } 121 } 122 123 /** 124 * Indicates whether the system currently has one or more Ethernet interfaces. 125 * @hide 126 */ 127 @UnsupportedAppUsage isAvailable()128 public boolean isAvailable() { 129 return getAvailableInterfaces().length > 0; 130 } 131 132 /** 133 * Indicates whether the system has given interface. 134 * 135 * @param iface Ethernet interface name 136 * @hide 137 */ 138 @UnsupportedAppUsage isAvailable(String iface)139 public boolean isAvailable(String iface) { 140 try { 141 return mService.isAvailable(iface); 142 } catch (RemoteException e) { 143 throw e.rethrowFromSystemServer(); 144 } 145 } 146 147 /** 148 * Adds a listener. 149 * @param listener A {@link Listener} to add. 150 * @throws IllegalArgumentException If the listener is null. 151 * @hide 152 */ 153 @UnsupportedAppUsage addListener(Listener listener)154 public void addListener(Listener listener) { 155 if (listener == null) { 156 throw new IllegalArgumentException("listener must not be null"); 157 } 158 mListeners.add(listener); 159 if (mListeners.size() == 1) { 160 try { 161 mService.addListener(mServiceListener); 162 } catch (RemoteException e) { 163 throw e.rethrowFromSystemServer(); 164 } 165 } 166 } 167 168 /** 169 * Returns an array of available Ethernet interface names. 170 * @hide 171 */ 172 @UnsupportedAppUsage getAvailableInterfaces()173 public String[] getAvailableInterfaces() { 174 try { 175 return mService.getAvailableInterfaces(); 176 } catch (RemoteException e) { 177 throw e.rethrowAsRuntimeException(); 178 } 179 } 180 181 /** 182 * Removes a listener. 183 * @param listener A {@link Listener} to remove. 184 * @throws IllegalArgumentException If the listener is null. 185 * @hide 186 */ 187 @UnsupportedAppUsage removeListener(Listener listener)188 public void removeListener(Listener listener) { 189 if (listener == null) { 190 throw new IllegalArgumentException("listener must not be null"); 191 } 192 mListeners.remove(listener); 193 if (mListeners.isEmpty()) { 194 try { 195 mService.removeListener(mServiceListener); 196 } catch (RemoteException e) { 197 throw e.rethrowFromSystemServer(); 198 } 199 } 200 } 201 202 /** 203 * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} 204 * as Ethernet interfaces. The effects of this method apply to any test interfaces that are 205 * already present on the system. 206 * @hide 207 */ 208 @TestApi setIncludeTestInterfaces(boolean include)209 public void setIncludeTestInterfaces(boolean include) { 210 try { 211 mService.setIncludeTestInterfaces(include); 212 } catch (RemoteException e) { 213 throw e.rethrowFromSystemServer(); 214 } 215 } 216 217 /** 218 * A request for a tethered interface. 219 */ 220 public static class TetheredInterfaceRequest { 221 private final IEthernetManager mService; 222 private final ITetheredInterfaceCallback mCb; 223 TetheredInterfaceRequest(@onNull IEthernetManager service, @NonNull ITetheredInterfaceCallback cb)224 private TetheredInterfaceRequest(@NonNull IEthernetManager service, 225 @NonNull ITetheredInterfaceCallback cb) { 226 this.mService = service; 227 this.mCb = cb; 228 } 229 230 /** 231 * Release the request, causing the interface to revert back from tethering mode if there 232 * is no other requestor. 233 */ release()234 public void release() { 235 try { 236 mService.releaseTetheredInterface(mCb); 237 } catch (RemoteException e) { 238 e.rethrowFromSystemServer(); 239 } 240 } 241 } 242 243 /** 244 * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. 245 */ 246 public interface TetheredInterfaceCallback { 247 /** 248 * Called when the tethered interface is available. 249 * @param iface The name of the interface. 250 */ onAvailable(@onNull String iface)251 void onAvailable(@NonNull String iface); 252 253 /** 254 * Called when the tethered interface is now unavailable. 255 */ onUnavailable()256 void onUnavailable(); 257 } 258 259 /** 260 * Request a tethered interface in tethering mode. 261 * 262 * <p>When this method is called and there is at least one ethernet interface available, the 263 * system will designate one to act as a tethered interface. If there is already a tethered 264 * interface, the existing interface will be used. 265 * @param callback A callback to be called once the request has been fulfilled. 266 */ 267 @RequiresPermission(anyOf = { 268 android.Manifest.permission.NETWORK_STACK, 269 android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK 270 }) 271 @NonNull requestTetheredInterface(@onNull final Executor executor, @NonNull final TetheredInterfaceCallback callback)272 public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, 273 @NonNull final TetheredInterfaceCallback callback) { 274 Objects.requireNonNull(callback, "Callback must be non-null"); 275 Objects.requireNonNull(executor, "Executor must be non-null"); 276 final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { 277 @Override 278 public void onAvailable(String iface) { 279 executor.execute(() -> callback.onAvailable(iface)); 280 } 281 282 @Override 283 public void onUnavailable() { 284 executor.execute(() -> callback.onUnavailable()); 285 } 286 }; 287 288 try { 289 mService.requestTetheredInterface(cbInternal); 290 } catch (RemoteException e) { 291 throw e.rethrowFromSystemServer(); 292 } 293 return new TetheredInterfaceRequest(mService, cbInternal); 294 } 295 } 296