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 17package com.android.server.wifi.aware; 18 19import android.Manifest; 20import android.app.AppOpsManager; 21import android.content.Context; 22import android.content.pm.PackageManager; 23import android.database.ContentObserver; 24import android.hardware.wifi.V1_0.NanStatusType; 25import android.net.wifi.aware.Characteristics; 26import android.net.wifi.aware.ConfigRequest; 27import android.net.wifi.aware.DiscoverySession; 28import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; 29import android.net.wifi.aware.IWifiAwareEventCallback; 30import android.net.wifi.aware.IWifiAwareMacAddressProvider; 31import android.net.wifi.aware.IWifiAwareManager; 32import android.net.wifi.aware.PublishConfig; 33import android.net.wifi.aware.SubscribeConfig; 34import android.os.Binder; 35import android.os.Handler; 36import android.os.HandlerThread; 37import android.os.IBinder; 38import android.os.RemoteException; 39import android.os.ResultReceiver; 40import android.os.ShellCallback; 41import android.provider.Settings; 42import android.util.Log; 43import android.util.SparseArray; 44import android.util.SparseIntArray; 45 46import com.android.server.wifi.FrameworkFacade; 47import com.android.server.wifi.WifiInjector; 48import com.android.server.wifi.util.WifiPermissionsUtil; 49import com.android.server.wifi.util.WifiPermissionsWrapper; 50 51import java.io.FileDescriptor; 52import java.io.PrintWriter; 53import 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 */ 61public 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 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 */ 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 */ 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 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 */ 153 public void startLate() { 154 Log.i(TAG, "Late initialization of Wi-Fi Aware service"); 155 156 mStateManager.startLate(); 157 } 158 159 @Override 160 public boolean isUsageEnabled() { 161 enforceAccessPermission(); 162 163 return mStateManager.isUsageEnabled(); 164 } 165 166 @Override 167 public Characteristics getCharacteristics() { 168 enforceAccessPermission(); 169 170 return mStateManager.getCapabilities() == null ? null 171 : mStateManager.getCapabilities().toPublicCharacteristics(); 172 } 173 174 @Override 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 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 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 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 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 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 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 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 424 public void requestMacAddresses(int uid, List peerIds, IWifiAwareMacAddressProvider callback) { 425 enforceNetworkStackPermission(); 426 427 mStateManager.requestMacAddresses(uid, peerIds, callback); 428 } 429 430 @Override 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 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 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 463 private void enforceAccessPermission() { 464 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, TAG); 465 } 466 467 private void enforceChangePermission() { 468 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, TAG); 469 } 470 471 private void enforceLocationPermission(String callingPackage, int uid) { 472 mWifiPermissionsUtil.enforceLocationPermission(callingPackage, uid); 473 } 474 475 private void enforceNetworkStackPermission() { 476 mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_STACK, TAG); 477 } 478} 479