/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi.aware; import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_128; import static android.net.wifi.aware.Characteristics.WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_256; import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_AWARE_VERBOSE_LOGGING_ENABLED; import android.Manifest; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; import android.net.wifi.IBooleanListener; import android.net.wifi.IIntegerListener; import android.net.wifi.IListListener; import android.net.wifi.WifiManager; import android.net.wifi.aware.AwareParams; import android.net.wifi.aware.AwareResources; import android.net.wifi.aware.Characteristics; import android.net.wifi.aware.ConfigRequest; import android.net.wifi.aware.DiscoverySession; import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; import android.net.wifi.aware.IWifiAwareEventCallback; import android.net.wifi.aware.IWifiAwareMacAddressProvider; import android.net.wifi.aware.IWifiAwareManager; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.BuildProperties; import com.android.server.wifi.Clock; import com.android.server.wifi.FrameworkFacade; import com.android.server.wifi.InterfaceConflictManager; import com.android.server.wifi.RunnerHandler; import com.android.server.wifi.SystemBuildProperties; import com.android.server.wifi.WifiInjector; import com.android.server.wifi.WifiSettingsConfigStore; import com.android.server.wifi.WifiThreadRunner; import com.android.server.wifi.hal.WifiNanIface.NanStatusCode; import com.android.server.wifi.util.NetdWrapper; import com.android.server.wifi.util.WifiPermissionsUtil; import com.android.server.wifi.util.WifiPermissionsWrapper; import com.android.wifi.resources.R; import java.io.FileDescriptor; import java.io.PrintWriter; /** * Implementation of the IWifiAwareManager AIDL interface. Performs validity * (permission and clientID-UID mapping) checks and delegates execution to the * WifiAwareStateManager singleton handler. Limited state to feedback which has to * be provided instantly: client and session IDs. */ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { private static final String TAG = "WifiAwareService"; private boolean mVerboseLoggingEnabled = false; private boolean mVerboseHalLoggingEnabled = false; private WifiPermissionsUtil mWifiPermissionsUtil; private WifiAwareStateManager mStateManager; private WifiAwareNativeManager mWifiAwareNativeManager; private WifiAwareNativeApi mWifiAwareNativeApi; private WifiAwareNativeCallback mWifiAwareNativeCallback; private WifiAwareShellCommand mShellCommand; private Handler mHandler; private final Object mLock = new Object(); private final SparseArray mDeathRecipientsByClientId = new SparseArray<>(); private int mNextClientId = 1; private final SparseIntArray mUidByClientId = new SparseIntArray(); private final Context mContext; private final BuildProperties mBuildProperties; private final FrameworkFacade mFrameworkFacade; public WifiAwareServiceImpl(Context context) { mContext = context; mBuildProperties = new SystemBuildProperties(); mFrameworkFacade = new FrameworkFacade(); } /** * Proxy for the final native call of the parent class. Enables mocking of * the function. */ public int getMockableCallingUid() { return getCallingUid(); } /** * Start the service: allocate a new thread (for now), start the handlers of * the components of the service. */ public void 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) { Log.i(TAG, "Starting Wi-Fi Aware service"); mWifiPermissionsUtil = wifiPermissionsUtil; mStateManager = awareStateManager; mShellCommand = awareShellCommand; mHandler = new RunnerHandler(handlerThread.getLooper(), mContext.getResources() .getInteger(R.integer.config_wifiConfigurationWifiRunnerThresholdInMs), WifiInjector.getInstance().getWifiHandlerLocalLog()); mWifiAwareNativeManager = wifiAwareNativeManager; mWifiAwareNativeApi = wifiAwareNativeApi; mWifiAwareNativeCallback = wifiAwareNativeCallback; mHandler.post(() -> { mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, wifiPermissionsUtil, permissionsWrapper, new Clock(), netdWrapper, interfaceConflictManager); settingsConfigStore.registerChangeListener( WIFI_AWARE_VERBOSE_LOGGING_ENABLED, (key, newValue) -> enableVerboseLogging(newValue), mHandler); enableVerboseLogging(settingsConfigStore.get(WIFI_AWARE_VERBOSE_LOGGING_ENABLED)); }); } private void enableVerboseLogging(boolean verboseEnabled) { mVerboseHalLoggingEnabled = verboseEnabled; updateVerboseLoggingEnabled(); boolean vDbg = verboseEnabled || mContext.getResources() .getBoolean(R.bool.config_aware_vdbg_enable_on_verbose_logging); mStateManager.enableVerboseLogging(mVerboseLoggingEnabled, mVerboseLoggingEnabled, vDbg); mWifiAwareNativeCallback.enableVerboseLogging(mVerboseLoggingEnabled); mWifiAwareNativeManager.enableVerboseLogging(mVerboseLoggingEnabled, mVerboseLoggingEnabled); mWifiAwareNativeApi.enableVerboseLogging(mVerboseLoggingEnabled, vDbg); } /** * Start/initialize portions of the service which require the boot stage to be complete. */ public void startLate() { Log.i(TAG, "Late initialization of Wi-Fi Aware service"); updateVerboseLoggingEnabled(); mHandler.post(() -> mStateManager.startLate()); } private void updateVerboseLoggingEnabled() { final int verboseAlwaysOnLevel = mContext.getResources().getInteger( R.integer.config_wifiVerboseLoggingAlwaysOnLevel); mVerboseLoggingEnabled = mFrameworkFacade.isVerboseLoggingAlwaysOn(verboseAlwaysOnLevel, mBuildProperties) || mVerboseHalLoggingEnabled; } @Override public boolean isUsageEnabled() { enforceAccessPermission(); return mStateManager.isUsageEnabled(); } @Override public Characteristics getCharacteristics() { enforceAccessPermission(); return mStateManager.getCapabilities() == null ? null : mStateManager.getCapabilities().toPublicCharacteristics( WifiInjector.getInstance().getDeviceConfigFacade()); } @Override public AwareResources getAvailableAwareResources() { enforceAccessPermission(); return new WifiThreadRunner(mHandler) .call(() -> mStateManager.getAvailableAwareResources(), null, TAG + "#getAvailableAwareResources"); } @Override public boolean isDeviceAttached() { enforceAccessPermission(); return mStateManager.isDeviceAttached(); } @Override public void enableInstantCommunicationMode(String callingPackage, boolean enable) { enforceChangePermission(); int uid = getMockableCallingUid(); if (uid != Process.SHELL_UID && uid != Process.ROOT_UID) { mWifiPermissionsUtil.checkPackage(uid, callingPackage); if (!mWifiPermissionsUtil.isSystem(callingPackage, uid) && !mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { Log.i(TAG, "enableInstantCommunicationMode not allowed for uid=" + uid); return; } } mStateManager.enableInstantCommunicationMode(enable); } @Override public boolean isInstantCommunicationModeEnabled() { enforceAccessPermission(); return mStateManager.isInstantCommModeGlobalEnable(); } @Override public boolean isSetChannelOnDataPathSupported() { enforceAccessPermission(); return mStateManager.isSetChannelOnDataPathSupported(); } @Override public void setAwareParams(AwareParams params) { enforceChangePermission(); int uid = getMockableCallingUid(); if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { throw new SecurityException("App not allowed to update Aware parameters " + "(uid = " + uid + ")"); } mStateManager.setAwareParams(params); } @Override public void resetPairedDevices(String callingPackage) { int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceChangePermission(); if (mVerboseLoggingEnabled) { Log.v(TAG, "resetPairedDevices: callingPackage=" + callingPackage); } mStateManager.resetPairedDevices(callingPackage); } @Override public void removePairedDevice(String callingPackage, String alias) { int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceChangePermission(); if (mVerboseLoggingEnabled) { Log.v(TAG, "removePairedDevice: callingPackage=" + callingPackage + ", alias=" + alias); } mStateManager.removePairedDevice(callingPackage, alias); } @Override public void getPairedDevices(String callingPackage, @NonNull IListListener listener) { if (listener == null) { throw new IllegalArgumentException("listener should not be null"); } int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceAccessPermission(); mStateManager.getPairedDevices(callingPackage, listener); } @Override public void setOpportunisticModeEnabled(String callingPackage, boolean enabled) { int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceChangePermission(); if (mVerboseLoggingEnabled) { Log.v( TAG, "setOpportunisticModeEnabled: callingPackage=" + callingPackage + ", enabled=" + enabled); } mStateManager.setOpportunisticPackage(callingPackage, enabled); } @Override public void isOpportunisticModeEnabled(String callingPackage, @NonNull IBooleanListener listener) { if (listener == null) { throw new IllegalArgumentException("listener should not be null"); } int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceAccessPermission(); mStateManager.isOpportunistic(callingPackage, listener); } @Override public void connect(final IBinder binder, String callingPackage, String callingFeatureId, IWifiAwareEventCallback callback, ConfigRequest configRequest, boolean notifyOnIdentityChanged, Bundle extras, boolean forOffloading) { enforceAccessPermission(); enforceChangePermission(); final int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); if (callback == null) { throw new IllegalArgumentException("Callback must not be null"); } if (binder == null) { throw new IllegalArgumentException("Binder must not be null"); } if (extras == null) { throw new IllegalArgumentException("extras bundle must not be null"); } if (notifyOnIdentityChanged) { enforceNearbyOrLocationPermission(callingPackage, callingFeatureId, getMockableCallingUid(), extras, "Wifi Aware attach"); } if (forOffloading && !mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { throw new SecurityException("Enable Wifi Aware for offloading require" + "OVERRIDE_WIFI_CONFIG permission"); } if (configRequest != null) { boolean networkStackPermission = checkNetworkStackPermission(); boolean manageNetworkSelectionPermission = mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid); if (!(networkStackPermission || manageNetworkSelectionPermission)) { throw new SecurityException("Insufficient permission to include a ConfigRequest"); } if (!networkStackPermission) { // OEM apps with only the network selection permission can provide a config request, // but they should only modify the vendor data field. ConfigRequest.Builder builder = new ConfigRequest.Builder(); if (SdkLevel.isAtLeastV()) { builder.setVendorData(configRequest.getVendorData()); } configRequest = builder.build(); } } else { configRequest = new ConfigRequest.Builder().build(); } configRequest.validate(); int pid = getCallingPid(); final int clientId; synchronized (mLock) { clientId = mNextClientId++; } if (mVerboseLoggingEnabled) { Log.v(TAG, "connect: uid=" + uid + ", clientId=" + clientId + ", configRequest=" + configRequest + ", notifyOnIdentityChanged=" + notifyOnIdentityChanged); } IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { @Override public void binderDied() { if (mVerboseLoggingEnabled) Log.v(TAG, "binderDied: clientId=" + clientId); binder.unlinkToDeath(this, 0); synchronized (mLock) { mDeathRecipientsByClientId.delete(clientId); mUidByClientId.delete(clientId); } mStateManager.disconnect(clientId); } }; try { binder.linkToDeath(dr, 0); } catch (RemoteException e) { Log.e(TAG, "Error on linkToDeath - " + e); try { callback.onConnectFail(NanStatusCode.INTERNAL_FAILURE); } catch (RemoteException e1) { Log.e(TAG, "Error on onConnectFail()"); } return; } synchronized (mLock) { mDeathRecipientsByClientId.put(clientId, dr); mUidByClientId.put(clientId, uid); } mStateManager.connect(clientId, uid, pid, callingPackage, callingFeatureId, callback, configRequest, notifyOnIdentityChanged, extras, forOffloading); } @Override public void disconnect(int clientId, IBinder binder) { enforceAccessPermission(); enforceChangePermission(); int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "disconnect: uid=" + uid + ", clientId=" + clientId); } if (binder == null) { throw new IllegalArgumentException("Binder must not be null"); } synchronized (mLock) { IBinder.DeathRecipient dr = mDeathRecipientsByClientId.get(clientId); if (dr != null) { binder.unlinkToDeath(dr, 0); mDeathRecipientsByClientId.delete(clientId); } mUidByClientId.delete(clientId); } mStateManager.disconnect(clientId); } @Override public void setMasterPreference(int clientId, IBinder binder, int mp) { int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (binder == null) { throw new IllegalArgumentException("Binder must not be null"); } if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { throw new SecurityException("setMasterPreference requires " + "OVERRIDE_WIFI_CONFIG permission"); } if (mp < 0) { throw new IllegalArgumentException( "Master Preference specification must be non-negative"); } if (mp == 1 || mp == 255 || mp > 255) { throw new IllegalArgumentException("Master Preference specification must not " + "exceed 255 or use 1 or 255 (reserved values)"); } if (mVerboseLoggingEnabled) { Log.v(TAG, "setMasterPreference: uid=" + uid + ", clientId=" + clientId); } mStateManager.setMasterPreference(clientId, mp); } @Override public void getMasterPreference(int clientId, IBinder binder, IIntegerListener listener) { int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (binder == null) { throw new IllegalArgumentException("Binder must not be null"); } if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { throw new SecurityException("getMasterPreference requires " + "OVERRIDE_WIFI_CONFIG permission"); } if (mVerboseLoggingEnabled) { Log.v(TAG, "getMasterPreference: uid=" + uid + ", clientId=" + clientId); } mStateManager.getMasterPreference(clientId, listener); } @Override public void terminateSession(int clientId, int sessionId) { enforceAccessPermission(); enforceChangePermission(); int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "terminateSession: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" + clientId); } mStateManager.terminateSession(clientId, sessionId); } @Override public void publish(String callingPackage, String callingFeatureId, int clientId, PublishConfig publishConfig, IWifiAwareDiscoverySessionCallback callback, Bundle extras) { enforceAccessPermission(); enforceChangePermission(); int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceNearbyOrLocationPermission(callingPackage, callingFeatureId, getMockableCallingUid(), extras, "Wifi Aware publish"); if (callback == null) { throw new IllegalArgumentException("Callback must not be null"); } if (publishConfig == null) { throw new IllegalArgumentException("PublishConfig must not be null"); } publishConfig.assertValid(mStateManager.getCharacteristics(), mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)); if (SdkLevel.isAtLeastU() && publishConfig.isSuspendable() && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { throw new SecurityException("App not allowed to use Aware suspension" + "(uid = " + uid + ")"); } enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "publish: uid=" + uid + ", clientId=" + clientId + ", publishConfig=" + publishConfig + ", callback=" + callback); } mStateManager.publish(clientId, publishConfig, callback); } @Override public void updatePublish(int clientId, int sessionId, PublishConfig publishConfig) { enforceAccessPermission(); enforceChangePermission(); if (publishConfig == null) { throw new IllegalArgumentException("PublishConfig must not be null"); } publishConfig.assertValid(mStateManager.getCharacteristics(), mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)); int uid = getMockableCallingUid(); if (SdkLevel.isAtLeastU() && publishConfig.isSuspendable() && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { throw new SecurityException("App not allowed to use Aware suspension" + "(uid = " + uid + ")"); } enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "updatePublish: uid=" + uid + ", clientId=" + clientId + ", sessionId=" + sessionId + ", config=" + publishConfig); } mStateManager.updatePublish(clientId, sessionId, publishConfig); } @Override public void subscribe(String callingPackage, String callingFeatureId, int clientId, SubscribeConfig subscribeConfig, IWifiAwareDiscoverySessionCallback callback, Bundle extras) { enforceAccessPermission(); enforceChangePermission(); int uid = getMockableCallingUid(); mWifiPermissionsUtil.checkPackage(uid, callingPackage); enforceNearbyOrLocationPermission(callingPackage, callingFeatureId, getMockableCallingUid(), extras, "Wifi Aware subscribe"); if (callback == null) { throw new IllegalArgumentException("Callback must not be null"); } if (subscribeConfig == null) { throw new IllegalArgumentException("SubscribeConfig must not be null"); } subscribeConfig.assertValid(mStateManager.getCharacteristics(), mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)); if (SdkLevel.isAtLeastU() && subscribeConfig.isSuspendable() && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { throw new SecurityException("App not allowed to use Aware suspension" + "(uid = " + uid + ")"); } enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "subscribe: uid=" + uid + ", clientId=" + clientId + ", config=" + subscribeConfig + ", callback=" + callback); } mStateManager.subscribe(clientId, subscribeConfig, callback); } @Override public void updateSubscribe(int clientId, int sessionId, SubscribeConfig subscribeConfig) { enforceAccessPermission(); enforceChangePermission(); if (subscribeConfig == null) { throw new IllegalArgumentException("SubscribeConfig must not be null"); } subscribeConfig.assertValid(mStateManager.getCharacteristics(), mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)); int uid = getMockableCallingUid(); if (SdkLevel.isAtLeastU() && subscribeConfig.isSuspendable() && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { throw new SecurityException("App not allowed to use Aware suspension" + "(uid = " + uid + ")"); } enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "updateSubscribe: uid=" + uid + ", clientId=" + clientId + ", sessionId=" + sessionId + ", config=" + subscribeConfig); } mStateManager.updateSubscribe(clientId, sessionId, subscribeConfig); } @Override public void sendMessage(int clientId, int sessionId, int peerId, byte[] message, int messageId, int retryCount) { enforceAccessPermission(); enforceChangePermission(); if (retryCount != 0) { enforceNetworkStackPermission(); } if (message != null && message.length > mStateManager.getCharacteristics().getMaxServiceSpecificInfoLength()) { throw new IllegalArgumentException( "Message length longer than supported by device characteristics"); } if (retryCount < 0 || retryCount > DiscoverySession.getMaxSendRetryCount()) { throw new IllegalArgumentException("Invalid 'retryCount' must be non-negative " + "and <= DiscoverySession.MAX_SEND_RETRY_COUNT"); } int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "sendMessage: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" + clientId + ", peerId=" + peerId + ", messageId=" + messageId + ", retryCount=" + retryCount); } mStateManager.sendMessage(uid, clientId, sessionId, peerId, message, messageId, retryCount); } @Override public void requestMacAddresses(int uid, int[] peerIds, IWifiAwareMacAddressProvider callback) { enforceNetworkStackPermission(); mStateManager.requestMacAddresses(uid, peerIds, callback); } @Override public void initiateNanPairingSetupRequest(int clientId, int sessionId, int peerId, String password, String pairingDeviceAlias, int cipherSuite) { enforceAccessPermission(); enforceChangePermission(); if (!mStateManager.getCharacteristics().isAwarePairingSupported()) { throw new IllegalArgumentException( "NAN pairing is not supported"); } if (pairingDeviceAlias == null) { throw new IllegalArgumentException( "initiateNanPairingRequest: invalid pairingDeviceAlias - must be non-null"); } if (cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_128 && cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_256) { throw new IllegalArgumentException( "initiateNanPairingRequest: cipher suite is invalid"); } int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "initiateNanPairingRequest: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" + clientId + ", peerId=" + peerId); } mStateManager.initiateNanPairingSetupRequest(clientId, sessionId, peerId, password, pairingDeviceAlias, cipherSuite); } @Override public void responseNanPairingSetupRequest(int clientId, int sessionId, int peerId, int requestId, String password, String pairingDeviceAlias, boolean accept, int cipherSuite) { enforceAccessPermission(); enforceChangePermission(); if (!mStateManager.getCharacteristics().isAwarePairingSupported()) { throw new IllegalArgumentException( "NAN pairing is not supported"); } if (accept) { if (pairingDeviceAlias == null) { throw new IllegalArgumentException( "responseNanPairingSetupRequest: invalid pairingDeviceAlias - " + "must be non-null"); } if (cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_128 && cipherSuite != WIFI_AWARE_CIPHER_SUITE_NCS_PK_PASN_256) { throw new IllegalArgumentException( "responseNanPairingSetupRequest: cipher suite is invalid"); } } int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "responsePairingRequest: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" + clientId + ", peerId=" + peerId); } mStateManager.responseNanPairingSetupRequest(clientId, sessionId, peerId, requestId, password, pairingDeviceAlias, accept, cipherSuite); } @Override public void initiateBootStrappingSetupRequest(int clientId, int sessionId, int peerId, int method) { enforceAccessPermission(); enforceChangePermission(); if (!mStateManager.getCharacteristics().isAwarePairingSupported()) { throw new IllegalArgumentException( "NAN pairing is not supported"); } int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (mVerboseLoggingEnabled) { Log.v(TAG, "initiateBootStrappingSetupRequest: sessionId=" + sessionId + ", uid=" + uid + ", clientId=" + clientId + ", peerId=" + peerId); } mStateManager.initiateBootStrappingSetupRequest(clientId, sessionId, peerId, method, 0, null); } @Override public void suspend(int clientId, int sessionId) { enforceAccessPermission(); enforceChangePermission(); int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { throw new SecurityException("App not allowed to use Aware suspension" + "(uid = " + uid + ")"); } if (!mStateManager.getCharacteristics().isSuspensionSupported()) { throw new UnsupportedOperationException("NAN suspension is not supported."); } if (mVerboseLoggingEnabled) { Log.v(TAG, "suspend: clientId=" + clientId + ", sessionId=" + sessionId); } mStateManager.suspend(clientId, sessionId); } @Override public void resume(int clientId, int sessionId) { enforceAccessPermission(); enforceChangePermission(); int uid = getMockableCallingUid(); enforceClientValidity(uid, clientId); if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) { throw new SecurityException("App not allowed to use Aware suspension" + "(uid = " + uid + ")"); } if (!mStateManager.getCharacteristics().isSuspensionSupported()) { throw new UnsupportedOperationException("NAN suspension is not supported."); } if (mVerboseLoggingEnabled) { Log.v(TAG, "resume: clientId=" + clientId + ", sessionId=" + sessionId); } mStateManager.resume(clientId, sessionId); } @Override public int handleShellCommand(@NonNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args) { return mShellCommand.exec( this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump WifiAwareService from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); return; } pw.println("Wi-Fi Aware Service"); synchronized (mLock) { pw.println(" mNextClientId: " + mNextClientId); pw.println(" mDeathRecipientsByClientId: " + mDeathRecipientsByClientId); pw.println(" mUidByClientId: " + mUidByClientId); } mStateManager.dump(fd, pw, args); } private void enforceClientValidity(int uid, int clientId) { synchronized (mLock) { int uidIndex = mUidByClientId.indexOfKey(clientId); if (uidIndex < 0 || mUidByClientId.valueAt(uidIndex) != uid) { throw new SecurityException("Attempting to use invalid uid+clientId mapping: uid=" + uid + ", clientId=" + clientId); } } } private void enforceAccessPermission() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, TAG); } private void enforceChangePermission() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, TAG); } private void enforceNearbyOrLocationPermission(String callingPackage, String callingFeatureId, int uid, Bundle extras, String message) { if (!SdkLevel.isAtLeastT() || mWifiPermissionsUtil.isTargetSdkLessThan(callingPackage, Build.VERSION_CODES.TIRAMISU, uid)) { mWifiPermissionsUtil.enforceLocationPermission(callingPackage, callingFeatureId, uid); } else { mWifiPermissionsUtil.enforceNearbyDevicesPermission(extras.getParcelable( WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE), true, message); } } private void enforceNetworkStackPermission() { mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_STACK, TAG); } private boolean checkNetworkStackPermission() { return mContext.checkCallingOrSelfPermission(Manifest.permission.NETWORK_STACK) == PackageManager.PERMISSION_GRANTED; } }