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 739244248281..903283e4dbd7 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 509c789e4080..af4d7e4d9724 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 4a22b6885203..3b41dc13602d 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 7a3282c241d4..25f05c01f964 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 f57df62b19e1..0cc1f464c974 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);      }      /**  |