DO NOT MERGE - Merge pie-platform-release (PPRL.190705.004) into master

Bug: 136196576
Change-Id: I4f4d036e5a1ed7b21cc816da2b57002902c989b6
diff --git a/OWNERS b/OWNERS
index 1ad5831..295c588 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,11 +1,4 @@
 etancohen@google.com
-kuh@google.com
-mett@google.com
 mplass@google.com
-nywang@google.com
-quiche@google.com
 rpius@google.com
 satk@google.com
-silberst@google.com
-sohanirao@google.com
-zqiu@google.com
diff --git a/libwifi_hal/Android.mk b/libwifi_hal/Android.mk
index 58e81ff..4e2232f 100644
--- a/libwifi_hal/Android.mk
+++ b/libwifi_hal/Android.mk
@@ -99,6 +99,9 @@
 else ifeq ($(BOARD_WLAN_DEVICE), MediaTek)
   # support MTK WIFI HAL
   LIB_WIFI_HAL := libwifi-hal-mt66xx
+else ifeq ($(BOARD_WLAN_DEVICE), rtl)
+  # support Realtek WIFI HAL
+  LIB_WIFI_HAL := libwifi-hal-rtl
 else ifeq ($(BOARD_WLAN_DEVICE), emulator)
   LIB_WIFI_HAL := libwifi-hal-emu
 endif
diff --git a/libwifi_hal/driver_tool.cpp b/libwifi_hal/driver_tool.cpp
index 3089ee0..0b393d7 100644
--- a/libwifi_hal/driver_tool.cpp
+++ b/libwifi_hal/driver_tool.cpp
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+
 #include "wifi_hal/driver_tool.h"
 
 #include <android-base/logging.h>
-#include <private/android_filesystem_config.h>
 
 #include "hardware_legacy/wifi.h"
 
@@ -35,7 +38,29 @@
     return true;  // HAL doesn't think we need to load firmware for any mode.
   }
 
