Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)

Bug: 166295507
Merged-In: I3d92a6de21a938f6b352ec26dc23420c0fe02b27
Change-Id: Ifdb80563ef042738778ebb8a7581a97c4e3d96e2
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 40f394a..257538d 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -32,6 +32,7 @@
         "android.hardware.tetheroffload.config-V1.0-java",
         "android.hardware.tetheroffload.control-V1.0-java",
         "net-utils-framework-common",
+        "net-utils-device-common",
     ],
     libs: [
         "framework-statsd.stubs.module_lib",
diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml
index 2b2fe45..e6444f3 100644
--- a/Tethering/AndroidManifest.xml
+++ b/Tethering/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <!-- Permissions must be defined here, and not in the base manifest, as the tethering
          running in the system server process does not need any permission, and having
          privileged permissions added would cause crashes on startup unless they are also
-         added to the privileged permissions whitelist for that package. -->
+         added to the privileged permissions allowlist for that package. -->
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
diff --git a/Tethering/AndroidManifestBase.xml b/Tethering/AndroidManifestBase.xml
index fa85f66..97c3988 100644
--- a/Tethering/AndroidManifestBase.xml
+++ b/Tethering/AndroidManifestBase.xml
@@ -23,6 +23,7 @@
     <application
         android:label="Tethering"
         android:defaultToDeviceProtectedStorage="true"
-        android:directBootAware="true">
+        android:directBootAware="true"
+        android:usesCleartextTraffic="true">
     </application>
 </manifest>
diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags
index 051fbd1..86b9033 100644
--- a/Tethering/proguard.flags
+++ b/Tethering/proguard.flags
@@ -1,5 +1,5 @@
 # Keep class's integer static field for MessageUtils to parsing their name.
--keep class com.android.networkstack.tethering.Tethering$TetherMasterSM {
+-keep class com.android.networkstack.tethering.Tethering$TetherMainSM {
     static final int CMD_*;
     static final int EVENT_*;
 }
diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml
index 9b9dcde..5f8d299 100644
--- a/Tethering/res/values/config.xml
+++ b/Tethering/res/values/config.xml
@@ -73,6 +73,9 @@
     <!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
     <bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
 
+    <!-- Use legacy wifi p2p dedicated address instead of randomize address. -->
+    <bool translatable="false" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip">false</bool>
+
     <!-- Dhcp range (min, max) to use for tethering purposes -->
     <string-array translatable="false" name="config_tether_dhcp_range">
     </string-array>
diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml
index 6a33d55..0ee7a99 100644
--- a/Tethering/res/values/overlayable.xml
+++ b/Tethering/res/values/overlayable.xml
@@ -30,6 +30,7 @@
             -->
             <item type="bool" name="config_tether_enable_bpf_offload"/>
             <item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+            <item type="bool" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip"/>
             <item type="integer" name="config_tether_offload_poll_interval"/>
             <item type="array" name="config_tether_upstream_types"/>
             <item type="bool" name="config_tether_upstream_automatic"/>
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 8af1797..673cbf0 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -197,15 +197,19 @@
     public static final int CMD_TETHER_UNREQUESTED          = BASE_IPSERVER + 2;
     // notification that this interface is down
     public static final int CMD_INTERFACE_DOWN              = BASE_IPSERVER + 3;
-    // notification from the master SM that it had trouble enabling IP Forwarding
+    // notification from the {@link Tethering.TetherMainSM} that it had trouble enabling IP
+    // Forwarding
     public static final int CMD_IP_FORWARDING_ENABLE_ERROR  = BASE_IPSERVER + 4;
-    // notification from the master SM that it had trouble disabling IP Forwarding
+    // notification from the {@link Tethering.TetherMainSM} SM that it had trouble disabling IP
+    // Forwarding
     public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5;
-    // notification from the master SM that it had trouble starting tethering
+    // notification from the {@link Tethering.TetherMainSM} SM that it had trouble starting
+    // tethering
     public static final int CMD_START_TETHERING_ERROR       = BASE_IPSERVER + 6;
-    // notification from the master SM that it had trouble stopping tethering
+    // notification from the {@link Tethering.TetherMainSM} that it had trouble stopping tethering
     public static final int CMD_STOP_TETHERING_ERROR        = BASE_IPSERVER + 7;
-    // notification from the master SM that it had trouble setting the DNS forwarders
+    // notification from the {@link Tethering.TetherMainSM} that it had trouble setting the DNS
+    // forwarders
     public static final int CMD_SET_DNS_FORWARDERS_ERROR    = BASE_IPSERVER + 8;
     // the upstream connection has changed
     public static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IPSERVER + 9;
@@ -423,9 +427,13 @@
             getHandler().post(() -> {
                 // We are on the handler thread: mDhcpServerStartIndex can be read safely.
                 if (mStartIndex != mDhcpServerStartIndex) {
-                    // This start request is obsolete. When the |server| binder token goes out of
-                    // scope, the garbage collector will finalize it, which causes the network stack
-                    // process garbage collector to collect the server itself.
+                     // This start request is obsolete. Explicitly stop the DHCP server to shut
+                     // down its thread. When the |server| binder token goes out of scope, the
+                     // garbage collector will finalize it, which causes the network stack process
+                     // garbage collector to collect the server itself.
+                    try {
+                        server.stop(null);
+                    } catch (RemoteException e) { }
                     return;
                 }
 
@@ -1316,7 +1324,7 @@
 
     /**
      * This state is terminal for the per interface state machine.  At this
-     * point, the master state machine should have removed this interface
+     * point, the tethering main state machine should have removed this interface
      * specific state machine from its list of possible recipients of
      * tethering requests.  The state machine itself will hang around until
      * the garbage collector finds it.
diff --git a/Tethering/src/android/net/util/TetheringMessageBase.java b/Tethering/src/android/net/util/TetheringMessageBase.java
index 1b763ce..29c0a81 100644
--- a/Tethering/src/android/net/util/TetheringMessageBase.java
+++ b/Tethering/src/android/net/util/TetheringMessageBase.java
@@ -19,7 +19,7 @@
  * This class defines Message.what base addresses for various state machine.
  */
 public class TetheringMessageBase {
-    public static final int BASE_MASTER   = 0;
+    public static final int BASE_MAIN_SM   = 0;
     public static final int BASE_IPSERVER = 100;
 
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 9dace70..bb7322f 100644
--- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -296,16 +296,16 @@
      * Reference TetheringManager.TETHERING_{@code *} for each tether type.
      *
      * @param config an object that encapsulates the various tethering configuration elements.
-     * Note: this method is only called from TetherMaster on the handler thread.
+     * Note: this method is only called from @{link Tethering.TetherMainSM} on the handler thread.
      * If there are new callers from different threads, the logic should move to
-     * masterHandler to avoid race conditions.
+     * @{link Tethering.TetherMainSM} handler to avoid race conditions.
      */
     public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
         if (DBG) mLog.i("reevaluateSimCardProvisioning");
 
         if (!mHandler.getLooper().isCurrentThread()) {
             // Except for test, this log should not appear in normal flow.
-            mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
+            mLog.log("reevaluateSimCardProvisioning() don't run in TetherMainSM thread");
         }
         mEntitlementCacheValue.clear();
         mCurrentEntitlementResults.clear();
diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index aa58a4b..fd9e360 100644
--- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,8 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
 import static java.util.Arrays.asList;
 
 import android.content.Context;
@@ -58,6 +60,7 @@
     private static final int BYTE_MASK = 0xff;
     // reserved for bluetooth tethering.
     private static final int BLUETOOTH_RESERVED = 44;
+    private static final int WIFI_P2P_RESERVED = 49;
     private static final byte DEFAULT_ID = (byte) 42;
 
     // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -71,15 +74,18 @@
     // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
     // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
     private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
+    private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
     private final IpPrefix mTetheringPrefix;
     private final ConnectivityManager mConnectivityMgr;
+    private final TetheringConfiguration mConfig;
 
-    public PrivateAddressCoordinator(Context context) {
+    public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
         mDownstreams = new ArraySet<>();
         mUpstreamPrefixMap = new ArrayMap<>();
         mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX);
         mConnectivityMgr = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
+        mConfig = config;
     }
 
     /**
@@ -141,12 +147,21 @@
         mUpstreamPrefixMap.removeAll(toBeRemoved);
     }
 
+    private boolean isReservedSubnet(final int subnet) {
+        return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
+    }
+
     /**
      * Pick a random available address and mark its prefix as in use for the provided IpServer,
      * returns null if there is no available address.
      */
     @Nullable
     public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+        if (mConfig.shouldEnableWifiP2pDedicatedIp()
+                && ipServer.interfaceType() == TETHERING_WIFI_P2P) {
+            return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
+        }
+
         // Address would be 192.168.[subAddress]/24.
         final byte[] bytes = mTetheringPrefix.getRawAddress();
         final int subAddress = getRandomSubAddr();
@@ -154,7 +169,7 @@
         bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
         for (int i = 0; i < MAX_UBYTE; i++) {
             final int newSubNet = (subNet + i) & BYTE_MASK;
-            if (newSubNet == BLUETOOTH_RESERVED) continue;
+            if (isReservedSubnet(newSubNet)) continue;
 
             bytes[2] = (byte) newSubNet;
             final InetAddress addr;
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 7508a65..7dd5290 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -50,7 +50,7 @@
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
-import static android.net.util.TetheringMessageBase.BASE_MASTER;
+import static android.net.util.TetheringMessageBase.BASE_MAIN_SM;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -159,7 +159,7 @@
     private static final boolean VDBG = false;
 
     private static final Class[] sMessageClasses = {
-            Tethering.class, TetherMasterSM.class, IpServer.class
+            Tethering.class, TetherMainSM.class, IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(sMessageClasses);
@@ -216,7 +216,7 @@
     private final ArrayMap<String, TetherState> mTetherStates;
     private final BroadcastReceiver mStateReceiver;
     private final Looper mLooper;
-    private final StateMachine mTetherMasterSM;
+    private final StateMachine mTetherMainSM;
     private final OffloadController mOffloadController;
     private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     // TODO: Figure out how to merge this and other downstream-tracking objects
@@ -273,10 +273,10 @@
         mTetherStates = new ArrayMap<>();
         mConnectedClientsTracker = new ConnectedClientsTracker();
 
-        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
-        mTetherMasterSM.start();
+        mTetherMainSM = new TetherMainSM("TetherMain", mLooper, deps);
+        mTetherMainSM.start();
 
-        mHandler = mTetherMasterSM.getHandler();
+        mHandler = mTetherMainSM.getHandler();
         mOffloadController = mDeps.getOffloadController(mHandler, mLog,
                 new OffloadController.Dependencies() {
 
@@ -285,8 +285,8 @@
                         return mConfig;
                     }
                 });
-        mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
-                TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+        mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMainSM, mLog,
+                TetherMainSM.EVENT_UPSTREAM_CALLBACK);
         mForwardedDownstreams = new LinkedHashSet<>();
 
         IntentFilter filter = new IntentFilter();
@@ -294,8 +294,8 @@
         // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
         // permission is changed according to entitlement check result.
         mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
-                () -> mTetherMasterSM.sendMessage(
-                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
+                () -> mTetherMainSM.sendMessage(
+                TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
         mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
             mLog.log("OBSERVED UiEnitlementFailed");
             stopTethering(downstream);
@@ -320,10 +320,13 @@
         mExecutor = new TetheringThreadExecutor(mHandler);
         mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
         mNetdCallback = new NetdCallback();
-        mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext);
 
         // Load tethering configuration.
         updateConfiguration();
+        // It is OK for the configuration to be passed to the PrivateAddressCoordinator at
+        // construction time because the only part of the configuration it uses is
+        // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
+        mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig);
 
         // Must be initialized after tethering configuration is loaded because BpfCoordinator
         // constructor needs to use the configuration.
@@ -945,7 +948,7 @@
             }
 
             if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
-            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+            mTetherMainSM.sendMessage(TetherMainSM.CMD_UPSTREAM_CHANGED);
         }
 
         private void handleUsbAction(Intent intent) {
@@ -1170,7 +1173,7 @@
     private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
         if (TextUtils.isEmpty(ifname)) return;
 
-        disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
+        disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* fake */ 0);
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
@@ -1381,23 +1384,23 @@
         return false;
     }
 
-    class TetherMasterSM extends StateMachine {
+    class TetherMainSM extends StateMachine {
         // an interface SM has requested Tethering/Local Hotspot
-        static final int EVENT_IFACE_SERVING_STATE_ACTIVE       = BASE_MASTER + 1;
+        static final int EVENT_IFACE_SERVING_STATE_ACTIVE       = BASE_MAIN_SM + 1;
         // an interface SM has unrequested Tethering/Local Hotspot
-        static final int EVENT_IFACE_SERVING_STATE_INACTIVE     = BASE_MASTER + 2;
+        static final int EVENT_IFACE_SERVING_STATE_INACTIVE     = BASE_MAIN_SM + 2;
         // upstream connection change - do the right thing
-        static final int CMD_UPSTREAM_CHANGED                   = BASE_MASTER + 3;
+        static final int CMD_UPSTREAM_CHANGED                   = BASE_MAIN_SM + 3;
         // we don't have a valid upstream conn, check again after a delay
-        static final int CMD_RETRY_UPSTREAM                     = BASE_MASTER + 4;
-        // Events from NetworkCallbacks that we process on the master state
+        static final int CMD_RETRY_UPSTREAM                     = BASE_MAIN_SM + 4;
+        // Events from NetworkCallbacks that we process on the main state
         // machine thread on behalf of the UpstreamNetworkMonitor.
-        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MASTER + 5;
+        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MAIN_SM + 5;
         // we treated the error and want now to clear it
-        static final int CMD_CLEAR_ERROR                        = BASE_MASTER + 6;
-        static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MASTER + 7;
+        static final int CMD_CLEAR_ERROR                        = BASE_MAIN_SM + 6;
+        static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MAIN_SM + 7;
         // Events from EntitlementManager to choose upstream again.
-        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MASTER + 8;
+        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MAIN_SM + 8;
         private final State mInitialState;
         private final State mTetherModeAliveState;
 
@@ -1425,7 +1428,7 @@
 
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
 
-        TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
+        TetherMainSM(String name, Looper looper, TetheringDependencies deps) {
             super(name, looper);
 
             mInitialState = new InitialState();
@@ -1479,7 +1482,7 @@
             }
         }
 
-        protected boolean turnOnMasterTetherSettings() {
+        protected boolean turnOnMainTetherSettings() {
             final TetheringConfiguration cfg = mConfig;
             try {
                 mNetd.ipfwdEnableForwarding(TAG);
@@ -1506,11 +1509,11 @@
                     return false;
                 }
             }
-            mLog.log("SET master tether settings: ON");
+            mLog.log("SET main tether settings: ON");
             return true;
         }
 
-        protected boolean turnOffMasterTetherSettings() {
+        protected boolean turnOffMainTetherSettings() {
             try {
                 mNetd.tetherStop();
             } catch (RemoteException | ServiceSpecificException e) {
@@ -1526,7 +1529,7 @@
                 return false;
             }
             transitionTo(mInitialState);
-            mLog.log("SET master tether settings: OFF");
+            mLog.log("SET main tether settings: OFF");
             return true;
         }
 
@@ -1730,7 +1733,7 @@
                     // TODO: Re-evaluate possible upstreams. Currently upstream
                     // reevaluation is triggered via received CONNECTIVITY_ACTION
                     // broadcasts that result in being passed a
-                    // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+                    // TetherMainSM.CMD_UPSTREAM_CHANGED.
                     handleNewUpstreamNetworkState(null);
                     break;
                 default:
@@ -1745,9 +1748,9 @@
 
             @Override
             public void enter() {
-                // If turning on master tether settings fails, we have already
+                // If turning on main tether settings fails, we have already
                 // transitioned to an error state; exit early.
-                if (!turnOnMasterTetherSettings()) {
+                if (!turnOnMainTetherSettings()) {
                     return;
                 }
 
@@ -1819,7 +1822,7 @@
                         if (mNotifyList.isEmpty()) {
                             // This transitions us out of TetherModeAliveState,
                             // either to InitialState or an error state.
-                            turnOffMasterTetherSettings();
+                            turnOffMainTetherSettings();
                             break;
                         }
 
@@ -2329,7 +2332,7 @@
         };
     }
 
-    // TODO: Move into TetherMasterSM.
+    // TODO: Move into TetherMainSM.
     private void notifyInterfaceStateChange(IpServer who, int state, int error) {
         final String iface = who.interfaceName();
         synchronized (mPublicSync) {
@@ -2344,27 +2347,27 @@
 
         mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
 
-        // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
-        // Thus we give a chance for TetherMasterSM to recover to InitialState
+        // If TetherMainSM is in ErrorState, TetherMainSM stays there.
+        // Thus we give a chance for TetherMainSM to recover to InitialState
         // by sending CMD_CLEAR_ERROR
         if (error == TETHER_ERROR_INTERNAL_ERROR) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+            mTetherMainSM.sendMessage(TetherMainSM.CMD_CLEAR_ERROR, who);
         }
         int which;
         switch (state) {
             case IpServer.STATE_UNAVAILABLE:
             case IpServer.STATE_AVAILABLE:
-                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
+                which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
                 break;
             case IpServer.STATE_TETHERED:
             case IpServer.STATE_LOCAL_ONLY:
-                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
+                which = TetherMainSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
                 break;
             default:
                 Log.wtf(TAG, "Unknown interface state: " + state);
                 return;
         }
-        mTetherMasterSM.sendMessage(which, state, 0, who);
+        mTetherMainSM.sendMessage(which, state, 0, who);
         sendTetherStateChangedBroadcast();
     }
 
@@ -2384,8 +2387,8 @@
         mLog.log(String.format(
                 "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
                 iface, IpServer.getStateString(state), newLp));
-        final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
-        mTetherMasterSM.sendMessage(which, state, 0, newLp);
+        final int which = TetherMainSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
+        mTetherMainSM.sendMessage(which, state, 0, newLp);
     }
 
     private void maybeTrackNewInterfaceLocked(final String iface) {
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index e1771a5..5783805 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -84,6 +84,9 @@
     public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
             "tether_enable_legacy_dhcp_server";
 
+    public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP =
+            "use_legacy_wifi_p2p_dedicated_ip";
+
     /**
      * Default value that used to periodic polls tether offload stats from tethering offload HAL
      * to make the data warnings work.
@@ -113,6 +116,7 @@
     private final int mOffloadPollInterval;
     // TODO: Add to TetheringConfigurationParcel if required.
     private final boolean mEnableBpfOffload;
+    private final boolean mEnableWifiP2pDedicatedIp;
 
     public TetheringConfiguration(Context ctx, SharedLog log, int id) {
         final SharedLog configLog = log.forSubComponent("config");
@@ -156,6 +160,10 @@
                 R.integer.config_tether_offload_poll_interval,
                 DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
 
+        mEnableWifiP2pDedicatedIp = getResourceBoolean(res,
+                R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip,
+                false /* defaultValue */);
+
         configLog.log(toString());
     }
 
@@ -199,6 +207,11 @@
         return !TextUtils.isEmpty(provisioningAppNoUi);
     }
 
