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 android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.net.IEthernetManager;
22 import android.net.IEthernetServiceListener;
23 import android.net.ITetheredInterfaceCallback;
24 import android.net.IpConfiguration;
25 import android.net.NetworkStack;
26 import android.os.Binder;
27 import android.os.Handler;
28 import android.os.HandlerThread;
29 import android.os.RemoteException;
30 import android.provider.Settings;
31 import android.util.Log;
32 import android.util.PrintWriterPrinter;
33 
34 import com.android.internal.util.IndentingPrintWriter;
35 
36 import java.io.FileDescriptor;
37 import java.io.PrintWriter;
38 import java.util.concurrent.atomic.AtomicBoolean;
39 
40 /**
41  * EthernetServiceImpl handles remote Ethernet operation requests by implementing
42  * the IEthernetManager interface.
43  */
44 public class EthernetServiceImpl extends IEthernetManager.Stub {
45     private static final String TAG = "EthernetServiceImpl";
46 
47     private final Context mContext;
48     private final AtomicBoolean mStarted = new AtomicBoolean(false);
49 
50     private Handler mHandler;
51     private EthernetTracker mTracker;
52 
EthernetServiceImpl(Context context)53     public EthernetServiceImpl(Context context) {
54         mContext = context;
55     }
56 
enforceAccessPermission()57     private void enforceAccessPermission() {
58         mContext.enforceCallingOrSelfPermission(
59                 android.Manifest.permission.ACCESS_NETWORK_STATE,
60                 "EthernetService");
61     }
62 
enforceUseRestrictedNetworksPermission()63     private void enforceUseRestrictedNetworksPermission() {
64         mContext.enforceCallingOrSelfPermission(
65                 android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS,
66                 "ConnectivityService");
67     }
68 
checkUseRestrictedNetworksPermission()69     private boolean checkUseRestrictedNetworksPermission() {
70         return mContext.checkCallingOrSelfPermission(
71                 android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS)
72                 == PackageManager.PERMISSION_GRANTED;
73     }
74 
start()75     public void start() {
76         Log.i(TAG, "Starting Ethernet service");
77 
78         HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
79         handlerThread.start();
80         mHandler = new Handler(handlerThread.getLooper());
81 
82         mTracker = new EthernetTracker(mContext, mHandler);
83         mTracker.start();
84 
85         mStarted.set(true);
86     }
87 
88     @Override
getAvailableInterfaces()89     public String[] getAvailableInterfaces() throws RemoteException {
90         enforceAccessPermission();
91 
92         return mTracker.getInterfaces(checkUseRestrictedNetworksPermission());
93     }
94 
95     /**
96      * Get Ethernet configuration
97      * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
98      */
99     @Override
getConfiguration(String iface)100     public IpConfiguration getConfiguration(String iface) {
101         enforceAccessPermission();
102 
103         if (mTracker.isRestrictedInterface(iface)) {
104             enforceUseRestrictedNetworksPermission();
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         if (!mStarted.get()) {
116             Log.w(TAG, "System isn't ready enough to change ethernet configuration");
117         }
118 
119         NetworkStack.checkNetworkStackPermission(mContext);
120 
121         if (mTracker.isRestrictedInterface(iface)) {
122             enforceUseRestrictedNetworksPermission();
123         }
124 
125         // TODO: this does not check proxy settings, gateways, etc.
126         // Fix this by making IpConfiguration a complete representation of static configuration.
127         mTracker.updateIpConfiguration(iface, new IpConfiguration(config));
128     }
129 
130     /**
131      * Indicates whether given interface is available.
132      */
133     @Override
isAvailable(String iface)134     public boolean isAvailable(String iface) {
135         enforceAccessPermission();
136 
137         if (mTracker.isRestrictedInterface(iface)) {
138             enforceUseRestrictedNetworksPermission();
139         }
140 
141         return mTracker.isTrackingInterface(iface);
142     }
143 
144     /**
145      * Adds a listener.
146      * @param listener A {@link IEthernetServiceListener} to add.
147      */
addListener(IEthernetServiceListener listener)148     public void addListener(IEthernetServiceListener listener) {
149         if (listener == null) {
150             throw new IllegalArgumentException("listener must not be null");
151         }
152         enforceAccessPermission();
153         mTracker.addListener(listener, checkUseRestrictedNetworksPermission());
154     }
155 
156     /**
157      * Removes a listener.
158      * @param listener A {@link IEthernetServiceListener} to remove.
159      */
removeListener(IEthernetServiceListener listener)160     public void removeListener(IEthernetServiceListener listener) {
161         if (listener == null) {
162             throw new IllegalArgumentException("listener must not be null");
163         }
164         enforceAccessPermission();
165         mTracker.removeListener(listener);
166     }
167 
168     @Override
setIncludeTestInterfaces(boolean include)169     public void setIncludeTestInterfaces(boolean include) {
170         NetworkStack.checkNetworkStackPermissionOr(mContext,
171                 android.Manifest.permission.NETWORK_SETTINGS);
172         mTracker.setIncludeTestInterfaces(include);
173     }
174 
175     @Override
requestTetheredInterface(ITetheredInterfaceCallback callback)176     public void requestTetheredInterface(ITetheredInterfaceCallback callback) {
177         NetworkStack.checkNetworkStackPermissionOr(mContext,
178                 android.Manifest.permission.NETWORK_SETTINGS);
179         mTracker.requestTetheredInterface(callback);
180     }
181 
182     @Override
releaseTetheredInterface(ITetheredInterfaceCallback callback)183     public void releaseTetheredInterface(ITetheredInterfaceCallback callback) {
184         NetworkStack.checkNetworkStackPermissionOr(mContext,
185                 android.Manifest.permission.NETWORK_SETTINGS);
186         mTracker.releaseTetheredInterface(callback);
187     }
188 
189     @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)190     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
191         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
192         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
193                 != PackageManager.PERMISSION_GRANTED) {
194             pw.println("Permission Denial: can't dump EthernetService from pid="
195                     + Binder.getCallingPid()
196                     + ", uid=" + Binder.getCallingUid());
197             return;
198         }
199 
200         pw.println("Current Ethernet state: ");
201         pw.increaseIndent();
202         mTracker.dump(fd, pw, args);
203         pw.decreaseIndent();
204 
205         pw.println("Handler:");
206         pw.increaseIndent();
207         mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
208         pw.decreaseIndent();
209     }
210 }
211