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