• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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