• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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