-  if (chown(WIFI_DRIVER_FW_PATH_PARAM, AID_WIFI, AID_WIFI) != 0) {
+  errno = 0;
+  struct passwd *pwd = getpwnam("wifi");
+  if (pwd == nullptr) {
+    if (errno == 0) {
+      PLOG(ERROR) << "No user 'wifi' found";
+    } else {
+      PLOG(ERROR) << "Error getting uid for wifi: " << strerror(errno);
+    }
+    return false;
+  }
+
+  errno = 0;
+  struct group *grp = getgrnam("wifi");
+  if (grp == nullptr) {
+    if (errno == 0) {
+      PLOG(ERROR) << "No group 'wifi' found";
+    } else {
+      PLOG(ERROR) << "Error getting gid for wifi: " << strerror(errno);
+    }
+    return false;
+  }
+
+  if (chown(WIFI_DRIVER_FW_PATH_PARAM, pwd->pw_uid, grp->gr_gid) != 0) {
     PLOG(ERROR) << "Error changing ownership of '" << WIFI_DRIVER_FW_PATH_PARAM
                 << "' to wifi:wifi";
     return false;
diff --git a/service/Android.bp b/service/Android.bp
new file mode 100644
index 0000000..091023e
--- /dev/null
+++ b/service/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2011 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.
+
+// Make the JNI part
+// ============================================================
+cc_library_shared {
+    name: "libwifi-service",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wno-unused-parameter",
+        "-Wno-unused-function",
+        "-Wunused-variable",
+        "-Winit-self",
+        "-Wwrite-strings",
+        "-Wshadow",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libnativehelper",
+        "libcutils",
+        "libutils",
+        "libdl",
+    ],
+
+    srcs: [
+        "jni/com_android_server_wifi_WifiNative.cpp",
+        "jni/jni_helper.cpp",
+    ],
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/service/Android.mk b/service/Android.mk
index 83dc143..b0ae8ed 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -16,31 +16,6 @@
 
 ifneq ($(TARGET_BUILD_PDK), true)
 
-# Make the JNI part
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -Wall -Werror -Wextra -Wno-unused-parameter -Wno-unused-function \
-                -Wunused-variable -Winit-self -Wwrite-strings -Wshadow
-
-LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-
-LOCAL_SHARED_LIBRARIES += \
-	liblog \
-	libnativehelper \
-	libcutils \
-	libutils \
-	libdl
-
-LOCAL_SRC_FILES := \
-	jni/com_android_server_wifi_WifiNative.cpp \
-	jni/jni_helper.cpp
-
-LOCAL_MODULE := libwifi-service
-
-include $(BUILD_SHARED_LIBRARY)
-
 # Build the java code
 # ============================================================
 
@@ -56,9 +31,7 @@
 	$(call all-logtags-files-under, java)
 
 LOCAL_JAVA_LIBRARIES := \
-	android.hidl.manager-V1.0-java \
-	bouncycastle \
-	conscrypt \
+	android.hidl.manager-V1.2-java \
 	error_prone_annotations \
 	jsr305 \
 	services
diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index 26cb4ff..4d1f2db 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -25,7 +25,8 @@
 import android.database.ContentObserver;
 import android.net.TrafficStats;
 import android.net.Uri;
-import android.net.ip.IpClient;
+import android.net.ip.IpClientCallbacks;
+import android.net.ip.IpClientUtil;
 import android.os.BatteryStats;
 import android.os.Handler;
 import android.os.IBinder;
@@ -144,9 +145,14 @@
         return TrafficStats.getRxPackets(iface);
     }
 
-    public IpClient makeIpClient(
-            Context context, String iface, IpClient.Callback callback) {
-        return new IpClient(context, iface, callback);
+    /**
+     * Request a new IpClient to be created asynchronously.
+     * @param context Context to use for creation.
+     * @param iface Interface the client should act on.
+     * @param callback IpClient event callbacks.
+     */
+    public void makeIpClient(Context context, String iface, IpClientCallbacks callback) {
+        IpClientUtil.makeIpClient(context, iface, callback);
     }
 
     /**
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 3c61217..439d169 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -32,8 +32,8 @@
 import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
 import android.hardware.wifi.V1_0.WifiStatus;
 import android.hardware.wifi.V1_0.WifiStatusCode;
-import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
+import android.hidl.manager.V1_2.IServiceManager;
 import android.os.Handler;
 import android.os.HidlSupport.Mutable;
 import android.os.HwRemoteBinder;
@@ -173,6 +173,7 @@
      */
     public void stop() {
         stopWifi();
+        mWifi = null;
     }
 
     /**
@@ -562,7 +563,7 @@
      */
     protected IWifi getWifiServiceMockable() {
         try {
-            return IWifi.getService();
+            return IWifi.getService(true /* retry */);
         } catch (RemoteException e) {
             Log.e(TAG, "Exception getting IWifi service: " + e);
             return null;
@@ -670,8 +671,9 @@
                 return false;
             }
             try {
-                return (mServiceManager.getTransport(IWifi.kInterfaceName, HAL_INSTANCE_NAME)
-                        != IServiceManager.Transport.EMPTY);
+                List<String> wifiServices =
+                        mServiceManager.listManifestByInterface(IWifi.kInterfaceName);
+                return !wifiServices.isEmpty();
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Exception while operating on IServiceManager: " + e);
                 return false;
@@ -1154,7 +1156,7 @@
 
     private boolean startWifi() {
         if (VDBG) Log.d(TAG, "startWifi");
-
+        initIWifiIfNecessary();
         synchronized (mLock) {
             try {
                 if (mWifi == null) {
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
index 5bf44ce..03925e8 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
@@ -2339,6 +2339,8 @@
         public void onNetworkRemoved(int id) {
             synchronized (mLock) {
                 logCallback("onNetworkRemoved");
+                // Reset 4way handshake state since network has been removed.
+                mStateIsFourway = false;
             }
         }
 
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 7dc938b..c8c4844 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -2463,31 +2463,22 @@
      */
     public void resetSimNetworks(boolean simPresent) {
         if (mVerboseLoggingEnabled) localLog("resetSimNetworks");
-        for (WifiConfiguration config : getInternalConfiguredNetworks()) {
-            if (TelephonyUtil.isSimConfig(config)) {
-                Pair<String, String> currentIdentity = null;
-                if (simPresent) {
-                    currentIdentity = TelephonyUtil.getSimIdentity(mTelephonyManager,
-                        new TelephonyUtil(), config);
-                }
-                if (mVerboseLoggingEnabled) {
-                    Log.d(TAG, "New identity for config " + config + ": " + currentIdentity);
-                }
+        if (simPresent) {
+            for (WifiConfiguration config : getInternalConfiguredNetworks()) {
+                if (TelephonyUtil.isSimConfig(config)) {
+                    Pair<String, String> currentIdentity =
+                            TelephonyUtil.getSimIdentity(mTelephonyManager,
+                                    new TelephonyUtil(), config);
 
-                // Update the loaded config
-                if (currentIdentity == null) {
-                    Log.d(TAG, "Identity is null for config:" + config);
-                    break;
-                }
-
-                if (config.enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) {
+                    // Update the loaded config
+                    if (currentIdentity == null) {
+                        Log.d(TAG, "Identity is null");
+                        break;
+                    }
                     config.enterpriseConfig.setIdentity(currentIdentity.first);
-                    // do not reset anonymous identity since it may be dependent on user-entry
-                    // (i.e. cannot re-request on every reboot/SIM re-entry)
-                } else {
-                    // reset identity as well: supplicant will ask us for it
-                    config.enterpriseConfig.setIdentity("");
-                    config.enterpriseConfig.setAnonymousIdentity("");
+                    if (config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.PEAP) {
+                        config.enterpriseConfig.setAnonymousIdentity("");
+                    }
                 }
             }
         }
@@ -2742,6 +2733,8 @@
         if (mConfiguredNetworks.sizeForAllUsers() == 0) {
             Log.w(TAG, "No stored networks found.");
         }
+        // resetSimNetworks may already have been called. Call it again to reset loaded SIM configs.
+        resetSimNetworks(mSimPresent);
         sendConfiguredNetworksChangedBroadcast();
         mPendingStoreRead = false;
     }
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 8d94862..0258834 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.wifi.util.NativeUtil;
+import com.android.server.wifi.util.TelephonyUtil;
 
 import java.nio.charset.StandardCharsets;
 import java.security.cert.X509Certificate;
@@ -195,9 +196,12 @@
                 return true;
             }
             if (!TextUtils.equals(existingEnterpriseConfig.getIdentity(),
-                                  newEnterpriseConfig.getIdentity())
-                    || !TextUtils.equals(existingEnterpriseConfig.getAnonymousIdentity(),
-                                         newEnterpriseConfig.getAnonymousIdentity())) {
+                                  newEnterpriseConfig.getIdentity())) {
+                return true;
+            }
+            if (!TelephonyUtil.isSimEapMethod(existingEnterpriseConfig.getEapMethod())
+                    && !TextUtils.equals(existingEnterpriseConfig.getAnonymousIdentity(),
+                    newEnterpriseConfig.getAnonymousIdentity())) {
                 return true;
             }
             if (!TextUtils.equals(existingEnterpriseConfig.getPassword(),
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 89a7f45..b2b4927 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -290,7 +290,8 @@
                 new WakeupLock(mWifiConfigManager, mWifiMetrics.getWakeupMetrics(), mClock),
                 WakeupEvaluator.fromContext(mContext), wakeupOnboarding, mWifiConfigManager,
                 mWifiConfigStore, mWifiMetrics.getWakeupMetrics(), this, mFrameworkFacade);
-        mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
+        mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService(),
+                mWifiStateMachine);
         mWifiController = new WifiController(mContext, mWifiStateMachine, wifiStateMachineLooper,
                 mSettingsStore, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade,
                 mWifiStateMachinePrime);
diff --git a/service/java/com/android/server/wifi/WifiLockManager.java b/service/java/com/android/server/wifi/WifiLockManager.java
index b1b3f11..569dce6 100644
--- a/service/java/com/android/server/wifi/WifiLockManager.java
+++ b/service/java/com/android/server/wifi/WifiLockManager.java
@@ -39,8 +39,14 @@
 
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
+    private final WifiStateMachine mWifiStateMachine;
 
     private final List<WifiLock> mWifiLocks = new ArrayList<>();
+    private int mCurrentOpMode;
+
+    // For shell command support
+    private boolean mForceHiPerfMode = false;
+
     // some wifi lock statistics
     private int mFullHighPerfLocksAcquired;
     private int mFullHighPerfLocksReleased;
@@ -49,9 +55,12 @@
     private int mScanLocksAcquired;
     private int mScanLocksReleased;
 
-    WifiLockManager(Context context, IBatteryStats batteryStats) {
+    WifiLockManager(Context context, IBatteryStats batteryStats,
+            WifiStateMachine wifiStateMachine) {
         mContext = context;
         mBatteryStats = batteryStats;
+        mWifiStateMachine = wifiStateMachine;
+        mCurrentOpMode = WifiManager.WIFI_MODE_NO_LOCKS_HELD;
     }
 
     /**
@@ -100,6 +109,11 @@
      * @return int representing the currently held (highest power consumption) lock.
      */
     public synchronized int getStrongestLockMode() {
+        // First check if mode is forced to hi-perf
+        if (mForceHiPerfMode) {
+            return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
+        }
+
         if (mWifiLocks.isEmpty()) {
             return WifiManager.WIFI_MODE_NO_LOCKS_HELD;
         }
@@ -171,6 +185,22 @@
         }
     }
 
+    /**
+     * Method Used for shell command support
+     *
+     * @param isEnabled True to force hi-perf mode, false to leave it up to acquired wifiLocks.
+     * @return True for success, false for failure (failure turns forcing mode off)
+     */
+    public boolean forceHiPerfMode(boolean isEnabled) {
+        mForceHiPerfMode = isEnabled;
+        if (!updateOpMode()) {
+            Slog.e(TAG, "Failed to force hi-perf mode, returning to normal mode");
+            mForceHiPerfMode = false;
+            return false;
+        }
+        return true;
+    }
+
     private static boolean isValidLockMode(int lockMode) {
         if (lockMode != WifiManager.WIFI_MODE_FULL
                 && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY
@@ -210,6 +240,9 @@
                     break;
             }
             lockAdded = true;
+
+            // Recalculate the operating mode
+            updateOpMode();
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -251,6 +284,9 @@
                     ++mScanLocksReleased;
                     break;
             }
+
+            // Recalculate the operating mode
+            updateOpMode();
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -258,6 +294,34 @@
         return true;
     }
 
+    private synchronized boolean updateOpMode() {
+        int newLockMode = getStrongestLockMode();
+
+        if (newLockMode == mCurrentOpMode) {
+            // No action is needed
+            return true;
+        }
+
+        if (mVerboseLoggingEnabled) {
+            Slog.d(TAG, "Current opMode: " + mCurrentOpMode + " New LockMode: " + newLockMode);
+        }
+
+        if (newLockMode == WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
+            if (!mWifiStateMachine.setPowerSave(false)) {
+                Slog.e(TAG, "Failed to disable power save");
+                return false;
+            }
+        } else {
+            if (!mWifiStateMachine.setPowerSave(true)) {
+                Slog.e(TAG, "Failed to enable power save");
+                return false;
+            }
+        }
+
+        // Now set the mode to the new value
+        mCurrentOpMode = newLockMode;
+        return true;
+    }
 
     private synchronized WifiLock findLockByBinder(IBinder binder) {
         for (WifiLock lock : mWifiLocks) {
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 6a8e063..7726f6e 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -57,7 +57,7 @@
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.Uri;
-import android.net.ip.IpClient;
+import android.net.ip.IpClientUtil;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
@@ -2513,8 +2513,8 @@
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
-        (new WifiShellCommand(mWifiStateMachine)).exec(this, in, out, err, args, callback,
-                resultReceiver);
+        (new WifiShellCommand(mWifiStateMachine, mWifiLockManager)).exec(this, in, out, err,
+                args, callback, resultReceiver);
     }
 
     @Override
@@ -2530,7 +2530,7 @@
             // WifiMetrics proto bytes were requested. Dump only these.
             mWifiStateMachine.updateWifiMetrics();
             mWifiMetrics.dump(fd, pw, args);
-        } else if (args != null && args.length > 0 && IpClient.DUMP_ARG.equals(args[0])) {
+        } else if (args != null && args.length > 0 && IpClientUtil.DUMP_ARG.equals(args[0])) {
             // IpClient dump was requested. Pass it along and take no further action.
             String[] ipClientArgs = new String[args.length - 1];
             System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length);
@@ -2581,12 +2581,6 @@
         }
     }
 
-    /**
-     * NOTE: WifiLocks do not serve a useful purpose in their current impl and will be removed
-     * (including the methods below).
-     *
-     * TODO: b/71548157
-     */
     @Override
     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
         mLog.info("acquireWifiLock uid=% lockMode=%")
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index f4db178..1f7f568 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -41,10 +41,12 @@
  */
 public class WifiShellCommand extends ShellCommand {
     private final WifiStateMachine mStateMachine;
+    private final WifiLockManager mWifiLockManager;
     private final IPackageManager mPM;
 
-    WifiShellCommand(WifiStateMachine stateMachine) {
+    WifiShellCommand(WifiStateMachine stateMachine, WifiLockManager wifiLockManager) {
         mStateMachine = stateMachine;
+        mWifiLockManager = wifiLockManager;
         mPM = AppGlobals.getPackageManager();
     }
 
@@ -99,6 +101,24 @@
                     pw.println("WifiStateMachine.mPollRssiIntervalMsecs = "
                             + mStateMachine.getPollRssiIntervalMsecs());
                     return 0;
+                case "force-hi-perf-mode": {
+                    boolean enabled;
+                    String nextArg = getNextArgRequired();
+                    if ("enabled".equals(nextArg)) {
+                        enabled = true;
+                    } else if ("disabled".equals(nextArg)) {
+                        enabled = false;
+                    } else {
+                        pw.println(
+                                "Invalid argument to 'force-hi-perf-mode' - must be 'enabled'"
+                                        + " or 'disabled'");
+                        return -1;
+                    }
+                    if (!mWifiLockManager.forceHiPerfMode(enabled)) {
+                        pw.println("Command execution failed");
+                    }
+                    return 0;
+                }
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -132,6 +152,8 @@
         pw.println("    Sets the interval between RSSI polls to <int> milliseconds.");
         pw.println("  get-poll-rssi-interval-msecs");
         pw.println("    Gets current interval between RSSI polls, in milliseconds.");
+        pw.println("  force-hi-perf-mode enabled|disabled");
+        pw.println("    Sets whether hi-perf mode is forced or left for normal operation.");
         pw.println();
     }
 }
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 390a102..44702c2 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -38,6 +38,7 @@
 import android.net.KeepalivePacketData;
 import android.net.LinkProperties;
 import android.net.MacAddress;
+import android.net.NattKeepalivePacketData;
 import android.net.Network;
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
@@ -48,10 +49,15 @@
 import android.net.NetworkRequest;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.SocketKeepalive;
+import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.StaticIpConfiguration;
+import android.net.TcpKeepalivePacketData;
 import android.net.TrafficStats;
-import android.net.dhcp.DhcpClient;
-import android.net.ip.IpClient;
+import android.net.ip.IIpClient;
+import android.net.ip.IpClientCallbacks;
+import android.net.ip.IpClientManager;
+import android.net.shared.ProvisioningConfiguration;
 import android.net.wifi.RssiPacketCountInfo;
 import android.net.wifi.ScanResult;
 import android.net.wifi.SupplicantState;
@@ -66,6 +72,7 @@
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.os.BatteryStats;
 import android.os.Bundle;
+import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -151,6 +158,7 @@
     private static final String EXTRA_OSU_ICON_QUERY_BSSID = "BSSID";
     private static final String EXTRA_OSU_ICON_QUERY_FILENAME = "FILENAME";
     private static final String EXTRA_OSU_PROVIDER = "OsuProvider";
+    private static final int IPCLIENT_TIMEOUT_MS = 10_000;
 
     private boolean mVerboseLoggingEnabled = false;
     private final WifiPermissionsWrapper mWifiPermissionsWrapper;
@@ -386,7 +394,8 @@
         return true;
     }
 
-    private IpClient mIpClient;
+    private volatile IpClientManager mIpClient;
+    private IpClientCallbacksImpl mIpClientCallbacks;
 
     // Channel for sending replies.
     private AsyncChannel mReplyChannel = new AsyncChannel();
@@ -413,10 +422,6 @@
 
     /* The base for wifi message types */
     static final int BASE = Protocol.BASE_WIFI;
-    /* Indicates Static IP succeeded */
-    static final int CMD_STATIC_IP_SUCCESS                              = BASE + 15;
-    /* Indicates Static IP failed */
-    static final int CMD_STATIC_IP_FAILURE                              = BASE + 16;
 
     static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE                 = BASE + 31;
 
@@ -632,15 +637,26 @@
     /* Read the APF program & data buffer */
     static final int CMD_READ_PACKET_FILTER                             = BASE + 208;
 
+    /** Used to add packet filter to apf. */
+    static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = BASE + 209;
+
+    /** Used to remove packet filter from apf. */
+    static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = BASE + 210;
+
     /* Indicates that diagnostics should time out a connection start event. */
     private static final int CMD_DIAGS_CONNECT_TIMEOUT                  = BASE + 252;
 
     // Start subscription provisioning with a given provider
     private static final int CMD_START_SUBSCRIPTION_PROVISIONING        = BASE + 254;
 
+    @VisibleForTesting
+    static final int CMD_PRE_DHCP_ACTION                                = BASE + 255;
+    private static final int CMD_PRE_DHCP_ACTION_COMPLETE               = BASE + 256;
+    private static final int CMD_POST_DHCP_ACTION                       = BASE + 257;
+
     // For message logging.
     private static final Class[] sMessageClasses = {
-            AsyncChannel.class, WifiStateMachine.class, DhcpClient.class };
+            AsyncChannel.class, WifiStateMachine.class };
     private static final SparseArray<String> sSmToString =
             MessageUtils.findMessageNames(sMessageClasses);
 
@@ -954,6 +970,12 @@
                 mWifiMetrics.getHandler());
     }
 
+    private void setMulticastFilter(boolean enabled) {
+        if (mIpClient != null) {
+            mIpClient.setMulticastFilter(enabled);
+        }
+    }
+
     /**
      * Class to implement the MulticastLockManager.FilterController callback.
      */
@@ -962,30 +984,35 @@
          * Start filtering Multicast v4 packets
          */
         public void startFilteringMulticastPackets() {
-            if (mIpClient != null) {
-                mIpClient.setMulticastFilter(true);
-            }
+            setMulticastFilter(true);
         }
 
         /**
          * Stop filtering Multicast v4 packets
          */
         public void stopFilteringMulticastPackets() {
-            if (mIpClient != null) {
-                mIpClient.setMulticastFilter(false);
-            }
+            setMulticastFilter(false);
         }
     }
 
-    class IpClientCallback extends IpClient.Callback {
+    class IpClientCallbacksImpl extends IpClientCallbacks {
+        private final ConditionVariable mWaitForCreationCv = new ConditionVariable(false);
+        private final ConditionVariable mWaitForStopCv = new ConditionVariable(false);
+
+        @Override
+        public void onIpClientCreated(IIpClient ipClient) {
+            mIpClient = new IpClientManager(ipClient, getName());
+            mWaitForCreationCv.open();
+        }
+
         @Override
         public void onPreDhcpAction() {
-            sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION);
+            sendMessage(CMD_PRE_DHCP_ACTION);
         }
 
         @Override
         public void onPostDhcpAction() {
-            sendMessage(DhcpClient.CMD_POST_DHCP_ACTION);
+            sendMessage(CMD_POST_DHCP_ACTION);
         }
 
         @Override
@@ -1043,6 +1070,19 @@
         public void setNeighborDiscoveryOffload(boolean enabled) {
             sendMessage(CMD_CONFIG_ND_OFFLOAD, (enabled ? 1 : 0));
         }
+
+        @Override
+        public void onQuit() {
+            mWaitForStopCv.open();
+        }
+
+        boolean awaitCreation() {
+            return mWaitForCreationCv.block(IPCLIENT_TIMEOUT_MS);
+        }
+
+        boolean awaitShutdown() {
+            return mWaitForStopCv.block(IPCLIENT_TIMEOUT_MS);
+        }
     }
 
     private void stopIpClient() {
@@ -1266,27 +1306,25 @@
     }
 
     private byte[] getDstMacForKeepalive(KeepalivePacketData packetData)
-            throws KeepalivePacketData.InvalidPacketException {
+            throws InvalidPacketException {
         try {
             InetAddress gateway = RouteInfo.selectBestRoute(
                     mLinkProperties.getRoutes(), packetData.dstAddress).getGateway();
             String dstMacStr = macAddressFromRoute(gateway.getHostAddress());
             return NativeUtil.macAddressToByteArray(dstMacStr);
         } catch (NullPointerException | IllegalArgumentException e) {
-            throw new KeepalivePacketData.InvalidPacketException(
-                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+            throw new InvalidPacketException(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
         }
     }
 
     private static int getEtherProtoForKeepalive(KeepalivePacketData packetData)
-            throws KeepalivePacketData.InvalidPacketException {
+            throws InvalidPacketException {
         if (packetData.dstAddress instanceof Inet4Address) {
             return OsConstants.ETH_P_IP;
         } else if (packetData.dstAddress instanceof Inet6Address) {
             return OsConstants.ETH_P_IPV6;
         } else {
-            throw new KeepalivePacketData.InvalidPacketException(
-                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
+            throw new InvalidPacketException(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
         }
     }
 
@@ -1299,7 +1337,7 @@
             packet = packetData.getPacket();
             dstMac = getDstMacForKeepalive(packetData);
             proto = getEtherProtoForKeepalive(packetData);
-        } catch (KeepalivePacketData.InvalidPacketException e) {
+        } catch (InvalidPacketException e) {
             return e.error;
         }
 
@@ -1308,9 +1346,9 @@
         if (ret != 0) {
             loge("startWifiIPPacketOffload(" + slot + ", " + intervalSeconds +
                     "): hardware error " + ret);
-            return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR;
+            return SocketKeepalive.ERROR_HARDWARE_ERROR;
         } else {
-            return ConnectivityManager.PacketKeepalive.SUCCESS;
+            return SocketKeepalive.SUCCESS;
         }
     }
 
@@ -1318,9 +1356,9 @@
         int ret = mWifiNative.stopSendingOffloadedPacket(mInterfaceName, slot);
         if (ret != 0) {
             loge("stopWifiIPPacketOffload(" + slot + "): hardware error " + ret);
-            return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR;
+            return SocketKeepalive.ERROR_HARDWARE_ERROR;
         } else {
-            return ConnectivityManager.PacketKeepalive.SUCCESS;
+            return SocketKeepalive.SUCCESS;
         }
     }
 
@@ -1864,7 +1902,8 @@
 
     public void dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mIpClient != null) {
-            mIpClient.dump(fd, pw, args);
+            // All dumpIpClient does is print this log message.
+            pw.println("IpClient logs have moved to dumpsys network_stack");
         }
     }
 
@@ -2212,7 +2251,7 @@
                 sb.append(Integer.toString(msg.arg2));
                 sb.append(" num=").append(mWifiConfigManager.getConfiguredNetworks().size());
                 break;
-            case DhcpClient.CMD_PRE_DHCP_ACTION:
+            case CMD_PRE_DHCP_ACTION:
                 sb.append(" ");
                 sb.append(Integer.toString(msg.arg1));
                 sb.append(" ");
@@ -2221,16 +2260,7 @@
                 sb.append(",").append(mWifiInfo.txBad);
                 sb.append(",").append(mWifiInfo.txRetries);
                 break;
-            case DhcpClient.CMD_POST_DHCP_ACTION:
-                sb.append(" ");
-                sb.append(Integer.toString(msg.arg1));
-                sb.append(" ");
-                sb.append(Integer.toString(msg.arg2));
-                if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
-                    sb.append(" OK ");
-                } else if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
-                    sb.append(" FAIL ");
-                }
+            case CMD_POST_DHCP_ACTION:
                 if (mLinkProperties != null) {
                     sb.append(" ");
                     sb.append(getLinkPropertiesSummary(mLinkProperties));
@@ -2330,23 +2360,7 @@
                 break;
             case CMD_IPV4_PROVISIONING_SUCCESS:
                 sb.append(" ");
-                if (msg.arg1 == DhcpClient.DHCP_SUCCESS) {
-                    sb.append("DHCP_OK");
-                } else if (msg.arg1 == CMD_STATIC_IP_SUCCESS) {
-                    sb.append("STATIC_OK");
-                } else {
-                    sb.append(Integer.toString(msg.arg1));
-                }
-                break;
-            case CMD_IPV4_PROVISIONING_FAILURE:
-                sb.append(" ");
-                if (msg.arg1 == DhcpClient.DHCP_FAILURE) {
-                    sb.append("DHCP_FAIL");
-                } else if (msg.arg1 == CMD_STATIC_IP_FAILURE) {
-                    sb.append("STATIC_FAIL");
-                } else {
-                    sb.append(Integer.toString(msg.arg1));
-                }
+                sb.append(/* DhcpResults */ msg.obj);
                 break;
             default:
                 sb.append(" ");
@@ -2813,7 +2827,7 @@
         // power settings when we control suspend mode optimizations.
         // TODO: Remove this comment when the driver is fixed.
         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false);
