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