Merge changes from topics "CATEGORY_ERROR_IKE", "CATEGORY_ERROR_NETWORK", "CATEGORY_ERROR_USER_DEACTIVATED", "CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED"

* changes:
  Send VPN manager event when there is a network error
  Send VPN manager event when there is an IkeProtocolException
  Send VPN manager event when VPN is deactivated
  Send VPN manager event when VPN always-on status is changed
diff --git a/core/api/current.txt b/core/api/current.txt
index 641b1a3..e4fc9f3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29612,6 +29612,7 @@
     field public static final int S = 31; // 0x1f
     field public static final int S_V2 = 32; // 0x20
     field public static final int TIRAMISU = 10000; // 0x2710
+    field public static final int UPSIDE_DOWN_CAKE = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 9db3cdc..fd87a61 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -100,10 +100,12 @@
     field public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2; // 0x2
     field public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1; // 0xffffffff
     field public static final int USB_HAL_NOT_SUPPORTED = -1; // 0xffffffff
+    field public static final int USB_HAL_RETRY = -2; // 0xfffffffe
     field public static final int USB_HAL_V1_0 = 10; // 0xa
     field public static final int USB_HAL_V1_1 = 11; // 0xb
     field public static final int USB_HAL_V1_2 = 12; // 0xc
     field public static final int USB_HAL_V1_3 = 13; // 0xd
+    field public static final int USB_HAL_V2_0 = 20; // 0x14
   }
 
 }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 95fc7ec..abc2b74 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4169,8 +4169,14 @@
   }
 
   public final class UsbPort {
+    method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
+    field public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1; // 0x1
+    field public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ENABLE_USB_DATA_ERROR_OTHER = 4; // 0x4
+    field public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3; // 0x3
+    field public static final int ENABLE_USB_DATA_SUCCESS = 0; // 0x0
   }
 
   public final class UsbPortStatus implements android.os.Parcelable {
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 7f07af7..3e79f18 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.ParcelableUsbPort;
@@ -136,7 +137,7 @@
     void resetUsbGadget();
 
     /* Set USB data on or off */
-    boolean enableUsbDataSignal(boolean enable);
+    boolean enableUsbData(in String portId, boolean enable, int operationId, in IUsbOperationInternal callback);
 
     /* Gets the USB Hal Version. */
     int getUsbHalVersion();
@@ -159,6 +160,6 @@
     /* Enable/disable contaminant detection */
     void enableContaminantDetection(in String portId, boolean enable);
 
-   /* Sets USB device connection handler. */
-   void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
+    /* Sets USB device connection handler. */
+    void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
 }
diff --git a/core/java/android/hardware/usb/IUsbOperationInternal.aidl b/core/java/android/hardware/usb/IUsbOperationInternal.aidl
new file mode 100644
index 0000000..3f3bbf6
--- /dev/null
+++ b/core/java/android/hardware/usb/IUsbOperationInternal.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+/**
+ * @hide
+ */
+oneway interface IUsbOperationInternal {
+void onOperationComplete(in int status);
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 964d7c1..df70bfd 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -36,6 +36,8 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
 import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbPort;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -48,6 +50,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.StringJoiner;
 
 /**
@@ -516,6 +519,14 @@
     public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
 
     /**
+     * Returned when the client has to retry querying the version.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int USB_HAL_RETRY = -2;
+
+    /**
      * The Value for USB hal is not presented.
      *
      * {@hide}
@@ -556,6 +567,14 @@
     public static final int USB_HAL_V1_3 = 13;
 
     /**
+     * Value for USB Hal Version v2.0.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int USB_HAL_V2_0 = 20;
+
+    /**
      * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
      * {@hide}
      */
@@ -664,6 +683,7 @@
             USB_HAL_V1_1,
             USB_HAL_V1_2,
             USB_HAL_V1_3,
+            USB_HAL_V2_0,
     })
     public @interface UsbHalVersion {}
 