+    /** Check whether dedicated wifi p2p address is enabled. */
+    public boolean shouldEnableWifiP2pDedicatedIp() {
+        return mEnableWifiP2pDedicatedIp;
+    }
+
     /** Does the dumping.*/
     public void dump(PrintWriter pw) {
         pw.print("activeDataSubId: ");
@@ -233,6 +246,9 @@
 
         pw.print("enableLegacyDhcpServer: ");
         pw.println(enableLegacyDhcpServer);
+
+        pw.print("enableWifiP2pDedicatedIp: ");
+        pw.println(mEnableWifiP2pDedicatedIp);
     }
 
     /** Returns the string representation of this object.*/
diff --git a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 320427c..b17065c 100644
--- a/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -63,7 +63,7 @@
  * Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
  *
  * The methods and data members of this class are only to be accessed and
- * modified from the tethering master state machine thread. Any other
+ * modified from the tethering main state machine thread. Any other
  * access semantics would necessitate the addition of locking.
  *
  * TODO: Move upstream selection logic here.
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 9bb01ae..64be2d9 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -50,7 +50,7 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.HandlerUtils;
 import com.android.testutils.TapPacketReader;
 
 import org.junit.After;
@@ -366,7 +366,7 @@
     private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
         final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
         mHandler.post(() -> reader.start());
