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