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