-        HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
+        HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
         return reader;
     }
 
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 30a9d22..3b72b5b 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -50,6 +50,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
@@ -73,6 +74,7 @@
 import android.net.RouteInfo;
 import android.net.TetherOffloadRuleParcel;
 import android.net.TetherStatsParcel;
+import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpEventCallbacks;
 import android.net.dhcp.IDhcpServer;
@@ -163,17 +165,6 @@
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
             boolean usingBpfOffload) throws Exception {
-        doAnswer(inv -> {
-            final IDhcpServerCallbacks cb = inv.getArgument(2);
-            new Thread(() -> {
-                try {
-                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
-                } catch (RemoteException e) {
-                    fail(e.getMessage());
-                }
-            }).run();
-            return null;
-        }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
         when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
         when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
 
@@ -225,6 +216,20 @@
         when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
     }
 
+    private void setUpDhcpServer() throws Exception {
+        doAnswer(inv -> {
+            final IDhcpServerCallbacks cb = inv.getArgument(2);
+            new Thread(() -> {
+                try {
+                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+                } catch (RemoteException e) {
+                    fail(e.getMessage());
+                }
+            }).run();
+            return null;
+        }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
+    }
+
     @Before public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
@@ -258,6 +263,8 @@
                         return mTetherConfig;
                     }
                 }));