@@ -1168,8 +1188,9 @@
     /**
      * Enable/Disable the USB data signaling.
      * <p>
-     * Enables/Disables USB data path in all the USB ports.
+     * Enables/Disables USB data path of the first port..
      * It will force to stop or restore USB data signaling.
+     * Call UsbPort API if the device has more than one UsbPort.
      * </p>
      *
      * @param enable enable or disable USB data signaling
@@ -1180,11 +1201,11 @@
      */
     @RequiresPermission(Manifest.permission.MANAGE_USB)
     public boolean enableUsbDataSignal(boolean enable) {
-        try {
-            return mService.enableUsbDataSignal(enable);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+        List<UsbPort> usbPorts = getPorts();
+        if (usbPorts.size() == 1) {
+            return usbPorts.get(0).enableUsbData(enable) == UsbPort.ENABLE_USB_DATA_SUCCESS;
         }
+        return false;
     }
 
     /**
@@ -1270,6 +1291,41 @@
     }
 
     /**
+     * Should only be called by {@link UsbPort#enableUsbData}.
+     * <p>
+     * Enables or disables USB data on the specific port.
+     *
+     * @param port USB port for which USB data needs to be enabled or disabled.
+     * @param enable Enable USB data when true.
+     *               Disable USB data when false.
+     * @param operationId operationId for the request.
+     * @param callback callback object to be invoked when the operation is complete.
+     * @return True when the operation is asynchronous. The caller must therefore call
+     *         {@link UsbOperationInternal#waitForOperationComplete} for processing
+     *         the result.
+     *         False when the operation is synchronous. Caller can proceed reading the result
+     *         through {@link UsbOperationInternal#getStatus}
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    boolean enableUsbData(@NonNull UsbPort port, boolean enable, int operationId,
+            IUsbOperationInternal callback) {
+        Objects.requireNonNull(port, "enableUsbData: port must not be null. opId:" + operationId);
+        try {
+            return mService.enableUsbData(port.getId(), enable, operationId, callback);
+        } catch (RemoteException e) {
+            Log.e(TAG, "enableUsbData: failed. opId:" + operationId, e);
+            try {
+                callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL);
+            } catch (RemoteException r) {
+                Log.e(TAG, "enableUsbData: failed to call onOperationComplete. opId:"
+                        + operationId, r);
+            }
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets the component that will handle USB device connection.
      * <p>
      * Setting component allows to specify external USB host manager to handle use cases, where
diff --git a/core/java/android/hardware/usb/UsbOperationInternal.java b/core/java/android/hardware/usb/UsbOperationInternal.java
new file mode 100644
index 0000000..9bc2b38
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbOperationInternal.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.usb;
+
+import android.annotation.IntDef;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbPort;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.TimeUnit;
+/**
+ * UsbOperationInternal allows UsbPort to support both synchronous and
+ * asynchronous function irrespective of whether the underlying hal
+ * method is synchronous or asynchronous.
+ *
+ * @hide
+ */
+public final class UsbOperationInternal extends IUsbOperationInternal.Stub {
+    private static final String TAG = "UsbPortStatus";
+    private final int mOperationID;
+    // Cached portId.
+    private final String mId;
+    // True implies operation did not timeout.
+    private boolean mOperationComplete;
+    private @UsbOperationStatus int mStatus;
+    final ReentrantLock mLock = new ReentrantLock();
+    final Condition mOperationWait  = mLock.newCondition();
+    // Maximum time the caller has to wait for onOperationComplete to be called.
+    private static final int USB_OPERATION_TIMEOUT_MSECS = 5000;
+
+    /**
+     * The requested operation was successfully completed.
+     * Returned in {@link onOperationComplete} and {@link getStatus}.
+     */
+    public static final int USB_OPERATION_SUCCESS = 0;
+
+    /**
+     * The requested operation failed due to internal error.
+     * Returned in {@link onOperationComplete} and {@link getStatus}.
+     */
+    public static final int USB_OPERATION_ERROR_INTERNAL = 1;
+
+    /**
+     * The requested operation failed as it's not supported.
+     * Returned in {@link onOperationComplete} and {@link getStatus}.
+     */
+    public static final int USB_OPERATION_ERROR_NOT_SUPPORTED = 2;
+
+    /**
+     * The requested operation failed as it's not supported.
+     * Returned in {@link onOperationComplete} and {@link getStatus}.
+     */
+    public static final int USB_OPERATION_ERROR_PORT_MISMATCH = 3;
+
+    @IntDef(prefix = { "USB_OPERATION_" }, value = {
+            USB_OPERATION_SUCCESS,
+            USB_OPERATION_ERROR_INTERNAL,
+            USB_OPERATION_ERROR_NOT_SUPPORTED,
+            USB_OPERATION_ERROR_PORT_MISMATCH
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface UsbOperationStatus{}
+
+    UsbOperationInternal(int operationID, String id) {
+        this.mOperationID = operationID;
+        this.mId = id;
+    }
+
+    /**
+     * Hal glue layer would directly call this function when the requested
+     * operation is complete.
+     */
+    @Override
+    public void onOperationComplete(@UsbOperationStatus int status) {
+        mLock.lock();
+        try {
+            mOperationComplete = true;
+            mStatus = status;
+            Log.i(TAG, "Port:" + mId + " opID:" + mOperationID + " status:" + mStatus);
+            mOperationWait.signal();
+        } finally {
+            mLock.unlock();
+        }
+    }
+
+    /**
+     * Caller invokes this function to wait for the operation to be complete.
+     */
+    public void waitForOperationComplete() {
+        mLock.lock();
+        try {
+            long now = System.currentTimeMillis();
+            long deadline = now + USB_OPERATION_TIMEOUT_MSECS;
+            // Wait in loop to overcome spurious wakeups.
+            do {
+                mOperationWait.await(deadline - System.currentTimeMillis(),
+                        TimeUnit.MILLISECONDS);
+            } while (!mOperationComplete && System.currentTimeMillis() < deadline);
+            if (!mOperationComplete) {
+                Log.e(TAG, "Port:" + mId + " opID:" + mOperationID
+                        + " operationComplete not received in " + USB_OPERATION_TIMEOUT_MSECS
+                        + "msecs");
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Port:" + mId + " opID:" + mOperationID + " operationComplete interrupted");
+        } finally {
+            mLock.unlock();
+        }
+    }
+
+    public @UsbOperationStatus int getStatus() {
+        return mOperationComplete ? mStatus : USB_OPERATION_ERROR_INTERNAL;
+    }
+}
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 274e23f..f469a3e 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -16,6 +16,10 @@
 
 package android.hardware.usb;
 
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED;
 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED;
 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
@@ -34,15 +38,23 @@
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
 
 import android.Manifest;
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.hardware.usb.UsbOperationInternal;
 import android.hardware.usb.V1_0.Constants;
+import android.os.Binder;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Represents a physical USB port and describes its characteristics.
@@ -51,6 +63,7 @@
  */
 @SystemApi
 public final class UsbPort {
+    private static final String TAG = "UsbPort";
     private final String mId;
     private final int mSupportedModes;
     private final UsbManager mUsbManager;
@@ -64,6 +77,47 @@
      */
     private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
+    /**
+     * The {@link #enableUsbData} request was successfully completed.
+     */
+    public static final int ENABLE_USB_DATA_SUCCESS = 0;
+
+    /**
+     * The {@link #enableUsbData} request failed due to internal error.
+     */
+    public static final int ENABLE_USB_DATA_ERROR_INTERNAL = 1;
+
+    /**
+     * The {@link #enableUsbData} request failed as it's not supported.
+     */
+    public static final int ENABLE_USB_DATA_ERROR_NOT_SUPPORTED = 2;
+
+    /**
+     * The {@link #enableUsbData} request failed as port id mismatched.
+     */
+    public static final int ENABLE_USB_DATA_ERROR_PORT_MISMATCH = 3;
+
+    /**
+     * The {@link #enableUsbData} request failed due to other reasons.
+     */
+    public static final int ENABLE_USB_DATA_ERROR_OTHER = 4;
+
+    /** @hide */
+    @IntDef(prefix = { "ENABLE_USB_DATA_" }, value = {
+            ENABLE_USB_DATA_SUCCESS,
+            ENABLE_USB_DATA_ERROR_INTERNAL,
+            ENABLE_USB_DATA_ERROR_NOT_SUPPORTED,
+            ENABLE_USB_DATA_ERROR_PORT_MISMATCH,
+            ENABLE_USB_DATA_ERROR_OTHER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface EnableUsbDataStatus{}
+
     /** @hide */
     public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
             int supportedContaminantProtectionModes,
@@ -157,7 +211,7 @@
      * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}.
      * </p><p>
      * Note: This function is asynchronous and may fail silently without applying
-     * the requested changes.  If this function does cause a status change to occur then
+     * the operationed changes.  If this function does cause a status change to occur then
      * a {@link UsbManager#ACTION_USB_PORT_CHANGED} broadcast will be sent.
      * </p>
      *
@@ -177,6 +231,47 @@
     }
 
     /**
+     * Enables/Disables Usb data on the port.
+     *
+     * @param enable When true enables USB data if disabled.
+     *               When false disables USB data if enabled.
+     * @return       {@link #ENABLE_USB_DATA_SUCCESS} when request completes successfully or
+     *               {@link #ENABLE_USB_DATA_ERROR_INTERNAL} when request fails due to internal
+     *               error or
+     *               {@link ENABLE_USB_DATA_ERROR_NOT_SUPPORTED} when not supported or
+     *               {@link ENABLE_USB_DATA_ERROR_PORT_MISMATCH} when request fails due to port id
+     *               mismatch or
+     *               {@link ENABLE_USB_DATA_ERROR_OTHER} when fails due to other reasons.
+     */
+    @CheckResult
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public @EnableUsbDataStatus int enableUsbData(boolean enable) {
+        // UID is added To minimize operationID overlap between two different packages.
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
+        Log.i(TAG, "enableUsbData opId:" + operationId
+                + " callingUid:" + Binder.getCallingUid());
+        UsbOperationInternal opCallback =
+                new UsbOperationInternal(operationId, mId);
+        if (mUsbManager.enableUsbData(this, enable, operationId, opCallback) == true) {
+            opCallback.waitForOperationComplete();
+        }
+
+        int result = opCallback.getStatus();
+        switch (result) {
+            case USB_OPERATION_SUCCESS:
+                return ENABLE_USB_DATA_SUCCESS;
+            case USB_OPERATION_ERROR_INTERNAL:
+                return ENABLE_USB_DATA_ERROR_INTERNAL;
+            case USB_OPERATION_ERROR_NOT_SUPPORTED:
+                return ENABLE_USB_DATA_ERROR_NOT_SUPPORTED;
+            case USB_OPERATION_ERROR_PORT_MISMATCH:
+                return ENABLE_USB_DATA_ERROR_PORT_MISMATCH;
+            default:
+                return ENABLE_USB_DATA_ERROR_OTHER;
+        }
+    }
+
+    /**
      * @hide
      **/
     public void enableContaminantDetection(boolean enable) {
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index bb7aff6..bd2f9aa 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.usb.V1_0.Constants;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -36,27 +35,29 @@
 @Immutable
 @SystemApi
 public final class UsbPortStatus implements Parcelable {
+    private static final String TAG = "UsbPortStatus";
     private final int mCurrentMode;
     private final @UsbPowerRole int mCurrentPowerRole;
     private final @UsbDataRole int mCurrentDataRole;
     private final int mSupportedRoleCombinations;
     private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
     private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
+    private final boolean mUsbDataEnabled;
 
     /**
      * Power role: This USB port does not have a power role.
      */
-    public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
+    public static final int POWER_ROLE_NONE = 0;
 
     /**
      * Power role: This USB port can act as a source (provide power).
      */
-    public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
+    public static final int POWER_ROLE_SOURCE = 1;
 
     /**
      * Power role: This USB port can act as a sink (receive power).
      */
-    public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
+    public static final int POWER_ROLE_SINK = 2;
 
     @IntDef(prefix = { "POWER_ROLE_" }, value = {
             POWER_ROLE_NONE,
@@ -69,17 +70,17 @@
     /**
      * Power role: This USB port does not have a data role.
      */
-    public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
+    public static final int DATA_ROLE_NONE = 0;
 
     /**
      * Data role: This USB port can act as a host (access data services).
      */
-    public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
+    public static final int DATA_ROLE_HOST = 1;
 
     /**
      * Data role: This USB port can act as a device (offer data services).
      */
-    public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
+    public static final int DATA_ROLE_DEVICE = 2;
 
     @IntDef(prefix = { "DATA_ROLE_" }, value = {
             DATA_ROLE_NONE,
@@ -92,15 +93,7 @@
     /**
      * There is currently nothing connected to this USB port.
      */
-    public static final int MODE_NONE = Constants.PortMode.NONE;
-
-    /**
-     * This USB port can act as a downstream facing port (host).
-     *
-     * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and
-     * {@link #DATA_ROLE_HOST} combination of roles (and possibly others as well).
-     */
-    public static final int MODE_DFP = Constants.PortMode.DFP;
+    public static final int MODE_NONE = 0;
 
     /**
      * This USB port can act as an upstream facing port (device).
@@ -108,7 +101,15 @@
      * <p> Implies that the port supports the {@link #POWER_ROLE_SINK} and
      * {@link #DATA_ROLE_DEVICE} combination of roles (and possibly others as well).
      */
-    public static final int MODE_UFP = Constants.PortMode.UFP;
+    public static final int MODE_UFP = 1 << 0;
+
+    /**
+     * This USB port can act as a downstream facing port (host).
+     *
+     * <p> Implies that the port supports the {@link #POWER_ROLE_SOURCE} and
+     * {@link #DATA_ROLE_HOST} combination of roles (and possibly others as well).
+     */
+    public static final int MODE_DFP = 1 << 1;
 
     /**
      * This USB port can act either as an downstream facing port (host) or as
@@ -120,87 +121,76 @@
      *
      * @hide
      */
-    public static final int MODE_DUAL = Constants.PortMode.DRP;
+    public static final int MODE_DUAL = MODE_UFP | MODE_DFP;
 
     /**
      * This USB port can support USB Type-C Audio accessory.
      */
-    public static final int MODE_AUDIO_ACCESSORY =
-            android.hardware.usb.V1_1.Constants.PortMode_1_1.AUDIO_ACCESSORY;
+    public static final int MODE_AUDIO_ACCESSORY = 1 << 2;
 
     /**
      * This USB port can support USB Type-C debug accessory.
      */
-    public static final int MODE_DEBUG_ACCESSORY =
-            android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
+    public static final int MODE_DEBUG_ACCESSORY = 1 << 3;
 
    /**
      * Contaminant presence detection not supported by the device.
      * @hide
      */
-    public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED =
-            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_SUPPORTED;
+    public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED = 0;
 
     /**
      * Contaminant presence detection supported but disabled.
      * @hide
      */
-    public static final int CONTAMINANT_DETECTION_DISABLED =
-            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DISABLED;
+    public static final int CONTAMINANT_DETECTION_DISABLED = 1;
 
     /**
      * Contaminant presence enabled but not detected.
      * @hide
      */
-    public static final int CONTAMINANT_DETECTION_NOT_DETECTED =
-            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_DETECTED;
+    public static final int CONTAMINANT_DETECTION_NOT_DETECTED = 2;
 
     /**
      * Contaminant presence enabled and detected.
      * @hide
      */
-    public static final int CONTAMINANT_DETECTION_DETECTED =
-            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DETECTED;
+    public static final int CONTAMINANT_DETECTION_DETECTED = 3;
 
     /**
      * Contaminant protection - No action performed upon detection of
      * contaminant presence.
      * @hide
      */
-    public static final int CONTAMINANT_PROTECTION_NONE =
-            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.NONE;
+    public static final int CONTAMINANT_PROTECTION_NONE = 0;
 
     /**
      * Contaminant protection - Port is forced to sink upon detection of
      * contaminant presence.
      * @hide
      */
-    public static final int CONTAMINANT_PROTECTION_SINK =
-            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SINK;
+    public static final int CONTAMINANT_PROTECTION_SINK = 1 << 0;
 
     /**
      * Contaminant protection - Port is forced to source upon detection of
      * contaminant presence.
      * @hide
      */
-    public static final int CONTAMINANT_PROTECTION_SOURCE =
-            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SOURCE;
+    public static final int CONTAMINANT_PROTECTION_SOURCE = 1 << 1;
 
     /**
      * Contaminant protection - Port is disabled upon detection of
      * contaminant presence.
      * @hide
      */
-    public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE =
-            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_DISABLE;
+    public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE = 1 << 2;
 
     /**
      * Contaminant protection - Port is disabled upon detection of
      * contaminant presence.
      * @hide
      */
-    public static final int CONTAMINANT_PROTECTION_DISABLED =
-            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.DISABLED;
+    public static final int CONTAMINANT_PROTECTION_DISABLED = 1 << 3;
 
     @IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
             CONTAMINANT_DETECTION_NOT_SUPPORTED,
@@ -234,6 +224,19 @@
     /** @hide */
     public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
             int supportedRoleCombinations, int contaminantProtectionStatus,
+            int contaminantDetectionStatus, boolean usbDataEnabled) {
+        mCurrentMode = currentMode;
+        mCurrentPowerRole = currentPowerRole;
+        mCurrentDataRole = currentDataRole;
+        mSupportedRoleCombinations = supportedRoleCombinations;
+        mContaminantProtectionStatus = contaminantProtectionStatus;
+        mContaminantDetectionStatus = contaminantDetectionStatus;
+        mUsbDataEnabled = usbDataEnabled;
+    }
+
+    /** @hide */
+    public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
+            int supportedRoleCombinations, int contaminantProtectionStatus,
             int contaminantDetectionStatus) {
         mCurrentMode = currentMode;
         mCurrentPowerRole = currentPowerRole;
@@ -241,6 +244,7 @@
         mSupportedRoleCombinations = supportedRoleCombinations;
         mContaminantProtectionStatus = contaminantProtectionStatus;
         mContaminantDetectionStatus = contaminantDetectionStatus;
+        mUsbDataEnabled = true;
     }
 
     /**
@@ -323,6 +327,15 @@
         return mContaminantProtectionStatus;
     }
 
+    /**
+     * Returns UsbData status.
+     *
+     * @hide
+     */
+    public boolean getUsbDataStatus() {
+        return mUsbDataEnabled;
+    }
+
     @NonNull
     @Override
     public String toString() {
@@ -336,6 +349,8 @@
                         + getContaminantDetectionStatus()
                 + ", contaminantProtectionStatus="
                         + getContaminantProtectionStatus()
+                + ", usbDataEnabled="
+                        + getUsbDataStatus()
                 + "}";
     }
 
@@ -352,6 +367,7 @@
         dest.writeInt(mSupportedRoleCombinations);
         dest.writeInt(mContaminantProtectionStatus);
         dest.writeInt(mContaminantDetectionStatus);
+        dest.writeBoolean(mUsbDataEnabled);
     }
 
     public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -364,9 +380,10 @@
             int supportedRoleCombinations = in.readInt();
             int contaminantProtectionStatus = in.readInt();
             int contaminantDetectionStatus = in.readInt();
+            boolean usbDataEnabled = in.readBoolean();
             return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
-                    contaminantDetectionStatus);
+                    contaminantDetectionStatus, usbDataEnabled);
         }
 
         @Override
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 45cc324d..141b141 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -406,7 +406,7 @@
         public static final String CODENAME = getString("ro.build.version.codename");
 
         /**
-         * All known codenames starting from {@link VERSION_CODES.Q}.
+         * All known codenames that are present in {@link VERSION_CODES}.
          *
          * <p>This includes in development codenames as well, i.e. if {@link #CODENAME} is not "REL"
          * then the value of that is present in this set.
@@ -1167,6 +1167,11 @@
          * Tiramisu.
          */
         public static final int TIRAMISU = CUR_DEVELOPMENT;
+
+        /**
+         * Upside Down Cake.
+         */
+        public static final int UPSIDE_DOWN_CAKE = CUR_DEVELOPMENT;
     }
 
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index b5466b6..49f4bf7 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -5,10 +5,14 @@
 ewol@google.com
 guojing@google.com
 jaysullivan@google.com
+kvakil@google.com
+mrulhania@google.com
+narayan@google.com
+ntmyren@google.com
 olekarg@google.com
 pyuli@google.com
-ntmyren@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+raphk@google.com
+rmacgregor@google.com
+sergeynv@google.com
 theianchen@google.com
 zhanghai@google.com
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4c1cc97..71b5354 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -306,6 +306,13 @@
     public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
 
     /**
+     * Namespace for all Kernel Multi-Gen LRU feature.
+     *
+     * @hide
+     */
+    public static final String NAMESPACE_MGLRU_NATIVE = "mglru_native";
+
+    /**
      * Namespace for all netd related features.
      *
      * @hide
diff --git a/core/java/android/speech/OWNERS b/core/java/android/speech/OWNERS
index 32f4822..462d8be 100644
--- a/core/java/android/speech/OWNERS
+++ b/core/java/android/speech/OWNERS
@@ -1,3 +1,4 @@
 volnov@google.com
 eugeniom@google.com
 schfan@google.com
+andreaambu@google.com
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f2ddf52..ffa577a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28283,7 +28283,7 @@
      *     {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be
      *     available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li>
      *
-     *     <li>Events from a touchpad will be delivered with the source
+     *     <li>Events from a touchpad or trackpad will be delivered with the source
      *     {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers
      *     on the touchpad will be available through {@link MotionEvent#getX(int)} and
      *     {@link MotionEvent#getY(int)}, and their relative movements are stored in
@@ -28292,6 +28292,12 @@
      *     <li>Events from other types of devices, such as touchscreens, will not be affected.</li>
      * </ul>
      * <p>
+     * When pointer capture changes, connected mouse and trackpad devices may be reconfigured,
+     * and their properties (such as their sources or motion ranges) may change. Use an
+     * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device
+     * changes (which may happen after enabling or disabling pointer capture), and use
+     * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}.
+     * <p>
      * Events captured through pointer capture will be dispatched to
      * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an
      * {@link OnCapturedPointerListener} is set, and otherwise to
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index 3260136..744fe59 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -244,7 +244,8 @@
         writeContaminantPresenceStatus(dump, "contaminant_presence_status",
                 UsbPortStatusProto.CONTAMINANT_PRESENCE_STATUS,
                 status.getContaminantDetectionStatus());
-
+        dump.write("usb_data_enabled", UsbPortStatusProto.USB_DATA_ENABLED,
+                status.getUsbDataStatus());
         dump.end(token);
     }
 }
diff --git a/core/java/com/android/internal/usb/OWNERS b/core/java/com/android/internal/usb/OWNERS
new file mode 100644
index 0000000..f7b2a37
--- /dev/null
+++ b/core/java/com/android/internal/usb/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 51185d4..f4f9f94 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1177,38 +1177,40 @@
 }
 
 /**
- * Make other apps data directory not visible in CE, DE storage.
+ * Hide the CE and DE data directories of non-related apps.
  *
- * Apps without app data isolation can detect if another app is installed on system,
- * by "touching" other apps data directory like /data/data/com.whatsapp, if it returns
- * "Permission denied" it means apps installed, otherwise it returns "File not found".
- * Traditional file permissions or SELinux can only block accessing those directories but
- * can't fix fingerprinting like this.
- * We fix it by "overlaying" data directory, and only relevant app data packages exists
- * in data directories.
+ * Without this, apps can detect if any app is installed by trying to "touch" the app's CE
+ * or DE data directory, e.g. /data/data/com.whatsapp.  This fails with EACCES if the app
+ * is installed, or ENOENT if it's not.  Traditional file permissions or SELinux can only
+ * block accessing those directories but can't fix fingerprinting like this.
+ *
+ * Instead, we hide non-related apps' data directories from the filesystem entirely by
+ * mounting tmpfs instances over their parent directories and bind-mounting in just the
+ * needed app data directories.  This is done in a private mount namespace.
  *
  * Steps:
- * 1). Collect a list of all related apps (apps with same uid and allowlisted apps) data info
- * (package name, data stored volume uuid, and inode number of its CE data directory)
- * 2). Mount tmpfs on /data/data, /data/user(_de) and /mnt/expand, so apps no longer
- * able to access apps data directly.
- * 3). For each related app, create its app data directory and bind mount the actual content
- * from apps data mirror directory. This works on both CE and DE storage, as DE storage
- * is always available even storage is FBE locked, while we use inode number to find
- * the encrypted DE directory in mirror so we can still bind mount it successfully.
+ * (1) Collect a list of all related apps (apps with same uid and allowlisted apps) data info
+ *     (package name, data stored volume uuid, and inode number of its CE data directory)
+ * (2) Mount tmpfs on /data/data and /data/user{,_de}, and on /mnt/expand/$volume/user{,_de}
+ *     for all adoptable storage volumes.  This hides all app data directories.
+ * (3) For each related app, create stubs for its data directories in the relevant tmpfs
+ *     instances, then bind mount in the actual directories from /data_mirror.  This works
+ *     for both the CE and DE directories.  DE storage is always unlocked, whereas the
+ *     app's CE directory can be found via inode number if CE storage is locked.
  *
- * Example:
- * 0). Assuming com.android.foo CE data is stored in /data/data and no shared uid
- * 1). Mount a tmpfs on /data/data, /data/user, /data/user_de, /mnt/expand
- * List = ["com.android.foo", "null" (volume uuid "null"=default),
- * 123456 (inode number)]
- * 2). On DE storage, we create a directory /data/user_de/0/com.com.android.foo, and bind
- * mount (in the app's mount namespace) it from /data_mirror/data_de/0/com.android.foo.
- * 3). We do similar for CE storage. But in direct boot mode, as /data_mirror/data_ce/0/ is
- * encrypted, we can't find a directory with name com.android.foo on it, so we will
- * use the inode number to find the right directory instead, which that directory content will
- * be decrypted after storage is decrypted.
- *
+ * Example assuming user 0, app "com.android.foo", no shared uid, and no adoptable storage:
+ * (1) Info = ["com.android.foo", "null" (volume uuid "null"=default), "123456" (inode number)]
+ * (2) Mount tmpfs on /data/data, /data/user, and /data/user_de.
+ * (3) For DE storage, create a directory /data/user_de/0/com.android.foo and bind mount
+ *     /data_mirror/data_de/0/com.android.foo onto it.
+ * (4) Do similar for CE storage.  But if the device is in direct boot mode, then CE
+ *     storage will be locked, so the app's CE data directory won't exist at the usual
+ *     path /data_mirror/data_ce/0/com.android.foo.  It will still exist in
+ *     /data_mirror/data_ce/0, but its filename will be an unpredictable no-key name.  In
+ *     this case, we use the inode number to find the right directory instead.  Note that
+ *     the bind-mounted app CE data directory will remain locked.  It will be unlocked
+ *     automatically if/when the user's CE storage is unlocked, since adding an encryption
+ *     key takes effect on a whole filesystem instance including all its mounts.
  */
 static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list,
     uid_t uid, const char* process_name,
@@ -1599,10 +1601,11 @@
     // since the directory is owned by root.
     if (!is_system_server && getuid() == 0) {
         const int rc = createProcessGroup(uid, getpid());
-        if (rc == -EROFS) {
-            ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
-        } else if (rc != 0) {
-            ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+        if (rc != 0) {
+            fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
+                                                "CONFIG_CGROUP_CPUACCT?")
+                                 : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid,
+                                                /* pid= */ 0, strerror(-rc)));
         }
     }
 
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 45f8c132..cd002da 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -195,9 +195,19 @@
 message UsbPortManagerProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
+    enum HalVersion {
+        V_UNKNOWN = 0;
+        V1_0 = 10;
+        V1_1 = 11;
+        V1_2 = 12;
+        V1_3 = 13;
+        V2 = 20;
+    }
+
     optional bool is_simulation_active = 1;
     repeated UsbPortInfoProto usb_ports = 2;
     optional bool enable_usb_data_signaling = 3;
+    optional HalVersion hal_version = 4;
 }
 
 message UsbPortInfoProto {
@@ -253,6 +263,7 @@
     optional DataRole data_role = 4;
     repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
     optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6;
+    optional bool usb_data_enabled = 7;
 }
 
 message UsbPortStatusRoleCombinationProto {
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index c112cbb..de2a013 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -51,6 +51,5 @@
     ],
 
     platform_apis: true,
-    sdk_version: "core_platform",
     test_suites: ["device-tests"],
 }
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index f87797a..43a9679 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -35,7 +35,6 @@
         "truth-prebuilt",
     ],
     test_suites: ["general-tests"],