-        mWifiNative.setPowerSave(mInterfaceName, false);
+        setPowerSave(false);
 
         // Update link layer stats
         getWifiLinkLayerStats();
@@ -2823,19 +2837,19 @@
             Message msg = new Message();
             msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY;
             msg.arg1 = WifiP2pServiceImpl.ENABLED;
-            msg.arg2 = DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE;
+            msg.arg2 = CMD_PRE_DHCP_ACTION_COMPLETE;
             msg.obj = WifiStateMachine.this;
             mWifiP2pChannel.sendMessage(msg);
         } else {
             // If the p2p service is not running, we can proceed directly.
-            sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
+            sendMessage(CMD_PRE_DHCP_ACTION_COMPLETE);
         }
     }
 
     void handlePostDhcpSetup() {
         /* Restore power save and suspend optimizations */
         setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true);
-        mWifiNative.setPowerSave(mInterfaceName, true);
+        setPowerSave(true);
 
         p2pSendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED);
 
@@ -2844,6 +2858,26 @@
                 mInterfaceName, WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
     }
 
+    /**
+     * Set power save mode
+     *
+     * @param ps true to enable power save (default behavior)
+     *           false to disable power save.
+     * @return true for success, false for failure
+     */
+    public boolean setPowerSave(boolean ps) {
+        if (mInterfaceName != null) {
+            if (mVerboseLoggingEnabled) {
+                Log.d(TAG, "Setting power save for: " + mInterfaceName + " to: " + ps);
+            }
+            mWifiNative.setPowerSave(mInterfaceName, ps);
+        } else {
+            Log.e(TAG, "Failed to setPowerSave, interfaceName is null");
+            return false;
+        }
+        return true;
+    }
+
     private static final long DIAGS_CONNECT_TIMEOUT_MILLIS = 60 * 1000;
     private long mDiagsConnectionStartMillis = -1;
     /**
@@ -3366,9 +3400,9 @@
                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
                 case WifiMonitor.ASSOCIATION_REJECTION_EVENT:
                 case CMD_RSSI_POLL:
-                case DhcpClient.CMD_PRE_DHCP_ACTION:
-                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
-                case DhcpClient.CMD_POST_DHCP_ACTION:
+                case CMD_PRE_DHCP_ACTION:
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
+                case CMD_POST_DHCP_ACTION:
                 case CMD_ENABLE_P2P:
                 case CMD_DISABLE_P2P_RSP:
                 case WifiMonitor.SUP_REQUEST_IDENTITY:
@@ -3458,14 +3492,14 @@
                     deferMessage(message);
                     break;
                 case CMD_START_IP_PACKET_OFFLOAD:
-                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
-                            message.arg1,
-                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
-                    break;
+                    /* fall-through */
                 case CMD_STOP_IP_PACKET_OFFLOAD:
-                    if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent(
-                            message.arg1,
-                            ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+                case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF:
+                case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF:
+                    if (mNetworkAgent != null) {
+                        mNetworkAgent.onSocketKeepaliveEvent(message.arg1,
+                                SocketKeepalive.ERROR_INVALID_NETWORK);
+                    }
                     break;
                 case CMD_START_RSSI_MONITORING_OFFLOAD:
                     messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
@@ -3654,8 +3688,13 @@
             }
         }
 
-        mIpClient = mFacade.makeIpClient(mContext, mInterfaceName, new IpClientCallback());
-        mIpClient.setMulticastFilter(true);
+        mIpClientCallbacks = new IpClientCallbacksImpl();
+        mFacade.makeIpClient(mContext, mInterfaceName, mIpClientCallbacks);
+        if (!mIpClientCallbacks.awaitCreation()) {
+            loge("Timeout waiting for IpClient");
+        }
+
+        setMulticastFilter(true);
         registerForWifiMonitorEvents();
         mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();
         setSupplicantLogLevel();
@@ -3704,7 +3743,7 @@
         mWifiNative.setSuspendOptimizations(mInterfaceName, mSuspendOptNeedsDisabled == 0
                 && mUserWantsSuspendOpt.get());
 
-        mWifiNative.setPowerSave(mInterfaceName, true);
+        setPowerSave(true);
 
         if (mP2pSupported) {
             p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
@@ -3732,11 +3771,10 @@
         mIsRunning = false;
         updateBatteryWorkSource(null);
 
-        if (mIpClient != null) {
-            mIpClient.shutdown();
+        if (mIpClient != null && mIpClient.shutdown()) {
             // Block to make sure IpClient has really shut down, lest cleanup
             // race with, say, bringup code over in tethering.
-            mIpClient.awaitShutdown();
+            mIpClientCallbacks.awaitShutdown();
         }
         mNetworkInfo.setIsAvailable(false);
         if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -4445,7 +4483,7 @@
                     int slot = message.arg1;
                     int ret = stopWifiIPPacketOffload(slot);
                     if (mNetworkAgent != null) {
-                        mNetworkAgent.onPacketKeepaliveEvent(slot, ret);
+                        mNetworkAgent.onSocketKeepaliveEvent(slot, ret);
                     }
                     break;
                 }
@@ -4593,18 +4631,30 @@
         }
 
         @Override
-        protected void startPacketKeepalive(Message msg) {
+        protected void startSocketKeepalive(Message msg) {
             WifiStateMachine.this.sendMessage(
                     CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
         }
 
         @Override
-        protected void stopPacketKeepalive(Message msg) {
+        protected void stopSocketKeepalive(Message msg) {
             WifiStateMachine.this.sendMessage(
                     CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj);
         }
 
         @Override
+        protected void addKeepalivePacketFilter(Message msg) {
+            WifiStateMachine.this.sendMessage(
+                    CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, msg.arg1, msg.arg2, msg.obj);
+        }
+
+        @Override
+        protected void removeKeepalivePacketFilter(Message msg) {
+            WifiStateMachine.this.sendMessage(
+                    CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, msg.arg1, msg.arg2, msg.obj);
+        }
+
+        @Override
         protected void setSignalStrengthThresholds(int[] thresholds) {
             // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring.
             // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and
@@ -4769,13 +4819,13 @@
             logStateAndMessage(message, this);
 
             switch (message.what) {
-                case DhcpClient.CMD_PRE_DHCP_ACTION:
+                case CMD_PRE_DHCP_ACTION:
                     handlePreDhcpSetup();
                     break;
-                case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
                     mIpClient.completedPreDhcpAction();
                     break;
-                case DhcpClient.CMD_POST_DHCP_ACTION:
+                case CMD_POST_DHCP_ACTION:
                     handlePostDhcpSetup();
                     // We advance to mConnectedState because IpClient will also send a
                     // CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
@@ -4955,6 +5005,37 @@
                     }
                     /* allow parent state to reset data for other networks */
                     return NOT_HANDLED;
+                case CMD_START_IP_PACKET_OFFLOAD: {
+                    int slot = message.arg1;
+                    int intervalSeconds = message.arg2;
+                    KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
+                    int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
+                    if (mNetworkAgent != null) {
+                        mNetworkAgent.onSocketKeepaliveEvent(slot, result);
+                    }
+                    break;
+                }
+                case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
+                    if (mIpClient != null) {
+                        final int slot = message.arg1;
+                        if (message.obj instanceof NattKeepalivePacketData) {
+                            final NattKeepalivePacketData pkt =
+                                    (NattKeepalivePacketData) message.obj;
+                            mIpClient.addKeepalivePacketFilter(slot, pkt);
+                        } else if (message.obj instanceof TcpKeepalivePacketData) {
+                            final TcpKeepalivePacketData pkt =
+                                    (TcpKeepalivePacketData) message.obj;
+                            mIpClient.addKeepalivePacketFilter(slot, pkt);
+                        }
+                    }
+                    break;
+                }
+                case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
+                    if (mIpClient != null) {
+                        mIpClient.removeKeepalivePacketFilter(message.arg1);
+                    }
+                    break;
+                }
                 default:
                     return NOT_HANDLED;
             }
@@ -5001,9 +5082,9 @@
             if (!TextUtils.isEmpty(mTcpBufferSizes)) {
                 mIpClient.setTcpBufferSizes(mTcpBufferSizes);
             }
-            final IpClient.ProvisioningConfiguration prov;
+            final ProvisioningConfiguration prov;
             if (!isUsingStaticIp) {
-                prov = IpClient.buildProvisioningConfiguration()
+                prov = new ProvisioningConfiguration.Builder()
                             .withPreDhcpAction()
                             .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
                             .withNetwork(getCurrentNetwork())
@@ -5012,7 +5093,7 @@
                             .build();
             } else {
                 StaticIpConfiguration staticIpConfig = currentConfig.getStaticIpConfiguration();
-                prov = IpClient.buildProvisioningConfiguration()
+                prov = new ProvisioningConfiguration.Builder()
                             .withStaticConfiguration(staticIpConfig)
                             .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
                             .withNetwork(getCurrentNetwork())
@@ -5419,16 +5500,6 @@
                         break;
                     }
                     break;
-                case CMD_START_IP_PACKET_OFFLOAD: {
-                    int slot = message.arg1;
-                    int intervalSeconds = message.arg2;
-                    KeepalivePacketData pkt = (KeepalivePacketData) message.obj;
-                    int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds);
-                    if (mNetworkAgent != null) {
-                        mNetworkAgent.onPacketKeepaliveEvent(slot, result);
-                    }
-                    break;
-                }
                 default:
                     return NOT_HANDLED;
             }
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index cff9a91..3941357 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.wifi;
 
+import android.annotation.NonNull;
 import android.hardware.wifi.V1_0.IWifiApIface;
 import android.hardware.wifi.V1_0.IWifiChip;
 import android.hardware.wifi.V1_0.IWifiChipEventCallback;
@@ -81,8 +82,6 @@
 
 import com.google.errorprone.annotations.CompileTimeConstant;
 
-import libcore.util.NonNull;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index c089c9c..c6c0507 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -33,7 +33,10 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.NetworkUtils;
-import android.net.ip.IpClient;
+import android.net.ip.IIpClient;
+import android.net.ip.IpClientCallbacks;
+import android.net.ip.IpClientUtil;
+import android.net.shared.ProvisioningConfiguration;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WpsInfo;
 import android.net.wifi.p2p.IWifiP2pManager;
@@ -52,6 +55,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -113,7 +117,8 @@
     private Context mContext;
 
     INetworkManagementService mNwService;
-    private IpClient mIpClient;
+    private IIpClient mIpClient;
+    private int mIpClientStartIndex = 0;
     private DhcpResults mDhcpResults;
 
     private P2pStateMachine mP2pStateMachine;