+
+        setUpDhcpServer();
     }
 
     @Test
@@ -965,6 +972,31 @@
         reset(mRaDaemon);
     }
 
+    @Test
+    public void testStopObsoleteDhcpServer() throws Exception {
+        final ArgumentCaptor<DhcpServerCallbacks> cbCaptor =
+                ArgumentCaptor.forClass(DhcpServerCallbacks.class);
+        doNothing().when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(),
+                cbCaptor.capture());
+        initStateMachine(TETHERING_WIFI);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        verify(mDhcpServer, never()).startWithCallbacks(any(), any());
+
+        // No stop dhcp server because dhcp server is not created yet.
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        verify(mDhcpServer, never()).stop(any());
+
+        // Stop obsolete dhcp server.
+        try {
+            final DhcpServerCallbacks cb = cbCaptor.getValue();
+            cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+            mLooper.dispatchAll();
+        } catch (RemoteException e) {
+            fail(e.getMessage());
+        }
+        verify(mDhcpServer).stop(any());
+    }
+
     private void assertDhcpServingParams(final DhcpServingParamsParcel params,
             final IpPrefix prefix) {
         // Last address byte is random
diff --git a/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java b/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java
index 1499f3b..91c7771 100644
--- a/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java
+++ b/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java
@@ -27,7 +27,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.testutils.MiscAssertsKt;
+import com.android.testutils.MiscAsserts;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -82,6 +82,6 @@
         request.showProvisioningUi = false;
         assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
 
-        MiscAssertsKt.assertFieldCountEquals(5, TetheringRequestParcel.class);
+        MiscAsserts.assertFieldCountEquals(5, TetheringRequestParcel.class);
     }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
