• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.networkstack.tethering;
18 
19 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20 import static android.Manifest.permission.NETWORK_STACK;
21 import static android.Manifest.permission.TETHER_PRIVILEGED;
22 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
23 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
24 import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
25 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
26 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
27 import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED;
28 import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
29 
30 import android.app.Service;
31 import android.bluetooth.BluetoothAdapter;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.net.IIntResultListener;
35 import android.net.INetworkStackConnector;
36 import android.net.ITetheringConnector;
37 import android.net.ITetheringEventCallback;
38 import android.net.NetworkCapabilities;
39 import android.net.NetworkRequest;
40 import android.net.NetworkStack;
41 import android.net.TetheringRequestParcel;
42 import android.net.dhcp.DhcpServerCallbacks;
43 import android.net.dhcp.DhcpServingParamsParcel;
44 import android.net.ip.IpServer;
45 import android.os.Binder;
46 import android.os.HandlerThread;
47 import android.os.IBinder;
48 import android.os.Looper;
49 import android.os.RemoteException;
50 import android.os.ResultReceiver;
51 import android.provider.Settings;
52 import android.util.Log;
53 
54 import androidx.annotation.NonNull;
55 import androidx.annotation.Nullable;
56 
57 import com.android.internal.annotations.VisibleForTesting;
58 
59 import java.io.FileDescriptor;
60 import java.io.PrintWriter;
61 
62 /**
63  * Android service used to manage tethering.
64  *
65  * <p>The service returns a binder for the system server to communicate with the tethering.
66  */
67 public class TetheringService extends Service {
68     private static final String TAG = TetheringService.class.getSimpleName();
69 
70     private TetheringConnector mConnector;
71 
72     @Override
onCreate()73     public void onCreate() {
74         final TetheringDependencies deps = makeTetheringDependencies();
75         // The Tethering object needs a fully functional context to start, so this can't be done
76         // in the constructor.
77         mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
78     }
79 
80     /**
81      * Make a reference to Tethering object.
82      */
83     @VisibleForTesting
makeTethering(TetheringDependencies deps)84     public Tethering makeTethering(TetheringDependencies deps) {
85         System.loadLibrary("tetherutilsjni");
86         return new Tethering(deps);
87     }
88 
89     @NonNull
90     @Override
onBind(Intent intent)91     public IBinder onBind(Intent intent) {
92         return mConnector;
93     }
94 
95     private static class TetheringConnector extends ITetheringConnector.Stub {
96         private final TetheringService mService;
97         private final Tethering mTethering;
98 
TetheringConnector(Tethering tether, TetheringService service)99         TetheringConnector(Tethering tether, TetheringService service) {
100             mTethering = tether;
101             mService = service;
102         }
103 
104         @Override
tether(String iface, String callerPkg, IIntResultListener listener)105         public void tether(String iface, String callerPkg, IIntResultListener listener) {
106             if (checkAndNotifyCommonError(callerPkg, listener)) return;
107 
108             try {
109                 listener.onResult(mTethering.tether(iface));
110             } catch (RemoteException e) { }
111         }
112 
113         @Override
untether(String iface, String callerPkg, IIntResultListener listener)114         public void untether(String iface, String callerPkg, IIntResultListener listener) {
115             if (checkAndNotifyCommonError(callerPkg, listener)) return;
116 
117             try {
118                 listener.onResult(mTethering.untether(iface));
119             } catch (RemoteException e) { }
120         }
121 
122         @Override
setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener)123         public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) {
124             if (checkAndNotifyCommonError(callerPkg, listener)) return;
125 
126             try {
127                 listener.onResult(mTethering.setUsbTethering(enable));
128             } catch (RemoteException e) { }
129         }
130 
131         @Override
startTethering(TetheringRequestParcel request, String callerPkg, IIntResultListener listener)132         public void startTethering(TetheringRequestParcel request, String callerPkg,
133                 IIntResultListener listener) {
134             if (checkAndNotifyCommonError(callerPkg,
135                     request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
136                     listener)) {
137                 return;
138             }
139 
140             mTethering.startTethering(request, listener);
141         }
142 
143         @Override
stopTethering(int type, String callerPkg, IIntResultListener listener)144         public void stopTethering(int type, String callerPkg, IIntResultListener listener) {
145             if (checkAndNotifyCommonError(callerPkg, listener)) return;
146 
147             try {
148                 mTethering.stopTethering(type);
149                 listener.onResult(TETHER_ERROR_NO_ERROR);
150             } catch (RemoteException e) { }
151         }
152 
153         @Override
requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi, String callerPkg)154         public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
155                 boolean showEntitlementUi, String callerPkg) {
156             if (checkAndNotifyCommonError(callerPkg, receiver)) return;
157 
158             mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
159         }
160 
161         @Override
registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg)162         public void registerTetheringEventCallback(ITetheringEventCallback callback,
163                 String callerPkg) {
164             try {
165                 if (!hasTetherAccessPermission()) {
166                     callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
167                     return;
168                 }
169                 mTethering.registerTetheringEventCallback(callback);
170             } catch (RemoteException e) { }
171         }
172 
173         @Override
unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg)174         public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
175                 String callerPkg) {
176             try {
177                 if (!hasTetherAccessPermission()) {
178                     callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
179                     return;
180                 }
181                 mTethering.unregisterTetheringEventCallback(callback);
182             } catch (RemoteException e) { }
183         }
184 
185         @Override
stopAllTethering(String callerPkg, IIntResultListener listener)186         public void stopAllTethering(String callerPkg, IIntResultListener listener) {
187             if (checkAndNotifyCommonError(callerPkg, listener)) return;
188 
189             try {
190                 mTethering.untetherAll();
191                 listener.onResult(TETHER_ERROR_NO_ERROR);
192             } catch (RemoteException e) { }
193         }
194 
195         @Override
isTetheringSupported(String callerPkg, IIntResultListener listener)196         public void isTetheringSupported(String callerPkg, IIntResultListener listener) {
197             if (checkAndNotifyCommonError(callerPkg, listener)) return;
198 
199             try {
200                 listener.onResult(TETHER_ERROR_NO_ERROR);
201             } catch (RemoteException e) { }
202         }
203 
204         @Override
dump(@onNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args)205         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
206                     @Nullable String[] args) {
207             mTethering.dump(fd, writer, args);
208         }
209 
checkAndNotifyCommonError(String callerPkg, IIntResultListener listener)210         private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) {
211             return checkAndNotifyCommonError(callerPkg, false /* onlyAllowPrivileged */, listener);
212         }
213 
checkAndNotifyCommonError(final String callerPkg, final boolean onlyAllowPrivileged, final IIntResultListener listener)214         private boolean checkAndNotifyCommonError(final String callerPkg,
215                 final boolean onlyAllowPrivileged, final IIntResultListener listener) {
216             try {
217                 if (!hasTetherChangePermission(callerPkg, onlyAllowPrivileged)) {
218                     listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
219                     return true;
220                 }
221                 if (!mTethering.isTetheringSupported()) {
222                     listener.onResult(TETHER_ERROR_UNSUPPORTED);
223                     return true;
224                 }
225             } catch (RemoteException e) {
226                 return true;
227             }
228 
229             return false;
230         }
231 
checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver)232         private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) {
233             if (!hasTetherChangePermission(callerPkg, false /* onlyAllowPrivileged */)) {
234                 receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
235                 return true;
236             }
237             if (!mTethering.isTetheringSupported()) {
238                 receiver.send(TETHER_ERROR_UNSUPPORTED, null);
239                 return true;
240             }
241 
242             return false;
243         }
244 
hasNetworkStackPermission()245         private boolean hasNetworkStackPermission() {
246             return checkCallingOrSelfPermission(NETWORK_STACK)
247                     || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK);
248         }
249 
hasTetherPrivilegedPermission()250         private boolean hasTetherPrivilegedPermission() {
251             return checkCallingOrSelfPermission(TETHER_PRIVILEGED);
252         }
253 
checkCallingOrSelfPermission(final String permission)254         private boolean checkCallingOrSelfPermission(final String permission) {
255             return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
256         }
257 
hasTetherChangePermission(final String callerPkg, final boolean onlyAllowPrivileged)258         private boolean hasTetherChangePermission(final String callerPkg,
259                 final boolean onlyAllowPrivileged) {
260             if (onlyAllowPrivileged && !hasNetworkStackPermission()) return false;
261 
262             if (hasTetherPrivilegedPermission()) return true;
263 
264             if (mTethering.isTetherProvisioningRequired()) return false;
265 
266             int uid = Binder.getCallingUid();
267             // If callerPkg's uid is not same as Binder.getCallingUid(),
268             // checkAndNoteWriteSettingsOperation will return false and the operation will be
269             // denied.
270             return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
271                     false /* throwException */);
272         }
273 
hasTetherAccessPermission()274         private boolean hasTetherAccessPermission() {
275             if (hasTetherPrivilegedPermission()) return true;
276 
277             return mService.checkCallingOrSelfPermission(
278                     ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
279         }
280     }
281 
282     /**
283      * Check if the package is a allowed to write settings. This also accounts that such an access
284      * happened.
285      *
286      * @return {@code true} iff the package is allowed to write settings.
287      */
288     @VisibleForTesting
checkAndNoteWriteSettingsOperation(@onNull Context context, int uid, @NonNull String callingPackage, boolean throwException)289     boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
290             @NonNull String callingPackage, boolean throwException) {
291         return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
292                 throwException);
293     }
294 
295     /**
296      * An injection method for testing.
297      */
298     @VisibleForTesting
makeTetheringDependencies()299     public TetheringDependencies makeTetheringDependencies() {
300         return new TetheringDependencies() {
301             @Override
302             public NetworkRequest getDefaultNetworkRequest() {
303                 // TODO: b/147280869, add a proper system API to replace this.
304                 final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
305                         .clearCapabilities()
306                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
307                         .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
308                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
309                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
310                         .build();
311                 return trackDefaultRequest;
312             }
313 
314             @Override
315             public Looper getTetheringLooper() {
316                 final HandlerThread tetherThread = new HandlerThread("android.tethering");
317                 tetherThread.start();
318                 return tetherThread.getLooper();
319             }
320 
321             @Override
322             public Context getContext() {
323                 return TetheringService.this;
324             }
325 
326             @Override
327             public IpServer.Dependencies getIpServerDependencies() {
328                 return new IpServer.Dependencies() {
329                     @Override
330                     public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
331                             DhcpServerCallbacks cb) {
332                         try {
333                             final INetworkStackConnector service = getNetworkStackConnector();
334                             if (service == null) return;
335 
336                             service.makeDhcpServer(ifName, params, cb);
337                         } catch (RemoteException e) {
338                             Log.e(TAG, "Fail to make dhcp server");
339                             try {
340                                 cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
341                             } catch (RemoteException re) { }
342                         }
343                     }
344                 };
345             }
346 
347             // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
348             // networkStackClient.
349             static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
350             private INetworkStackConnector getNetworkStackConnector() {
351                 IBinder connector;
352                 try {
353                     final long before = System.currentTimeMillis();
354                     while ((connector = NetworkStack.getService()) == null) {
355                         if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
356                             Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
357                             return null;
358                         }
359                         Thread.sleep(200);
360                     }
361                 } catch (InterruptedException e) {
362                     Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
363                     return null;
364                 }
365                 return INetworkStackConnector.Stub.asInterface(connector);
366             }
367 
368             @Override
369             public BluetoothAdapter getBluetoothAdapter() {
370                 return BluetoothAdapter.getDefaultAdapter();
371             }
372         };
373     }
374 }
375