@@ -443,49 +448,78 @@
     }
 
     private void stopIpClient() {
+        // Invalidate all previous start requests
+        mIpClientStartIndex++;
         if (mIpClient != null) {
-            mIpClient.stop();
+            try {
+                mIpClient.stop();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             mIpClient = null;
         }
         mDhcpResults = null;
     }
 
-    private void startIpClient(String ifname) {
+    private void startIpClient(String ifname, Handler smHandler) {
         stopIpClient();
+        mIpClientStartIndex++;
+        IpClientUtil.makeIpClient(mContext, ifname, new IpClientCallbacksImpl(
+                mIpClientStartIndex, smHandler));
+    }
 
-        mIpClient = new IpClient(mContext, ifname,
-                new IpClient.Callback() {
-                    @Override
-                    public void onPreDhcpAction() {
-                        mP2pStateMachine.sendMessage(IPC_PRE_DHCP_ACTION);
-                    }
-                    @Override
-                    public void onPostDhcpAction() {
-                        mP2pStateMachine.sendMessage(IPC_POST_DHCP_ACTION);
-                    }
-                    @Override
-                    public void onNewDhcpResults(DhcpResults dhcpResults) {
-                        mP2pStateMachine.sendMessage(IPC_DHCP_RESULTS, dhcpResults);
-                    }
-                    @Override
-                    public void onProvisioningSuccess(LinkProperties newLp) {
-                        mP2pStateMachine.sendMessage(IPC_PROVISIONING_SUCCESS);
-                    }
-                    @Override
-                    public void onProvisioningFailure(LinkProperties newLp) {
-                        mP2pStateMachine.sendMessage(IPC_PROVISIONING_FAILURE);
-                    }
-                },
-                mNwService);
+    private class IpClientCallbacksImpl extends IpClientCallbacks {
+        private final int mStartIndex;
+        private final Handler mHandler;
 
-        final IpClient.ProvisioningConfiguration config =
-                mIpClient.buildProvisioningConfiguration()
-                         .withoutIPv6()
-                         .withoutIpReachabilityMonitor()
-                         .withPreDhcpAction(30 * 1000)
-                         .withProvisioningTimeoutMs(36 * 1000)
-                         .build();
-        mIpClient.startProvisioning(config);
+        private IpClientCallbacksImpl(int startIndex, Handler handler) {
+            mStartIndex = startIndex;
+            mHandler = handler;
+        }
+
+        @Override
+        public void onIpClientCreated(IIpClient ipClient) {
+            mHandler.post(() -> {
+                if (mIpClientStartIndex != mStartIndex) {
+                    // This start request is obsolete
+                    return;
+                }
+
+                final ProvisioningConfiguration config =
+                        new ProvisioningConfiguration.Builder()
+                                .withoutIPv6()
+                                .withoutIpReachabilityMonitor()
+                                .withPreDhcpAction(30 * 1000)
+                                .withProvisioningTimeoutMs(36 * 1000)
+                                .build();
+                try {
+                    mIpClient.startProvisioning(config.toStableParcelable());
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
+            });
+        }
+
+        @Override
+        public void onPreDhcpAction() {
+            mP2pStateMachine.sendMessage(IPC_PRE_DHCP_ACTION);
+        }
+        @Override
+        public void onPostDhcpAction() {
+            mP2pStateMachine.sendMessage(IPC_POST_DHCP_ACTION);
+        }
+        @Override
+        public void onNewDhcpResults(DhcpResults dhcpResults) {
+            mP2pStateMachine.sendMessage(IPC_DHCP_RESULTS, dhcpResults);
+        }
+        @Override
+        public void onProvisioningSuccess(LinkProperties newLp) {
+            mP2pStateMachine.sendMessage(IPC_PROVISIONING_SUCCESS);
+        }
+        @Override
+        public void onProvisioningFailure(LinkProperties newLp) {
+            mP2pStateMachine.sendMessage(IPC_PROVISIONING_FAILURE);
+        }
     }
 
     /**
@@ -624,10 +658,10 @@
         pw.println("mDeathDataByBinder " + mDeathDataByBinder);
         pw.println();
 
-        final IpClient ipClient = mIpClient;
+        final IIpClient ipClient = mIpClient;
         if (ipClient != null) {
             pw.println("mIpClient:");
-            ipClient.dump(fd, pw, args);
+            IpClientUtil.dumpIpClient(ipClient, fd, pw, args);
         }
     }
 
@@ -1971,7 +2005,7 @@
                             startDhcpServer(mGroup.getInterface());
                         } else {
                             mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
-                            startIpClient(mGroup.getInterface());
+                            startIpClient(mGroup.getInterface(), getHandler());
                             WifiP2pDevice groupOwner = mGroup.getOwner();
                             WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
                             if (peer != null) {
@@ -2233,7 +2267,11 @@
                         break;
                     case IPC_PRE_DHCP_ACTION:
                         mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);
-                        mIpClient.completedPreDhcpAction();
+                        try {
+                            mIpClient.completedPreDhcpAction();
+                        } catch (RemoteException e) {
+                            e.rethrowFromSystemServer();
+                        }
                         break;
                     case IPC_POST_DHCP_ACTION:
                         mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
@@ -2253,7 +2291,7 @@
                                 mNwService.addInterfaceToLocalNetwork(
                                         ifname, mDhcpResults.getRoutes(ifname));
                             }
-                        } catch (RemoteException e) {
+                        } catch (Exception e) {
                             loge("Failed to add iface to local network " + e);
                         }
                         break;
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index 09a5ebf..262357a 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -21,17 +21,16 @@
 #include <sys/klog.h>
 
 #include <log/log.h>
-#include <nativehelper/JniConstants.h>
-#include <nativehelper/ScopedBytes.h>
-#include <nativehelper/ScopedUtfChars.h>
 #include <jni.h>
+#include <nativehelper/jni_macros.h>
+#include <nativehelper/JNIHelp.h>
 
 #include "jni_helper.h"
 
 namespace android {
 
 
-static jbyteArray android_net_wifi_readKernelLog(JNIEnv *env, jclass cls) {
+static jbyteArray android_net_wifi_readKernelLogNative(JNIEnv *env, jclass cls) {
     JNIHelper helper(env);
     ALOGV("Reading kernel logs");
 
@@ -78,16 +77,12 @@
  * JNI registration.
  */
 static JNINativeMethod gWifiMethods[] = {
-    /* name, signature, funcPtr */
-    {"readKernelLogNative", "()[B", (void*)android_net_wifi_readKernelLog},
+    NATIVE_METHOD(android_net_wifi, readKernelLogNative, "()[B"),
 };
 
 /* User to register native functions */
 extern "C"
 jint Java_com_android_server_wifi_WifiNative_registerNatives(JNIEnv* env, jclass clazz) {
-    // initialization needed for unit test APK
-    JniConstants::init(env);
-
     return jniRegisterNativeMethods(env,
             "com/android/server/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
 }
diff --git a/tests/wifitests/Android.mk b/tests/wifitests/Android.mk
index 75149c0..d2a5549 100644
--- a/tests/wifitests/Android.mk
+++ b/tests/wifitests/Android.mk
@@ -35,10 +35,6 @@
 # This only works if the class name matches the file name and the directory structure
 # matches the package.
 local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
-# Utility variables to allow replacing a space with a comma
-comma:= ,
-empty:=
-space:= $(empty) $(empty)
 # Convert class name list to jacoco exclude list
 # This appends a * to all classes and replace the space separators with commas.
 # These patterns will match all classes in this module and their inner classes.
@@ -66,10 +62,9 @@
 
 LOCAL_JAVA_LIBRARIES := \
 	android.test.runner \
-	android.hidl.manager-V1.0-java \
+	android.hidl.manager-V1.2-java \
 	android.test.base \
-	android.test.mock \
-	conscrypt
+	android.test.mock
 
 # These must be explicitly included because they are not normally accessible
 # from apps.
@@ -82,15 +77,19 @@
 	libbacktrace \
 	libbase \
 	libbinder \
+	libbinderthreadstate \
 	libc++ \
+	ld-android \
+	libdl_android \
 	libcamera_client \
 	libcamera_metadata \
+	libcgrouprc \
 	libcutils \
 	libexpat \
 	libgui \
 	libhardware \
-	libicui18n \
-	libicuuc \
+	libandroidicu \
+	libjsoncpp \
 	liblzma \
 	libmedia \
 	libnativehelper \
@@ -98,14 +97,13 @@
 	libnetutils \
 	libnl \
 	libpowermanager \
+	libprocessgroup \
 	libsonivox \
-	libspeexresampler \
 	libstagefright_foundation \
 	libstdc++ \
 	libsync \
 	libwifi-system \
 	libui \
-	libunwind \
 	libunwindstack \
 	libutils \
 	libvndksupport \
diff --git a/tests/wifitests/coverage.sh b/tests/wifitests/coverage.sh
index 6eec65b..33b9f30 100755
--- a/tests/wifitests/coverage.sh
+++ b/tests/wifitests/coverage.sh
@@ -28,16 +28,13 @@
 
 # build this module so we can run its tests, and
 # build system/core so we can invoke `adb`, and
-# build jacoco-report-classes.jar so we can generate the report
-make \
+# build jacoco-cli.jar so we can generate the report
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
   EMMA_INSTRUMENT=true \
   EMMA_INSTRUMENT_FRAMEWORK=false \
   EMMA_INSTRUMENT_STATIC=true \
   ANDROID_COMPILE_WITH_JACK=false \
   SKIP_BOOT_JARS_CHECK=true \
-  -j32 \
-  -C $ANDROID_BUILD_TOP \
-  -f build/core/main.mk \
   MODULES-IN-frameworks-opt-net-wifi-tests \
   MODULES-IN-system-core \
   MODULES-IN-external-jacoco \
diff --git a/tests/wifitests/runtests.sh b/tests/wifitests/runtests.sh
index 97ce239..d3b92ad 100755
--- a/tests/wifitests/runtests.sh
+++ b/tests/wifitests/runtests.sh
@@ -31,7 +31,7 @@
 echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/opt/net/wifi/tests"
 # NOTE Don't actually run the command above since this shell doesn't inherit functions from the
 #      caller.
-make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-opt-net-wifi-tests
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode MODULES-IN-frameworks-opt-net-wifi-tests
 
 set -x # print commands
 
diff --git a/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java b/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java
index d45edcd..0c12608 100644
--- a/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java
@@ -58,7 +58,7 @@
     private static final String TEST_CARRIER_NAME = "Test Carrier";
     private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
             new SubscriptionInfo(TEST_SUBSCRIPTION_ID, null, 0, TEST_CARRIER_NAME, null, 0, 0,
-                    null, 0, null, 0, 0, null);
+                    null, 0, null, "0", "0", null, false, null, null);
 
     @Mock Context mContext;
     @Mock CarrierConfigManager mCarrierConfigManager;
@@ -192,7 +192,8 @@
         int updatedInternalEapType = WifiEnterpriseConfig.Eap.AKA;
         String updatedCarrierName = "Updated Carrier";
         SubscriptionInfo updatedSubscriptionInfo = new SubscriptionInfo(TEST_SUBSCRIPTION_ID,
-                null, 0, updatedCarrierName, null, 0, 0, null, 0, null, 0, 0, null);
+                null, 0, updatedCarrierName, null, 0, 0, null, 0, null, "0", "0", null,
+                false, null, null);
         when(mSubscriptionManager.getActiveSubscriptionInfoList())
                 .thenReturn(Arrays.asList(new SubscriptionInfo[] {updatedSubscriptionInfo}));
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUBSCRIPTION_ID))
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index f18c52d..3d1d8d3 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -49,8 +49,8 @@
 import android.hardware.wifi.V1_0.IfaceType;
 import android.hardware.wifi.V1_0.WifiStatus;
 import android.hardware.wifi.V1_0.WifiStatusCode;
-import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
+import android.hidl.manager.V1_2.IServiceManager;
 import android.os.Handler;
 import android.os.IHwBinder;
 import android.os.test.TestLooper;