index b291438..ce52ae2 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
@@ -30,8 +30,8 @@
 import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID;
 import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
 import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
-import static com.android.testutils.MiscAssertsKt.assertContainsAll;
-import static com.android.testutils.MiscAssertsKt.assertThrows;
+import static com.android.testutils.MiscAsserts.assertContainsAll;
+import static com.android.testutils.MiscAsserts.assertThrows;
 import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals;
 
 import static junit.framework.Assert.assertNotNull;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 2c0df6f..8e93c2e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,11 @@
  */
 package com.android.networkstack.tethering;
 
+import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.Mockito.never;
@@ -54,22 +59,34 @@
     @Mock private IpServer mHotspotIpServer;
     @Mock private IpServer mUsbIpServer;
     @Mock private IpServer mEthernetIpServer;
+    @Mock private IpServer mWifiP2pIpServer;
     @Mock private Context mContext;
     @Mock private ConnectivityManager mConnectivityMgr;
+    @Mock private TetheringConfiguration mConfig;
 
     private PrivateAddressCoordinator mPrivateAddressCoordinator;
     private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+    private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
     private final Network mWifiNetwork = new Network(1);
     private final Network mMobileNetwork = new Network(2);
     private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
 
+    private void setUpIpServers() throws Exception {
+        when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
+        when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
+        when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
+        when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr);
         when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
