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 com.android.server.ethernet; 18 19 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 20 import static android.net.NetworkCapabilities.TRANSPORT_TEST; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.net.EthernetNetworkSpecifier; 27 import android.net.EthernetNetworkUpdateRequest; 28 import android.net.IEthernetManager; 29 import android.net.IEthernetServiceListener; 30 import android.net.INetworkInterfaceOutcomeReceiver; 31 import android.net.ITetheredInterfaceCallback; 32 import android.net.IpConfiguration; 33 import android.net.NetworkCapabilities; 34 import android.net.NetworkSpecifier; 35 import android.os.Handler; 36 import android.os.RemoteException; 37 import android.util.Log; 38 import android.util.PrintWriterPrinter; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.internal.util.IndentingPrintWriter; 42 import com.android.net.module.util.PermissionUtils; 43 44 import java.io.FileDescriptor; 45 import java.io.PrintWriter; 46 import java.util.List; 47 import java.util.Objects; 48 import java.util.concurrent.atomic.AtomicBoolean; 49 50 /** 51 * EthernetServiceImpl handles remote Ethernet operation requests by implementing 52 * the IEthernetManager interface. 53 */ 54 public class EthernetServiceImpl extends IEthernetManager.Stub { 55 private static final String TAG = "EthernetServiceImpl"; 56 57 @VisibleForTesting 58 final AtomicBoolean mStarted = new AtomicBoolean(false); 59 private final Context mContext; 60 private final Handler mHandler; 61 private final EthernetTracker mTracker; 62 EthernetServiceImpl(@onNull final Context context, @NonNull final Handler handler, @NonNull final EthernetTracker tracker)63 EthernetServiceImpl(@NonNull final Context context, @NonNull final Handler handler, 64 @NonNull final EthernetTracker tracker) { 65 mContext = context; 66 mHandler = handler; 67 mTracker = tracker; 68 } 69 enforceAutomotiveDevice(final @NonNull String methodName)70 private void enforceAutomotiveDevice(final @NonNull String methodName) { 71 PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE, 72 methodName + " is only available on automotive devices."); 73 } 74 checkUseRestrictedNetworksPermission()75 private boolean checkUseRestrictedNetworksPermission() { 76 return PermissionUtils.checkAnyPermissionOf(mContext, 77 android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS); 78 } 79 start()80 public void start() { 81 Log.i(TAG, "Starting Ethernet service"); 82 mTracker.start(); 83 mStarted.set(true); 84 } 85 throwIfEthernetNotStarted()86 private void throwIfEthernetNotStarted() { 87 if (!mStarted.get()) { 88 throw new IllegalStateException("System isn't ready to change ethernet configurations"); 89 } 90 } 91 92 @Override getAvailableInterfaces()93 public String[] getAvailableInterfaces() throws RemoteException { 94 PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); 95 return mTracker.getClientModeInterfaces(checkUseRestrictedNetworksPermission()); 96 } 97 98 /** 99 * Get Ethernet configuration 100 * @return the Ethernet Configuration, contained in {@link IpConfiguration}. 101 */ 102 @Override getConfiguration(String iface)103 public IpConfiguration getConfiguration(String iface) { 104 PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); 105 if (mTracker.isRestrictedInterface(iface)) { 106 PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); 107 } 108 109 return new IpConfiguration(mTracker.getIpConfiguration(iface)); 110 } 111 112 /** 113 * Set Ethernet configuration 114 */ 115 @Override setConfiguration(String iface, IpConfiguration config)116 public void setConfiguration(String iface, IpConfiguration config) { 117 throwIfEthernetNotStarted(); 118 119 PermissionUtils.enforceNetworkStackPermission(mContext); 120 if (mTracker.isRestrictedInterface(iface)) { 121 PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); 122 } 123 124 // TODO: this does not check proxy settings, gateways, etc. 125 // Fix this by making IpConfiguration a complete representation of static configuration. 126 mTracker.updateIpConfiguration(iface, new IpConfiguration(config)); 127 } 128 129 /** 130 * Indicates whether given interface is available. 131 */ 132 @Override isAvailable(String iface)133 public boolean isAvailable(String iface) { 134 PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); 135 if (mTracker.isRestrictedInterface(iface)) { 136 PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG); 137 } 138 139 return mTracker.isTrackingInterface(iface); 140 } 141 142 /** 143 * Adds a listener. 144 * @param listener A {@link IEthernetServiceListener} to add. 145 */ addListener(IEthernetServiceListener listener)146 public void addListener(IEthernetServiceListener listener) throws RemoteException { 147 Objects.requireNonNull(listener, "listener must not be null"); 148 PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); 149 mTracker.addListener(listener, checkUseRestrictedNetworksPermission()); 150 } 151 152 /** 153 * Removes a listener. 154 * @param listener A {@link IEthernetServiceListener} to remove. 155 */ removeListener(IEthernetServiceListener listener)156 public void removeListener(IEthernetServiceListener listener) { 157 if (listener == null) { 158 throw new IllegalArgumentException("listener must not be null"); 159 } 160 PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); 161 mTracker.removeListener(listener); 162 } 163 164 @Override setIncludeTestInterfaces(boolean include)165 public void setIncludeTestInterfaces(boolean include) { 166 PermissionUtils.enforceNetworkStackPermissionOr(mContext, 167 android.Manifest.permission.NETWORK_SETTINGS); 168 mTracker.setIncludeTestInterfaces(include); 169 } 170 171 @Override requestTetheredInterface(ITetheredInterfaceCallback callback)172 public void requestTetheredInterface(ITetheredInterfaceCallback callback) { 173 Objects.requireNonNull(callback, "callback must not be null"); 174 PermissionUtils.enforceNetworkStackPermissionOr(mContext, 175 android.Manifest.permission.NETWORK_SETTINGS); 176 mTracker.requestTetheredInterface(callback); 177 } 178 179 @Override releaseTetheredInterface(ITetheredInterfaceCallback callback)180 public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { 181 Objects.requireNonNull(callback, "callback must not be null"); 182 PermissionUtils.enforceNetworkStackPermissionOr(mContext, 183 android.Manifest.permission.NETWORK_SETTINGS); 184 mTracker.releaseTetheredInterface(callback); 185 } 186 187 @Override dump(FileDescriptor fd, PrintWriter writer, String[] args)188 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 189 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 190 if (!PermissionUtils.checkDumpPermission(mContext, TAG, pw)) return; 191 192 pw.println("Current Ethernet state: "); 193 pw.increaseIndent(); 194 mTracker.dump(fd, pw, args); 195 pw.decreaseIndent(); 196 197 pw.println("Handler:"); 198 pw.increaseIndent(); 199 mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); 200 pw.decreaseIndent(); 201 } 202 enforceNetworkManagementPermission()203 private void enforceNetworkManagementPermission() { 204 mContext.enforceCallingOrSelfPermission( 205 android.Manifest.permission.MANAGE_ETHERNET_NETWORKS, 206 "EthernetServiceImpl"); 207 } 208 enforceManageTestNetworksPermission()209 private void enforceManageTestNetworksPermission() { 210 mContext.enforceCallingOrSelfPermission( 211 android.Manifest.permission.MANAGE_TEST_NETWORKS, 212 "EthernetServiceImpl"); 213 } 214 validateOrSetNetworkSpecifier(String iface, NetworkCapabilities nc)215 private void validateOrSetNetworkSpecifier(String iface, NetworkCapabilities nc) { 216 final NetworkSpecifier spec = nc.getNetworkSpecifier(); 217 if (spec == null) { 218 nc.setNetworkSpecifier(new EthernetNetworkSpecifier(iface)); 219 return; 220 } 221 if (!(spec instanceof EthernetNetworkSpecifier)) { 222 throw new IllegalArgumentException("Invalid specifier type for request."); 223 } 224 if (!((EthernetNetworkSpecifier) spec).getInterfaceName().matches(iface)) { 225 throw new IllegalArgumentException("Invalid interface name set on specifier."); 226 } 227 } 228 maybeValidateTestCapabilities(String iface, NetworkCapabilities nc)229 private void maybeValidateTestCapabilities(String iface, NetworkCapabilities nc) { 230 if (!mTracker.isValidTestInterface(iface)) { 231 return; 232 } 233 if (!nc.hasTransport(TRANSPORT_TEST)) { 234 throw new IllegalArgumentException( 235 "Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST."); 236 } 237 } 238 maybeValidateEthernetTransport(String iface, NetworkCapabilities nc)239 private void maybeValidateEthernetTransport(String iface, NetworkCapabilities nc) { 240 if (mTracker.isValidTestInterface(iface)) { 241 return; 242 } 243 if (!nc.hasSingleTransport(TRANSPORT_ETHERNET)) { 244 throw new IllegalArgumentException("Invalid transport type for request."); 245 } 246 } 247 enforceAdminPermission(final String iface, boolean enforceAutomotive, final String logMessage)248 private void enforceAdminPermission(final String iface, boolean enforceAutomotive, 249 final String logMessage) { 250 if (mTracker.isValidTestInterface(iface)) { 251 enforceManageTestNetworksPermission(); 252 } else { 253 enforceNetworkManagementPermission(); 254 if (enforceAutomotive) { 255 enforceAutomotiveDevice(logMessage); 256 } 257 } 258 } 259 260 @Override updateConfiguration(@onNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, @Nullable final INetworkInterfaceOutcomeReceiver cb)261 public void updateConfiguration(@NonNull final String iface, 262 @NonNull final EthernetNetworkUpdateRequest request, 263 @Nullable final INetworkInterfaceOutcomeReceiver cb) { 264 Objects.requireNonNull(iface); 265 Objects.requireNonNull(request); 266 throwIfEthernetNotStarted(); 267 268 // TODO: validate that iface is listed in overlay config_ethernet_interfaces 269 // only automotive devices are allowed to set the NetworkCapabilities using this API 270 final NetworkCapabilities nc = request.getNetworkCapabilities(); 271 enforceAdminPermission( 272 iface, nc != null, "updateConfiguration() with non-null capabilities"); 273 if (nc != null) { 274 validateOrSetNetworkSpecifier(iface, nc); 275 maybeValidateTestCapabilities(iface, nc); 276 maybeValidateEthernetTransport(iface, nc); 277 } 278 279 mTracker.updateConfiguration( 280 iface, request.getIpConfiguration(), nc, new EthernetCallback(cb)); 281 } 282 283 @Override enableInterface(@onNull final String iface, @Nullable final INetworkInterfaceOutcomeReceiver cb)284 public void enableInterface(@NonNull final String iface, 285 @Nullable final INetworkInterfaceOutcomeReceiver cb) { 286 Log.i(TAG, "enableInterface called with: iface=" + iface + ", cb=" + cb); 287 Objects.requireNonNull(iface); 288 throwIfEthernetNotStarted(); 289 290 enforceAdminPermission(iface, false, "enableInterface()"); 291 292 mTracker.setInterfaceEnabled(iface, true /* enabled */, new EthernetCallback(cb)); 293 } 294 295 @Override disableInterface(@onNull final String iface, @Nullable final INetworkInterfaceOutcomeReceiver cb)296 public void disableInterface(@NonNull final String iface, 297 @Nullable final INetworkInterfaceOutcomeReceiver cb) { 298 Log.i(TAG, "disableInterface called with: iface=" + iface + ", cb=" + cb); 299 Objects.requireNonNull(iface); 300 throwIfEthernetNotStarted(); 301 302 enforceAdminPermission(iface, false, "disableInterface()"); 303 304 mTracker.setInterfaceEnabled(iface, false /* enabled */, new EthernetCallback(cb)); 305 } 306 307 @Override setEthernetEnabled(boolean enabled)308 public void setEthernetEnabled(boolean enabled) { 309 PermissionUtils.enforceNetworkStackPermissionOr(mContext, 310 android.Manifest.permission.NETWORK_SETTINGS); 311 312 mTracker.setEthernetEnabled(enabled); 313 } 314 315 @Override getInterfaceList()316 public List<String> getInterfaceList() { 317 PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG); 318 return mTracker.getInterfaceList(); 319 } 320 } 321