@@ -72,6 +72,7 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -130,9 +131,8 @@
                 anyLong())).thenReturn(true);
         when(mServiceManagerMock.registerForNotifications(anyString(), anyString(),
                 any(IServiceNotification.Stub.class))).thenReturn(true);
-        when(mServiceManagerMock.getTransport(
-                eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
-                .thenReturn(IServiceManager.Transport.HWBINDER);
+        when(mServiceManagerMock.listManifestByInterface(eq(IWifi.kInterfaceName)))
+                .thenReturn(new ArrayList(Arrays.asList("default")));
         when(mWifiMock.linkToDeath(any(IHwBinder.DeathRecipient.class), anyLong())).thenReturn(
                 true);
         when(mWifiMock.registerEventCallback(any(IWifiEventCallback.class))).thenReturn(mStatusOk);
@@ -509,9 +509,8 @@
      */
     @Test
     public void testIsSupportedFalse() throws Exception {
-        when(mServiceManagerMock.getTransport(
-                eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
-                .thenReturn(IServiceManager.Transport.EMPTY);
+        when(mServiceManagerMock.listManifestByInterface(eq(IWifi.kInterfaceName)))
+                .thenReturn(new ArrayList());
         mInOrder = inOrder(mServiceManagerMock, mWifiMock);
         executeAndValidateInitializationSequence(false);
         assertFalse(mDut.isSupported());
@@ -2216,9 +2215,9 @@
         mInOrder.verify(mServiceManagerMock).registerForNotifications(eq(IWifi.kInterfaceName),
                 eq(""), mServiceNotificationCaptor.capture());
 
-        // The service should already be up at this point.
-        mInOrder.verify(mServiceManagerMock).getTransport(eq(IWifi.kInterfaceName),
-                eq(HalDeviceManager.HAL_INSTANCE_NAME));
+        // If not using the lazy version of the IWifi service, the process should already be up at
+        // this point.
+        mInOrder.verify(mServiceManagerMock).listManifestByInterface(eq(IWifi.kInterfaceName));
 
         // verify: wifi initialization sequence if vendor HAL is supported.
         if (isSupported) {
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
index b4ea5af..b5ca09c 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.*;
 
+import android.annotation.NonNull;
 import android.app.test.MockAnswerUtil;
 import android.content.Context;
 import android.hardware.wifi.supplicant.V1_0.ISupplicant;
@@ -54,8 +55,6 @@
 import com.android.server.wifi.hotspot2.WnmData;
 import com.android.server.wifi.util.NativeUtil;
 
-import libcore.util.NonNull;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -1201,6 +1200,30 @@
                 eq(WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD), eq(-1));
     }
 
+    /**
+     * Tests the handling of incorrect network passwords, edge case.
+     *
+     * If the network is removed during 4-way handshake, do not call it a password mismatch.
+     */
+    @Test
+    public void testNetworkRemovedDuring4way() throws Exception {
+        executeAndValidateInitializationSequence();
+        assertNotNull(mISupplicantStaIfaceCallback);
+
+        int reasonCode = 3;
+
+        mISupplicantStaIfaceCallback.onStateChanged(
+                ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE,
+                NativeUtil.macAddressToByteArray(BSSID),
+                SUPPLICANT_NETWORK_ID,
+                NativeUtil.decodeSsid(SUPPLICANT_SSID));
+        mISupplicantStaIfaceCallback.onNetworkRemoved(SUPPLICANT_NETWORK_ID);
+        mISupplicantStaIfaceCallback.onDisconnected(
+                NativeUtil.macAddressToByteArray(BSSID), true, reasonCode);
+        verify(mWifiMonitor, times(0)).broadcastAuthenticationFailureEvent(any(), anyInt(),
+                anyInt());
+    }
+
      /**
       * Tests the handling of incorrect network passwords, edge case.
       *
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index a4bc61a..7606849 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -3563,6 +3563,133 @@
         assertEquals(newMac, retrievedConfig.getRandomizedMacAddress());
     }
 
+    /**
+     * Verifies that the method resetSimNetworks updates SIM presence status and SIM configs.
+     */
+    @Test
+    public void testResetSimNetworks() {
+        String expectedIdentity = "13214561234567890@wlan.mnc456.mcc321.3gppnetwork.org";
+        when(mTelephonyManager.getSubscriberId()).thenReturn("3214561234567890");
+        when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(mTelephonyManager.getSimOperator()).thenReturn("321456");
+        when(mTelephonyManager.getCarrierInfoForImsiEncryption(anyInt())).thenReturn(null);
+
+        WifiConfiguration network = WifiConfigurationTestUtil.createEapNetwork();
+        WifiConfiguration simNetwork = WifiConfigurationTestUtil.createEapNetwork(
+                WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
+        WifiConfiguration peapSimNetwork = WifiConfigurationTestUtil.createEapNetwork(
+                WifiEnterpriseConfig.Eap.PEAP, WifiEnterpriseConfig.Phase2.SIM);
+        network.enterpriseConfig.setIdentity("identity1");
+        network.enterpriseConfig.setAnonymousIdentity("anonymous_identity1");
+        simNetwork.enterpriseConfig.setIdentity("identity2");
+        simNetwork.enterpriseConfig.setAnonymousIdentity("anonymous_identity2");
+        peapSimNetwork.enterpriseConfig.setIdentity("identity3");
+        peapSimNetwork.enterpriseConfig.setAnonymousIdentity("anonymous_identity3");
+        verifyAddNetworkToWifiConfigManager(network);
+        verifyAddNetworkToWifiConfigManager(simNetwork);
+        verifyAddNetworkToWifiConfigManager(peapSimNetwork);
+
+        // Verify SIM is not present initially.
+        assertFalse(mWifiConfigManager.isSimPresent());
+
+        // Call resetSimNetworks with true(SIM is present).
+        mWifiConfigManager.resetSimNetworks(true);
+
+        // Verify SIM is present, SIM configs are reset and non-SIM configs are not changed.
+        assertTrue(mWifiConfigManager.isSimPresent());
+        WifiConfigurationTestUtil.assertConfigurationEqualForConfigManagerAddOrUpdate(
+                network,
+                mWifiConfigManager.getConfiguredNetworkWithPassword(network.networkId));
+        WifiConfiguration retrievedSimNetwork =
+                mWifiConfigManager.getConfiguredNetwork(simNetwork.networkId);
+        assertEquals(expectedIdentity, retrievedSimNetwork.enterpriseConfig.getIdentity());
+        assertTrue(retrievedSimNetwork.enterpriseConfig.getAnonymousIdentity().isEmpty());
+        WifiConfiguration retrievedPeapSimNetwork =
+                mWifiConfigManager.getConfiguredNetwork(peapSimNetwork.networkId);
+        assertEquals(expectedIdentity, retrievedPeapSimNetwork.enterpriseConfig.getIdentity());
+        assertFalse(retrievedPeapSimNetwork.enterpriseConfig.getAnonymousIdentity().isEmpty());
+
+        // Call resetSimNetworks with false(SIM is not present).
+        when(mTelephonyManager.getSubscriberId()).thenReturn("3214561234567891");
+        retrievedSimNetwork.enterpriseConfig.setAnonymousIdentity("anonymous_identity22");
+        verifyUpdateNetworkToWifiConfigManagerWithoutIpChange(retrievedSimNetwork);
+        mWifiConfigManager.resetSimNetworks(false);
+
+        // Verify SIM is not present and all configs are not changed.
+        assertFalse(mWifiConfigManager.isSimPresent());
+        WifiConfigurationTestUtil.assertConfigurationEqualForConfigManagerAddOrUpdate(
+                network,
+                mWifiConfigManager.getConfiguredNetworkWithPassword(network.networkId));
+        WifiConfigurationTestUtil.assertConfigurationEqualForConfigManagerAddOrUpdate(
+                retrievedSimNetwork,
+                mWifiConfigManager.getConfiguredNetworkWithPassword(simNetwork.networkId));
+        WifiConfigurationTestUtil.assertConfigurationEqualForConfigManagerAddOrUpdate(
+                retrievedPeapSimNetwork,
+                mWifiConfigManager.getConfiguredNetworkWithPassword(peapSimNetwork.networkId));
+    }
+
+    /**
+     * Verifies that the method resetSimNetworks updates SIM presence status if
+     * getSimIdentity returns null.
+     */
+    @Test
+    public void testResetSimNetworksWithNullIdentity() {
+        WifiConfiguration simNetwork = WifiConfigurationTestUtil.createEapNetwork(
+                WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
+        verifyAddNetworkToWifiConfigManager(simNetwork);
+
+        assertFalse(mWifiConfigManager.isSimPresent());
+
+        mWifiConfigManager.resetSimNetworks(true);
+        assertTrue(mWifiConfigManager.isSimPresent());
+
+        mWifiConfigManager.resetSimNetworks(false);
+        assertFalse(mWifiConfigManager.isSimPresent());
+    }
+
+    /**
+     * Verifies that SIM config is reset if store is read after the method resetSimNetworks
+     * is called.
+     */
+    @Test
+    public void testResetSimNetworksIsCalledAgainAfterLoadFromStore() {
+        String expectedIdentity = "13214561234567890@wlan.mnc456.mcc321.3gppnetwork.org";
+        when(mTelephonyManager.getSubscriberId()).thenReturn("3214561234567890");
+        when(mTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
+        when(mTelephonyManager.getSimOperator()).thenReturn("321456");
+        when(mTelephonyManager.getCarrierInfoForImsiEncryption(anyInt())).thenReturn(null);
+
+        WifiConfiguration simNetwork = WifiConfigurationTestUtil.createEapNetwork(
+                WifiEnterpriseConfig.Eap.SIM, WifiEnterpriseConfig.Phase2.NONE);
+        simNetwork.enterpriseConfig.setIdentity("identity");
+        simNetwork.enterpriseConfig.setAnonymousIdentity("anonymous_identity");
+
+        // Set up the store data.
+        List<WifiConfiguration> sharedNetworks = new ArrayList<WifiConfiguration>() {
+            {
+                add(simNetwork);
+            }
+        };
+        setupStoreDataForRead(sharedNetworks, new ArrayList<WifiConfiguration>(),
+                new HashSet<String>());
+
+        // 1. Call resetSimNetworks with true(SIM is present).
+        mWifiConfigManager.resetSimNetworks(true);
+
+        // Verify SIM is present.
+        assertTrue(mWifiConfigManager.isSimPresent());
+
+        // 2. Read from store now.
+        assertTrue(mWifiConfigManager.loadFromStore());
+
+        // Verify SIM is present just in case and SIM config is reset.
+        assertTrue(mWifiConfigManager.isSimPresent());
+        WifiConfiguration retrievedSimNetwork =
+                mWifiConfigManager.getConfiguredNetwork(simNetwork.networkId);
+        assertEquals(expectedIdentity, retrievedSimNetwork.enterpriseConfig.getIdentity());
+        assertTrue(retrievedSimNetwork.enterpriseConfig.getAnonymousIdentity().isEmpty());
+    }
+
     private NetworkUpdateResult verifyAddOrUpdateNetworkWithProxySettingsAndPermissions(
             boolean withNetworkSettings,
             boolean withProfileOwnerPolicy,
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index 7bb2437..3774fec 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -614,6 +614,21 @@
     }
 
     /**
+     * Verify that WifiConfigurationUtil.isSameNetwork returns true when two WifiConfiguration
+     * objects have the different EAP anonymous(pseudonym) identity in EAP-SIM.
+     */
+    @Test
+    public void testIsSameNetworkReturnsTrueOnDifferentEapAnonymousIdentityInEapSim() {
+        WifiConfiguration network1 = WifiConfigurationTestUtil.createEapNetwork(TEST_SSID);
+        WifiConfiguration network2 = WifiConfigurationTestUtil.createEapNetwork(TEST_SSID);
+        network1.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        network2.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        network1.enterpriseConfig.setAnonymousIdentity("Identity1");
+        network2.enterpriseConfig.setAnonymousIdentity("Identity2");
+        assertTrue(WifiConfigurationUtil.isSameNetwork(network1, network2));
+    }
+
+    /**
      * Verify the instance of {@link android.net.wifi.WifiScanner.PnoSettings.PnoNetwork} created
      * for a EAP network using {@link WifiConfigurationUtil#createPnoNetwork(WifiConfiguration)
      * }.
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
index 013aa4e..35d4bf4 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
@@ -43,8 +43,11 @@
 @SmallTest
 public class WifiLockManagerTest {
 
-    private static final int DEFAULT_TEST_UID_1 = 35;
+    private static final int DEFAULT_TEST_UID_1 = 52;
     private static final int DEFAULT_TEST_UID_2 = 53;
+    private static final int DEFAULT_TEST_UID_3 = 54;
+    private static final int DEFAULT_TEST_UID_4 = 55;
+
     private static final int WIFI_LOCK_MODE_INVALID = -1;
     private static final String TEST_WIFI_LOCK_TAG = "TestTag";
 
@@ -55,6 +58,7 @@
     WorkSource mWorkSource;
     WorkSource mChainedWorkSource;
     @Mock Context mContext;
+    @Mock WifiStateMachine mWsm;
 
     /**
      * Method to setup a WifiLockManager for the tests.
@@ -69,7 +73,7 @@
                 .addNode(DEFAULT_TEST_UID_2, "tag2");
 
         MockitoAnnotations.initMocks(this);
-        mWifiLockManager = new WifiLockManager(mContext, mBatteryStats);
+        mWifiLockManager = new WifiLockManager(mContext, mBatteryStats, mWsm);
     }
 
     private void acquireWifiLockSuccessful(int lockMode, String tag, IBinder binder, WorkSource ws)
@@ -315,6 +319,296 @@
     }
 
     /**
+     * Test when acquiring a hi-perf lock,
+     * WifiLockManager calls to disable power save mechanism.
+     */
+    @Test
+    public void testHiPerfLockAcquireCauseDisablePS() throws Exception {
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        verify(mWsm).setPowerSave(eq(false));
+    }
+
+    /**
+     * Test when releasing a hi-perf lock,
+     * WifiLockManager calls to enable power save mechanism.
+     */
+    @Test
+    public void testHiPerfLockReleaseCauseEnablePS() throws Exception {
+        InOrder inOrder = inOrder(mWsm);
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+
+        releaseWifiLockSuccessful(mBinder);
+        assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+    }
+
+    /**
+     * Test when acquiring two hi-perf locks, then releasing them.
+     * WifiLockManager calls to disable/enable power save mechanism only once.
+     */
+    @Test
+    public void testHiPerfLockAcquireReleaseTwice() throws Exception {
+        InOrder inOrder = inOrder(mWsm);
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+        // Acquire the first lock
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+
+        // Now acquire another lock
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder2, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        // Release the first lock
+        releaseWifiLockSuccessful(mBinder);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        // Release the second lock
+        releaseWifiLockSuccessful(mBinder2);
+        assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+    }
+
+    /**
+     * Test when acquiring/releasing multiple locks of different types.
+     * This is a combination of test cases described above.
+     */
+    @Test
+    public void testHiPerfLockAcquireReleaseMultiple() throws Exception {
+        IBinder fullLockBinder = mock(IBinder.class);
+        WorkSource fullLockWS = new WorkSource(DEFAULT_TEST_UID_1);
+        IBinder fullLockBinder2 = mock(IBinder.class);
+        WorkSource fullLockWS2 = new WorkSource(DEFAULT_TEST_UID_2);
+        IBinder scanOnlyLockBinder = mock(IBinder.class);
+        WorkSource scanOnlyLockWS = new WorkSource(DEFAULT_TEST_UID_3);
+        IBinder hiPerfLockBinder = mock(IBinder.class);
+        WorkSource hiPerfLockWS = new WorkSource(DEFAULT_TEST_UID_4);
+
+        InOrder inOrder = inOrder(mWsm);
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+
+        // Acquire the first lock as FULL
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "",
+                fullLockBinder, fullLockWS);
+        assertEquals(WifiManager.WIFI_MODE_FULL,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        // Now acquire another lock with SCAN-ONLY
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_SCAN_ONLY, "",
+                scanOnlyLockBinder, scanOnlyLockWS);
+        assertEquals(WifiManager.WIFI_MODE_FULL,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        // Now acquire another lock with HIGH-PERF
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                hiPerfLockBinder, hiPerfLockWS);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+
+       // Release the FULL lock
+        releaseWifiLockSuccessful(fullLockBinder);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        // Release the HIGH-PERF lock
+        releaseWifiLockSuccessful(hiPerfLockBinder);
+        assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+
+        // Acquire the FULL lock again
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "",
+                fullLockBinder2, fullLockWS2);
+        assertEquals(WifiManager.WIFI_MODE_FULL,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+        // Release the FULL lock
+        releaseWifiLockSuccessful(fullLockBinder2);
+        assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        // Release the SCAN-ONLY lock
+        releaseWifiLockSuccessful(scanOnlyLockBinder);
+        assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+    }
+
+    /**
+     * Test failure case when setPowerSave() fails, during acquisition of hi-perf lock
+     * Note, the lock is still acquired despite the failure in setPowerSave().
+     * On any new lock activity, the setPowerSave() will be attempted if still needed.
+     */
+    @Test
+    public void testHiPerfLockAcquireFail() throws Exception {
+        IBinder fullLockBinder = mock(IBinder.class);
+        WorkSource fullLockWS = new WorkSource(DEFAULT_TEST_UID_1);
+
+        InOrder inOrder = inOrder(mWsm);
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(false);
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+
+        // Now attempting adding some other lock, WifiLockManager should retry setPowerSave()
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "",
+                fullLockBinder, fullLockWS);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+    }
+
+    /**
+     * Test failure case when setPowerSave() fails, during release of hi-perf lock
+     * Note, the lock is still released despite the failure in setPowerSave().
+     * On any new lock activity, the setPowerSave() will be re-attempted if still needed.
+     */
+    @Test
+    public void testHiPerfLockReleaseFail() throws Exception {
+        IBinder fullLockBinder = mock(IBinder.class);
+        WorkSource fullLockWS = new WorkSource(DEFAULT_TEST_UID_1);
+
+        InOrder inOrder = inOrder(mWsm);
+        when(mWsm.setPowerSave(false)).thenReturn(true);
+        when(mWsm.setPowerSave(true)).thenReturn(false);
+
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+        releaseWifiLockSuccessful(mBinder);
+        assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+
+        // Now attempting adding some other lock, WifiLockManager should retry setPowerSave()
+        when(mWsm.setPowerSave(true)).thenReturn(true);
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL, "",
+                fullLockBinder, fullLockWS);
+        assertEquals(WifiManager.WIFI_MODE_FULL,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+    }
+
+    /**
+     * Test when forcing hi-perf mode, that it overrides apps requests
+     * until it is no longer forced.
+     */
+    @Test
+    public void testForceHiPerf() throws Exception {
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+        InOrder inOrder = inOrder(mWsm);
+
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_SCAN_ONLY, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY,
+                mWifiLockManager.getStrongestLockMode());
+        assertTrue(mWifiLockManager.forceHiPerfMode(true));
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+        assertTrue(mWifiLockManager.forceHiPerfMode(false));
+        assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+    }
+
+    /**
+     * Test when forcing hi-perf mode, and aquire/release of hi-perf locks
+     */
+    @Test
+    public void testForceHiPerfAcqRelHiPerf() throws Exception {
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+        InOrder inOrder = inOrder(mWsm);
+
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+
+        assertTrue(mWifiLockManager.forceHiPerfMode(true));
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        releaseWifiLockSuccessful(mBinder);
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+
+        assertTrue(mWifiLockManager.forceHiPerfMode(false));
+        assertEquals(WifiManager.WIFI_MODE_NO_LOCKS_HELD,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(true));
+    }
+
+    /**
+     * Test when trying to force hi-perf to true twice back to back
+     */
+    @Test
+    public void testForceHiPerfTwice() throws Exception {
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(true);
+        InOrder inOrder = inOrder(mWsm);
+
+        assertTrue(mWifiLockManager.forceHiPerfMode(true));
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+
+        assertTrue(mWifiLockManager.forceHiPerfMode(true));
+        assertEquals(WifiManager.WIFI_MODE_FULL_HIGH_PERF,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm, never()).setPowerSave(anyBoolean());
+    }
+
+    /**
+     * Test when failure when forcing hi-perf mode
+     */
+    @Test
+    public void testForceHiPerfFailure() throws Exception {
+        when(mWsm.setPowerSave(anyBoolean())).thenReturn(false);
+        InOrder inOrder = inOrder(mWsm);
+
+        acquireWifiLockSuccessful(WifiManager.WIFI_MODE_SCAN_ONLY, "",
+                mBinder, mWorkSource);
+        assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY,
+                mWifiLockManager.getStrongestLockMode());
+
+        assertFalse(mWifiLockManager.forceHiPerfMode(true));
+        assertEquals(WifiManager.WIFI_MODE_SCAN_ONLY,
+                mWifiLockManager.getStrongestLockMode());
+        inOrder.verify(mWsm).setPowerSave(eq(false));
+    }
+
+    /**
      * Verfies that dump() does not fail when no locks are held.
      */
     @Test
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 8154a02..cbba323 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -19,6 +19,8 @@
 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY;
 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
 
+import static com.android.server.wifi.WifiStateMachine.CMD_PRE_DHCP_ACTION;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -46,8 +48,8 @@
 import android.net.NetworkInfo;
 import android.net.NetworkMisc;
 import android.net.NetworkRequest;
-import android.net.dhcp.DhcpClient;
-import android.net.ip.IpClient;
+import android.net.ip.IIpClient;
+import android.net.ip.IpClientCallbacks;
 import android.net.wifi.ScanResult;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
@@ -204,14 +206,13 @@
         IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class);
         when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder);
 
-        when(facade.makeIpClient(any(Context.class), anyString(), any(IpClient.Callback.class)))
-                .then(new AnswerWithArguments() {
-                    public IpClient answer(
-                            Context context, String ifname, IpClient.Callback callback) {
-                        mIpClientCallback = callback;
-                        return mIpClient;
-                    }
-                });
+        doAnswer(new AnswerWithArguments() {
+            public void answer(
+                    Context context, String ifname, IpClientCallbacks callback) {
+                mIpClientCallback = callback;
+                callback.onIpClientCreated(mIpClient);
+            }
+        }).when(facade).makeIpClient(any(), anyString(), any());
 
         return facade;
     }