-    sdk_version: "test_current",
     platform_apis: true,
 }
 
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 05ec00f..b521184 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -73,7 +73,6 @@
     ],
 
     platform_apis: true,
-    sdk_version: "core_platform",
     test_suites: ["device-tests"],
 
     certificate: "platform",
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index 0b3f9bb..5435113 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -45,6 +45,10 @@
     jni_libs: ["libshim_jni"],
 
     uses_libs: ["android.test.runner"],
+
+    apex_available: [
+        "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
+    ],
 }
 
 genrule {
@@ -84,6 +88,7 @@
         "//apex_available:platform",
         "com.android.apex.cts.shim.v1",
         "com.android.apex.cts.shim.v2",
+        "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
         "com.android.apex.cts.shim.v2_no_hashtree",
         "com.android.apex.cts.shim.v2_legacy",
         "com.android.apex.cts.shim.v2_sdk_target_p",
@@ -159,6 +164,7 @@
         "//apex_available:platform",
         "com.android.apex.cts.shim.v1",
         "com.android.apex.cts.shim.v2",
+        "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
         "com.android.apex.cts.shim.v2_no_hashtree",
         "com.android.apex.cts.shim.v2_legacy",
         "com.android.apex.cts.shim.v2_sdk_target_p",
diff --git a/packages/CtsShim/build/jni/Android.bp b/packages/CtsShim/build/jni/Android.bp
index ba586db..2dbf2a2 100644
--- a/packages/CtsShim/build/jni/Android.bp
+++ b/packages/CtsShim/build/jni/Android.bp
@@ -32,6 +32,7 @@
         "//apex_available:platform",
         "com.android.apex.cts.shim.v1",
         "com.android.apex.cts.shim.v2",
+        "com.android.apex.cts.shim.v2_apk_in_apex_upgrades",
         "com.android.apex.cts.shim.v2_no_hashtree",
         "com.android.apex.cts.shim.v2_legacy",
         "com.android.apex.cts.shim.v2_sdk_target_p",
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 40662536..4a3350e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -320,7 +320,7 @@
         info.className = Switch::class.java.name
     }
 
-    override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
+    override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
         if (super.performAccessibilityAction(host, action, args)) {
             return true
         }
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 99e12a8..ce0e69c 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -91,6 +91,10 @@
                 if (!volume.isMountedWritable()) {
                     continue;
                 }
+                // gsid only supports vfat external storage.
+                if (!"vfat".equalsIgnoreCase(volume.fsType)) {
+                    continue;
+                }
                 DiskInfo disk = volume.getDisk();
                 long mega = disk.size >> 20;
                 Slog.i(TAG, volume.getPath() + ": " + mega + " MB");
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 81627a0..2ab477f 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1803,7 +1803,10 @@
             mComputedNightMode = false;
             return;
         }