-        mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext));
+        when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
+        setUpIpServers();
+        mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
     }
 
     @Test
@@ -256,4 +273,38 @@
         final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
         assertEquals(predefinedPrefix, ethPrefix);
     }
+
+    private int getSubAddress(final byte... ipv4Address) {
+        assertEquals(4, ipv4Address.length);
+
+        int subnet = Byte.toUnsignedInt(ipv4Address[2]);
+        return (subnet << 8) + ipv4Address[3];
+    }
+
+    private void assertReseveredWifiP2pPrefix() throws Exception {
+        LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+                mHotspotIpServer);
+        final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
+        final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+        assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
+        mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+    }
+
+    @Test
+    public void testEnableLegacyWifiP2PAddress() throws Exception {
+        when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+                getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+        // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix
+        // is resevered.
+        assertReseveredWifiP2pPrefix();
+
+        when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(true);
+        assertReseveredWifiP2pPrefix();
+
+        // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
+        LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+                mWifiP2pIpServer);
+        assertEquals(mLegacyWifiP2pAddress, address);
+        mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
+    }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index a9ac4e2..dc0940c 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -128,6 +128,8 @@
                 .thenReturn(new String[0]);
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 false);
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+                .thenReturn(false);
         initializeBpfOffloadConfiguration(true, null /* unset */);
 
         mHasTelephonyManager = true;
@@ -413,4 +415,17 @@
                 R.string.config_mobile_hotspot_provision_response)).thenReturn(
                 PROVISIONING_APP_RESPONSE);
     }
+
+    @Test
+    public void testEnableLegacyWifiP2PAddress() throws Exception {
+        final TetheringConfiguration defaultCfg = new TetheringConfiguration(
+                mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp());
+
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+                .thenReturn(true);
+        final TetheringConfiguration testCfg = new TetheringConfiguration(
+                mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp());
+    }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
index 4b6bbac..75c819b 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
@@ -18,33 +18,40 @@
 
 import android.app.Notification
 import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
 import android.content.Context
+import android.content.Intent
 import android.content.pm.ActivityInfo
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.content.pm.ResolveInfo
 import android.content.res.Resources
 import android.net.ConnectivityManager.TETHERING_WIFI
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
 import android.os.Handler
 import android.os.HandlerThread
 import android.os.Looper
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
 import android.os.UserHandle
+import android.provider.Settings
 import android.telephony.TelephonyManager
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
 import com.android.internal.util.test.BroadcastInterceptingContext
+import com.android.networkstack.tethering.TetheringNotificationUpdater.ACTION_DISABLE_TETHERING
 import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE
 import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM
 import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID
 import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID
 import com.android.networkstack.tethering.TetheringNotificationUpdater.ROAMING_NOTIFICATION_ID
 import com.android.networkstack.tethering.TetheringNotificationUpdater.VERIZON_CARRIER_ID
+import com.android.networkstack.tethering.TetheringNotificationUpdater.getSettingsPackageName
 import com.android.testutils.waitForIdle
 import org.junit.After
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
 import org.junit.Assert.fail
 import org.junit.Before
 import org.junit.Test
@@ -87,12 +94,17 @@
     // every test but should always be initialized before use (or the test should crash).
     private lateinit var context: TestContext
     private lateinit var notificationUpdater: TetheringNotificationUpdater
+
+    // Initializing the following members depends on initializing some of the mocks and
+    // is more logically done in setup().
     private lateinit var fakeTetheringThread: HandlerThread
 
     private val ROAMING_CAPABILITIES = NetworkCapabilities()
     private val HOME_CAPABILITIES = NetworkCapabilities().addCapability(NET_CAPABILITY_NOT_ROAMING)
     private val NOTIFICATION_ICON_ID = R.drawable.stat_sys_tether_general
     private val TIMEOUT_MS = 500L
