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, String callingAttributionTag, IIntResultListener listener)105         public void tether(String iface, String callerPkg, String callingAttributionTag,
106                 IIntResultListener listener) {
107             if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
108 
109             try {
110                 listener.onResult(mTethering.tether(iface));
111             } catch (RemoteException e) { }
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             try {
120                 listener.onResult(mTethering.untether(iface));
121             } catch (RemoteException e) { }
122         }
123 
124         @Override
setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag, IIntResultListener listener)125         public void setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag,
126                 IIntResultListener listener) {
127             if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
128 
129             try {
130                 listener.onResult(mTethering.setUsbTethering(enable));
131             } catch (RemoteException e) { }
132         }
133 
134         @Override
startTethering(TetheringRequestParcel request, String callerPkg, String callingAttributionTag, IIntResultListener listener)135         public void startTethering(TetheringRequestParcel request, String callerPkg,
136                 String callingAttributionTag, IIntResultListener listener) {
137             if (checkAndNotifyCommonError(callerPkg,
138                     callingAttributionTag,
139                     request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
140                     listener)) {
141                 return;
142             }
143 
144             mTethering.startTethering(request, listener);
145         }
146 
147         @Override
stopTethering(int type, String callerPkg, String callingAttributionTag, IIntResultListener listener)148         public void stopTethering(int type, String callerPkg, String callingAttributionTag,
149                 IIntResultListener listener) {
150             if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
151 
152             try {
153                 mTethering.stopTethering(type);
154                 listener.onResult(TETHER_ERROR_NO_ERROR);
155             } catch (RemoteException e) { }
156         }
157 
158         @Override
requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi, String callerPkg, String callingAttributionTag)159         public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
160                 boolean showEntitlementUi, String callerPkg, String callingAttributionTag) {
161             if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, receiver)) return;
162 
163             mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
164         }
165 
166         @Override
registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg)167         public void registerTetheringEventCallback(ITetheringEventCallback callback,
168                 String callerPkg) {
169             try {
170                 if (!hasTetherAccessPermission()) {
171                     callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
172                     return;
173                 }
174                 mTethering.registerTetheringEventCallback(callback);
175             } catch (RemoteException e) { }
176         }
177 
178         @Override
unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg)179         public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
180                 String callerPkg) {
181             try {
182                 if (!hasTetherAccessPermission()) {
183                     callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
184                     return;
185                 }
186                 mTethering.unregisterTetheringEventCallback(callback);
187             } catch (RemoteException e) { }
188         }
189 
190         @Override
stopAllTethering(String callerPkg, String callingAttributionTag, IIntResultListener listener)191         public void stopAllTethering(String callerPkg, String callingAttributionTag,
192                 IIntResultListener listener) {
193             if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
194 
195             try {
196                 mTethering.untetherAll();
197                 listener.onResult(TETHER_ERROR_NO_ERROR);
198             } catch (RemoteException e) { }
199         }
200 
201         @Override
isTetheringSupported(String callerPkg, String callingAttributionTag, IIntResultListener listener)202         public void isTetheringSupported(String callerPkg, String callingAttributionTag,
203                 IIntResultListener listener) {
204             if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
205 
206             try {
207                 listener.onResult(TETHER_ERROR_NO_ERROR);
208             } catch (RemoteException e) { }
209         }
210 
211         @Override
dump(@onNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args)212         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
213                     @Nullable String[] args) {
214             mTethering.dump(fd, writer, args);
215         }
216 
checkAndNotifyCommonError(final String callerPkg, final String callingAttributionTag, final IIntResultListener listener)217         private boolean checkAndNotifyCommonError(final String callerPkg,
218                 final String callingAttributionTag, final IIntResultListener listener) {
219             return checkAndNotifyCommonError(callerPkg, callingAttributionTag,
220                     false /* onlyAllowPrivileged */, listener);
221         }
222 
checkAndNotifyCommonError(final String callerPkg, final String callingAttributionTag, final boolean onlyAllowPrivileged, final IIntResultListener listener)223         private boolean checkAndNotifyCommonError(final String callerPkg,
224                 final String callingAttributionTag, final boolean onlyAllowPrivileged,
225                 final IIntResultListener listener) {
226             try {
227                 if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
228                         onlyAllowPrivileged)) {
229                     listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
230                     return true;
231                 }
232                 if (!mTethering.isTetheringSupported()) {
233                     listener.onResult(TETHER_ERROR_UNSUPPORTED);
234                     return true;
235                 }
236             } catch (RemoteException e) {
237                 return true;
238             }
239 
240             return false;
241         }
242 
checkAndNotifyCommonError(final String callerPkg, final String callingAttributionTag, final ResultReceiver receiver)243         private boolean checkAndNotifyCommonError(final String callerPkg,
244                 final String callingAttributionTag, final ResultReceiver receiver) {
245             if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
246                     false /* onlyAllowPrivileged */)) {
247                 receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
248                 return true;
249             }
250             if (!mTethering.isTetheringSupported()) {
251                 receiver.send(TETHER_ERROR_UNSUPPORTED, null);
252                 return true;
253             }
254 
255             return false;
256         }
257 
hasNetworkStackPermission()258         private boolean hasNetworkStackPermission() {
259             return checkCallingOrSelfPermission(NETWORK_STACK)
260                     || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK);
261         }
262 
hasTetherPrivilegedPermission()263         private boolean hasTetherPrivilegedPermission() {
264             return checkCallingOrSelfPermission(TETHER_PRIVILEGED);
265         }
266 
checkCallingOrSelfPermission(final String permission)267         private boolean checkCallingOrSelfPermission(final String permission) {
268             return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
269         }
270 
hasTetherChangePermission(final String callerPkg, final String callingAttributionTag, final boolean onlyAllowPrivileged)271         private boolean hasTetherChangePermission(final String callerPkg,
272                 final String callingAttributionTag, final boolean onlyAllowPrivileged) {
273             if (onlyAllowPrivileged && !hasNetworkStackPermission()) return false;
274 
275             if (hasTetherPrivilegedPermission()) return true;
276 
277             if (mTethering.isTetherProvisioningRequired()) return false;
278 
279             int uid = Binder.getCallingUid();
280 
281             // If callerPkg's uid is not same as Binder.getCallingUid(),
282             // checkAndNoteWriteSettingsOperation will return false and the operation will be
283             // denied.
284             return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
285                     callingAttributionTag, false /* throwException */);
286         }
287 
hasTetherAccessPermission()288         private boolean hasTetherAccessPermission() {
289             if (hasTetherPrivilegedPermission()) return true;
290 
291             return mService.checkCallingOrSelfPermission(
292                     ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
293         }
294     }
295 
296     /**
297      * Check if the package is a allowed to write settings. This also accounts that such an access
298      * happened.
299      *
300      * @return {@code true} iff the package is allowed to write settings.
301      */
302     @VisibleForTesting
checkAndNoteWriteSettingsOperation(@onNull Context context, int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, boolean throwException)303     boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
304             @NonNull String callingPackage, @Nullable String callingAttributionTag,
305             boolean throwException) {
306         return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
307                 throwException);
308     }
309 
310     /**
311      * An injection method for testing.
312      */
313     @VisibleForTesting
makeTetheringDependencies()314     public TetheringDependencies makeTetheringDependencies() {
315         return new TetheringDependencies() {
316             @Override
317             public NetworkRequest getDefaultNetworkRequest() {
318                 // TODO: b/147280869, add a proper system API to replace this.
319                 final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
320                         .clearCapabilities()
321                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
322                         .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
323                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
324                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
325                         .build();
326                 return trackDefaultRequest;
327             }
328 
329             @Override
330             public Looper getTetheringLooper() {
331                 final HandlerThread tetherThread = new HandlerThread("android.tethering");
332                 tetherThread.start();
333                 return tetherThread.getLooper();
334             }
335 
336             @Override
337             public Context getContext() {
338                 return TetheringService.this;
339             }
340 
341             @Override
342             public IpServer.Dependencies getIpServerDependencies() {
343                 return new IpServer.Dependencies() {
344                     @Override
345                     public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
346                             DhcpServerCallbacks cb) {
347                         try {
348                             final INetworkStackConnector service = getNetworkStackConnector();
349                             if (service == null) return;
350 
351                             service.makeDhcpServer(ifName, params, cb);
352                         } catch (RemoteException e) {
353                             Log.e(TAG, "Fail to make dhcp server");
354                             try {
355                                 cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
356                             } catch (RemoteException re) { }
357                         }
358                     }
359                 };
360             }
361 
362             // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
363             // networkStackClient.
364             static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
365             private INetworkStackConnector getNetworkStackConnector() {
366                 IBinder connector;
367                 try {
368                     final long before = System.currentTimeMillis();
369                     while ((connector = NetworkStack.getService()) == null) {
370                         if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
371                             Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
372                             return null;
373                         }
374                         Thread.sleep(200);
375                     }
376                 } catch (InterruptedException e) {
377                     Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
378                     return null;
379                 }
380                 return INetworkStackConnector.Stub.asInterface(connector);
381             }
382 
383             @Override
384             public BluetoothAdapter getBluetoothAdapter() {
385                 return BluetoothAdapter.getDefaultAdapter();
386             }
387         };
388     }
389 }
390