-        resetNightModeOverrideLocked();
+        if (mNightMode != MODE_NIGHT_AUTO || (mTwilightManager != null
+                && mTwilightManager.getLastTwilightState() != null)) {
+            resetNightModeOverrideLocked();
+        }
     }
 
     private boolean resetNightModeOverrideLocked() {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index dc80c4b..ca16f57 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2425,8 +2425,8 @@
             if (!regularZygote) {
                 // webview and app zygote don't have the permission to create the nodes
                 if (Process.createProcessGroup(uid, startResult.pid) < 0) {
-                    Slog.e(ActivityManagerService.TAG, "Unable to create process group for "
-                            + app.processName + " (" + startResult.pid + ")");
+                    throw new AssertionError("Unable to create process group for " + app.processName
+                            + " (" + startResult.pid + ")");
                 }
             }
 
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c5ac390..d01030b 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -86,6 +86,7 @@
         DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
         DeviceConfig.NAMESPACE_LMKD_NATIVE,
         DeviceConfig.NAMESPACE_MEDIA_NATIVE,
+        DeviceConfig.NAMESPACE_MGLRU_NATIVE,
         DeviceConfig.NAMESPACE_NETD_NATIVE,
         DeviceConfig.NAMESPACE_NNAPI_NATIVE,
         DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0c47efe..3858d7a 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -174,6 +174,7 @@
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkIdentity;
@@ -236,6 +237,7 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
+import android.util.SparseSetArray;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
@@ -624,6 +626,9 @@
     /** Map from network ID to last observed roaming state */
     @GuardedBy("mNetworkPoliciesSecondLock")
     private final SparseBooleanArray mNetworkRoaming = new SparseBooleanArray();
+    /** Map from network ID to the last ifaces on it */
+    @GuardedBy("mNetworkPoliciesSecondLock")
+    private SparseSetArray<String> mNetworkToIfaces = new SparseSetArray<>();
 
     /** Map from netId to subId as of last update */
     @GuardedBy("mNetworkPoliciesSecondLock")
@@ -1343,11 +1348,28 @@
         return changed;
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
+    private boolean updateNetworkToIfacesNL(int netId, @NonNull ArraySet<String> newIfaces) {
+        // TODO: Add a facility SparseSetArray.contains(key) to return whether the key exists.
+        final ArraySet<String> lastIfaces = mNetworkToIfaces.get(netId);
+        final boolean changed = lastIfaces == null ? true : !lastIfaces.equals(newIfaces);
+
+        if (changed) {
+            // Changed on the same network should remove last ifaces and add new ifaces.
+            // TODO: Add a facility SparseSetArray.put(key, value) for replacing the
+            //       value for a given key.
+            mNetworkToIfaces.remove(netId);
+            for (String iface : newIfaces) {
+                mNetworkToIfaces.add(netId, iface);
+            }
+        }
+        return changed;
+    }
+
     private final NetworkCallback mNetworkCallback = new NetworkCallback() {
         @Override
-        public void onCapabilitiesChanged(Network network,
-                NetworkCapabilities networkCapabilities) {
-            if (network == null || networkCapabilities == null) return;
+        public void onCapabilitiesChanged(@NonNull Network network,
+                @NonNull NetworkCapabilities networkCapabilities) {
 
             synchronized (mNetworkPoliciesSecondLock) {
                 final boolean newMetered = !networkCapabilities
@@ -1366,6 +1388,25 @@
                 }
             }
         }
+
+        @Override
+        public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties lp) {
+            synchronized (mNetworkPoliciesSecondLock) {
+                final ArraySet<String> newIfaces = new ArraySet<>(lp.getAllInterfaceNames());
+                final boolean ifacesChanged = updateNetworkToIfacesNL(network.getNetId(),
+                        newIfaces);
+                if (ifacesChanged) {
+                    updateNetworkRulesNL();
+                }
+            }
+        }
+
+        @Override
+        public void onLost(@NonNull Network network) {
+            synchronized (mNetworkPoliciesSecondLock) {
+                mNetworkToIfaces.remove(network.getNetId());
+            }
+        }
     };
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fad18d2..7d1dbc5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13257,7 +13257,8 @@
             // Don't use profiles since that may cause compilation to be skipped.
             final int res = performDexOptInternalWithDependenciesLI(pkg, pkgSetting,
                     new DexoptOptions(packageName,
-                            getDefaultCompilerFilter(),
+                            REASON_CMDLINE,
+                            getDefaultCompilerFilter(), null /* splitName */,
                             DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE));
 
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 7e4f0e7..0a03338 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -25,7 +25,6 @@
 
 android_test_helper_app {
     name: "PackageManagerServiceDeviceSideTests",
-    sdk_version: "test_current",
     srcs: ["src/**/*.kt"],
     libs: [
         "android.test.base",
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 01feacd..4dc5423 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -29,6 +29,7 @@
         "android.hardware.usb-V1.1-java",
         "android.hardware.usb-V1.2-java",
         "android.hardware.usb-V1.3-java",
+        "android.hardware.usb-V1-java",
         "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.usb.gadget-V1.1-java",
         "android.hardware.usb.gadget-V1.2-java",
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index ec28040..d472639 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_PORT_MISMATCH;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
 import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
@@ -25,6 +27,12 @@
 import static android.hardware.usb.UsbPortStatus.MODE_UFP;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_POWER_ROLE_SOURCE;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_POWER_ROLE_SINK;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_DATA_ROLE_HOST;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_DATA_ROLE_DEVICE;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_MODE_DFP;
+import static com.android.server.usb.hal.port.UsbPortHal.HAL_MODE_UFP;
 
 import static com.android.internal.usb.DumpUtils.writePort;
 import static com.android.internal.usb.DumpUtils.writePortStatus;
@@ -38,6 +46,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbManager;
 import android.hardware.usb.UsbPort;
@@ -74,9 +83,13 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.FgThread;
+import com.android.server.usb.hal.port.RawPortInfo;
+import com.android.server.usb.hal.port.UsbPortHal;
+import com.android.server.usb.hal.port.UsbPortHalInstance;
 
 import java.util.ArrayList;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 
 /**
  * Allows trusted components to control the properties of physical USB ports
@@ -109,16 +122,9 @@
     // The system context.
     private final Context mContext;
 
-    // Proxy object for the usb hal daemon.
-    @GuardedBy("mLock")
-    private IUsb mProxy = null;
-
     // Callback when the UsbPort status is changed by the kernel.
     // Mostly due a command sent by the remote Usb device.
-    private HALCallback mHALCallback = new HALCallback(null, this);
-
-    // Cookie sent for usb hal death notification.
-    private static final int USB_HAL_DEATH_COOKIE = 1000;
+    //private HALCallback mHALCallback = new HALCallback(null, this);
 
     // Used as the key while sending the bundle to Main thread.
     private static final String PORT_INFO = "port_info";
@@ -156,36 +162,23 @@
      */
     private int mIsPortContaminatedNotificationId;
 
-    private boolean mEnableUsbDataSignaling;
-    protected int mCurrentUsbHalVersion;
+    private UsbPortHal mUsbPortHal;
+
+    private long mTransactionId;
 
     public UsbPortManager(Context context) {
         mContext = context;
-        try {
-            ServiceNotification serviceNotification = new ServiceNotification();
-
-            boolean ret = IServiceManager.getService()
-                    .registerForNotifications("android.hardware.usb@1.0::IUsb",
-                            "", serviceNotification);
-            if (!ret) {
-                logAndPrint(Log.ERROR, null,
-                        "Failed to register service start notification");
-            }
-        } catch (RemoteException e) {
-            logAndPrintException(null,
-                    "Failed to register service start notification", e);
-            return;
-        }
-        connectToProxy(null);
+        mUsbPortHal = UsbPortHalInstance.getInstance(this, null);
+        logAndPrint(Log.DEBUG, null, "getInstance done");
     }
 
     public void systemReady() {
-	mSystemReady = true;
-        if (mProxy != null) {
+        mSystemReady = true;
+        if (mUsbPortHal != null) {
+            mUsbPortHal.systemReady();
             try {
-                mProxy.queryPortStatus();
-                mEnableUsbDataSignaling = true;
-            } catch (RemoteException e) {
+                mUsbPortHal.queryPortStatus(++mTransactionId);
+            } catch (Exception e) {
                 logAndPrintException(null,
                         "ServiceStart: Failed to query port status", e);
             }
@@ -340,13 +333,9 @@
         }
 
         try {
-            // Oneway call into the hal. Use the castFrom method from HIDL.
-            android.hardware.usb.V1_2.IUsb proxy = android.hardware.usb.V1_2.IUsb.castFrom(mProxy);
-            proxy.enableContaminantPresenceDetection(portId, enable);
-        } catch (RemoteException e) {
+            mUsbPortHal.enableContaminantPresenceDetection(portId, enable, ++mTransactionId);
+        } catch (Exception e) {
             logAndPrintException(pw, "Failed to set contaminant detection", e);
-        } catch (ClassCastException e) {
-            logAndPrintException(pw, "Method only applicable to V1.2 or above implementation", e);
         }
     }
 
@@ -355,46 +344,79 @@
      *
      * @param enable enable or disable USB data signaling
      */
-    public boolean enableUsbDataSignal(boolean enable) {
-        try {
-            mEnableUsbDataSignaling = enable;
-            // Call into the hal. Use the castFrom method from HIDL.
-            android.hardware.usb.V1_3.IUsb proxy = android.hardware.usb.V1_3.IUsb.castFrom(mProxy);
-            return proxy.enableUsbDataSignal(enable);
-        } catch (RemoteException e) {
-            logAndPrintException(null, "Failed to set USB data signaling", e);
-            return false;
-        } catch (ClassCastException e) {
-            logAndPrintException(null, "Method only applicable to V1.3 or above implementation", e);
+    public boolean enableUsbData(@NonNull String portId, boolean enable, int transactionId,
+            @NonNull IUsbOperationInternal callback, IndentingPrintWriter pw) {
+        Objects.requireNonNull(callback);
+        Objects.requireNonNull(portId);
+        final PortInfo portInfo = mPorts.get(portId);
+        if (portInfo == null) {
+            logAndPrint(Log.ERROR, pw, "enableUsbData: No such port: " + portId
+                    + " opId:" + transactionId);
+            try {
+                callback.onOperationComplete(USB_OPERATION_ERROR_PORT_MISMATCH);
+            } catch (RemoteException e) {
+                logAndPrintException(pw,
+                        "enableUsbData: Failed to call OperationComplete. opId:"
+                        + transactionId, e);
+            }
             return false;
         }
+
+        try {
+            try {
+                return mUsbPortHal.enableUsbData(portId, enable, transactionId, callback);
+            } catch (Exception e) {
+                logAndPrintException(pw,
+                    "enableUsbData: Failed to invoke enableUsbData. opId:"
+                    + transactionId , e);
+                callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(pw,
+                    "enableUsbData: Failed to call onOperationComplete. opId:"
+                    + transactionId, e);
+        }
+
+        return false;
     }
 
     /**
      * Get USB HAL version
      *
      * @param none
+     * @return {@link UsbManager#USB_HAL_RETRY} returned when hal version
+     *         is yet to be determined.
      */
     public int getUsbHalVersion() {
-        return mCurrentUsbHalVersion;
+        if (mUsbPortHal != null) {
+            try {
+                return mUsbPortHal.getUsbHalVersion();
+            } catch (RemoteException e) {
+                return UsbManager.USB_HAL_RETRY;
+            }
+        }
+        return UsbManager.USB_HAL_RETRY;
     }
 
-    /**
-     * update USB HAL version
-     *
-     * @param none
-     */
-    private void updateUsbHalVersion() {
-        if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
-            mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_3;
-        } else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) {
-            mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_2;
-        } else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) {
-            mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_1;
-        } else {
-            mCurrentUsbHalVersion = UsbManager.USB_HAL_V1_0;
-        }
-        logAndPrint(Log.INFO, null, "USB HAL version: " + mCurrentUsbHalVersion);
+    private int toHalUsbDataRole(int usbDataRole) {
+        if (usbDataRole == DATA_ROLE_DEVICE)
+            return HAL_DATA_ROLE_DEVICE;
+        else
+            return HAL_DATA_ROLE_HOST;
+    }
+
+    private int toHalUsbPowerRole(int usbPowerRole) {
+        if (usbPowerRole == POWER_ROLE_SINK)
+            return HAL_POWER_ROLE_SINK;
+        else
+            return HAL_POWER_ROLE_SOURCE;
+    }
+
+    private int toHalUsbMode(int usbMode) {
+        if (usbMode == MODE_UFP)
+            return HAL_MODE_UFP;
+        else
+            return HAL_MODE_DFP;
     }
 
     public void setPortRoles(String portId, int newPowerRole, int newDataRole,
@@ -473,7 +495,7 @@
                 sim.currentPowerRole = newPowerRole;
                 sim.currentDataRole = newDataRole;
                 updatePortsLocked(pw, null);
-            } else if (mProxy != null) {
+            } else if (mUsbPortHal != null) {
                 if (currentMode != newMode) {
                     // Changing the mode will have the side-effect of also changing
                     // the power and data roles but it might take some time to apply
@@ -485,44 +507,37 @@
                     logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: "
                             + "portId=" + portId
                             + ", newMode=" + UsbPort.modeToString(newMode));
-                    PortRole newRole = new PortRole();
-                    newRole.type = PortRoleType.MODE;
-                    newRole.role = newMode;
                     try {
-                        mProxy.switchRole(portId, newRole);
-                    } catch (RemoteException e) {
+                        mUsbPortHal.switchMode(portId, toHalUsbMode(newMode), ++mTransactionId);
+                    } catch (Exception e) {
                         logAndPrintException(pw, "Failed to set the USB port mode: "
                                 + "portId=" + portId
-                                + ", newMode=" + UsbPort.modeToString(newRole.role), e);
+                                + ", newMode=" + UsbPort.modeToString(newMode), e);
                     }
                 } else {
                     // Change power and data role independently as needed.
                     if (currentPowerRole != newPowerRole) {
-                        PortRole newRole = new PortRole();
-                        newRole.type = PortRoleType.POWER_ROLE;
-                        newRole.role = newPowerRole;
                         try {
-                            mProxy.switchRole(portId, newRole);
-                        } catch (RemoteException e) {
+                            mUsbPortHal.switchPowerRole(portId, toHalUsbPowerRole(newPowerRole),
+                                    ++mTransactionId);
+                        } catch (Exception e) {
                             logAndPrintException(pw, "Failed to set the USB port power role: "
                                             + "portId=" + portId
                                             + ", newPowerRole=" + UsbPort.powerRoleToString
-                                            (newRole.role),
+                                            (newPowerRole),
                                     e);
                             return;
                         }
                     }
                     if (currentDataRole != newDataRole) {
-                        PortRole newRole = new PortRole();
-                        newRole.type = PortRoleType.DATA_ROLE;
-                        newRole.role = newDataRole;
                         try {
-                            mProxy.switchRole(portId, newRole);
-                        } catch (RemoteException e) {
+                            mUsbPortHal.switchDataRole(portId, toHalUsbDataRole(newDataRole),
+                                    ++mTransactionId);
+                        } catch (Exception e) {
                             logAndPrintException(pw, "Failed to set the USB port data role: "
                                             + "portId=" + portId
-                                            + ", newDataRole=" + UsbPort.dataRoleToString(newRole
-                                            .role),
+                                            + ", newDataRole=" + UsbPort.dataRoleToString
+                                            (newDataRole),
                                     e);
                         }
                     }
@@ -531,6 +546,15 @@
         }
     }
 
+    public void updatePorts(ArrayList<RawPortInfo> newPortInfo) {
+        Message message = mHandler.obtainMessage();
+        Bundle bundle = new Bundle();
+        bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
+        message.what = MSG_UPDATE_PORTS;
+        message.setData(bundle);
+        mHandler.sendMessage(message);
+    }
+
     public void addSimulatedPort(String portId, int supportedModes, IndentingPrintWriter pw) {
         synchronized (mLock) {
             if (mSimulatedPorts.containsKey(portId)) {
@@ -662,191 +686,12 @@
                 portInfo.dump(dump, "usb_ports", UsbPortManagerProto.USB_PORTS);
             }
 
-            dump.write("enable_usb_data_signaling", UsbPortManagerProto.ENABLE_USB_DATA_SIGNALING,
-                    mEnableUsbDataSignaling);
+            dump.write("usb_hal_version", UsbPortManagerProto.HAL_VERSION, getUsbHalVersion());
         }
 
         dump.end(token);
     }
 
-    private static class HALCallback extends IUsbCallback.Stub {
-        public IndentingPrintWriter pw;
-        public UsbPortManager portManager;
-
-        HALCallback(IndentingPrintWriter pw, UsbPortManager portManager) {
-            this.pw = pw;
-            this.portManager = portManager;
-        }
-
-        public void notifyPortStatusChange(
-                ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
-            if (!portManager.mSystemReady) {
-                return;
-            }
-
-            if (retval != Status.SUCCESS) {
-                logAndPrint(Log.ERROR, pw, "port status enquiry failed");
-                return;
-            }
-
-            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
-
-            for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
-                RawPortInfo temp = new RawPortInfo(current.portName,
-                        current.supportedModes, CONTAMINANT_PROTECTION_NONE,
-                        current.currentMode,
-                        current.canChangeMode, current.currentPowerRole,
-                        current.canChangePowerRole,
-                        current.currentDataRole, current.canChangeDataRole,
-                        false, CONTAMINANT_PROTECTION_NONE,
-                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
-                newPortInfo.add(temp);
-                logAndPrint(Log.INFO, pw, "ClientCallback V1_0: " + current.portName);
-            }
-
-            Message message = portManager.mHandler.obtainMessage();
-            Bundle bundle = new Bundle();
-            bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
-            message.what = MSG_UPDATE_PORTS;
-            message.setData(bundle);
-            portManager.mHandler.sendMessage(message);
-        }
-
-
-        public void notifyPortStatusChange_1_1(ArrayList<PortStatus_1_1> currentPortStatus,
-                int retval) {
-            if (!portManager.mSystemReady) {
-                return;
-            }
-
-            if (retval != Status.SUCCESS) {
-                logAndPrint(Log.ERROR, pw, "port status enquiry failed");
-                return;
-            }
-
-            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
-
-            int numStatus = currentPortStatus.size();
-            for (int i = 0; i < numStatus; i++) {
-                PortStatus_1_1 current = currentPortStatus.get(i);
-                RawPortInfo temp = new RawPortInfo(current.status.portName,
-                        current.supportedModes, CONTAMINANT_PROTECTION_NONE,
-                        current.currentMode,
-                        current.status.canChangeMode, current.status.currentPowerRole,
-                        current.status.canChangePowerRole,
-                        current.status.currentDataRole, current.status.canChangeDataRole,
-                        false, CONTAMINANT_PROTECTION_NONE,
-                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
-                newPortInfo.add(temp);
-                logAndPrint(Log.INFO, pw, "ClientCallback V1_1: " + current.status.portName);
-            }
-
-            Message message = portManager.mHandler.obtainMessage();
-            Bundle bundle = new Bundle();
-            bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
-            message.what = MSG_UPDATE_PORTS;
-            message.setData(bundle);
-            portManager.mHandler.sendMessage(message);
-        }
-
-        public void notifyPortStatusChange_1_2(
-                ArrayList<PortStatus> currentPortStatus, int retval) {
-            if (!portManager.mSystemReady) {
-                return;
-            }
-
-            if (retval != Status.SUCCESS) {
-                logAndPrint(Log.ERROR, pw, "port status enquiry failed");
-                return;
-            }
-
-            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
-
-            int numStatus = currentPortStatus.size();
-            for (int i = 0; i < numStatus; i++) {
-                PortStatus current = currentPortStatus.get(i);
-                RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
-                        current.status_1_1.supportedModes,
-                        current.supportedContaminantProtectionModes,
-                        current.status_1_1.currentMode,
-                        current.status_1_1.status.canChangeMode,
-                        current.status_1_1.status.currentPowerRole,
-                        current.status_1_1.status.canChangePowerRole,
-                        current.status_1_1.status.currentDataRole,
-                        current.status_1_1.status.canChangeDataRole,
-                        current.supportsEnableContaminantPresenceProtection,
-                        current.contaminantProtectionStatus,
-                        current.supportsEnableContaminantPresenceDetection,
-                        current.contaminantDetectionStatus);
-                newPortInfo.add(temp);
-                logAndPrint(Log.INFO, pw, "ClientCallback V1_2: "
-                        + current.status_1_1.status.portName);
-            }
-
-            Message message = portManager.mHandler.obtainMessage();
-            Bundle bundle = new Bundle();
-            bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
-            message.what = MSG_UPDATE_PORTS;
-            message.setData(bundle);
-            portManager.mHandler.sendMessage(message);
-        }
-
-        public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
-            if (retval == Status.SUCCESS) {
-                logAndPrint(Log.INFO, pw, portName + " role switch successful");
-            } else {
-                logAndPrint(Log.ERROR, pw, portName + " role switch failed");
-            }
-        }
-    }
-
-    final class DeathRecipient implements HwBinder.DeathRecipient {
-        public IndentingPrintWriter pw;
-
-        DeathRecipient(IndentingPrintWriter pw) {
-            this.pw = pw;
-        }
-
-        @Override
-        public void serviceDied(long cookie) {
-            if (cookie == USB_HAL_DEATH_COOKIE) {
-                logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
-                synchronized (mLock) {
-                    mProxy = null;
-                }
-            }
-        }
-    }
-
-    final class ServiceNotification extends IServiceNotification.Stub {
-        @Override
-        public void onRegistration(String fqName, String name, boolean preexisting) {
-            logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
-            connectToProxy(null);
-        }
-    }
-
-    private void connectToProxy(IndentingPrintWriter pw) {
-        synchronized (mLock) {
-            if (mProxy != null) {
-                return;
-            }
-
-            try {
-                mProxy = IUsb.getService();
-                mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
-                mProxy.setCallback(mHALCallback);
-                mProxy.queryPortStatus();
-                updateUsbHalVersion();
-            } catch (NoSuchElementException e) {
-                logAndPrintException(pw, "connectToProxy: usb hal service not found."
-                        + " Did the service fail to start?", e);
-            } catch (RemoteException e) {
-                logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
-            }
-        }
-    }
-
     /**
      * Simulated ports directly add the new roles to mSimulatedPorts before calling.
      * USB hal callback populates and sends the newPortInfo.
@@ -869,7 +714,8 @@
                         portInfo.supportsEnableContaminantPresenceProtection,
                         portInfo.contaminantProtectionStatus,
                         portInfo.supportsEnableContaminantPresenceDetection,
-                        portInfo.contaminantDetectionStatus, pw);
+                        portInfo.contaminantDetectionStatus,
+                        portInfo.usbDataEnabled, pw);
             }
         } else {
             for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -881,7 +727,8 @@
                         currentPortInfo.supportsEnableContaminantPresenceProtection,
                         currentPortInfo.contaminantProtectionStatus,
                         currentPortInfo.supportsEnableContaminantPresenceDetection,
-                        currentPortInfo.contaminantDetectionStatus, pw);
+                        currentPortInfo.contaminantDetectionStatus,
+                        currentPortInfo.usbDataEnabled, pw);
             }
         }
 
@@ -917,6 +764,7 @@
             int contaminantProtectionStatus,
             boolean supportsEnableContaminantPresenceDetection,
             int contaminantDetectionStatus,
+            boolean usbDataEnabled,
             IndentingPrintWriter pw) {
         // Only allow mode switch capability for dual role ports.
         // Validate that the current mode matches the supported modes we expect.
@@ -975,7 +823,7 @@
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
-                    contaminantDetectionStatus);
+                    contaminantDetectionStatus, usbDataEnabled);
             mPorts.put(portId, portInfo);
         } else {
             // Validate that ports aren't changing definition out from under us.
@@ -1012,7 +860,7 @@
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
-                    contaminantDetectionStatus)) {
+                    contaminantDetectionStatus, usbDataEnabled)) {
                 portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
             } else {
                 portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1141,14 +989,14 @@
         }
     }
 
-    private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+    public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
         Slog.println(priority, TAG, msg);
         if (pw != null) {
             pw.println(msg);
         }
     }
 
-    private static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
+    public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
         Slog.e(TAG, msg, e);
         if (pw != null) {
             pw.println(msg + e);
@@ -1179,7 +1027,7 @@
     /**
      * Describes a USB port.
      */
-    private static final class PortInfo {
+    public static final class PortInfo {
         public static final int DISPOSITION_ADDED = 0;
         public static final int DISPOSITION_CHANGED = 1;
         public static final int DISPOSITION_READY = 2;
@@ -1224,7 +1072,7 @@
                     != supportedRoleCombinations) {
                 mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                         supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
-                        UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED);
+                        UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED, true);
                 dispositionChanged = true;
             }
 