+    private val ACTIVITY_PENDING_INTENT = 0
+    private val BROADCAST_PENDING_INTENT = 1
 
     private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) {
         override fun createContextAsUser(user: UserHandle, flags: Int) =
@@ -146,10 +158,43 @@
         fakeTetheringThread.quitSafely()
     }
 
+    private fun verifyActivityPendingIntent(intent: Intent, flags: Int) {
+        // Use FLAG_NO_CREATE to verify whether PendingIntent has FLAG_IMMUTABLE flag(forcefully add
+        // the flag in creating arguments). If the described PendingIntent does not already exist,
+        // getActivity() will return null instead of PendingIntent object.
+        val pi = PendingIntent.getActivity(
+                context.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
+                0 /* requestCode */,
+                intent,
+                flags or FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE,
+                null /* options */)
+        assertNotNull("Activity PendingIntent with FLAG_IMMUTABLE does not exist.", pi)
+    }
+
+    private fun verifyBroadcastPendingIntent(intent: Intent, flags: Int) {
+        // Use FLAG_NO_CREATE to verify whether PendingIntent has FLAG_IMMUTABLE flag(forcefully add
+        // the flag in creating arguments). If the described PendingIntent does not already exist,
+        // getBroadcast() will return null instead of PendingIntent object.
+        val pi = PendingIntent.getBroadcast(
+                context.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
+                0 /* requestCode */,
+                intent,
+                flags or FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE)
+        assertNotNull("Broadcast PendingIntent with FLAG_IMMUTABLE does not exist.", pi)
+    }
+
     private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE)
     private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT)
 
-    private fun verifyNotification(iconId: Int, title: String, text: String, id: Int) {
+    private fun verifyNotification(
+        iconId: Int,
+        title: String,
+        text: String,
+        id: Int,
+        intentSenderType: Int,
+        intent: Intent,
+        flags: Int
+    ) {
         verify(notificationManager, never()).cancel(any(), eq(id))
 
         val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
@@ -161,6 +206,11 @@
         assertEquals(title, notification.title())
         assertEquals(text, notification.text())
 
+        when (intentSenderType) {
+            ACTIVITY_PENDING_INTENT -> verifyActivityPendingIntent(intent, flags)
+            BROADCAST_PENDING_INTENT -> verifyBroadcastPendingIntent(intent, flags)
+        }
+
         reset(notificationManager)
     }
 
@@ -176,6 +226,10 @@
 
     @Test
     fun testRestrictedNotification() {
+        val settingsIntent = Intent(Settings.ACTION_TETHER_SETTINGS)
+                .setPackage(getSettingsPackageName(context.packageManager))
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
         // Set test sub id.
         notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
         verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID))
@@ -183,7 +237,7 @@
         // User restrictions on. Show restricted notification.
         notificationUpdater.notifyTetheringDisabledByRestriction()
         verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE,
-                RESTRICTED_NOTIFICATION_ID)
+                RESTRICTED_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE)
 
         // User restrictions off. Clear notification.
         notificationUpdater.tetheringRestrictionLifted()
@@ -196,7 +250,7 @@
         // User restrictions on again. Show restricted notification.
         notificationUpdater.notifyTetheringDisabledByRestriction()
         verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE,
-                RESTRICTED_NOTIFICATION_ID)
+                RESTRICTED_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE)
     }
 
     val MAX_BACKOFF_MS = 200L
@@ -234,6 +288,8 @@
 
     @Test
     fun testNoUpstreamNotification() {
+        val disableIntent = Intent(ACTION_DISABLE_TETHERING).setPackage(context.packageName)
+
         // Set test sub id.
         notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
         verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID))
@@ -246,7 +302,8 @@
         notificationUpdater.onUpstreamCapabilitiesChanged(null)
         notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS)
         verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE,
-                NO_UPSTREAM_NOTIFICATION_ID)
+                NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent,
+                FLAG_IMMUTABLE)
 
         // Same capabilities changed. Nothing happened.
         notificationUpdater.onUpstreamCapabilitiesChanged(null)
@@ -260,7 +317,8 @@
         notificationUpdater.onUpstreamCapabilitiesChanged(null)
         notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS)
         verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE,
-                NO_UPSTREAM_NOTIFICATION_ID)
+                NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent,
+                FLAG_IMMUTABLE)
 
         // No downstream.
         notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
@@ -305,6 +363,11 @@
 
     @Test
     fun testRoamingNotification() {
+        val disableIntent = Intent(ACTION_DISABLE_TETHERING).setPackage(context.packageName)
+        val settingsIntent = Intent(Settings.ACTION_TETHER_SETTINGS)
+                .setPackage(getSettingsPackageName(context.packageManager))
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
         // Set test sub id.
         notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
         verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID))
@@ -316,7 +379,7 @@
         // Upstream capabilities changed to roaming state. Show roaming notification.
         notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES)
         verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE,