@@ -334,7 +335,7 @@
     Context mContext;
     MockResources mResources;
     FrameworkFacade mFrameworkFacade;
-    IpClient.Callback mIpClientCallback;
+    IpClientCallbacks mIpClientCallback;
     PhoneStateListener mPhoneStateListener;
     NetworkRequest mDefaultNetworkRequest;
     OsuProvider mOsuProvider;
@@ -359,7 +360,7 @@
     @Mock PasspointManager mPasspointManager;
     @Mock SelfRecovery mSelfRecovery;
     @Mock WifiPermissionsUtil mWifiPermissionsUtil;
-    @Mock IpClient mIpClient;
+    @Mock IIpClient mIpClient;
     @Mock TelephonyManager mTelephonyManager;
     @Mock WrongPasswordNotifier mWrongPasswordNotifier;
     @Mock Clock mClock;
@@ -456,6 +457,10 @@
         when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
         when(mWifiPermissionsWrapper.getLocalMacAddressPermission(anyInt()))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
+        doAnswer(inv -> {
+            mIpClientCallback.onQuit();
+            return null;
+        }).when(mIpClient).shutdown();
         initializeWsm();
 
         mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
@@ -535,7 +540,8 @@
      */
     private void sendDefaultNetworkRequest(int score) {
         mNetworkFactoryChannel.sendMessage(
-                NetworkFactory.CMD_REQUEST_NETWORK, score, 0, mDefaultNetworkRequest);
+                NetworkFactory.CMD_REQUEST_NETWORK, score, NetworkFactory.SerialNumber.NONE,
+                mDefaultNetworkRequest);
         mLooper.dispatchAll();
     }
 
