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