1 /* 2 * Copyright (C) 2016 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.server.wifi.aware; 18 19 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; 20 21 import android.Manifest; 22 import android.annotation.NonNull; 23 import android.app.AppOpsManager; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.hardware.wifi.V1_0.NanStatusType; 27 import android.net.wifi.WifiManager; 28 import android.net.wifi.aware.AwareParams; 29 import android.net.wifi.aware.AwareResources; 30 import android.net.wifi.aware.Characteristics; 31 import android.net.wifi.aware.ConfigRequest; 32 import android.net.wifi.aware.DiscoverySession; 33 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 34 import android.net.wifi.aware.IWifiAwareEventCallback; 35 import android.net.wifi.aware.IWifiAwareMacAddressProvider; 36 import android.net.wifi.aware.IWifiAwareManager; 37 import android.net.wifi.aware.PublishConfig; 38 import android.net.wifi.aware.SubscribeConfig; 39 import android.os.Binder; 40 import android.os.Build; 41 import android.os.Bundle; 42 import android.os.Handler; 43 import android.os.HandlerThread; 44 import android.os.IBinder; 45 import android.os.ParcelFileDescriptor; 46 import android.os.Process; 47 import android.os.RemoteException; 48 import android.util.Log; 49 import android.util.SparseArray; 50 import android.util.SparseIntArray; 51 52 import com.android.modules.utils.build.SdkLevel; 53 import com.android.server.wifi.Clock; 54 import com.android.server.wifi.InterfaceConflictManager; 55 import com.android.server.wifi.WifiSettingsConfigStore; 56 import com.android.server.wifi.util.NetdWrapper; 57 import com.android.server.wifi.util.WifiPermissionsUtil; 58 import com.android.server.wifi.util.WifiPermissionsWrapper; 59 60 import java.io.FileDescriptor; 61 import java.io.PrintWriter; 62 63 /** 64 * Implementation of the IWifiAwareManager AIDL interface. Performs validity 65 * (permission and clientID-UID mapping) checks and delegates execution to the 66 * WifiAwareStateManager singleton handler. Limited state to feedback which has to 67 * be provided instantly: client and session IDs. 68 */ 69 public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { 70 private static final String TAG = "WifiAwareService"; 71 private boolean mDbg = false; 72 73 private Context mContext; 74 private AppOpsManager mAppOps; 75 private WifiPermissionsUtil mWifiPermissionsUtil; 76 private WifiAwareStateManager mStateManager; 77 private WifiAwareShellCommand mShellCommand; 78 private Handler mHandler; 79 80 private final Object mLock = new Object(); 81 private final SparseArray<IBinder.DeathRecipient> mDeathRecipientsByClientId = 82 new SparseArray<>(); 83 private int mNextClientId = 1; 84 private final SparseIntArray mUidByClientId = new SparseIntArray(); 85 WifiAwareServiceImpl(Context context)86 public WifiAwareServiceImpl(Context context) { 87 mContext = context; 88 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 89 } 90 91 /** 92 * Proxy for the final native call of the parent class. Enables mocking of 93 * the function. 94 */ getMockableCallingUid()95 public int getMockableCallingUid() { 96 return getCallingUid(); 97 } 98 99 /** 100 * Start the service: allocate a new thread (for now), start the handlers of 101 * the components of the service. 102 */ start(HandlerThread handlerThread, WifiAwareStateManager awareStateManager, WifiAwareShellCommand awareShellCommand, WifiAwareMetrics awareMetrics, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper, WifiSettingsConfigStore settingsConfigStore, WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, WifiAwareNativeCallback wifiAwareNativeCallback, NetdWrapper netdWrapper, InterfaceConflictManager interfaceConflictManager)103 public void start(HandlerThread handlerThread, WifiAwareStateManager awareStateManager, 104 WifiAwareShellCommand awareShellCommand, WifiAwareMetrics awareMetrics, 105 WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper, 106 WifiSettingsConfigStore settingsConfigStore, 107 WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, 108 WifiAwareNativeCallback wifiAwareNativeCallback, NetdWrapper netdWrapper, 109 InterfaceConflictManager interfaceConflictManager) { 110 Log.i(TAG, "Starting Wi-Fi Aware service"); 111 112 mWifiPermissionsUtil = wifiPermissionsUtil; 113 mStateManager = awareStateManager; 114 mShellCommand = awareShellCommand; 115 mHandler = new Handler(handlerThread.getLooper()); 116 117 mHandler.post(() -> { 118 mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, 119 wifiPermissionsUtil, permissionsWrapper, new Clock(), netdWrapper, 120 interfaceConflictManager); 121 122 settingsConfigStore.registerChangeListener( 123 WIFI_VERBOSE_LOGGING_ENABLED, 124 (key, newValue) -> enableVerboseLogging(newValue, awareStateManager, 125 wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback), 126 mHandler); 127 enableVerboseLogging(settingsConfigStore.get(WIFI_VERBOSE_LOGGING_ENABLED), 128 awareStateManager, 129 wifiAwareNativeManager, wifiAwareNativeApi, 130 wifiAwareNativeCallback); 131 }); 132 } 133 enableVerboseLogging(boolean dbg, WifiAwareStateManager awareStateManager, WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, WifiAwareNativeCallback wifiAwareNativeCallback)134 private void enableVerboseLogging(boolean dbg, WifiAwareStateManager awareStateManager, 135 WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi, 136 WifiAwareNativeCallback wifiAwareNativeCallback) { 137 mDbg = dbg; 138 awareStateManager.enableVerboseLogging(dbg); 139 if (awareStateManager.mDataPathMgr != null) { // needed for unit tests 140 awareStateManager.mDataPathMgr.enableVerboseLogging(dbg); 141 } 142 wifiAwareNativeCallback.enableVerboseLogging(dbg); 143 wifiAwareNativeManager.enableVerboseLogging(dbg); 144 wifiAwareNativeApi.enableVerboseLogging(dbg); 145 } 146 147 /** 148 * Start/initialize portions of the service which require the boot stage to be complete. 149 */ startLate()150 public void startLate() { 151 Log.i(TAG, "Late initialization of Wi-Fi Aware service"); 152 153 mHandler.post(() -> mStateManager.startLate()); 154 } 155 156 @Override isUsageEnabled()157 public boolean isUsageEnabled() { 158 enforceAccessPermission(); 159 160 return mStateManager.isUsageEnabled(); 161 } 162 163 @Override getCharacteristics()164 public Characteristics getCharacteristics() { 165 enforceAccessPermission(); 166 167 return mStateManager.getCapabilities() == null ? null 168 : mStateManager.getCapabilities().toPublicCharacteristics(); 169 } 170 171 @Override getAvailableAwareResources()172 public AwareResources getAvailableAwareResources() { 173 enforceAccessPermission(); 174 return mStateManager.getAvailableAwareResources(); 175 } 176 177 @Override isDeviceAttached()178 public boolean isDeviceAttached() { 179 enforceAccessPermission(); 180 return mStateManager.isDeviceAttached(); 181 } 182 183 @Override enableInstantCommunicationMode(String callingPackage, boolean enable)184 public void enableInstantCommunicationMode(String callingPackage, boolean enable) { 185 enforceChangePermission(); 186 int uid = getMockableCallingUid(); 187 if (uid != Process.SHELL_UID && uid != Process.ROOT_UID) { 188 mWifiPermissionsUtil.checkPackage(uid, callingPackage); 189 if (!mWifiPermissionsUtil.isSystem(callingPackage, uid) 190 && !mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { 191 Log.i(TAG, "enableInstantCommunicationMode not allowed for uid=" + uid); 192 return; 193 } 194 } 195 mStateManager.enableInstantCommunicationMode(enable); 196 } 197 198 @Override isInstantCommunicationModeEnabled()199 public boolean isInstantCommunicationModeEnabled() { 200 enforceAccessPermission(); 201 return mStateManager.isInstantCommModeGlobalEnable(); 202 } 203 204 @Override isSetChannelOnDataPathSupported()205 public boolean isSetChannelOnDataPathSupported() { 206 enforceAccessPermission(); 207 return mStateManager.isSetChannelOnDataPathSupported(); 208 } 209 210 @Override setAwareParams(AwareParams params)211 public void setAwareParams(AwareParams params) { 212 enforceChangePermission(); 213 int uid = getMockableCallingUid(); 214 if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { 215 throw new SecurityException("App not allowed to update Aware parameters " 216 + "(uid = " + uid + ")"); 217 } 218 mStateManager.setAwareParams(params); 219 } 220 221 @Override connect(final IBinder binder, String callingPackage, String callingFeatureId, IWifiAwareEventCallback callback, ConfigRequest configRequest, boolean notifyOnIdentityChanged, Bundle extras)222 public void connect(final IBinder binder, String callingPackage, String callingFeatureId, 223 IWifiAwareEventCallback callback, ConfigRequest configRequest, 224 boolean notifyOnIdentityChanged, Bundle extras) { 225 enforceAccessPermission(); 226 enforceChangePermission(); 227 228 final int uid = getMockableCallingUid(); 229 mWifiPermissionsUtil.checkPackage(uid, callingPackage); 230 231 if (callback == null) { 232 throw new IllegalArgumentException("Callback must not be null"); 233 } 234 if (binder == null) { 235 throw new IllegalArgumentException("Binder must not be null"); 236 } 237 238 if (extras == null) { 239 throw new IllegalArgumentException("extras bundle must not be null"); 240 } 241 242 if (notifyOnIdentityChanged) { 243 enforceNearbyOrLocationPermission(callingPackage, callingFeatureId, 244 getMockableCallingUid(), extras, "Wifi Aware attach"); 245 } 246 247 if (configRequest != null) { 248 enforceNetworkStackPermission(); 249 } else { 250 configRequest = new ConfigRequest.Builder().build(); 251 } 252 configRequest.validate(); 253 254 255 int pid = getCallingPid(); 256 257 final int clientId; 258 synchronized (mLock) { 259 clientId = mNextClientId++; 260 } 261 262 if (mDbg) { 263 Log.v(TAG, "connect: uid=" + uid + ", clientId=" + clientId + ", configRequest" 264 + configRequest + ", notifyOnIdentityChanged=" + notifyOnIdentityChanged); 265 } 266 267 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { 268 @Override 269 public void binderDied() { 270 if (mDbg) Log.v(TAG, "binderDied: clientId=" + clientId); 271 binder.unlinkToDeath(this, 0); 272 273 synchronized (mLock) { 274 mDeathRecipientsByClientId.delete(clientId); 275 mUidByClientId.delete(clientId); 276 } 277 278 mStateManager.disconnect(clientId); 279 } 280 }; 281 282 try { 283 binder.linkToDeath(dr, 0); 284 } catch (RemoteException e) { 285 Log.e(TAG, "Error on linkToDeath - " + e); 286 try { 287 callback.onConnectFail(NanStatusType.INTERNAL_FAILURE); 288 } catch (RemoteException e1) { 289 Log.e(TAG, "Error on onConnectFail()"); 290 } 291 return; 292 } 293 294 synchronized (mLock) { 295 mDeathRecipientsByClientId.put(clientId, dr); 296 mUidByClientId.put(clientId, uid); 297 } 298 299 mStateManager.connect(clientId, uid, pid, callingPackage, callingFeatureId, callback, 300 configRequest, notifyOnIdentityChanged, extras); 301 } 302 303 @Override disconnect(int clientId, IBinder binder)304 public void disconnect(int clientId, IBinder binder) { 305 enforceAccessPermission(); 306 enforceChangePermission(); 307 308 int uid = getMockableCallingUid(); 309 enforceClientValidity(uid, clientId); 310 if (mDbg) Log.v(TAG, "disconnect: uid=" + uid + ", clientId=" + clientId); 311 312 if (binder == null) { 313 throw new IllegalArgumentException("Binder must not be null"); 314 } 315 316 synchronized (mLock) { 317 IBinder.DeathRecipient dr = mDeathRecipientsByClientId.get(clientId); 318 if (dr != null) { 319 binder.unlinkToDeath(dr, 0); 320 mDeathRecipientsByClientId.delete(clientId); 321 } 322 mUidByClientId.delete(clientId); 323 } 324 325 mStateManager.disconnect(clientId); 326 } 327 328 @Override terminateSession(int clientId, int sessionId)329 public void terminateSession(int clientId, int sessionId) { 330 enforceAccessPermission(); 331 enforceChangePermission(); 332 333 int uid = getMockableCallingUid(); 334 enforceClientValidity(uid, clientId); 335 if (mDbg) { 336 Log.v(TAG, "terminateSession: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" 337 + clientId); 338 } 339 340 mStateManager.terminateSession(clientId, sessionId); 341 } 342 343 @Override publish(String callingPackage, String callingFeatureId, int clientId, PublishConfig publishConfig, IWifiAwareDiscoverySessionCallback callback, Bundle extras)344 public void publish(String callingPackage, String callingFeatureId, int clientId, 345 PublishConfig publishConfig, IWifiAwareDiscoverySessionCallback callback, 346 Bundle extras) { 347 enforceAccessPermission(); 348 enforceChangePermission(); 349 350 int uid = getMockableCallingUid(); 351 mWifiPermissionsUtil.checkPackage(uid, callingPackage); 352 353 enforceNearbyOrLocationPermission(callingPackage, callingFeatureId, 354 getMockableCallingUid(), extras, "Wifi Aware publish"); 355 356 if (callback == null) { 357 throw new IllegalArgumentException("Callback must not be null"); 358 } 359 if (publishConfig == null) { 360 throw new IllegalArgumentException("PublishConfig must not be null"); 361 } 362 publishConfig.assertValid(mStateManager.getCharacteristics(), 363 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT) 364 ); 365 366 enforceClientValidity(uid, clientId); 367 if (mDbg) { 368 Log.v(TAG, "publish: uid=" + uid + ", clientId=" + clientId + ", publishConfig=" 369 + publishConfig + ", callback=" + callback); 370 } 371 372 mStateManager.publish(clientId, publishConfig, callback); 373 } 374 375 @Override updatePublish(int clientId, int sessionId, PublishConfig publishConfig)376 public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) { 377 enforceAccessPermission(); 378 enforceChangePermission(); 379 380 if (publishConfig == null) { 381 throw new IllegalArgumentException("PublishConfig must not be null"); 382 } 383 publishConfig.assertValid(mStateManager.getCharacteristics(), 384 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT) 385 ); 386 387 int uid = getMockableCallingUid(); 388 enforceClientValidity(uid, clientId); 389 if (mDbg) { 390 Log.v(TAG, "updatePublish: uid=" + uid + ", clientId=" + clientId + ", sessionId=" 391 + sessionId + ", config=" + publishConfig); 392 } 393 394 mStateManager.updatePublish(clientId, sessionId, publishConfig); 395 } 396 397 @Override subscribe(String callingPackage, String callingFeatureId, int clientId, SubscribeConfig subscribeConfig, IWifiAwareDiscoverySessionCallback callback, Bundle extras)398 public void subscribe(String callingPackage, String callingFeatureId, int clientId, 399 SubscribeConfig subscribeConfig, IWifiAwareDiscoverySessionCallback callback, 400 Bundle extras) { 401 enforceAccessPermission(); 402 enforceChangePermission(); 403 404 int uid = getMockableCallingUid(); 405 mWifiPermissionsUtil.checkPackage(uid, callingPackage); 406 407 enforceNearbyOrLocationPermission(callingPackage, callingFeatureId, 408 getMockableCallingUid(), extras, "Wifi Aware subscribe"); 409 410 if (callback == null) { 411 throw new IllegalArgumentException("Callback must not be null"); 412 } 413 if (subscribeConfig == null) { 414 throw new IllegalArgumentException("SubscribeConfig must not be null"); 415 } 416 subscribeConfig.assertValid(mStateManager.getCharacteristics(), 417 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT) 418 ); 419 420 enforceClientValidity(uid, clientId); 421 if (mDbg) { 422 Log.v(TAG, "subscribe: uid=" + uid + ", clientId=" + clientId + ", config=" 423 + subscribeConfig + ", callback=" + callback); 424 } 425 426 mStateManager.subscribe(clientId, subscribeConfig, callback); 427 } 428 429 @Override updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig)430 public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) { 431 enforceAccessPermission(); 432 enforceChangePermission(); 433 434 if (subscribeConfig == null) { 435 throw new IllegalArgumentException("SubscribeConfig must not be null"); 436 } 437 subscribeConfig.assertValid(mStateManager.getCharacteristics(), 438 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT) 439 ); 440 441 int uid = getMockableCallingUid(); 442 enforceClientValidity(uid, clientId); 443 if (mDbg) { 444 Log.v(TAG, "updateSubscribe: uid=" + uid + ", clientId=" + clientId + ", sessionId=" 445 + sessionId + ", config=" + subscribeConfig); 446 } 447 448 mStateManager.updateSubscribe(clientId, sessionId, subscribeConfig); 449 } 450 451 @Override sendMessage(int clientId, int sessionId, int peerId, byte[] message, int messageId, int retryCount)452 public void sendMessage(int clientId, int sessionId, int peerId, byte[] message, int messageId, 453 int retryCount) { 454 enforceAccessPermission(); 455 enforceChangePermission(); 456 457 if (retryCount != 0) { 458 enforceNetworkStackPermission(); 459 } 460 461 if (message != null && message.length 462 > mStateManager.getCharacteristics().getMaxServiceSpecificInfoLength()) { 463 throw new IllegalArgumentException( 464 "Message length longer than supported by device characteristics"); 465 } 466 if (retryCount < 0 || retryCount > DiscoverySession.getMaxSendRetryCount()) { 467 throw new IllegalArgumentException("Invalid 'retryCount' must be non-negative " 468 + "and <= DiscoverySession.MAX_SEND_RETRY_COUNT"); 469 } 470 471 int uid = getMockableCallingUid(); 472 enforceClientValidity(uid, clientId); 473 if (mDbg) { 474 Log.v(TAG, 475 "sendMessage: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" 476 + clientId + ", peerId=" + peerId + ", messageId=" + messageId 477 + ", retryCount=" + retryCount); 478 } 479 480 mStateManager.sendMessage(uid, clientId, sessionId, peerId, message, messageId, retryCount); 481 } 482 483 @Override requestMacAddresses(int uid, int[] peerIds, IWifiAwareMacAddressProvider callback)484 public void requestMacAddresses(int uid, int[] peerIds, IWifiAwareMacAddressProvider callback) { 485 enforceNetworkStackPermission(); 486 487 mStateManager.requestMacAddresses(uid, peerIds, callback); 488 } 489 490 @Override handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)491 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 492 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 493 @NonNull String[] args) { 494 return mShellCommand.exec( 495 this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), 496 args); 497 } 498 499 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)500 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 501 if (mContext.checkCallingOrSelfPermission( 502 android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 503 pw.println("Permission Denial: can't dump WifiAwareService from pid=" 504 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 505 return; 506 } 507 pw.println("Wi-Fi Aware Service"); 508 synchronized (mLock) { 509 pw.println(" mNextClientId: " + mNextClientId); 510 pw.println(" mDeathRecipientsByClientId: " + mDeathRecipientsByClientId); 511 pw.println(" mUidByClientId: " + mUidByClientId); 512 } 513 mStateManager.dump(fd, pw, args); 514 } 515 enforceClientValidity(int uid, int clientId)516 private void enforceClientValidity(int uid, int clientId) { 517 synchronized (mLock) { 518 int uidIndex = mUidByClientId.indexOfKey(clientId); 519 if (uidIndex < 0 || mUidByClientId.valueAt(uidIndex) != uid) { 520 throw new SecurityException("Attempting to use invalid uid+clientId mapping: uid=" 521 + uid + ", clientId=" + clientId); 522 } 523 } 524 } 525 enforceAccessPermission()526 private void enforceAccessPermission() { 527 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, TAG); 528 } 529 enforceChangePermission()530 private void enforceChangePermission() { 531 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, TAG); 532 } 533 enforceNearbyOrLocationPermission(String callingPackage, String callingFeatureId, int uid, Bundle extras, String message)534 private void enforceNearbyOrLocationPermission(String callingPackage, String callingFeatureId, 535 int uid, Bundle extras, String message) { 536 if (!SdkLevel.isAtLeastT() || mWifiPermissionsUtil.isTargetSdkLessThan(callingPackage, 537 Build.VERSION_CODES.TIRAMISU, 538 uid)) { 539 mWifiPermissionsUtil.enforceLocationPermission(callingPackage, callingFeatureId, uid); 540 } else { 541 mWifiPermissionsUtil.enforceNearbyDevicesPermission(extras.getParcelable( 542 WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE), true, message); 543 } 544 545 } 546 enforceNetworkStackPermission()547 private void enforceNetworkStackPermission() { 548 mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_STACK, TAG); 549 } 550 } 551