blob: bf7fb042ed3f1810b34d321ff3456a5d75cf142f [file] [log] [blame]
markchien0df2ebc42019-09-30 14:40:57 +08001/*
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
markchien503be612020-04-12 21:41:29 +080017package com.android.networkstack.tethering;
markchien0df2ebc42019-09-30 14:40:57 +080018
markchien5788f2a2020-05-08 18:55:26 +080019import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20import static android.Manifest.permission.TETHER_PRIVILEGED;
markchien6d06f6d2019-12-16 20:15:20 +080021import static android.content.pm.PackageManager.PERMISSION_GRANTED;
22import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
23import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
24import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
25import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED;
markchien986750b2019-12-06 15:24:53 +080026import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
markchien6d06f6d2019-12-16 20:15:20 +080027
markchien0df2ebc42019-09-30 14:40:57 +080028import android.app.Service;
markchien3fe660b2019-12-05 12:04:59 +080029import android.bluetooth.BluetoothAdapter;
markchien0df2ebc42019-09-30 14:40:57 +080030import android.content.Context;
31import android.content.Intent;
markchien6d06f6d2019-12-16 20:15:20 +080032import android.net.IIntResultListener;
33import android.net.INetworkStackConnector;
markchien0df2ebc42019-09-30 14:40:57 +080034import android.net.ITetheringConnector;
markchien6d06f6d2019-12-16 20:15:20 +080035import android.net.ITetheringEventCallback;
markchien87d3f7d2020-01-08 20:58:23 +080036import android.net.NetworkCapabilities;
markchien0df2ebc42019-09-30 14:40:57 +080037import android.net.NetworkRequest;
Remi NGUYEN VAN438018d2020-03-18 18:31:39 +090038import android.net.NetworkStack;
markchien06889172020-01-20 19:31:56 +080039import android.net.TetheringRequestParcel;
markchien6d06f6d2019-12-16 20:15:20 +080040import android.net.dhcp.DhcpServerCallbacks;
41import android.net.dhcp.DhcpServingParamsParcel;
42import android.net.ip.IpServer;
markchien6d06f6d2019-12-16 20:15:20 +080043import android.os.Binder;
markchien0df2ebc42019-09-30 14:40:57 +080044import android.os.HandlerThread;
45import android.os.IBinder;
46import android.os.Looper;
markchien6d06f6d2019-12-16 20:15:20 +080047import android.os.RemoteException;
markchien0df2ebc42019-09-30 14:40:57 +080048import android.os.ResultReceiver;
markchien0df2ebc42019-09-30 14:40:57 +080049import android.provider.Settings;
markchien6d06f6d2019-12-16 20:15:20 +080050import android.util.Log;
markchien0df2ebc42019-09-30 14:40:57 +080051
52import androidx.annotation.NonNull;
53import androidx.annotation.Nullable;
54
55import com.android.internal.annotations.VisibleForTesting;
56
57import java.io.FileDescriptor;
58import java.io.PrintWriter;
59
60/**
61 * Android service used to manage tethering.
62 *
63 * <p>The service returns a binder for the system server to communicate with the tethering.
64 */
65public class TetheringService extends Service {
66 private static final String TAG = TetheringService.class.getSimpleName();
67
markchien0df2ebc42019-09-30 14:40:57 +080068 private TetheringConnector mConnector;
markchien0df2ebc42019-09-30 14:40:57 +080069
70 @Override
71 public void onCreate() {
markchiencb8860c2020-05-12 00:08:27 +080072 final TetheringDependencies deps = makeTetheringDependencies();
73 // The Tethering object needs a fully functional context to start, so this can't be done
74 // in the constructor.
75 mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
markchien0df2ebc42019-09-30 14:40:57 +080076 }
77
78 /**
79 * Make a reference to Tethering object.
80 */
81 @VisibleForTesting
82 public Tethering makeTethering(TetheringDependencies deps) {
markchien771c3e92019-12-07 22:02:28 +080083 System.loadLibrary("tetherutilsjni");
markchien0df2ebc42019-09-30 14:40:57 +080084 return new Tethering(deps);
85 }
86
markchien0df2ebc42019-09-30 14:40:57 +080087 @NonNull
88 @Override
89 public IBinder onBind(Intent intent) {
markchiencb8860c2020-05-12 00:08:27 +080090 return mConnector;
markchien0df2ebc42019-09-30 14:40:57 +080091 }
92
93 private static class TetheringConnector extends ITetheringConnector.Stub {
markchien6d06f6d2019-12-16 20:15:20 +080094 private final TetheringService mService;
95 private final Tethering mTethering;
markchien0df2ebc42019-09-30 14:40:57 +080096
markchien6d06f6d2019-12-16 20:15:20 +080097 TetheringConnector(Tethering tether, TetheringService service) {
98 mTethering = tether;
99 mService = service;
markchien0df2ebc42019-09-30 14:40:57 +0800100 }
101
102 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800103 public void tether(String iface, String callerPkg, IIntResultListener listener) {
104 if (checkAndNotifyCommonError(callerPkg, listener)) return;
105
106 try {
107 listener.onResult(mTethering.tether(iface));
108 } catch (RemoteException e) { }
markchien0df2ebc42019-09-30 14:40:57 +0800109 }
110
111 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800112 public void untether(String iface, String callerPkg, IIntResultListener listener) {
113 if (checkAndNotifyCommonError(callerPkg, listener)) return;
114
115 try {
116 listener.onResult(mTethering.untether(iface));
117 } catch (RemoteException e) { }
markchien0df2ebc42019-09-30 14:40:57 +0800118 }
119
120 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800121 public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) {
122 if (checkAndNotifyCommonError(callerPkg, listener)) return;
123
124 try {
125 listener.onResult(mTethering.setUsbTethering(enable));
126 } catch (RemoteException e) { }
markchien0df2ebc42019-09-30 14:40:57 +0800127 }
128
129 @Override
markchien06889172020-01-20 19:31:56 +0800130 public void startTethering(TetheringRequestParcel request, String callerPkg,
131 IIntResultListener listener) {
markchien5788f2a2020-05-08 18:55:26 +0800132 if (checkAndNotifyCommonError(callerPkg,
133 request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
134 listener)) {
135 return;
136 }
markchien6d06f6d2019-12-16 20:15:20 +0800137
markchien06889172020-01-20 19:31:56 +0800138 mTethering.startTethering(request, listener);
markchien0df2ebc42019-09-30 14:40:57 +0800139 }
140
141 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800142 public void stopTethering(int type, String callerPkg, IIntResultListener listener) {
143 if (checkAndNotifyCommonError(callerPkg, listener)) return;
144
145 try {
146 mTethering.stopTethering(type);
147 listener.onResult(TETHER_ERROR_NO_ERROR);
148 } catch (RemoteException e) { }
markchien0df2ebc42019-09-30 14:40:57 +0800149 }
150
151 @Override
152 public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
markchien6d06f6d2019-12-16 20:15:20 +0800153 boolean showEntitlementUi, String callerPkg) {
154 if (checkAndNotifyCommonError(callerPkg, receiver)) return;
155
156 mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
markchien0df2ebc42019-09-30 14:40:57 +0800157 }
158
159 @Override
markchien6d06f6d2019-12-16 20:15:20 +0800160 public void registerTetheringEventCallback(ITetheringEventCallback callback,
161 String callerPkg) {
162 try {
markchien5788f2a2020-05-08 18:55:26 +0800163 if (!hasTetherAccessPermission()) {
markchien6d06f6d2019-12-16 20:15:20 +0800164 callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
165 return;
166 }
167 mTethering.registerTetheringEventCallback(callback);
168 } catch (RemoteException e) { }
markchien0df2ebc42019-09-30 14:40:57 +0800169 }
markchien6d06f6d2019-12-16 20:15:20 +0800170
171 @Override
172 public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
173 String callerPkg) {
174 try {
markchien5788f2a2020-05-08 18:55:26 +0800175 if (!hasTetherAccessPermission()) {
markchien6d06f6d2019-12-16 20:15:20 +0800176 callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
177 return;
178 }
179 mTethering.unregisterTetheringEventCallback(callback);
180 } catch (RemoteException e) { }
181 }
182
183 @Override
184 public void stopAllTethering(String callerPkg, IIntResultListener listener) {
185 if (checkAndNotifyCommonError(callerPkg, listener)) return;
186
187 try {
188 mTethering.untetherAll();
189 listener.onResult(TETHER_ERROR_NO_ERROR);
190 } catch (RemoteException e) { }
191 }
192
193 @Override
194 public void isTetheringSupported(String callerPkg, IIntResultListener listener) {
195 if (checkAndNotifyCommonError(callerPkg, listener)) return;
196
197 try {
198 listener.onResult(TETHER_ERROR_NO_ERROR);
199 } catch (RemoteException e) { }
200 }
201
202 @Override
203 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
204 @Nullable String[] args) {
205 mTethering.dump(fd, writer, args);
206 }
207
208 private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) {
markchien5788f2a2020-05-08 18:55:26 +0800209 return checkAndNotifyCommonError(callerPkg, false /* onlyAllowPrivileged */, listener);
210 }
211
212 private boolean checkAndNotifyCommonError(final String callerPkg,
213 final boolean onlyAllowPrivileged, final IIntResultListener listener) {
markchien6d06f6d2019-12-16 20:15:20 +0800214 try {
markchien5788f2a2020-05-08 18:55:26 +0800215 if (!hasTetherChangePermission(callerPkg, onlyAllowPrivileged)) {
markchien6d06f6d2019-12-16 20:15:20 +0800216 listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
217 return true;
218 }
markchiencb8860c2020-05-12 00:08:27 +0800219 if (!mTethering.isTetheringSupported()) {
markchien6d06f6d2019-12-16 20:15:20 +0800220 listener.onResult(TETHER_ERROR_UNSUPPORTED);
221 return true;
222 }
223 } catch (RemoteException e) {
224 return true;
225 }
226
227 return false;
228 }
229
230 private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) {
markchien5788f2a2020-05-08 18:55:26 +0800231 if (!hasTetherChangePermission(callerPkg, false /* onlyAllowPrivileged */)) {
markchien6d06f6d2019-12-16 20:15:20 +0800232 receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
233 return true;
234 }
markchiencb8860c2020-05-12 00:08:27 +0800235 if (!mTethering.isTetheringSupported()) {
markchien6d06f6d2019-12-16 20:15:20 +0800236 receiver.send(TETHER_ERROR_UNSUPPORTED, null);
237 return true;
238 }
239
240 return false;
241 }
242
markchien5788f2a2020-05-08 18:55:26 +0800243 private boolean hasTetherPrivilegedPermission() {
244 return mService.checkCallingOrSelfPermission(TETHER_PRIVILEGED) == PERMISSION_GRANTED;
245 }
246
247 private boolean hasTetherChangePermission(final String callerPkg,
248 final boolean onlyAllowPrivileged) {
249 if (hasTetherPrivilegedPermission()) return true;
250
251 if (onlyAllowPrivileged || mTethering.isTetherProvisioningRequired()) return false;
252
253 int uid = Binder.getCallingUid();
254 // If callerPkg's uid is not same as Binder.getCallingUid(),
255 // checkAndNoteWriteSettingsOperation will return false and the operation will be
256 // denied.
257 return Settings.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
258 false /* throwException */);
259 }
260
261 private boolean hasTetherAccessPermission() {
262 if (hasTetherPrivilegedPermission()) return true;
263
264 return mService.checkCallingOrSelfPermission(
265 ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
266 }
markchien0df2ebc42019-09-30 14:40:57 +0800267 }
268
markchien0df2ebc42019-09-30 14:40:57 +0800269 /**
270 * An injection method for testing.
271 */
272 @VisibleForTesting
markchiencb8860c2020-05-12 00:08:27 +0800273 public TetheringDependencies makeTetheringDependencies() {
274 return new TetheringDependencies() {
275 @Override
276 public NetworkRequest getDefaultNetworkRequest() {
277 // TODO: b/147280869, add a proper system API to replace this.
278 final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
279 .clearCapabilities()
280 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
281 .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
282 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
283 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
284 .build();
285 return trackDefaultRequest;
286 }
markchien0df2ebc42019-09-30 14:40:57 +0800287
markchiencb8860c2020-05-12 00:08:27 +0800288 @Override
289 public Looper getTetheringLooper() {
290 final HandlerThread tetherThread = new HandlerThread("android.tethering");
291 tetherThread.start();
292 return tetherThread.getLooper();
293 }
markchien0df2ebc42019-09-30 14:40:57 +0800294
markchiencb8860c2020-05-12 00:08:27 +0800295 @Override
296 public Context getContext() {
297 return TetheringService.this;
298 }
markchien0df2ebc42019-09-30 14:40:57 +0800299
markchiencb8860c2020-05-12 00:08:27 +0800300 @Override
301 public IpServer.Dependencies getIpServerDependencies() {
302 return new IpServer.Dependencies() {
303 @Override
304 public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
305 DhcpServerCallbacks cb) {
306 try {
307 final INetworkStackConnector service = getNetworkStackConnector();
308 if (service == null) return;
markchien6d06f6d2019-12-16 20:15:20 +0800309
markchiencb8860c2020-05-12 00:08:27 +0800310 service.makeDhcpServer(ifName, params, cb);
311 } catch (RemoteException e) {
312 Log.e(TAG, "Fail to make dhcp server");
markchien6d06f6d2019-12-16 20:15:20 +0800313 try {
markchiencb8860c2020-05-12 00:08:27 +0800314 cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
315 } catch (RemoteException re) { }
markchien6d06f6d2019-12-16 20:15:20 +0800316 }
markchien6d06f6d2019-12-16 20:15:20 +0800317 }
markchiencb8860c2020-05-12 00:08:27 +0800318 };
319 }
markchien3fe660b2019-12-05 12:04:59 +0800320
markchiencb8860c2020-05-12 00:08:27 +0800321 // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
322 // networkStackClient.
323 static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
324 private INetworkStackConnector getNetworkStackConnector() {
325 IBinder connector;
326 try {
327 final long before = System.currentTimeMillis();
328 while ((connector = NetworkStack.getService()) == null) {
329 if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
330 Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
331 return null;
332 }
333 Thread.sleep(200);
334 }
335 } catch (InterruptedException e) {
336 Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
337 return null;
markchien3fe660b2019-12-05 12:04:59 +0800338 }
markchiencb8860c2020-05-12 00:08:27 +0800339 return INetworkStackConnector.Stub.asInterface(connector);
340 }
341
342 @Override
343 public BluetoothAdapter getBluetoothAdapter() {
344 return BluetoothAdapter.getDefaultAdapter();
345 }
346 };
markchien0df2ebc42019-09-30 14:40:57 +0800347 }
348}