diff options
-rw-r--r-- | core/jni/android_net_wifi_Wifi.cpp | 10 | ||||
-rw-r--r-- | services/java/com/android/server/WifiService.java | 51 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiManager.java | 15 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiNative.java | 2 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateTracker.java | 103 |
5 files changed, 163 insertions, 18 deletions
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 7392442..903283e 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -493,6 +493,15 @@ static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject claz return doBooleanCommand("BLACKLIST clear", "OK"); } +static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject clazz, jboolean enabled) +{ + char cmdstr[25]; + + snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETSUSPEND %d", enabled ? 0 : 1); + return doBooleanCommand(cmdstr, "OK"); +} + + static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info) { jint ipaddr, gateway, mask, dns1, dns2, server, lease; @@ -571,6 +580,7 @@ static JNINativeMethod gWifiMethods[] = { { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand }, { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand }, { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand }, + { "setSuspendOptimizationsCommand", "(Z)Z", (void*) android_net_wifi_setSuspendOptimizationsCommand}, { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError }, diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 509c789..af4d7e4 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -116,6 +116,8 @@ public class WifiService extends IWifiManager.Stub { private final LockList mLocks = new LockList(); // some wifi lock statistics + private int mFullHighPerfLocksAcquired; + private int mFullHighPerfLocksReleased; private int mFullLocksAcquired; private int mFullLocksReleased; private int mScanLocksAcquired; @@ -1782,8 +1784,8 @@ public class WifiService extends IWifiManager.Stub { msg.sendToTarget(); } - private void sendStartMessage(boolean scanOnlyMode) { - Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget(); + private void sendStartMessage(int lockMode) { + Message.obtain(mWifiHandler, MESSAGE_START_WIFI, lockMode, 0).sendToTarget(); } private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) { @@ -1801,12 +1803,15 @@ public class WifiService extends IWifiManager.Stub { boolean wifiEnabled = getPersistedWifiEnabled(); boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden; boolean lockHeld = mLocks.hasLocks(); - int strongestLockMode; + int strongestLockMode = WifiManager.WIFI_MODE_FULL; boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode; boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld; - if (mDeviceIdle && lockHeld) { + + if (lockHeld) { strongestLockMode = mLocks.getStrongestLockMode(); - } else { + } + /* If device is not idle, lockmode cannot be scan only */ + if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) { strongestLockMode = WifiManager.WIFI_MODE_FULL; } @@ -1827,7 +1832,7 @@ public class WifiService extends IWifiManager.Stub { sWakeLock.acquire(); sendEnableMessage(true, false, mLastEnableUid); sWakeLock.acquire(); - sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); + sendStartMessage(strongestLockMode); } else if (!mWifiStateTracker.isDriverStopped()) { int wakeLockTimeout = Settings.Secure.getInt( @@ -1905,8 +1910,10 @@ public class WifiService extends IWifiManager.Stub { break; case MESSAGE_START_WIFI: - mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0); + mWifiStateTracker.setScanOnlyMode(msg.arg1 == WifiManager.WIFI_MODE_SCAN_ONLY); mWifiStateTracker.restart(); + mWifiStateTracker.setHighPerfMode(msg.arg1 == + WifiManager.WIFI_MODE_FULL_HIGH_PERF); sWakeLock.release(); break; @@ -1986,8 +1993,10 @@ public class WifiService extends IWifiManager.Stub { } pw.println(); pw.println("Locks acquired: " + mFullLocksAcquired + " full, " + + mFullHighPerfLocksAcquired + " full high perf, " + mScanLocksAcquired + " scan"); pw.println("Locks released: " + mFullLocksReleased + " full, " + + mFullHighPerfLocksReleased + " full high perf, " + mScanLocksReleased + " scan"); pw.println(); pw.println("Locks held:"); @@ -2042,11 +2051,15 @@ public class WifiService extends IWifiManager.Stub { if (mList.isEmpty()) { return WifiManager.WIFI_MODE_FULL; } - for (WifiLock l : mList) { - if (l.mMode == WifiManager.WIFI_MODE_FULL) { - return WifiManager.WIFI_MODE_FULL; - } + + if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) { + return WifiManager.WIFI_MODE_FULL_HIGH_PERF; } + + if (mFullLocksAcquired > mFullLocksReleased) { + return WifiManager.WIFI_MODE_FULL; + } + return WifiManager.WIFI_MODE_SCAN_ONLY; } @@ -2085,7 +2098,11 @@ public class WifiService extends IWifiManager.Stub { public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) { + if (lockMode != WifiManager.WIFI_MODE_FULL && + lockMode != WifiManager.WIFI_MODE_SCAN_ONLY && + lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) { + Slog.e(TAG, "Illegal argument, lockMode= " + lockMode); + if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode); return false; } WifiLock wifiLock = new WifiLock(lockMode, tag, binder); @@ -2107,6 +2124,12 @@ public class WifiService extends IWifiManager.Stub { ++mFullLocksAcquired; mBatteryStats.noteFullWifiLockAcquired(uid); break; + case WifiManager.WIFI_MODE_FULL_HIGH_PERF: + ++mFullHighPerfLocksAcquired; + /* Treat high power as a full lock for battery stats */ + mBatteryStats.noteFullWifiLockAcquired(uid); + break; + case WifiManager.WIFI_MODE_SCAN_ONLY: ++mScanLocksAcquired; mBatteryStats.noteScanWifiLockAcquired(uid); @@ -2146,6 +2169,10 @@ public class WifiService extends IWifiManager.Stub { ++mFullLocksReleased; mBatteryStats.noteFullWifiLockReleased(uid); break; + case WifiManager.WIFI_MODE_FULL_HIGH_PERF: + ++mFullHighPerfLocksReleased; + mBatteryStats.noteFullWifiLockReleased(uid); + break; case WifiManager.WIFI_MODE_SCAN_ONLY: ++mScanLocksReleased; mBatteryStats.noteScanWifiLockReleased(uid); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 4a22b68..3b41dc1 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -307,6 +307,16 @@ public class WifiManager { public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; /** + * In this Wi-Fi lock mode, Wi-Fi will behave as in the mode + * {@link #WIFI_MODE_FULL} but it operates at high performance + * at the expense of power. This mode should be used + * only when the wifi connection needs to have minimum loss and low + * latency as it can impact the battery life. + * @hide + */ + public static final int WIFI_MODE_FULL_HIGH_PERF = 3; + + /** * In this Wi-Fi lock mode, Wi-Fi will be kept active, * and will behave normally, i.e., it will attempt to automatically * establish a connection to a remembered access point that is @@ -993,8 +1003,9 @@ public class WifiManager { /** * Creates a new WifiLock. * - * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and - * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks. + * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL}, + * {@link #WIFI_MODE_SCAN_ONLY} and {@link #WIFI_MODE_FULL_HIGH_PERF} for descriptions + * of the types of Wi-Fi locks. * @param tag a tag for the WifiLock to identify it in debugging messages. This string is * never shown to the user under normal conditions, but should be descriptive * enough to identify your application and the specific WifiLock within it, if it diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 7a3282c..25f05c0 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -149,6 +149,8 @@ public class WifiNative { public native static String getDhcpError(); + public native static boolean setSuspendOptimizationsCommand(boolean enabled); + /** * Wait for the supplicant to send an event, returning the event string. * @return the event string sent by the supplicant. diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index f57df62..0cc1f46 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -276,6 +276,9 @@ public class WifiStateTracker extends NetworkStateTracker { private boolean mIsScanModeActive; private boolean mEnableRssiPolling; + private boolean mIsHighPerfEnabled; + private int mPowerModeRefCount = 0; + private int mOptimizationsDisabledRefCount = 0; /** * One of {@link WifiManager#WIFI_STATE_DISABLED}, @@ -659,6 +662,67 @@ public class WifiStateTracker extends NetworkStateTracker { } } + /** + * Set suspend mode optimizations. These include: + * - packet filtering + * - turn off roaming + * - DTIM settings + * + * Uses reference counting to keep the suspend optimizations disabled + * as long as one entity wants optimizations disabled. + * + * For example, WifiLock can keep suspend optimizations disabled + * or the user setting (wifi never sleeps) can keep suspend optimizations + * disabled. As long as one entity wants it disabled, it should stay + * that way + * + * @param enabled true if optimizations need enabled, false otherwise + */ + public synchronized void setSuspendModeOptimizations(boolean enabled) { + + /* It is good to plumb suspend optimization enable + * or disable even if ref count indicates already done + * since we could have a case of previous failure. + */ + if (!enabled) { + mOptimizationsDisabledRefCount++; + } else { + mOptimizationsDisabledRefCount--; + if (mOptimizationsDisabledRefCount > 0) { + return; + } else { + /* Keep refcount from becoming negative */ + mOptimizationsDisabledRefCount = 0; + } + } + + if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) { + return; + } + + WifiNative.setSuspendOptimizationsCommand(enabled); + } + + + /** + * Set high performance mode of operation. This would mean + * use active power mode and disable suspend optimizations + * @param enabled true if enabled, false otherwise + */ + public synchronized void setHighPerfMode(boolean enabled) { + if (mIsHighPerfEnabled != enabled) { + if (enabled) { + setPowerMode(DRIVER_POWER_MODE_ACTIVE); + setSuspendModeOptimizations(false); + } else { + setPowerMode(DRIVER_POWER_MODE_AUTO); + setSuspendModeOptimizations(true); + } + mIsHighPerfEnabled = enabled; + Log.d(TAG,"high performance mode: " + enabled); + } + } + private void checkIsBluetoothPlaying() { boolean isBluetoothPlaying = false; @@ -744,6 +808,9 @@ public class WifiStateTracker extends NetworkStateTracker { dhcpThread.start(); mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(), this); mIsScanModeActive = true; + mIsHighPerfEnabled = false; + mOptimizationsDisabledRefCount = 0; + mPowerModeRefCount = 0; mTornDownByConnMgr = false; mLastBssid = null; mLastSsid = null; @@ -1947,13 +2014,41 @@ public class WifiStateTracker extends NetworkStateTracker { * @param mode * DRIVER_POWER_MODE_AUTO * DRIVER_POWER_MODE_ACTIVE - * @return {@code true} if the operation succeeds, {@code false} otherwise + * + * Uses reference counting to keep power mode active + * as long as one entity wants power mode to be active. + * + * For example, WifiLock high perf mode can keep power mode active + * or a DHCP session can keep it active. As long as one entity wants + * it enabled, it should stay that way + * */ - public synchronized boolean setPowerMode(int mode) { + private synchronized void setPowerMode(int mode) { + + /* It is good to plumb power mode change + * even if ref count indicates already done + * since we could have a case of previous failure. + */ + switch(mode) { + case DRIVER_POWER_MODE_ACTIVE: + mPowerModeRefCount++; + break; + case DRIVER_POWER_MODE_AUTO: + mPowerModeRefCount--; + if (mPowerModeRefCount > 0) { + return; + } else { + /* Keep refcount from becoming negative */ + mPowerModeRefCount = 0; + } + break; + } + if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) { - return false; + return; } - return WifiNative.setPowerModeCommand(mode); + + WifiNative.setPowerModeCommand(mode); } /** |