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