@@ -1243,7 +1091,7 @@
                 int currentPowerRole, boolean canChangePowerRole,
                 int currentDataRole, boolean canChangeDataRole,
                 int supportedRoleCombinations, int contaminantProtectionStatus,
-                int contaminantDetectionStatus) {
+                int contaminantDetectionStatus, boolean usbDataEnabled) {
             boolean dispositionChanged = false;
 
             mCanChangeMode = canChangeMode;
@@ -1258,10 +1106,12 @@
                     || mUsbPortStatus.getContaminantProtectionStatus()
                     != contaminantProtectionStatus
                     || mUsbPortStatus.getContaminantDetectionStatus()
-                    != contaminantDetectionStatus) {
+                    != contaminantDetectionStatus
+                    || mUsbPortStatus.getUsbDataStatus()
+                    != usbDataEnabled){
                 mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                         supportedRoleCombinations, contaminantProtectionStatus,
-                        contaminantDetectionStatus);
+                        contaminantDetectionStatus, usbDataEnabled);
                 dispositionChanged = true;
             }
 
@@ -1290,7 +1140,6 @@
                     UsbPortInfoProto.CONNECTED_AT_MILLIS, mConnectedAtMillis);
             dump.write("last_connect_duration_millis",
                     UsbPortInfoProto.LAST_CONNECT_DURATION_MILLIS, mLastConnectDurationMillis);
-
             dump.end(token);
         }
 
@@ -1304,115 +1153,4 @@
                     + ", lastConnectDurationMillis=" + mLastConnectDurationMillis;
         }
     }
-
-    /**
-     * Used for storing the raw data from the kernel
-     * Values of the member variables mocked directly incase of emulation.
-     */
-    private static final class RawPortInfo implements Parcelable {
-        public final String portId;
-        public final int supportedModes;
-        public final int supportedContaminantProtectionModes;
-        public int currentMode;
-        public boolean canChangeMode;
-        public int currentPowerRole;
-        public boolean canChangePowerRole;
-        public int currentDataRole;
-        public boolean canChangeDataRole;
-        public boolean supportsEnableContaminantPresenceProtection;
-        public int contaminantProtectionStatus;
-        public boolean supportsEnableContaminantPresenceDetection;
-        public int contaminantDetectionStatus;
-
-        RawPortInfo(String portId, int supportedModes) {
-            this.portId = portId;
-            this.supportedModes = supportedModes;
-            this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
-            this.supportsEnableContaminantPresenceProtection = false;
-            this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
-            this.supportsEnableContaminantPresenceDetection = false;
-            this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
-        }
-
-        RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
-                int currentMode, boolean canChangeMode,
-                int currentPowerRole, boolean canChangePowerRole,
-                int currentDataRole, boolean canChangeDataRole,
-                boolean supportsEnableContaminantPresenceProtection,
-                int contaminantProtectionStatus,
-                boolean supportsEnableContaminantPresenceDetection,
-                int contaminantDetectionStatus) {
-            this.portId = portId;
-            this.supportedModes = supportedModes;
-            this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
-            this.currentMode = currentMode;
-            this.canChangeMode = canChangeMode;
-            this.currentPowerRole = currentPowerRole;
-            this.canChangePowerRole = canChangePowerRole;
-            this.currentDataRole = currentDataRole;
-            this.canChangeDataRole = canChangeDataRole;
-            this.supportsEnableContaminantPresenceProtection =
-                    supportsEnableContaminantPresenceProtection;
-            this.contaminantProtectionStatus = contaminantProtectionStatus;
-            this.supportsEnableContaminantPresenceDetection =
-                    supportsEnableContaminantPresenceDetection;
-            this.contaminantDetectionStatus = contaminantDetectionStatus;
-        }
-
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(portId);
-            dest.writeInt(supportedModes);
-            dest.writeInt(supportedContaminantProtectionModes);
-            dest.writeInt(currentMode);
-            dest.writeByte((byte) (canChangeMode ? 1 : 0));
-            dest.writeInt(currentPowerRole);
-            dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
-            dest.writeInt(currentDataRole);
-            dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
-            dest.writeBoolean(supportsEnableContaminantPresenceProtection);
-            dest.writeInt(contaminantProtectionStatus);
-            dest.writeBoolean(supportsEnableContaminantPresenceDetection);
-            dest.writeInt(contaminantDetectionStatus);
-        }
-
-        public static final Parcelable.Creator<RawPortInfo> CREATOR =
-                new Parcelable.Creator<RawPortInfo>() {
-            @Override
-            public RawPortInfo createFromParcel(Parcel in) {
-                String id = in.readString();
-                int supportedModes = in.readInt();
-                int supportedContaminantProtectionModes = in.readInt();
-                int currentMode = in.readInt();
-                boolean canChangeMode = in.readByte() != 0;
-                int currentPowerRole = in.readInt();
-                boolean canChangePowerRole = in.readByte() != 0;
-                int currentDataRole = in.readInt();
-                boolean canChangeDataRole = in.readByte() != 0;
-                boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
-                int contaminantProtectionStatus = in.readInt();
-                boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
-                int contaminantDetectionStatus = in.readInt();
-                return new RawPortInfo(id, supportedModes,
-                        supportedContaminantProtectionModes, currentMode, canChangeMode,
-                        currentPowerRole, canChangePowerRole,
-                        currentDataRole, canChangeDataRole,
-                        supportsEnableContaminantPresenceProtection,
-                        contaminantProtectionStatus,
-                        supportsEnableContaminantPresenceDetection,
-                        contaminantDetectionStatus);
-            }
-
-            @Override
-            public RawPortInfo[] newArray(int size) {
-                return new RawPortInfo[size];
-            }
-        };
-    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 3d3538d..28227fc 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
 import static android.hardware.usb.UsbPortStatus.MODE_DFP;