-                ROAMING_NOTIFICATION_ID)
+                ROAMING_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE)
 
         // Same capabilities change. Nothing happened.
         notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES)
@@ -329,14 +392,15 @@
         // Upstream capabilities changed to roaming state again. Show roaming notification.
         notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES)
         verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE,
-                ROAMING_NOTIFICATION_ID)
+                ROAMING_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE)
 
         // No upstream. Clear roaming notification and show no upstream notification.
         notificationUpdater.onUpstreamCapabilitiesChanged(null)
         notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS)
         verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false)
         verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE,
-                NO_UPSTREAM_NOTIFICATION_ID)
+                NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent,
+                FLAG_IMMUTABLE)
 
         // No downstream.
         notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
@@ -347,7 +411,8 @@
         notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS)
         verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false)
         verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE,
-                NO_UPSTREAM_NOTIFICATION_ID)
+                NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent,
+                FLAG_IMMUTABLE)
 
         // Set R.bool.config_upstream_roaming_notification to false and change upstream
         // network to roaming state again. No roaming notification.
@@ -363,8 +428,7 @@
         val testSettingsPackageName = "com.android.test.settings"
         val pm = mock(PackageManager::class.java)
         doReturn(null).`when`(pm).resolveActivity(any(), anyInt())
-        assertEquals(defaultSettingsPackageName,
-                TetheringNotificationUpdater.getSettingsPackageName(pm))
+        assertEquals(defaultSettingsPackageName, getSettingsPackageName(pm))
 
         val resolveInfo = ResolveInfo().apply {
             activityInfo = ActivityInfo().apply {
@@ -375,7 +439,6 @@
             }
         }
         doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt())
-        assertEquals(testSettingsPackageName,
-                TetheringNotificationUpdater.getSettingsPackageName(pm))
+        assertEquals(testSettingsPackageName, getSettingsPackageName(pm))
     }
 }
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 1b710d0..1fe3840 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -143,7 +143,7 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.testutils.MiscAssertsKt;
+import com.android.testutils.MiscAsserts;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -337,11 +337,11 @@
     }
 
     public class MockTetheringDependencies extends TetheringDependencies {
-        StateMachine mUpstreamNetworkMonitorMasterSM;
+        StateMachine mUpstreamNetworkMonitorSM;
         ArrayList<IpServer> mIpv6CoordinatorNotifyList;
 
         public void reset() {
-            mUpstreamNetworkMonitorMasterSM = null;
+            mUpstreamNetworkMonitorSM = null;
             mIpv6CoordinatorNotifyList = null;
         }
 
@@ -368,7 +368,7 @@
         @Override
         public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
                 StateMachine target, SharedLog log, int what) {
-            mUpstreamNetworkMonitorMasterSM = target;
+            mUpstreamNetworkMonitorSM = target;
             return mUpstreamNetworkMonitor;
         }
 
@@ -911,8 +911,8 @@
         initTetheringUpstream(upstreamState);
 
         // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
-        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+        mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+                Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
                 UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
                 0,
                 upstreamState);
@@ -1126,7 +1126,7 @@
         verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
         // This never gets called because of the exception thrown above.
         verify(mNetd, times(0)).tetherStartWithConfiguration(any());
-        // When the master state machine transitions to an error state it tells
+        // When the main state machine transitions to an error state it tells
         // downstream interfaces, which causes us to tell Wi-Fi about the error
         // so it can take down AP mode.
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
@@ -1360,7 +1360,7 @@
         assertEquals(0, parcel.localOnlyList.length);
         assertEquals(0, parcel.erroredIfaceList.length);
         assertEquals(0, parcel.lastErrorList.length);
-        MiscAssertsKt.assertFieldCountEquals(5, TetherStatesParcel.class);
+        MiscAsserts.assertFieldCountEquals(5, TetherStatesParcel.class);
     }
 
     @Test
@@ -1753,8 +1753,8 @@
 
     @Test
     public void testUpstreamNetworkChanged() {
-        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
-                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+        final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+                mTetheringDependencies.mUpstreamNetworkMonitorSM;
         final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
         initTetheringUpstream(upstreamState);
         stateMachine.chooseUpstreamType(true);
@@ -1765,8 +1765,8 @@
 
     @Test
     public void testUpstreamCapabilitiesChanged() {
-        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
-                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+        final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+                mTetheringDependencies.mUpstreamNetworkMonitorSM;
         final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
         initTetheringUpstream(upstreamState);
         stateMachine.chooseUpstreamType(true);
@@ -1891,8 +1891,8 @@
                 any(), any());
         reset(mNetd, mUsbManager);
         upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork);
-        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+        mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+                Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
                 UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
                 0,
                 upstreamNetwork);
@@ -1929,8 +1929,8 @@
 
         final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState(
                 upstreamAddress, 16, wifiNetwork);
-        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+        mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+                Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
                 UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
                 0,
                 upstreamNetwork);