@@ -1022,7 +1028,7 @@
         config.networkId = FRAMEWORK_NETWORK_ID + 1;
         setupAndStartConnectSequence(config);
         validateSuccessfulConnectSequence(config);
-        verify(mWifiPermissionsUtil, times(4)).checkNetworkSettingsPermission(anyInt());
+        verify(mWifiPermissionsUtil, atLeastOnce()).checkNetworkSettingsPermission(anyInt());
     }
 
     /**
@@ -1304,8 +1310,7 @@
     public void smToString() throws Exception {
         assertEquals("CMD_CHANNEL_HALF_CONNECTED", mWsm.smToString(
                 AsyncChannel.CMD_CHANNEL_HALF_CONNECTED));
-        assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString(
-                DhcpClient.CMD_PRE_DHCP_ACTION));
+        assertEquals("CMD_PRE_DHCP_ACTION", mWsm.smToString(CMD_PRE_DHCP_ACTION));
         assertEquals("CMD_IP_REACHABILITY_LOST", mWsm.smToString(
                 WifiStateMachine.CMD_IP_REACHABILITY_LOST));
     }
@@ -2129,7 +2134,7 @@
         ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
         verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(),
                 any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class),
-                anyInt(), any(NetworkMisc.class));
+                anyInt(), any(NetworkMisc.class), anyInt());
 
         ArrayList<Integer> thresholdsArray = new ArrayList();
         thresholdsArray.add(RSSI_THRESHOLD_MAX);
@@ -2407,7 +2412,6 @@
         mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE, null);
         mLooper.dispatchAll();
         verify(mIpClient).shutdown();
-        verify(mIpClient).awaitShutdown();
     }
 
     /**
@@ -2459,7 +2463,7 @@
         ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
         verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(),
                 any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class),
-                anyInt(), any(NetworkMisc.class));
+                anyInt(), any(NetworkMisc.class), anyInt());
 
         WifiConfiguration currentNetwork = new WifiConfiguration();
         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
@@ -2493,7 +2497,7 @@
         ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
         verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(),
                 any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class),
-                anyInt(), any(NetworkMisc.class));
+                anyInt(), any(NetworkMisc.class), anyInt());
 
         WifiConfiguration currentNetwork = new WifiConfiguration();
         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
@@ -2528,7 +2532,7 @@
         ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
         verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(),
                 any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class),
-                anyInt(), any(NetworkMisc.class));
+                anyInt(), any(NetworkMisc.class), anyInt());
 
         WifiConfiguration currentNetwork = new WifiConfiguration();
         currentNetwork.networkId = FRAMEWORK_NETWORK_ID;
@@ -2561,7 +2565,7 @@
         ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
         verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(),
                 any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class),
-                anyInt(), any(NetworkMisc.class));
+                anyInt(), any(NetworkMisc.class), anyInt());
 
         when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(FRAMEWORK_NETWORK_ID + 1);
 
@@ -2577,4 +2581,38 @@
         verify(mWifiConfigManager).updateNetworkSelectionStatus(
                 FRAMEWORK_NETWORK_ID, NETWORK_SELECTION_ENABLE);
     }
+
+    /**
+     * Verify that when ordered to setPowerSave(true) while Interface is created,
+     * WifiNative is called with the right powerSave mode.
+     */
+    @Test
+    public void verifySetPowerSaveTrueSuccess() throws Exception {
+        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE, WIFI_IFACE_NAME);
+        assertTrue(mWsm.setPowerSave(true));
+        verify(mWifiNative).setPowerSave(WIFI_IFACE_NAME, true);
+    }
+
+    /**
+     * Verify that when ordered to setPowerSave(false) while Interface is created,
+     * WifiNative is called with the right powerSave mode.
+     */
+    @Test
+    public void verifySetPowerSaveFalseSuccess() throws Exception {
+        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE, WIFI_IFACE_NAME);
+        assertTrue(mWsm.setPowerSave(false));
+        verify(mWifiNative).setPowerSave(WIFI_IFACE_NAME, false);
+    }
+
+    /**
+     * Verify that when interface is not created yet (InterfaceName is null),
+     * then setPowerSave() returns with error and no call in WifiNative happens.
+     */
+    @Test
+    public void verifySetPowerSaveFailure() throws Exception {
+        boolean powerSave = true;
+        mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE, null);
+        assertFalse(mWsm.setPowerSave(powerSave));
+        verify(mWifiNative, never()).setPowerSave(anyString(), anyBoolean());
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index ebeecbd..1de6ad0 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
@@ -81,6 +81,7 @@
 import android.hardware.wifi.V1_2.IWifiChipEventCallback.RadioModeInfo;
 import android.net.KeepalivePacketData;
 import android.net.MacAddress;
+import android.net.NattKeepalivePacketData;
 import android.net.apf.ApfCapabilities;
 import android.net.wifi.RttManager;
 import android.net.wifi.ScanResult;
@@ -1112,7 +1113,8 @@
         int slot = 13;
         int millis = 16000;
 
-        KeepalivePacketData kap = KeepalivePacketData.nattKeepalivePacket(src, 63000, dst, 4500);
+        KeepalivePacketData kap =
+                NattKeepalivePacketData.nattKeepalivePacket(src, 63000, dst, 4500);
 
         when(mIWifiStaIface.startSendingKeepAlivePackets(
                 anyInt(), any(), anyShort(), any(), any(), anyInt()
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 1b17219..508ee2f 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
@@ -429,7 +429,7 @@
                 first = false;
             }
             inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
-                    any(), anyInt(), any());
+                    any(), anyInt(), any(), anyInt());
             agentMessengers[i] = messengerCaptor.getValue();
             inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
                     eq(false), anyLong());
@@ -538,7 +538,7 @@
         inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
         inOrder.verify(mMockNwMgt).enableIpv6(anyString());
         inOrder.verify(mMockCm).registerNetworkAgent(agentMessengerCaptor.capture(), any(), any(),
-                any(), anyInt(), any());
+                any(), anyInt(), any(), anyInt());
         inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
                 eq(true), anyLong());
         inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
@@ -647,7 +647,7 @@
                 inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
                 inOrder.verify(mMockNwMgt).enableIpv6(anyString());
                 inOrder.verify(mMockCm).registerNetworkAgent(any(), any(), any(), any(), anyInt(),
-                        any());
+                        any(), anyInt());
                 inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
                         eq(true), anyLong());
                 inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
@@ -1072,7 +1072,7 @@
             inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
             inOrder.verify(mMockNwMgt).enableIpv6(anyString());
             inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(), any(),
-                    any(), anyInt(), any());
+                    any(), anyInt(), any(), anyInt());
             inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
                     eq(useDirect), anyLong());
             inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());
@@ -1178,7 +1178,7 @@
                 inOrder.verify(mMockNwMgt).setInterfaceUp(anyString());
                 inOrder.verify(mMockNwMgt).enableIpv6(anyString());
                 inOrder.verify(mMockCm).registerNetworkAgent(messengerCaptor.capture(), any(),
-                        any(), any(), anyInt(), any());
+                        any(), any(), anyInt(), any(), anyInt());
                 inOrderM.verify(mAwareMetricsMock).recordNdpStatus(eq(NanStatusType.SUCCESS),
                         eq(useDirect), anyLong());
                 inOrderM.verify(mAwareMetricsMock).recordNdpCreation(anyInt(), any());