@@ -35,6 +36,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.hardware.usb.IUsbManager;
+import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
@@ -44,6 +46,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.usb.UsbServiceDumpProto;
@@ -762,19 +765,30 @@
     }
 
     @Override
-    public boolean enableUsbDataSignal(boolean enable) {
+    public boolean enableUsbData(String portId, boolean enable, int operationId,
+            IUsbOperationInternal callback) {
+        Objects.requireNonNull(portId, "enableUsbData: portId must not be null. opId:"
+                + operationId);
+        Objects.requireNonNull(callback, "enableUsbData: callback must not be null. opId:"
+                + operationId);
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-
         final long ident = Binder.clearCallingIdentity();
+        boolean wait;
         try {
             if (mPortManager != null) {
-                return mPortManager.enableUsbDataSignal(enable);
+                wait = mPortManager.enableUsbData(portId, enable, operationId, callback, null);
             } else {
-                return false;
+                wait = false;
+                try {
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "enableUsbData: Failed to call onOperationComplete", e);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
+        return wait;
     }
 
     @Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
new file mode 100644
index 0000000..9c6cbbd
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.hal.port;
+
+import android.hardware.usb.UsbPortStatus;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Used for storing the raw data from the HAL.
+ * Values of the member variables mocked directly in case of emulation.
+ */
+public final class RawPortInfo implements Parcelable {
+    public final String portId;
+    public final int supportedModes;
+    public final int supportedContaminantProtectionModes;
+    public int currentMode;
+    public boolean canChangeMode;
+    public int currentPowerRole;
+    public boolean canChangePowerRole;
+    public int currentDataRole;
+    public boolean canChangeDataRole;
+    public boolean supportsEnableContaminantPresenceProtection;
+    public int contaminantProtectionStatus;
+    public boolean supportsEnableContaminantPresenceDetection;
+    public int contaminantDetectionStatus;
+    public boolean usbDataEnabled;
+
+    public RawPortInfo(String portId, int supportedModes) {
+        this.portId = portId;
+        this.supportedModes = supportedModes;
+        this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+        this.supportsEnableContaminantPresenceProtection = false;
+        this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+        this.supportsEnableContaminantPresenceDetection = false;
+        this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
+        this.usbDataEnabled = true;
+    }
+
+    public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
+            int currentMode, boolean canChangeMode,
+            int currentPowerRole, boolean canChangePowerRole,
+            int currentDataRole, boolean canChangeDataRole,
+            boolean supportsEnableContaminantPresenceProtection,
+            int contaminantProtectionStatus,
+            boolean supportsEnableContaminantPresenceDetection,
+            int contaminantDetectionStatus,
+            boolean usbDataEnabled) {
+        this.portId = portId;
+        this.supportedModes = supportedModes;
+        this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
+        this.currentMode = currentMode;
+        this.canChangeMode = canChangeMode;
+        this.currentPowerRole = currentPowerRole;
+        this.canChangePowerRole = canChangePowerRole;
+        this.currentDataRole = currentDataRole;
+        this.canChangeDataRole = canChangeDataRole;
+        this.supportsEnableContaminantPresenceProtection =
+                supportsEnableContaminantPresenceProtection;
+        this.contaminantProtectionStatus = contaminantProtectionStatus;
+        this.supportsEnableContaminantPresenceDetection =
+                supportsEnableContaminantPresenceDetection;
+        this.contaminantDetectionStatus = contaminantDetectionStatus;
+        this.usbDataEnabled = usbDataEnabled;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(portId);
+        dest.writeInt(supportedModes);
+        dest.writeInt(supportedContaminantProtectionModes);
+        dest.writeInt(currentMode);
+        dest.writeByte((byte) (canChangeMode ? 1 : 0));
+        dest.writeInt(currentPowerRole);
+        dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
+        dest.writeInt(currentDataRole);
+        dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
+        dest.writeBoolean(supportsEnableContaminantPresenceProtection);
+        dest.writeInt(contaminantProtectionStatus);
+        dest.writeBoolean(supportsEnableContaminantPresenceDetection);
+        dest.writeInt(contaminantDetectionStatus);
+        dest.writeBoolean(usbDataEnabled);
+    }
+
+    public static final Parcelable.Creator<RawPortInfo> CREATOR =
+            new Parcelable.Creator<RawPortInfo>() {
+        @Override
+        public RawPortInfo createFromParcel(Parcel in) {
+            String id = in.readString();
+            int supportedModes = in.readInt();
+            int supportedContaminantProtectionModes = in.readInt();
+            int currentMode = in.readInt();
+            boolean canChangeMode = in.readByte() != 0;
+            int currentPowerRole = in.readInt();
+            boolean canChangePowerRole = in.readByte() != 0;
+            int currentDataRole = in.readInt();
+            boolean canChangeDataRole = in.readByte() != 0;
+            boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
+            int contaminantProtectionStatus = in.readInt();
+            boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
+            int contaminantDetectionStatus = in.readInt();
+            boolean usbDataEnabled = in.readBoolean();
+            return new RawPortInfo(id, supportedModes,
+                    supportedContaminantProtectionModes, currentMode, canChangeMode,
+                    currentPowerRole, canChangePowerRole,
+                    currentDataRole, canChangeDataRole,
+                    supportsEnableContaminantPresenceProtection,
+                    contaminantProtectionStatus,
+                    supportsEnableContaminantPresenceDetection,
+                    contaminantDetectionStatus, usbDataEnabled);
+        }
+
+        @Override
+        public RawPortInfo[] newArray(int size) {
+            return new RawPortInfo[size];
+        }
+    };
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
new file mode 100644
index 0000000..1efcd9c
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.hal.port;
+
+import static android.hardware.usb.UsbManager.USB_HAL_V2_0;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+import static com.android.server.usb.UsbPortManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.ContaminantProtectionStatus;
+import android.hardware.usb.IUsb;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.PortMode;
+import android.hardware.usb.Status;
+import android.hardware.usb.IUsbCallback;
+import android.hardware.usb.PortRole;
+import android.hardware.usb.PortStatus;
+import android.os.ServiceManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbPortManager;
+import com.android.server.usb.hal.port.RawPortInfo;
+
+import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * Implements the methods to interact with AIDL USB HAL.
+ */
+public final class UsbPortAidl implements UsbPortHal {
+    private static final String TAG = UsbPortAidl.class.getSimpleName();
+    private static final String USB_AIDL_SERVICE =
+            "android.hardware.usb.IUsb/default";
+    private static final LongSparseArray<IUsbOperationInternal>
+                sCallbacks = new LongSparseArray<>();
+    // Proxy object for the usb hal daemon.
+    @GuardedBy("mLock")
+    private IUsb mProxy;
+    private UsbPortManager mPortManager;
+    public IndentingPrintWriter mPw;
+    // Mutex for all mutable shared state.
+    private final Object mLock = new Object();
+    // Callback when the UsbPort status is changed by the kernel.
+    private HALCallback mHALCallback;
+    private IBinder mBinder;
+    private boolean mSystemReady;
+    private long mTransactionId;
+
+    public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                throw new RemoteException("IUsb not initialized yet");
+            }
+        }
+        logAndPrint(Log.INFO, null, "USB HAL AIDL version: USB_HAL_V2_0");
+        return USB_HAL_V2_0;
+    }
+
+    @Override
+    public void systemReady() {
+        mSystemReady = true;
+    }
+
+    public void serviceDied() {
+        logAndPrint(Log.ERROR, mPw, "Usb AIDL hal service died");
+        synchronized (mLock) {
+            mProxy = null;
+        }
+        connectToProxy(null);
+    }
+
+    private void connectToProxy(IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            if (mProxy != null) {
+                return;
+            }
+
+            try {
+                mBinder = ServiceManager.waitForService(USB_AIDL_SERVICE);
+                mProxy = IUsb.Stub.asInterface(mBinder);
+                mBinder.linkToDeath(this::serviceDied, 0);
+                mProxy.setCallback(mHALCallback);
+                mProxy.queryPortStatus(++mTransactionId);
+            } catch (NoSuchElementException e) {
+                logAndPrintException(pw, "connectToProxy: usb hal service not found."
+                        + " Did the service fail to start?", e);
+            } catch (RemoteException e) {
+                logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
+            }
+        }
+    }
+
+    static boolean isServicePresent(IndentingPrintWriter pw) {
+        try {
+            return ServiceManager.isDeclared(USB_AIDL_SERVICE);
+        } catch (NoSuchElementException e) {
+            logAndPrintException(pw, "connectToProxy: usb Aidl hal service not found.", e);
+        }
+
+        return false;
+    }
+
+    public UsbPortAidl(UsbPortManager portManager, IndentingPrintWriter pw) {
+        mPortManager = Objects.requireNonNull(portManager);
+        mPw = pw;
+        mHALCallback = new HALCallback(null, mPortManager, this);
+        connectToProxy(mPw);
+    }
+
+    @Override
+    public void enableContaminantPresenceDetection(String portName, boolean enable,
+            long operationID) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID: "
+                        + operationID);
+                return;
+            }
+
+            try {
+                // Oneway call into the hal. Use the castFrom method from HIDL.
+                mProxy.enableContaminantPresenceDetection(portName, enable, operationID);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set contaminant detection. opID:"
+                        + operationID, e);
+            }
+        }
+    }
+
+    @Override
+    public void queryPortStatus(long operationID) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+                        + operationID);
+                return;
+            }
+
+            try {
+                mProxy.queryPortStatus(operationID);
+            } catch (RemoteException e) {
+                logAndPrintException(null, "ServiceStart: Failed to query port status. opID:"
+                        + operationID, e);
+            }
+       }
+    }
+
+    @Override
+    public void switchMode(String portId, @HalUsbPortMode int newMode, long operationID) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+                        + operationID);
+                return;
+            }
+
+            PortRole newRole = new PortRole();
+            newRole.setMode((byte)newMode);
+            try {
+                mProxy.switchRole(portId, newRole, operationID);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set the USB port mode: "
+                        + "portId=" + portId
+                        + ", newMode=" + UsbPort.modeToString(newMode)
+                        + "opID:" + operationID, e);
+            }
+        }
+    }
+
+    @Override
+    public void switchPowerRole(String portId, @HalUsbPowerRole int newPowerRole,
+            long operationID) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+                        + operationID);
+                return;
+            }
+
+            PortRole newRole = new PortRole();
+            newRole.setPowerRole((byte)newPowerRole);
+            try {
+                mProxy.switchRole(portId, newRole, operationID);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set the USB power role: portId=" + portId
+                        + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+                        + "opID:" + operationID, e);
+            }
+        }
+    }
+
+    @Override
+    public void switchDataRole(String portId, @HalUsbDataRole int newDataRole, long operationID) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry ! opID:"
+                        + operationID);
+                return;
+            }
+
+            PortRole newRole = new PortRole();
+            newRole.setDataRole((byte)newDataRole);
+            try {
+                mProxy.switchRole(portId, newRole, operationID);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set the USB data role: portId=" + portId
+                        + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)
+                        + "opID:" + operationID, e);
+            }
+        }
+    }
+
+    @Override
+    public boolean enableUsbData(String portName, boolean enable, long operationID,
+            IUsbOperationInternal callback) {
+        Objects.requireNonNull(portName);
+        Objects.requireNonNull(callback);
+        long key = operationID;
+        synchronized (mLock) {
+            try {
+                if (mProxy == null) {
+                    logAndPrint(Log.ERROR, mPw,
+                            "enableUsbData: Proxy is null. Retry !opID:"
+                            + operationID);
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                    return false;
+                }
+                while (sCallbacks.get(key) != null) {
+                    key = ThreadLocalRandom.current().nextInt();
+                }
+                if (key != operationID) {
+                    logAndPrint(Log.INFO, mPw, "enableUsbData: operationID exists ! opID:"
+                            + operationID + " key:" + key);
+                }
+                try {
+                    sCallbacks.put(key, callback);
+                    mProxy.enableUsbData(portName, enable, key);
+                } catch (RemoteException e) {
+                    logAndPrintException(mPw,
+                            "enableUsbData: Failed to invoke enableUsbData: portID="
+                            + portName + "opID:" + operationID, e);
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                    sCallbacks.remove(key);
+                    return false;
+                }
+            } catch (RemoteException e) {
+                logAndPrintException(mPw,
+                        "enableUsbData: Failed to call onOperationComplete portID="
+                        + portName + "opID:" + operationID, e);
+                sCallbacks.remove(key);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private static class HALCallback extends IUsbCallback.Stub {
+        public IndentingPrintWriter mPw;
+        public UsbPortManager mPortManager;
+        public UsbPortAidl mUsbPortAidl;
+
+        HALCallback(IndentingPrintWriter pw, UsbPortManager portManager, UsbPortAidl usbPortAidl) {
+            this.mPw = pw;
+            this.mPortManager = portManager;
+            this.mUsbPortAidl = usbPortAidl;
+        }
+
+        /**
+         * Converts from AIDL defined mode constants to UsbPortStatus constants.
+         * AIDL does not gracefully support bitfield when combined with enums.
+         */
+        private int toPortMode(byte aidlPortMode) {
+            switch (aidlPortMode) {
+                case PortMode.NONE:
+                    return UsbPortStatus.MODE_NONE;
+                case PortMode.UFP:
+                    return UsbPortStatus.MODE_UFP;
+                case PortMode.DFP:
+                    return UsbPortStatus.MODE_DFP;
+                case PortMode.DRP:
+                    return UsbPortStatus.MODE_DUAL;
+                case PortMode.AUDIO_ACCESSORY:
+                    return UsbPortStatus.MODE_AUDIO_ACCESSORY;
+                case PortMode.DEBUG_ACCESSORY:
+                    return UsbPortStatus.MODE_DEBUG_ACCESSORY;
+                default:
+                    UsbPortManager.logAndPrint(Log.ERROR, mPw, "Unrecognized aidlPortMode:"
+                            + aidlPortMode);
+                    return UsbPortStatus.MODE_NONE;
+            }
+        }
+
+        private int toSupportedModes(byte[] aidlPortModes) {
+            int supportedModes = UsbPortStatus.MODE_NONE;
+
+            for (byte aidlPortMode : aidlPortModes) {
+                supportedModes |= toPortMode(aidlPortMode);
+            }
+
+            return supportedModes;
+        }
+
+        /**
+         * Converts from AIDL defined contaminant protection constants to UsbPortStatus constants.
+         * AIDL does not gracefully support bitfield when combined with enums.
+         * Common to both ContaminantProtectionMode and ContaminantProtectionStatus.
+         */
+        private int toContaminantProtectionStatus(byte aidlContaminantProtection) {
+            switch (aidlContaminantProtection) {
+                case ContaminantProtectionStatus.NONE:
+                    return UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+                case ContaminantProtectionStatus.FORCE_SINK:
+                    return UsbPortStatus.CONTAMINANT_PROTECTION_SINK;
+                case ContaminantProtectionStatus.FORCE_SOURCE:
+                    return UsbPortStatus.CONTAMINANT_PROTECTION_SOURCE;
+                case ContaminantProtectionStatus.FORCE_DISABLE:
+                    return UsbPortStatus.CONTAMINANT_PROTECTION_FORCE_DISABLE;
+                case ContaminantProtectionStatus.DISABLED:
+                    return UsbPortStatus.CONTAMINANT_PROTECTION_DISABLED;
+                default:
+                    UsbPortManager.logAndPrint(Log.ERROR, mPw,
+                            "Unrecognized aidlContaminantProtection:"
+                            + aidlContaminantProtection);
+                    return UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+            }
+        }
+
+        private int toSupportedContaminantProtectionModes(byte[] aidlModes) {
+            int supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+
+            for (byte aidlMode : aidlModes) {
+                supportedContaminantProtectionModes |= toContaminantProtectionStatus(aidlMode);
+            }
+
+            return supportedContaminantProtectionModes;
+        }
+
+        @Override
+        public void notifyPortStatusChange(
+               android.hardware.usb.PortStatus[] currentPortStatus, int retval) {
+            if (!mUsbPortAidl.mSystemReady) {
+                return;
+            }
+
+            if (retval != Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+                return;
+            }
+
+            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+            int numStatus = currentPortStatus.length;
+            for (int i = 0; i < numStatus; i++) {
+                PortStatus current = currentPortStatus[i];
+                RawPortInfo temp = new RawPortInfo(current.portName,
+                        toSupportedModes(current.supportedModes),
+                        toSupportedContaminantProtectionModes(current
+                                .supportedContaminantProtectionModes),
+                        toPortMode(current.currentMode),
+                        current.canChangeMode,
+                        current.currentPowerRole,
+                        current.canChangePowerRole,
+                        current.currentDataRole,
+                        current.canChangeDataRole,
+                        current.supportsEnableContaminantPresenceProtection,
+                        toContaminantProtectionStatus(current.contaminantProtectionStatus),
+                        current.supportsEnableContaminantPresenceDetection,
+                        current.contaminantDetectionStatus,
+                        current.usbDataEnabled);
+                newPortInfo.add(temp);
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback AIDL V1: "
+                        + current.portName);
+            }
+            mPortManager.updatePorts(newPortInfo);
+        }
+
+        @Override
+        public void notifyRoleSwitchStatus(String portName, PortRole role, int retval,
+                long operationID) {
+            if (retval == Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.INFO, mPw, portName
+                        + " role switch successful. opID:"
+                        + operationID);
+            } else {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + " role switch failed. err:"
+                        + retval
+                        + "opID:" + operationID);
+            }
+        }
+
+        @Override
+        public void notifyQueryPortStatus(String portName, int retval, long operationID) {
+            if (retval == Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.INFO, mPw, portName + ": opID:"
+                        + operationID + " successful");
+            } else {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + ": opID:"
+                        + operationID + " failed. err:" + retval);
+            }
+        }
+
+        @Override
+        public void notifyEnableUsbDataStatus(String portName, boolean enable, int retval,
+                long operationID) {
+            if (retval == Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyEnableUsbDataStatus:"
+                        + portName + ": opID:"
+                        + operationID + " enable:" + enable);
+            } else {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+                        + "notifyEnableUsbDataStatus: opID:"
+                        + operationID + " failed. err:" + retval);
+            }
+            try {
+                sCallbacks.get(operationID).onOperationComplete(retval == Status.SUCCESS
+                        ? USB_OPERATION_SUCCESS
+                        : USB_OPERATION_ERROR_INTERNAL);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw,
+                        "notifyEnableUsbDataStatus: Failed to call onOperationComplete",
+                        e);
+            }
+        }
+
+        @Override
+        public void notifyContaminantEnabledStatus(String portName, boolean enable, int retval,
+                long operationID) {
+            if (retval == Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyContaminantEnabledStatus:"
+                        + portName + ": opID:"
+                        + operationID + " enable:" + enable);
+            } else {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+                        + "notifyContaminantEnabledStatus: opID:"
+                        + operationID + " failed. err:" + retval);
+            }
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return IUsbCallback.HASH;
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return IUsbCallback.VERSION;
+        }
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
new file mode 100644
index 0000000..e7f9bc2
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.hal.port;
+
+import android.annotation.IntDef;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.os.RemoteException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.String;
+
+/**
+ * @hide
+ */
+public interface UsbPortHal {
+    /**
+     * Power role: This USB port can act as a source (provide power).
+     * @hide
+     */
+    public static final int HAL_POWER_ROLE_SOURCE = 1;
+
+    /**
+     * Power role: This USB port can act as a sink (receive power).
+     * @hide
+     */
+    public static final int HAL_POWER_ROLE_SINK = 2;
+
+    @IntDef(prefix = { "HAL_POWER_ROLE_" }, value = {
+            HAL_POWER_ROLE_SOURCE,
+            HAL_POWER_ROLE_SINK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalUsbPowerRole{}
+
+    /**
+     * Data role: This USB port can act as a host (access data services).
+     * @hide
+     */
+    public static final int HAL_DATA_ROLE_HOST = 1;
+
+    /**
+     * Data role: This USB port can act as a device (offer data services).
+     * @hide
+     */
+    public static final int HAL_DATA_ROLE_DEVICE = 2;
+
+    @IntDef(prefix = { "HAL_DATA_ROLE_" }, value = {
+            HAL_DATA_ROLE_HOST,
+            HAL_DATA_ROLE_DEVICE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalUsbDataRole{}
+
+    /**
+     * This USB port can act as a downstream facing port (host).
+     *
+     * @hide
+     */
+    public static final int HAL_MODE_DFP = 1;
+
+    /**
+     * This USB port can act as an upstream facing port (device).
+     *
+     * @hide
+     */
+    public static final int HAL_MODE_UFP = 2;
+    @IntDef(prefix = { "HAL_MODE_" }, value = {
+            HAL_MODE_DFP,
+            HAL_MODE_UFP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalUsbPortMode{}
+
+    /**
+     * UsbPortManager would call this when the system is done booting.
+     */
+    public void systemReady();
+
+    /**
+     * Invoked to enable/disable contaminant presence detection on the USB port.
+     *
+     * @param portName Port Identifier.
+     * @param enable Enable contaminant presence detection when true.
+     *               Disable when false.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void enableContaminantPresenceDetection(String portName, boolean enable,
+            long transactionId);
+
+    /**
+     * Invoked to query port status of all the ports.
+     *
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void queryPortStatus(long transactionId);
+
+    /**
+     * Invoked to switch USB port mode.
+     *
+     * @param portName Port Identifier.
+     * @param mode New mode that the port is switching into.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void switchMode(String portName, @HalUsbPortMode int mode, long transactionId);
+
+    /**
+     * Invoked to switch USB port power role.
+     *
+     * @param portName Port Identifier.
+     * @param powerRole New power role that the port is switching into.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void switchPowerRole(String portName, @HalUsbPowerRole int powerRole,
+            long transactionId);
+
+    /**
+     * Invoked to switch USB port data role.
+     *
+     * @param portName Port Identifier.
+     * @param dataRole New data role that the port is switching into.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void switchDataRole(String portName, @HalUsbDataRole int dataRole, long transactionId);
+
+    /**
+     * Invoked to query the version of current hal implementation.
+     */
+    public @UsbHalVersion int getUsbHalVersion() throws RemoteException;
+
+    /**
+     * Invoked to enable/disable UsbData on the specified port.
+     *
+     * @param portName Port Identifier.
+     * @param enable Enable USB data when true.
+     *               Disable when false.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     * @param callback callback object to be invoked to invoke the status of the operation upon
+     *                 completion.
+     * @param callback callback object to be invoked when the operation is complete.
+     * @return True when the operation is asynchronous. The caller of
+     *         {@link UsbOperationCallbackInternal} must therefore call
+     *         {@link UsbOperationCallbackInternal#waitForOperationComplete} for processing
+     *         the result.
+     *         False when the operation is synchronous. Caller can proceed reading the result
+     *         through {@link UsbOperationCallbackInternal#getStatus}
+     */
+    public boolean enableUsbData(String portName, boolean enable, long transactionId,
+            IUsbOperationInternal callback);
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java
new file mode 100644
index 0000000..41f9fae
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHalInstance.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.hal.port;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.hal.port.UsbPortHidl;
+import com.android.server.usb.hal.port.UsbPortAidl;
+import com.android.server.usb.UsbPortManager;
+
+import android.util.Log;
+/**
+ * Helper class that queries the underlying hal layer to populate UsbPortHal instance.
+ */
+public final class UsbPortHalInstance {
+
+    public static UsbPortHal getInstance(UsbPortManager portManager, IndentingPrintWriter pw) {
+
+        logAndPrint(Log.DEBUG, null, "Querying USB HAL version");
+        if (UsbPortHidl.isServicePresent(null)) {
+            logAndPrint(Log.INFO, null, "USB HAL HIDL present");
+            return new UsbPortHidl(portManager, pw);
+        }
+        if (UsbPortAidl.isServicePresent(null)) {
+            logAndPrint(Log.INFO, null, "USB HAL AIDL present");
+            return new UsbPortAidl(portManager, pw);
+        }
+
+        return null;
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
new file mode 100644
index 0000000..00d0d06
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.hal.port;
+
+import static android.hardware.usb.UsbManager.USB_HAL_NOT_SUPPORTED;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_0;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_1;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_2;
+import static android.hardware.usb.UsbManager.USB_HAL_V1_3;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_ERROR_NOT_SUPPORTED;
+import static android.hardware.usb.UsbOperationInternal.USB_OPERATION_SUCCESS;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.MODE_DFP;
+import static android.hardware.usb.UsbPortStatus.MODE_DUAL;
+import static android.hardware.usb.UsbPortStatus.MODE_UFP;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+import static com.android.server.usb.UsbPortManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.V1_0.IUsb;
+import android.hardware.usb.V1_0.PortRoleType;
+import android.hardware.usb.V1_0.Status;
+import android.hardware.usb.V1_1.PortStatus_1_1;
+import android.hardware.usb.V1_2.IUsbCallback;
+import android.hardware.usb.V1_0.PortRole;
+import android.hardware.usb.V1_2.PortStatus;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IHwBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbPortManager;
+import com.android.server.usb.hal.port.RawPortInfo;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+/**
+ *
+ */
+public final class UsbPortHidl implements UsbPortHal {
+    private static final String TAG = UsbPortHidl.class.getSimpleName();
+    // Cookie sent for usb hal death notification.
+    private static final int USB_HAL_DEATH_COOKIE = 1000;
+    // Proxy object for the usb hal daemon.
+    @GuardedBy("mLock")
+    private IUsb mProxy;
+    private UsbPortManager mPortManager;
+    public IndentingPrintWriter mPw;
+    // Mutex for all mutable shared state.
+    private final Object mLock = new Object();
+    // Callback when the UsbPort status is changed by the kernel.
+    private HALCallback mHALCallback;
+    private boolean mSystemReady;
+    // Workaround since HIDL HAL versions report UsbDataEnabled status in UsbPortStatus;
+    private static boolean sUsbDataEnabled = true;
+
+    public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
+        int version;
+        synchronized(mLock) {
+            if (mProxy == null) {
+                throw new RemoteException("IUsb not initialized yet");
+            }
+            if (android.hardware.usb.V1_3.IUsb.castFrom(mProxy) != null) {
+                version = USB_HAL_V1_3;
+            } else if (android.hardware.usb.V1_2.IUsb.castFrom(mProxy) != null) {
+                version = USB_HAL_V1_2;
+            } else if (android.hardware.usb.V1_1.IUsb.castFrom(mProxy) != null) {
+                version = USB_HAL_V1_1;
+            } else {
+                version = USB_HAL_V1_0;
+            }
+            logAndPrint(Log.INFO, null, "USB HAL HIDL version: " + version);
+            return version;
+        }
+    }
+
+    final class DeathRecipient implements IHwBinder.DeathRecipient {
+        public IndentingPrintWriter pw;
+
+        DeathRecipient(IndentingPrintWriter pw) {
+            this.pw = pw;
+        }
+
+        @Override
+        public void serviceDied(long cookie) {
+            if (cookie == USB_HAL_DEATH_COOKIE) {
+                logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
+                synchronized (mLock) {
+                    mProxy = null;
+                }
+            }
+        }
+    }
+
+    final class ServiceNotification extends IServiceNotification.Stub {
+        @Override
+        public void onRegistration(String fqName, String name, boolean preexisting) {
+            logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
+            connectToProxy(null);
+        }
+    }
+
+    private void connectToProxy(IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            if (mProxy != null) {
+                return;
+            }
+
+            try {
+                mProxy = IUsb.getService();
+                mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
+                mProxy.setCallback(mHALCallback);
+                mProxy.queryPortStatus();
+                //updateUsbHalVersion();
+            } catch (NoSuchElementException e) {
+                logAndPrintException(pw, "connectToProxy: usb hal service not found."
+                        + " Did the service fail to start?", e);
+            } catch (RemoteException e) {
+                logAndPrintException(pw, "connectToProxy: usb hal service not responding", e);
+            }
+        }
+    }
+
+    @Override
+    public void systemReady() {
+        mSystemReady = true;
+    }
+
+    static boolean isServicePresent(IndentingPrintWriter pw) {
+        try {
+            IUsb.getService(true);
+        } catch (NoSuchElementException e) {
+            logAndPrintException(pw, "connectToProxy: usb hidl hal service not found.", e);
+            return false;
+        } catch (RemoteException e) {
+            logAndPrintException(pw, "IUSB hal service present but failed to get service", e);
+        }
+
+        return true;
+    }
+
+    public UsbPortHidl(UsbPortManager portManager, IndentingPrintWriter pw) {
+        mPortManager = Objects.requireNonNull(portManager);
+        mPw = pw;
+        mHALCallback = new HALCallback(null, mPortManager, this);
+        try {
+            ServiceNotification serviceNotification = new ServiceNotification();
+
+            boolean ret = IServiceManager.getService()
+                    .registerForNotifications("android.hardware.usb@1.0::IUsb",
+                            "", serviceNotification);
+            if (!ret) {
+                logAndPrint(Log.ERROR, null,
+                        "Failed to register service start notification");
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(null,
+                    "Failed to register service start notification", e);
+            return;
+        }
+        connectToProxy(mPw);
+    }
+
+    @Override
+    public void enableContaminantPresenceDetection(String portName, boolean enable,
+            long transactionId) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+                return;
+            }
+
+            try {
+                // Oneway call into the hal. Use the castFrom method from HIDL.
+                android.hardware.usb.V1_2.IUsb proxy =
+                        android.hardware.usb.V1_2.IUsb.castFrom(mProxy);
+                proxy.enableContaminantPresenceDetection(portName, enable);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set contaminant detection", e);
+            } catch (ClassCastException e)  {
+                logAndPrintException(mPw, "Method only applicable to V1.2 or above implementation",
+                    e);
+            }
+        }
+    }
+
+    @Override
+    public void queryPortStatus(long transactionId) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+                return;
+            }
+
+            try {
+                mProxy.queryPortStatus();
+            } catch (RemoteException e) {
+                logAndPrintException(null, "ServiceStart: Failed to query port status", e);
+            }
+       }
+    }
+
+    @Override
+    public void switchMode(String portId, @HalUsbPortMode int newMode, long transactionId) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+                return;
+            }
+
+            PortRole newRole = new PortRole();
+            newRole.type = PortRoleType.MODE;
+            newRole.role = newMode;
+            try {
+                mProxy.switchRole(portId, newRole);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set the USB port mode: "
+                    + "portId=" + portId
+                    + ", newMode=" + UsbPort.modeToString(newRole.role), e);
+            }
+        }
+    }
+
+    @Override
+    public void switchPowerRole(String portId, @HalUsbPowerRole int newPowerRole,
+            long transactionId) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+                return;
+            }
+
+            PortRole newRole = new PortRole();
+            newRole.type = PortRoleType.POWER_ROLE;
+            newRole.role = newPowerRole;
+            try {
+                mProxy.switchRole(portId, newRole);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set the USB power role: portId=" + portId
+                    + ", newPowerRole=" + UsbPort.powerRoleToString(newRole.role), e);
+            }
+        }
+    }
+
+    @Override
+    public void switchDataRole(String portId, @HalUsbDataRole int newDataRole, long transactionId) {
+        synchronized (mLock) {
+            if (mProxy == null) {
+                logAndPrint(Log.ERROR, mPw, "Proxy is null. Retry !");
+                return;
+            }
+
+            PortRole newRole = new PortRole();
+            newRole.type = PortRoleType.DATA_ROLE;
+            newRole.role = newDataRole;
+            try {
+                mProxy.switchRole(portId, newRole);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to set the USB data role: portId=" + portId
+                    + ", newDataRole=" + UsbPort.dataRoleToString(newRole.role), e);
+            }
+        }
+    }
+
+    @Override
+    public boolean enableUsbData(String portName, boolean enable, long transactionId,
+            IUsbOperationInternal callback) {
+        int halVersion;
+
+        try {
+            halVersion = getUsbHalVersion();
+        } catch (RemoteException e) {
+            logAndPrintException(mPw, "Failed to query USB HAL version. opID:"
+                    + transactionId
+                    + " portId:" + portName, e);
+            return false;
+        }
+
+        if (halVersion != USB_HAL_V1_3) {
+            try {
+                callback.onOperationComplete(USB_OPERATION_ERROR_NOT_SUPPORTED);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+                        + transactionId
+                        + " portId:" + portName, e);
+            }
+            return false;
+        }
+
+        boolean success;
+        synchronized(mLock) {
+            try {
+                android.hardware.usb.V1_3.IUsb proxy
+                        = android.hardware.usb.V1_3.IUsb.castFrom(mProxy);
+                success = proxy.enableUsbDataSignal(enable);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw, "Failed enableUsbData: opId:" + transactionId
+                        + " portId=" + portName , e);
+                try {
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                } catch (RemoteException r) {
+                    logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+                            + transactionId
+                            + " portId:" + portName, r);
+                }
+                return false;
+            }
+        }
+        if (success) {
+            sUsbDataEnabled = enable;
+        }
+
+        try {
+            callback.onOperationComplete(success
+                    ? USB_OPERATION_SUCCESS
+                    : USB_OPERATION_ERROR_INTERNAL);
+        } catch (RemoteException r) {
+            logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+                + transactionId
+                + " portId:" + portName, r);
+        }
+        return false;
+    }
+
+    private static class HALCallback extends IUsbCallback.Stub {
+        public IndentingPrintWriter mPw;
+        public UsbPortManager mPortManager;
+        public UsbPortHidl mUsbPortHidl;
+
+        HALCallback(IndentingPrintWriter pw, UsbPortManager portManager, UsbPortHidl usbPortHidl) {
+            this.mPw = pw;
+            this.mPortManager = portManager;
+            this.mUsbPortHidl = usbPortHidl;
+        }
+
+        public void notifyPortStatusChange(
+                ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
+            if (!mUsbPortHidl.mSystemReady) {
+                return;
+            }
+
+            if (retval != Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+                return;
+            }
+
+            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+            for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
+                RawPortInfo temp = new RawPortInfo(current.portName,
+                        current.supportedModes, CONTAMINANT_PROTECTION_NONE,
+                        current.currentMode,
+                        current.canChangeMode, current.currentPowerRole,
+                        current.canChangePowerRole,
+                        current.currentDataRole, current.canChangeDataRole,
+                        false, CONTAMINANT_PROTECTION_NONE,
+                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataEnabled);
+                newPortInfo.add(temp);
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
+                        + current.portName);
+            }
+
+            mPortManager.updatePorts(newPortInfo);
+        }
+
+
+        public void notifyPortStatusChange_1_1(ArrayList<PortStatus_1_1> currentPortStatus,
+                int retval) {
+            if (!mUsbPortHidl.mSystemReady) {
+                return;
+            }
+
+            if (retval != Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+                return;
+            }
+
+            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+            int numStatus = currentPortStatus.size();
+            for (int i = 0; i < numStatus; i++) {
+                PortStatus_1_1 current = currentPortStatus.get(i);
+                RawPortInfo temp = new RawPortInfo(current.status.portName,
+                        current.supportedModes, CONTAMINANT_PROTECTION_NONE,
+                        current.currentMode,
+                        current.status.canChangeMode, current.status.currentPowerRole,
+                        current.status.canChangePowerRole,
+                        current.status.currentDataRole, current.status.canChangeDataRole,
+                        false, CONTAMINANT_PROTECTION_NONE,
+                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataEnabled);
+                newPortInfo.add(temp);
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
+                        + current.status.portName);
+            }
+            mPortManager.updatePorts(newPortInfo);
+        }
+
+        public void notifyPortStatusChange_1_2(
+                ArrayList<PortStatus> currentPortStatus, int retval) {
+            if (!mUsbPortHidl.mSystemReady) {
+                return;
+            }
+
+            if (retval != Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, "port status enquiry failed");
+                return;
+            }
+
+            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+            int numStatus = currentPortStatus.size();
+            for (int i = 0; i < numStatus; i++) {
+                PortStatus current = currentPortStatus.get(i);
+                RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
+                        current.status_1_1.supportedModes,
+                        current.supportedContaminantProtectionModes,
+                        current.status_1_1.currentMode,
+                        current.status_1_1.status.canChangeMode,
+                        current.status_1_1.status.currentPowerRole,
+                        current.status_1_1.status.canChangePowerRole,
+                        current.status_1_1.status.currentDataRole,
+                        current.status_1_1.status.canChangeDataRole,
+                        current.supportsEnableContaminantPresenceProtection,
+                        current.contaminantProtectionStatus,
+                        current.supportsEnableContaminantPresenceDetection,
+                        current.contaminantDetectionStatus,
+                        sUsbDataEnabled);
+                newPortInfo.add(temp);
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
+                        + current.status_1_1.status.portName);
+            }
+            mPortManager.updatePorts(newPortInfo);
+        }
+
+        public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
+            if (retval == Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.INFO, mPw, portName + " role switch successful");
+            } else {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, portName + " role switch failed");
+            }
+        }
+    }
+}
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 7ea4ab1..0aca293 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@
 
 static ApiVersion sDevelopmentSdkLevel = 10000;
 static const auto sDevelopmentSdkCodeNames =
-    std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu"});
+    std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu", "UpsideDownCake"});
 
 static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
     {0x021c, 1},