diff options
author | Etan Cohen <etancohen@google.com> | 2017-05-11 23:38:14 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-05-11 23:38:16 +0000 |
commit | 2b8d172f337298ac1da2f9a69662474529e11bc1 (patch) | |
tree | 1fd29a888d4f751350a70ca263ecbb69bb0caddc | |
parent | 813bba29bf7d48c1d829841457cf27365e0aaa68 (diff) | |
parent | c760a66378bbd844eb421658799b4d55c76b98fa (diff) |
Merge "[AWARE] Initial power optimization framework - hooks & config"
10 files changed, 797 insertions, 68 deletions
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java index 9395e6a5d..14ce22fb2 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java @@ -36,6 +36,7 @@ import android.net.wifi.aware.ConfigRequest; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.os.RemoteException; +import android.os.ShellCommand; import android.util.Log; import libcore.util.HexEncoding; @@ -44,13 +45,15 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; /** * Translates Wi-Fi Aware requests from the framework to the HAL (HIDL). * * Delegates the management of the NAN interface to WifiAwareNativeManager. */ -public class WifiAwareNativeApi { +public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellCommand { private static final String TAG = "WifiAwareNativeApi"; private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true @@ -63,6 +66,70 @@ public class WifiAwareNativeApi { mHal = wifiAwareNativeManager; } + /* + * Parameters settable through the shell command. + */ + public static final String PARAM_DW_ON_INACTIVE_24GHZ = "dw_on_inactive_24ghz"; + public static final String PARAM_DW_ON_INACTIVE_5GHZ = "dw_on_inactive_5ghz"; + public static final String PARAM_DW_ON_IDLE_24GHZ = "dw_on_idle_24ghz"; + public static final String PARAM_DW_ON_IDLE_5GHZ = "dw_on_idle_5ghz"; + + private Map<String, Integer> mSettableParameters = new HashMap<>(); + { + mSettableParameters.put(PARAM_DW_ON_INACTIVE_24GHZ, -1); // -1 mean no-op, don't override + mSettableParameters.put(PARAM_DW_ON_INACTIVE_5GHZ, -1); // -1 mean no-op, don't override + mSettableParameters.put(PARAM_DW_ON_IDLE_24GHZ, -1); // -1 mean no-op, don't override + mSettableParameters.put(PARAM_DW_ON_IDLE_5GHZ, -1); // -1 mean no-op, don't override + } + + /** + * Interpreter of adb shell command 'adb shell wifiaware native_api ...'. + * + * @return -1 if parameter not recognized or invalid value, 0 otherwise. + */ + @Override + public int onCommand(ShellCommand parentShell) { + final PrintWriter pw = parentShell.getErrPrintWriter(); + + String subCmd = parentShell.getNextArgRequired(); + if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'"); + switch (subCmd) { + case "set": { + String name = parentShell.getNextArgRequired(); + if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'"); + if (!mSettableParameters.containsKey(name)) { + pw.println("Unknown parameter name -- '" + name + "'"); + return -1; + } + + String valueStr = parentShell.getNextArgRequired(); + if (VDBG) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'"); + int value; + try { + value = Integer.valueOf(valueStr); + } catch (NumberFormatException e) { + pw.println("Can't convert value to integer -- '" + valueStr + "'"); + return -1; + } + mSettableParameters.put(name, value); + return 0; + } + default: + pw.println("Unknown 'wifiaware native_api <cmd>'"); + } + + return -1; + } + + @Override + public void onHelp(String command, ShellCommand parentShell) { + final PrintWriter pw = parentShell.getOutPrintWriter(); + + pw.println(" " + command); + pw.println(" set <name> <value>: sets named parameter to value. Names: " + + mSettableParameters.keySet()); + } + /** * Query the firmware's capabilities. * @@ -101,13 +168,17 @@ public class WifiAwareNativeApi { * @param notifyIdentityChange Indicates whether or not to get address change callbacks. * @param initialConfiguration Specifies whether initial configuration * (true) or an update (false) to the configuration. + * @param isInteractive PowerManager.isInteractive + * @param isIdle PowerManager.isIdle */ public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest, - boolean notifyIdentityChange, boolean initialConfiguration) { + boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive, + boolean isIdle) { if (VDBG) { Log.v(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest=" + configRequest + ", notifyIdentityChange=" + notifyIdentityChange - + ", initialConfiguration=" + initialConfiguration); + + ", initialConfiguration=" + initialConfiguration + + ", isInteractive=" + isInteractive + ", isIdle=" + isIdle); } IWifiNanIface iface = mHal.getWifiNanIface(); @@ -190,6 +261,8 @@ public class WifiAwareNativeApi { req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; + updateConfigForPowerSettings(req.configParams, isInteractive, isIdle); + status = iface.enableRequest(transactionId, req); } else { NanConfigRequest req = new NanConfigRequest(); @@ -238,6 +311,8 @@ public class WifiAwareNativeApi { } req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; + updateConfigForPowerSettings(req, isInteractive, isIdle); + status = iface.configRequest(transactionId, req); } if (status.code == WifiStatusCode.SUCCESS) { @@ -767,6 +842,33 @@ public class WifiAwareNativeApi { // utilities /** + * Update the NAN configuration to reflect the current power settings. + */ + private void updateConfigForPowerSettings(NanConfigRequest req, boolean isInteractive, + boolean isIdle) { + if (isIdle) { // lowest power state: doze + updateSingleConigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ], + mSettableParameters.get(PARAM_DW_ON_IDLE_5GHZ)); + updateSingleConigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ], + mSettableParameters.get(PARAM_DW_ON_IDLE_24GHZ)); + } else if (!isInteractive) { // intermediate power state: inactive + updateSingleConigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ], + mSettableParameters.get(PARAM_DW_ON_INACTIVE_5GHZ)); + updateSingleConigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ], + mSettableParameters.get(PARAM_DW_ON_INACTIVE_24GHZ)); + } + + // else do nothing - normal power state + } + + private void updateSingleConigForPowerSettings(NanBandSpecificConfig cfg, int override) { + if (override != -1) { + cfg.validDiscoveryWindowIntervalVal = true; + cfg.discoveryWindowIntervalVal = (byte) override; + } + } + + /** * Returns the strongest supported cipher suite. * * Baseline is very simple: 256 > 128 > 0. @@ -829,6 +931,8 @@ public class WifiAwareNativeApi { * Dump the internal state of the class. */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("WifiAwareNativeApi:"); + pw.println(" mSettableParameters: " + mSettableParameters); mHal.dump(fd, pw, args); } } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java index f1945808f..9d2f3d062 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java @@ -23,6 +23,7 @@ import android.hardware.wifi.V1_0.WifiStatusCode; import android.os.RemoteException; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.HalDeviceManager; import java.io.FileDescriptor; @@ -31,7 +32,7 @@ import java.io.PrintWriter; /** * Manages the interface to Wi-Fi Aware HIDL (HAL). */ -class WifiAwareNativeManager { +public class WifiAwareNativeManager { private static final String TAG = "WifiAwareNativeManager"; private static final boolean DBG = false; @@ -78,12 +79,20 @@ class WifiAwareNativeManager { } } - /* package */ IWifiNanIface getWifiNanIface() { + /** + * Returns the native HAL WifiNanIface through which commands to the NAN HAL are dispatched. + * Return may be null if not initialized/available. + */ + @VisibleForTesting + public IWifiNanIface getWifiNanIface() { synchronized (mLock) { return mWifiNanIface; } } + /** + * Attempt to obtain the HAL NAN interface. If available then enables Aware usage. + */ private void tryToGetAware() { synchronized (mLock) { if (DBG) Log.d(TAG, "tryToGetAware: mWifiNanIface=" + mWifiNanIface); diff --git a/service/java/com/android/server/wifi/aware/WifiAwareService.java b/service/java/com/android/server/wifi/aware/WifiAwareService.java index bd8156e17..6aceb6adc 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareService.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareService.java @@ -62,9 +62,12 @@ public final class WifiAwareService extends SystemService { wifiAwareStateManager, halDeviceManager, wifiAwareNativeCallback); WifiAwareNativeApi wifiAwareNativeApi = new WifiAwareNativeApi(wifiAwareNativeManager); wifiAwareStateManager.setNative(wifiAwareNativeApi); + WifiAwareShellCommand wifiAwareShellCommand = new WifiAwareShellCommand(); + wifiAwareShellCommand.register("native_api", wifiAwareNativeApi); + wifiAwareShellCommand.register("state_mgr", wifiAwareStateManager); HandlerThread awareHandlerThread = wifiInjector.getWifiAwareHandlerThread(); - mImpl.start(awareHandlerThread, wifiAwareStateManager); + mImpl.start(awareHandlerThread, wifiAwareStateManager, wifiAwareShellCommand); wifiAwareNativeManager.start(); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { mImpl.startLate(); diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java index 49e3bb9a7..74898bf69 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java @@ -55,6 +55,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { private Context mContext; private WifiAwareStateManager mStateManager; + private WifiAwareShellCommand mShellCommand; private final Object mLock = new Object(); private final SparseArray<IBinder.DeathRecipient> mDeathRecipientsByClientId = @@ -79,10 +80,12 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { * 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) { + public void start(HandlerThread handlerThread, WifiAwareStateManager awareStateManager, + WifiAwareShellCommand awareShellCommand) { Log.i(TAG, "Starting Wi-Fi Aware service"); mStateManager = awareStateManager; + mShellCommand = awareShellCommand; mStateManager.start(mContext, handlerThread.getLooper()); } @@ -375,8 +378,7 @@ public class WifiAwareServiceImpl extends IWifiAwareManager.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { - (new WifiAwareShellCommand(mStateManager)).exec(this, in, out, err, args, callback, - resultReceiver); + mShellCommand.exec(this, in, out, err, args, callback, resultReceiver); } @Override diff --git a/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java b/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java index de8bfa73b..46b08634b 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareShellCommand.java @@ -16,34 +16,50 @@ package com.android.server.wifi.aware; -import android.app.AppGlobals; -import android.content.pm.IPackageManager; import android.os.Binder; import android.os.ShellCommand; +import android.text.TextUtils; +import android.util.Log; import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; /** * Interprets and executes 'adb shell cmd wifiaware [args]'. */ public class WifiAwareShellCommand extends ShellCommand { - private final WifiAwareStateManager mStateManager; - private final IPackageManager mPM; + private static final String TAG = "WifiAwareShellCommand"; - WifiAwareShellCommand(WifiAwareStateManager stateManager) { - mStateManager = stateManager; - mPM = AppGlobals.getPackageManager(); + private Map<String, DelegatedShellCommand> mDelegatedCommands = new HashMap<>(); + + /** + * Register an delegated command interpreter for the specified 'command'. Each class can + * interpret and execute their own commands. + */ + public void register(String command, DelegatedShellCommand shellCommand) { + if (mDelegatedCommands.containsKey(command)) { + Log.e(TAG, "register: overwriting existing command -- '" + command + "'"); + } + + mDelegatedCommands.put(command, shellCommand); } @Override public int onCommand(String cmd) { checkRootPermission(); - final PrintWriter pw = getOutPrintWriter(); + final PrintWriter pw = getErrPrintWriter(); try { - switch (cmd != null ? cmd : "") { - default: - return handleDefaultCommands(cmd); + DelegatedShellCommand delegatedCmd = null; + if (!TextUtils.isEmpty(cmd)) { + delegatedCmd = mDelegatedCommands.get(cmd); + } + + if (delegatedCmd != null) { + return delegatedCmd.onCommand(this); + } else { + return handleDefaultCommands(cmd); } } catch (Exception e) { pw.println("Exception: " + e); @@ -67,6 +83,28 @@ public class WifiAwareShellCommand extends ShellCommand { pw.println("Wi-Fi Aware (wifiaware) commands:"); pw.println(" help"); pw.println(" Print this help text."); + for (Map.Entry<String, DelegatedShellCommand> sce: mDelegatedCommands.entrySet()) { + sce.getValue().onHelp(sce.getKey(), this); + } pw.println(); } + + /** + * Interface that delegated command targets must implement. They are passed the parent shell + * command (the real command interpreter) from which they can obtain arguments. + */ + public interface DelegatedShellCommand { + /** + * Execute the specified command. Use the parent shell to obtain arguments. Note that the + * first argument (which specified the delegated shell) has already been extracted. + */ + int onCommand(ShellCommand parentShell); + + /** + * Print out help for the delegated command. The name of the delegated command is passed + * as a first argument as an assist (prevents hard-coding of that string in multiple + * places). + */ + void onHelp(String command, ShellCommand parentShell); + } } diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java index f3b7be4b1..c2f6a79ed 100644 --- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java +++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java @@ -16,8 +16,10 @@ package com.android.server.wifi.aware; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.hardware.wifi.V1_0.NanStatusType; import android.net.wifi.RttManager; import android.net.wifi.aware.Characteristics; @@ -31,7 +33,9 @@ import android.net.wifi.aware.WifiAwareNetworkSpecifier; import android.os.Bundle; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; import android.os.RemoteException; +import android.os.ShellCommand; import android.os.SystemClock; import android.os.UserHandle; import android.util.ArrayMap; @@ -50,6 +54,7 @@ import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Arrays; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @@ -57,7 +62,7 @@ import java.util.Map; /** * Manages the state of the Wi-Fi Aware system service. */ -public class WifiAwareStateManager { +public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShellCommand { private static final String TAG = "WifiAwareStateManager"; private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true @@ -108,6 +113,7 @@ public class WifiAwareStateManager { private static final int COMMAND_TYPE_RESPOND_TO_DATA_PATH_SETUP_REQUEST = 117; private static final int COMMAND_TYPE_END_DATA_PATH = 118; private static final int COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE = 119; + private static final int COMMAND_TYPE_RECONFIGURE = 120; private static final int RESPONSE_TYPE_ON_CONFIG_SUCCESS = 200; private static final int RESPONSE_TYPE_ON_CONFIG_FAIL = 201; @@ -190,6 +196,7 @@ public class WifiAwareStateManager { private WifiAwareStateMachine mSm; private WifiAwareRttStateManager mRtt; private WifiAwareDataPathStateManager mDataPathMgr; + private PowerManager mPowerManager; private final SparseArray<WifiAwareClientState> mClients = new SparseArray<>(); private ConfigRequest mCurrentAwareConfiguration = null; @@ -202,10 +209,72 @@ public class WifiAwareStateManager { // empty } + /** + * Inject references to other manager objects. Needed to resolve + * circular dependencies and to allow mocking. + */ public void setNative(WifiAwareNativeApi wifiAwareNativeApi) { mWifiAwareNativeApi = wifiAwareNativeApi; } + /* + * parameters settable through shell command + */ + public static final String PARAM_ON_IDLE_DISABLE_AWARE = "on_idle_disable_aware"; + + private Map<String, Integer> mSettableParameters = new HashMap<>(); + { + mSettableParameters.put(PARAM_ON_IDLE_DISABLE_AWARE, 0); // 0 = false + } + + /** + * Interpreter of adb shell command 'adb shell wifiaware native_api ...'. + * + * @return -1 if parameter not recognized or invalid value, 0 otherwise. + */ + @Override + public int onCommand(ShellCommand parentShell) { + final PrintWriter pw = parentShell.getErrPrintWriter(); + + String subCmd = parentShell.getNextArgRequired(); + if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'"); + switch (subCmd) { + case "set": { + String name = parentShell.getNextArgRequired(); + if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'"); + if (!mSettableParameters.containsKey(name)) { + pw.println("Unknown parameter name -- '" + name + "'"); + return -1; + } + + String valueStr = parentShell.getNextArgRequired(); + if (VDBG) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'"); + int value; + try { + value = Integer.valueOf(valueStr); + } catch (NumberFormatException e) { + pw.println("Can't convert value to integer -- '" + valueStr + "'"); + return -1; + } + mSettableParameters.put(name, value); + return 0; + } + default: + pw.println("Unknown 'wifiaware state_mgr <cmd>'"); + } + + return -1; + } + + @Override + public void onHelp(String command, ShellCommand parentShell) { + final PrintWriter pw = parentShell.getOutPrintWriter(); + + pw.println(" " + command); + pw.println(" set <name> <value>: sets named parameter to value. Names: " + + mSettableParameters.keySet()); + } + /** * Initialize the handler of the state manager with the specified thread * looper. @@ -223,6 +292,36 @@ public class WifiAwareStateManager { mRtt = new WifiAwareRttStateManager(); mDataPathMgr = new WifiAwareDataPathStateManager(this); mDataPathMgr.start(mContext, mSm.getHandler().getLooper()); + + mPowerManager = mContext.getSystemService(PowerManager.class); + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_SCREEN_ON); + intentFilter.addAction(Intent.ACTION_SCREEN_OFF); + intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (VDBG) Log.v(TAG, "BroadcastReceiver: action=" + action); + if (action.equals(Intent.ACTION_SCREEN_ON) + || action.equals(Intent.ACTION_SCREEN_OFF)) { + reconfigure(); + } + + if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) { + if (mSettableParameters.get(PARAM_ON_IDLE_DISABLE_AWARE) != 0) { + if (mPowerManager.isDeviceIdleMode()) { + disableUsage(); + } else { + enableUsage(); + } + } else { + reconfigure(); + } + } + } + }, intentFilter); } /** @@ -292,6 +391,17 @@ public class WifiAwareStateManager { } /** + * Place a request to reconfigure Aware. No additional input - intended to use current + * power settings when executed. Thus possibly entering or exiting power saving mode if + * needed (or do nothing if Aware is not active). + */ + public void reconfigure() { + Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); + msg.arg1 = COMMAND_TYPE_RECONFIGURE; + mSm.sendMessage(msg); + } + + /** * Place a request to stop a discovery session on the state machine queue. */ public void terminateSession(int clientId, int sessionId) { @@ -392,6 +502,11 @@ public class WifiAwareStateManager { * only happens when a connection is created. */ public void enableUsage() { + if (mSettableParameters.get(PARAM_ON_IDLE_DISABLE_AWARE) != 0 + && mPowerManager.isDeviceIdleMode()) { + Log.d(TAG, "enableUsage(): while device is in IDLE mode - ignoring"); + return; + } Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND); msg.arg1 = COMMAND_TYPE_ENABLE_USAGE; mSm.sendMessage(msg); @@ -1220,6 +1335,9 @@ public class WifiAwareStateManager { waitForResponse = disconnectLocal(mCurrentTransactionId, clientId); break; } + case COMMAND_TYPE_RECONFIGURE: + waitForResponse = reconfigureLocal(mCurrentTransactionId); + break; case COMMAND_TYPE_TERMINATE_SESSION: { int clientId = msg.arg2; int sessionId = (Integer) msg.obj; @@ -1576,6 +1694,13 @@ public class WifiAwareStateManager { onConfigFailedLocal(mCurrentCommand, NanStatusType.INTERNAL_FAILURE); break; } + case COMMAND_TYPE_RECONFIGURE: + /* + * Reconfigure timed-out. There is nothing to do but log the issue - which + * will be done in the callback. + */ + onConfigFailedLocal(mCurrentCommand, NanStatusType.INTERNAL_FAILURE); + break; case COMMAND_TYPE_TERMINATE_SESSION: { Log.wtf(TAG, "processTimeout: TERMINATE_SESSION - shouldn't be waiting!"); break; @@ -1826,7 +1951,8 @@ public class WifiAwareStateManager { doesAnyClientNeedIdentityChangeNotifications() || notifyIdentityChange; boolean success = mWifiAwareNativeApi.enableAndConfigure(transactionId, merged, - notificationRequired, mCurrentAwareConfiguration == null); + notificationRequired, mCurrentAwareConfiguration == null, + mPowerManager.isInteractive(), mPowerManager.isDeviceIdleMode()); if (!success) { try { callback.onConnectFail(NanStatusType.INTERNAL_FAILURE); @@ -1870,7 +1996,22 @@ public class WifiAwareStateManager { } return mWifiAwareNativeApi.enableAndConfigure(transactionId, merged, notificationReqs, - false); + false, mPowerManager.isInteractive(), mPowerManager.isDeviceIdleMode()); + } + + private boolean reconfigureLocal(short transactionId) { + if (VDBG) Log.v(TAG, "reconfigureLocal(): transactionId=" + transactionId); + + if (mClients.size() == 0) { + // no clients - Aware is not enabled, nothing to reconfigure + return false; + } + + boolean notificationReqs = doesAnyClientNeedIdentityChangeNotifications(); + + return mWifiAwareNativeApi.enableAndConfigure(transactionId, mCurrentAwareConfiguration, + notificationReqs, false, mPowerManager.isInteractive(), + mPowerManager.isDeviceIdleMode()); } private void terminateSessionLocal(int clientId, int sessionId) { @@ -2166,6 +2307,10 @@ public class WifiAwareStateManager { /* * NOP (i.e. updated configuration after disconnecting a client) */ + } else if (completedCommand.arg1 == COMMAND_TYPE_RECONFIGURE) { + /* + * NOP (i.e. updated configuration at power saving event) + */ } else { Log.wtf(TAG, "onConfigCompletedLocal: unexpected completedCommand=" + completedCommand); return; @@ -2198,11 +2343,15 @@ public class WifiAwareStateManager { * shouldn't fail but there's nothing to do - the old configuration * is still up-and-running). */ + } else if (failedCommand.arg1 == COMMAND_TYPE_RECONFIGURE) { + /* + * NOP (configuration change as part of possibly power saving event - should not + * fail but there's nothing to do). + */ } else { Log.wtf(TAG, "onConfigFailedLocal: unexpected failedCommand=" + failedCommand); return; } - } private void onSessionConfigSuccessLocal(Message completedCommand, int pubSubId, @@ -2709,6 +2858,7 @@ public class WifiAwareStateManager { for (int i = 0; i < mClients.size(); ++i) { mClients.valueAt(i).dump(fd, pw, args); } + pw.println(" mSettableParameters: " + mSettableParameters); mSm.dump(fd, pw, args); mRtt.dump(fd, pw, args); mDataPathMgr.dump(fd, pw, args); diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java index 8835d75b8..f0758934a 100644 --- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java @@ -55,8 +55,10 @@ import android.net.wifi.aware.WifiAwareNetworkSpecifier; import android.net.wifi.aware.WifiAwareSession; import android.os.Handler; import android.os.INetworkManagementService; +import android.os.IPowerManager; import android.os.Message; import android.os.Messenger; +import android.os.PowerManager; import android.os.Process; import android.os.test.TestLooper; import android.test.suitebuilder.annotation.SmallTest; @@ -97,6 +99,7 @@ public class WifiAwareDataPathStateManagerTest { @Mock private IWifiAwareEventCallback mMockCallback; @Mock IWifiAwareDiscoverySessionCallback mMockSessionCallback; TestAlarmManager mAlarmManager; + private PowerManager mMockPowerManager; @Rule public ErrorCollector collector = new ErrorCollector(); @@ -112,11 +115,18 @@ public class WifiAwareDataPathStateManagerTest { when(mMockContext.getSystemService(Context.ALARM_SERVICE)) .thenReturn(mAlarmManager.getAlarmManager()); - when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mMockCm); - mMockLooper = new TestLooper(); mMockLooperHandler = new Handler(mMockLooper.getLooper()); + IPowerManager powerManagerService = mock(IPowerManager.class); + mMockPowerManager = new PowerManager(mMockContext, powerManagerService, + new Handler(mMockLooper.getLooper())); + + when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mMockCm); + when(mMockContext.getSystemServiceName(PowerManager.class)).thenReturn( + Context.POWER_SERVICE); + when(mMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager); + mDut = new WifiAwareStateManager(); mDut.setNative(mMockNative); mDut.start(mMockContext, mMockLooper.getLooper()); @@ -124,7 +134,7 @@ public class WifiAwareDataPathStateManagerTest { when(mMockNative.getCapabilities(anyShort())).thenReturn(true); when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(), - anyBoolean())).thenReturn(true); + anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(true); when(mMockNative.disable(anyShort())).thenReturn(true); when(mMockNative.publish(anyShort(), anyInt(), any())).thenReturn(true); when(mMockNative.subscribe(anyShort(), anyInt(), any())) @@ -145,6 +155,9 @@ public class WifiAwareDataPathStateManagerTest { when(mMockNetworkInterface.configureAgentProperties(any(), any(), anyInt(), any(), any(), any())).thenReturn(true); + when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false); + when(mMockPowerManager.isInteractive()).thenReturn(true); + installDataPathStateManagerMocks(); } @@ -884,7 +897,7 @@ public class WifiAwareDataPathStateManagerTest { false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mMockCallback).onConnectSuccess(clientId); diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java new file mode 100644 index 000000000..956418997 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2017 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 org.hamcrest.core.IsEqual.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyShort; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.wifi.V1_0.IWifiNanIface; +import android.hardware.wifi.V1_0.NanBandIndex; +import android.hardware.wifi.V1_0.NanConfigRequest; +import android.hardware.wifi.V1_0.NanEnableRequest; +import android.hardware.wifi.V1_0.WifiStatus; +import android.hardware.wifi.V1_0.WifiStatusCode; +import android.net.wifi.aware.ConfigRequest; +import android.os.RemoteException; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ErrorCollector; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.PrintWriter; + +/** + * Unit test harness for WifiAwareNativeApi + */ +public class WifiAwareNativeApiTest { + @Mock WifiAwareNativeManager mWifiAwareNativeManagerMock; + @Mock IWifiNanIface mIWifiNanIfaceMock; + + @Rule public ErrorCollector collector = new ErrorCollector(); + + private WifiAwareNativeApi mDut; + + /** + * Initializes mocks. + */ + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mWifiAwareNativeManagerMock.getWifiNanIface()).thenReturn(mIWifiNanIfaceMock); + + WifiStatus status = new WifiStatus(); + status.code = WifiStatusCode.SUCCESS; + when(mIWifiNanIfaceMock.enableRequest(anyShort(), any())).thenReturn(status); + when(mIWifiNanIfaceMock.configRequest(anyShort(), any())).thenReturn(status); + + mDut = new WifiAwareNativeApi(mWifiAwareNativeManagerMock); + } + + /** + * Test that the set parameter shell command executor works when parameters are valid. + */ + @Test + public void testSetParameterShellCommandSuccess() { + setSettableParam(WifiAwareNativeApi.PARAM_DW_ON_IDLE_5GHZ, Integer.toString(1), true); + } + + /** + * Test that the set parameter shell command executor fails on incorrect name. + */ + @Test + public void testSetParameterShellCommandInvalidParameterName() { + setSettableParam("XXX", Integer.toString(1), false); + } + + /** + * Test that the set parameter shell command executor fails on invalid value (not convertible + * to an int). + */ + @Test + public void testSetParameterShellCommandInvalidValue() { + setSettableParam(WifiAwareNativeApi.PARAM_DW_ON_IDLE_5GHZ, "garbage", false); + } + + /** + * Validate that the configuration parameters used to manage power state behavior is + * using default values at the default power state. + */ + @Test + public void testEnableAndConfigPowerSettingsDefaults() throws RemoteException { + NanConfigRequest config = validateEnableAndConfigure((short) 10, + new ConfigRequest.Builder().build(), true, true, true, false); + + collector.checkThat("validDiscoveryWindowIntervalVal-5", false, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] + .validDiscoveryWindowIntervalVal)); + collector.checkThat("validDiscoveryWindowIntervalVal-24", false, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] + .validDiscoveryWindowIntervalVal)); + } + + /** + * Validate that the configuration parameters used to manage power state behavior is + * using the specified non-interactive values when in that power state. + */ + @Test + public void testEnableAndConfigPowerSettingsNoneInteractive() throws RemoteException { + byte interactive5 = 2; + byte interactive24 = 3; + + setPowerConfigurationParams(interactive5, interactive24, (byte) -1, (byte) -1); + NanConfigRequest config = validateEnableAndConfigure((short) 10, + new ConfigRequest.Builder().build(), false, false, false, false); + + collector.checkThat("validDiscoveryWindowIntervalVal-5", true, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] + .validDiscoveryWindowIntervalVal)); + collector.checkThat("discoveryWindowIntervalVal-5", interactive5, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] + .discoveryWindowIntervalVal)); + collector.checkThat("validDiscoveryWindowIntervalVal-24", true, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] + .validDiscoveryWindowIntervalVal)); + collector.checkThat("discoveryWindowIntervalVal-24", interactive24, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] + .discoveryWindowIntervalVal)); + } + + /** + * Validate that the configuration parameters used to manage power state behavior is + * using the specified idle (doze) values when in that power state. + */ + @Test + public void testEnableAndConfigPowerSettingsIdle() throws RemoteException { + byte idle5 = 2; + byte idle24 = -1; + + setPowerConfigurationParams((byte) -1, (byte) -1, idle5, idle24); + NanConfigRequest config = validateEnableAndConfigure((short) 10, + new ConfigRequest.Builder().build(), false, true, false, true); + + collector.checkThat("validDiscoveryWindowIntervalVal-5", true, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] + .validDiscoveryWindowIntervalVal)); + collector.checkThat("discoveryWindowIntervalVal-5", idle5, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] + .discoveryWindowIntervalVal)); + collector.checkThat("validDiscoveryWindowIntervalVal-24", false, + equalTo(config.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] + .validDiscoveryWindowIntervalVal)); + } + + // utilities + + private void setPowerConfigurationParams(byte interactive5, byte interactive24, byte idle5, + byte idle24) { + setSettableParam(WifiAwareNativeApi.PARAM_DW_ON_INACTIVE_5GHZ, + Integer.toString(interactive5), true); + setSettableParam(WifiAwareNativeApi.PARAM_DW_ON_INACTIVE_24GHZ, + Integer.toString(interactive24), true); + setSettableParam(WifiAwareNativeApi.PARAM_DW_ON_IDLE_5GHZ, Integer.toString(idle5), true); + setSettableParam(WifiAwareNativeApi.PARAM_DW_ON_IDLE_24GHZ, Integer.toString(idle24), true); + } + + private void setSettableParam(String name, String value, boolean expectSuccess) { + PrintWriter pwMock = mock(PrintWriter.class); + WifiAwareShellCommand parentShellMock = mock(WifiAwareShellCommand.class); + when(parentShellMock.getNextArgRequired()).thenReturn("set").thenReturn(name).thenReturn( + value); + when(parentShellMock.getErrPrintWriter()).thenReturn(pwMock); + + collector.checkThat(mDut.onCommand(parentShellMock), equalTo(expectSuccess ? 0 : -1)); + } + + private NanConfigRequest validateEnableAndConfigure(short transactionId, + ConfigRequest configRequest, boolean notifyIdentityChange, boolean initialConfiguration, + boolean isInteractive, boolean isIdle) throws RemoteException { + mDut.enableAndConfigure(transactionId, configRequest, notifyIdentityChange, + initialConfiguration, isInteractive, isIdle); + + ArgumentCaptor<NanEnableRequest> enableReqCaptor = ArgumentCaptor.forClass( + NanEnableRequest.class); + ArgumentCaptor<NanConfigRequest> configReqCaptor = ArgumentCaptor.forClass( + NanConfigRequest.class); + NanConfigRequest config; + + if (initialConfiguration) { + verify(mIWifiNanIfaceMock).enableRequest(eq(transactionId), enableReqCaptor.capture()); + config = enableReqCaptor.getValue().configParams; + } else { + verify(mIWifiNanIfaceMock).configRequest(eq(transactionId), configReqCaptor.capture()); + config = configReqCaptor.getValue(); + } + + collector.checkThat("disableDiscoveryAddressChangeIndication", !notifyIdentityChange, + equalTo(config.disableDiscoveryAddressChangeIndication)); + collector.checkThat("disableStartedClusterIndication", !notifyIdentityChange, + equalTo(config.disableStartedClusterIndication)); + collector.checkThat("disableJoinedClusterIndication", !notifyIdentityChange, + equalTo(config.disableJoinedClusterIndication)); + + return config; + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java index b5e12d29c..1ab6898f5 100644 --- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java @@ -70,6 +70,8 @@ public class WifiAwareServiceImplTest { @Mock private WifiAwareStateManager mAwareStateManagerMock; @Mock + private WifiAwareShellCommand mWifiAwareShellCommandMock; + @Mock private IBinder mBinderMock; @Mock private IWifiAwareEventCallback mCallbackMock; @@ -114,7 +116,7 @@ public class WifiAwareServiceImplTest { mDut = new WifiAwareServiceImplSpy(mContextMock); mDut.fakeUid = mDefaultUid; - mDut.start(mHandlerThreadMock, mAwareStateManagerMock); + mDut.start(mHandlerThreadMock, mAwareStateManagerMock, mWifiAwareShellCommandMock); verify(mAwareStateManagerMock).start(eq(mContextMock), any()); } diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java index fd4d5c794..a8d310a4b 100644 --- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java @@ -38,8 +38,10 @@ import android.Manifest; import android.app.AppOpsManager; import android.app.test.MockAnswerUtil; import android.app.test.TestAlarmManager; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.wifi.V1_0.NanStatusType; import android.net.ConnectivityManager; @@ -50,7 +52,10 @@ import android.net.wifi.aware.IWifiAwareEventCallback; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.net.wifi.aware.WifiAwareManager; +import android.os.Handler; +import android.os.IPowerManager; import android.os.Message; +import android.os.PowerManager; import android.os.UserHandle; import android.os.test.TestLooper; import android.test.suitebuilder.annotation.SmallTest; @@ -86,11 +91,14 @@ public class WifiAwareStateManagerTest { private TestLooper mMockLooper; private Random mRandomNg = new Random(15687); private WifiAwareStateManager mDut; + @Mock private WifiAwareNativeManager mMockNativeManager; @Mock private WifiAwareNativeApi mMockNative; @Mock private Context mMockContext; @Mock private AppOpsManager mMockAppOpsManager; @Mock private WifiAwareRttStateManager mMockAwareRttStateManager; TestAlarmManager mAlarmManager; + private PowerManager mMockPowerManager; + private BroadcastReceiver mPowerBcastReceiver; @Mock private WifiAwareDataPathStateManager mMockAwareDataPathStatemanager; @Rule @@ -109,9 +117,18 @@ public class WifiAwareStateManagerTest { when(mMockContext.getSystemService(Context.ALARM_SERVICE)) .thenReturn(mAlarmManager.getAlarmManager()); + mMockLooper = new TestLooper(); + + IPowerManager powerManagerService = mock(IPowerManager.class); + mMockPowerManager = new PowerManager(mMockContext, powerManagerService, + new Handler(mMockLooper.getLooper())); + when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mock(ConnectivityManager.class)); when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager); + when(mMockContext.getSystemServiceName(PowerManager.class)).thenReturn( + Context.POWER_SERVICE); + when(mMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager); when(mMockContext.checkPermission(eq(android.Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED); when(mMockContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), @@ -120,16 +137,20 @@ public class WifiAwareStateManagerTest { any())).thenReturn(AppOpsManager.MODE_ERRORED); when(mMockAppOpsManager.noteOp(eq(AppOpsManager.OP_COARSE_LOCATION), anyInt(), any())).thenReturn(AppOpsManager.MODE_ERRORED); + when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false); + when(mMockPowerManager.isInteractive()).thenReturn(true); - mMockLooper = new TestLooper(); - + ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass( + BroadcastReceiver.class); mDut = new WifiAwareStateManager(); mDut.setNative(mMockNative); mDut.start(mMockContext, mMockLooper.getLooper()); + verify(mMockContext).registerReceiver(bcastRxCaptor.capture(), any(IntentFilter.class)); + mPowerBcastReceiver = bcastRxCaptor.getValue(); installMocksInStateManager(mDut, mMockAwareRttStateManager, mMockAwareDataPathStatemanager); when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(), - anyBoolean())).thenReturn(true); + anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(true); when(mMockNative.disable(anyShort())).thenReturn(true); when(mMockNative.publish(anyShort(), anyInt(), any())).thenReturn(true); when(mMockNative.subscribe(anyShort(), anyInt(), any())) @@ -142,6 +163,32 @@ public class WifiAwareStateManagerTest { } /** + * Test that the set parameter shell command executor works when parameters are valid. + */ + @Test + public void testSetParameterShellCommandSuccess() { + setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(1), + true); + } + + /** + * Test that the set parameter shell command executor fails on incorrect name. + */ + @Test + public void testSetParameterShellCommandInvalidParameterName() { + setSettableParam("XXX", Integer.toString(1), false); + } + + /** + * Test that the set parameter shell command executor fails on invalid value (not convertible + * to an int). + */ + @Test + public void testSetParameterShellCommandInvalidValue() { + setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, "garbage", false); + } + + /** * Validate that Aware data-path interfaces are brought up and down correctly. */ @Test @@ -243,7 +290,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -276,7 +323,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -300,7 +347,7 @@ public class WifiAwareStateManagerTest { InOrder inOrder = inOrder(mMockContext, mMockNative, mockCallback); when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(), - anyBoolean())).thenReturn(false); + anyBoolean(), eq(true), eq(false))).thenReturn(false); // (1) check initial state mDut.enableUsage(); @@ -314,7 +361,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); inOrder.verify(mockCallback).onConnectFail(NanStatusType.INTERNAL_FAILURE); validateInternalClientInfoCleanedUp(clientId); @@ -358,7 +405,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId1, uid, pid, callingPackage, mockCallback1, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); short transactionId = transactionIdCapture.getValue(); mDut.onConfigSuccessResponse(transactionId); mMockLooper.dispatchAll(); @@ -367,7 +414,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId2, uid, pid, callingPackage, mockCallback2, configRequest, true); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionIdCapture.capture(), - eq(configRequest), eq(true), eq(false)); + eq(configRequest), eq(true), eq(false), eq(true), eq(false)); transactionId = transactionIdCapture.getValue(); mDut.onConfigSuccessResponse(transactionId); mMockLooper.dispatchAll(); @@ -443,7 +490,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -499,7 +546,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -563,7 +610,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -637,7 +684,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -719,7 +766,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -777,7 +824,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -842,7 +889,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -915,7 +962,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -998,7 +1045,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1070,7 +1117,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1176,7 +1223,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1270,7 +1317,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1353,7 +1400,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1420,7 +1467,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1544,7 +1591,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1629,7 +1676,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1715,7 +1762,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1811,7 +1858,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -1941,7 +1988,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2154,7 +2201,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2245,7 +2292,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId1, uid, pid, callingPackage, mockCallback1, configRequest1, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - crCapture.capture(), eq(false), eq(true)); + crCapture.capture(), eq(false), eq(true), eq(true), eq(false)); collector.checkThat("merge: stage 1", crCapture.getValue(), equalTo(configRequest1)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); @@ -2261,7 +2308,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId3, uid, pid, callingPackage, mockCallback3, configRequest3, true); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - crCapture.capture(), eq(true), eq(false)); + crCapture.capture(), eq(true), eq(false), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback3).onConnectSuccess(clientId3); @@ -2282,7 +2329,7 @@ public class WifiAwareStateManagerTest { mMockLooper.dispatchAll(); validateInternalClientInfoCleanedUp(clientId3); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - crCapture.capture(), eq(false), eq(false)); + crCapture.capture(), eq(false), eq(false), eq(true), eq(false)); collector.checkThat("configRequest1", configRequest1, equalTo(crCapture.getValue())); @@ -2337,7 +2384,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2411,7 +2458,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2454,7 +2501,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); verifyNoMoreInteractions(mMockNative, mockCallback, mockSessionCallback); } @@ -2488,7 +2535,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); short transactionIdConfig = transactionId.getValue(); mDut.onConfigSuccessResponse(transactionIdConfig); mMockLooper.dispatchAll(); @@ -2544,7 +2591,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest), - eq(false), eq(true)); + eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2598,7 +2645,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2650,7 +2697,7 @@ public class WifiAwareStateManagerTest { mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); mMockLooper.dispatchAll(); inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), - eq(configRequest), eq(false), eq(true)); + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); mDut.onConfigSuccessResponse(transactionId.getValue()); mMockLooper.dispatchAll(); inOrder.verify(mockCallback).onConnectSuccess(clientId); @@ -2674,6 +2721,116 @@ public class WifiAwareStateManagerTest { } } + /** + * Validate configuration changes on power state changes when Aware is not disabled on doze. + */ + @Test + public void testConfigOnPowerStateChanges() throws Exception { + final int clientId = 188; + final int uid = 1000; + final int pid = 2000; + final String callingPackage = "com.google.somePackage"; + + ConfigRequest configRequest = new ConfigRequest.Builder().build(); + + ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); + IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); + InOrder inOrder = inOrder(mMockNative, mockCallback); + + mDut.enableUsage(); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); + mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); + mMockLooper.dispatchAll(); + + // (1) connect + mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); + mDut.onConfigSuccessResponse(transactionId.getValue()); + mMockLooper.dispatchAll(); + inOrder.verify(mockCallback).onConnectSuccess(clientId); + + // (2) power state change: SCREEN OFF + simulatePowerStateChangeInteractive(false); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), + eq(configRequest), eq(false), eq(false), eq(false), eq(false)); + mDut.onConfigSuccessResponse(transactionId.getValue()); + mMockLooper.dispatchAll(); + + // (3) power state change: DOZE + simulatePowerStateChangeDoze(true); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), + eq(configRequest), eq(false), eq(false), eq(false), eq(true)); + mDut.onConfigSuccessResponse(transactionId.getValue()); + mMockLooper.dispatchAll(); + + // (4) restore power state to default + simulatePowerStateChangeInteractive(true); // effectively treated as no-doze + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), + eq(configRequest), eq(false), eq(false), eq(true), eq(true)); + mDut.onConfigSuccessResponse(transactionId.getValue()); + mMockLooper.dispatchAll(); + + verifyNoMoreInteractions(mMockNative, mockCallback); + } + + /** + * Validate aware enable/disable during doze transitions. + */ + @Test + public void testEnableDisableOnDoze() throws Exception { + final int clientId = 188; + final int uid = 1000; + final int pid = 2000; + final String callingPackage = "com.google.somePackage"; + + setSettableParam(WifiAwareStateManager.PARAM_ON_IDLE_DISABLE_AWARE, Integer.toString(1), + true); + + ConfigRequest configRequest = new ConfigRequest.Builder().build(); + + ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class); + IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class); + InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback); + + mDut.enableUsage(); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).getCapabilities(transactionId.capture()); + mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities()); + mMockLooper.dispatchAll(); + + // (1) connect + mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), + eq(configRequest), eq(false), eq(true), eq(true), eq(false)); + mDut.onConfigSuccessResponse(transactionId.getValue()); + mMockLooper.dispatchAll(); + inOrder.verify(mockCallback).onConnectSuccess(clientId); + + // (3) power state change: DOZE + simulatePowerStateChangeDoze(true); + mMockLooper.dispatchAll(); + inOrder.verify(mMockNative).disable((short) 0); + validateCorrectAwareStatusChangeBroadcast(inOrder, false); + + // (4) power state change: SCREEN ON (but DOZE still on - fakish but expect no changes) + simulatePowerStateChangeInteractive(false); + mMockLooper.dispatchAll(); + + // (5) power state change: DOZE OFF + simulatePowerStateChangeDoze(false); + mMockLooper.dispatchAll(); + validateCorrectAwareStatusChangeBroadcast(inOrder, true); + + verifyNoMoreInteractions(mMockNativeManager, mMockNative, mockCallback); + } + /* * Tests of internal state of WifiAwareStateManager: very limited (not usually * a good idea). However, these test that the internal state is cleaned-up @@ -2751,6 +2908,16 @@ public class WifiAwareStateManagerTest { /* * Utilities */ + private void setSettableParam(String name, String value, boolean expectSuccess) { + PrintWriter pwMock = mock(PrintWriter.class); + WifiAwareShellCommand parentShellMock = mock(WifiAwareShellCommand.class); + when(parentShellMock.getNextArgRequired()).thenReturn("set").thenReturn(name).thenReturn( + value); + when(parentShellMock.getErrPrintWriter()).thenReturn(pwMock); + + collector.checkThat(mDut.onCommand(parentShellMock), equalTo(expectSuccess ? 0 : -1)); + } + private void dumpDut(String prefix) { StringWriter sw = new StringWriter(); mDut.dump(null, new PrintWriter(sw), null); @@ -2825,6 +2992,29 @@ public class WifiAwareStateManagerTest { } } + /** + * Simulate power state change due to doze. Changes the power manager return values and + * dispatches a broadcast. + */ + private void simulatePowerStateChangeDoze(boolean isDozeOn) { + when(mMockPowerManager.isDeviceIdleMode()).thenReturn(isDozeOn); + + Intent intent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + mPowerBcastReceiver.onReceive(mMockContext, intent); + } + + /** + * Simulate power state change due to interactive mode change (screen on/off). Changes the power + * manager return values and dispatches a broadcast. + */ + private void simulatePowerStateChangeInteractive(boolean isInteractive) { + when(mMockPowerManager.isInteractive()).thenReturn(isInteractive); + + Intent intent = new Intent( + isInteractive ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF); + mPowerBcastReceiver.onReceive(mMockContext, intent); + } + private static Capabilities getCapabilities() { Capabilities cap = new Capabilities(); cap.maxConcurrentAwareClusters = 1; |