Support IUsb AIDL interface

UsbPortManager is made to support both AIDL & HIDL interface until
HIDL is deprecated eventually. UsbPortHal abstract class is defined
which the UsbPortManager grabs an instance of from UsbPortHalInstance
method to talk to the Hal implementation process. UsbPortHalInstance
queries the underlying hal implementation and instantiates UsbPortHal
with either UsbPortHidl or UsbPortAidl based on the IUsb interface
implemented by HAL implementation.

go/iusb-aidl-migrate.

Bug: 200993386
Bug: 199357330
Bug: 211677613
Bug: 213312081
Bug: 199358576
Test: Manually tested through UI.
CTS-Coverage-Bug: 215019881
Change-Id: I246fd6e5bee8138d3ad3b6994665a1d4788c8789
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 70bb13a..25ea0b0 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -113,10 +113,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 45fac2e..0c8ee6e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4686,8 +4686,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 c29a948..03eb461 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;
 
 /**
@@ -517,6 +520,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}
@@ -557,6 +568,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}
      */
@@ -665,6 +684,7 @@
             USB_HAL_V1_1,
             USB_HAL_V1_2,
             USB_HAL_V1_3,
+            USB_HAL_V2_0,
     })
     public @interface UsbHalVersion {}
 
@@ -1169,8 +1189,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
@@ -1181,11 +1202,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;
     }
 
     /**
@@ -1271,6 +1292,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/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/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 97097ff..c27aab5 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -196,9 +196,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 {
@@ -254,6 +264,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/services/usb/Android.bp b/services/usb/Android.bp
index 01feacd..3b50fa4 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..6f91a2a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -0,0 +1,466 @@
+/*
+ * 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);
+            }
+        }
+    }
+}
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");
+            }
+        }
+    }
+}