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