Merge "Support extraData in SpaLogger API."
diff --git a/Android.bp b/Android.bp
index 4e7eba2..3d25bc1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -100,7 +100,7 @@
         ":android.hardware.gnss-V2-java-source",
         ":android.hardware.graphics.common-V3-java-source",
         ":android.hardware.keymaster-V4-java-source",
-        ":android.hardware.security.keymint-V2-java-source",
+        ":android.hardware.security.keymint-V3-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
         ":android.hardware.tv.tuner-V1-java-source",
         ":android.security.apc-java-source",
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index bb31c11..b2300ce 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -89,7 +89,7 @@
     // If the overlay supplies a target overlayable name, the resource must belong to the
     // overlayable defined with the specified name to be overlaid.
     return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
-                 overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
+                 overlay_info.target_name.c_str(), (*overlayable_info)->name.data());
   }
 
   // Enforce policy restrictions if the resource is declared as overlayable.
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 7d80493..26e20f6 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -29,12 +29,18 @@
 import java.util.function.Consumer;
 import java.util.concurrent.Executor;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class UsbCommand extends Svc.Command {
     public UsbCommand() {
         super("usb");
     }
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     @Override
     public String shortHelp() {
         return "Control Usb state";
@@ -92,8 +98,10 @@
 
             if ("setFunctions".equals(args[1])) {
                 try {
+                    int operationId = sUsbOperationCount.incrementAndGet();
+                    System.out.println("setCurrentFunctions opId:" + operationId);
                     usbMgr.setCurrentFunctions(UsbManager.usbFunctionsFromString(
-                            args.length >= 3 ? args[2] : ""));
+                            args.length >= 3 ? args[2] : ""), operationId);
                 } catch (RemoteException e) {
                     System.err.println("Error communicating with UsbManager: " + e);
                 }
diff --git a/core/api/current.txt b/core/api/current.txt
index a03a753..787370a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6969,6 +6969,7 @@
     method @Deprecated public void onStart(android.content.Intent, int);
     method public int onStartCommand(android.content.Intent, int, int);
     method public void onTaskRemoved(android.content.Intent);
+    method public void onTimeout(int);
     method public void onTrimMemory(int);
     method public boolean onUnbind(android.content.Intent);
     method public final void startForeground(int, android.app.Notification);
@@ -12475,6 +12476,7 @@
     field @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL}, anyOf={android.Manifest.permission.MANAGE_OWN_CALLS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4
     field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 512; // 0x200
+    field public static final int FOREGROUND_SERVICE_TYPE_SHORT_SERVICE = 2048; // 0x800
     field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1073741824; // 0x40000000
     field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1024; // 0x400
     field public int flags;
@@ -15481,7 +15483,6 @@
   }
 
   public static class PathIterator.Segment {
-    ctor public PathIterator.Segment(@NonNull int, @NonNull float[], float);
     method public float getConicWeight();
     method @NonNull public float[] getPoints();
     method @NonNull public int getVerb();
@@ -48693,6 +48694,7 @@
     method public float getRefreshRate();
     method public int getRotation();
     method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
+    method @NonNull public android.view.DisplayShape getShape();
     method @Deprecated public void getSize(android.graphics.Point);
     method public int getState();
     method public android.view.Display.Mode[] getSupportedModes();
@@ -48773,6 +48775,13 @@
     method @NonNull public android.view.DisplayCutout.Builder setWaterfallInsets(@NonNull android.graphics.Insets);
   }
 
+  public final class DisplayShape implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.Path getPath();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.DisplayShape> CREATOR;
+  }
+
   public final class DragAndDropPermissions implements android.os.Parcelable {
     method public int describeContents();
     method public void release();
@@ -52154,6 +52163,7 @@
     method @Deprecated @NonNull public android.view.WindowInsets consumeStableInsets();
     method @Deprecated @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
     method @Nullable public android.view.DisplayCutout getDisplayCutout();
+    method @Nullable public android.view.DisplayShape getDisplayShape();
     method @NonNull public android.graphics.Insets getInsets(int);
     method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
     method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
@@ -52189,6 +52199,7 @@
     ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
     method @NonNull public android.view.WindowInsets build();
     method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+    method @NonNull public android.view.WindowInsets.Builder setDisplayShape(@NonNull android.view.DisplayShape);
     method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
     method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b6e2d2a..3228ce6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -121,6 +121,7 @@
     field public static final int GADGET_HAL_V1_0 = 10; // 0xa
     field public static final int GADGET_HAL_V1_1 = 11; // 0xb
     field public static final int GADGET_HAL_V1_2 = 12; // 0xc
+    field public static final int GADGET_HAL_V2_0 = 20; // 0x14
     field public static final int USB_DATA_TRANSFER_RATE_10G = 10240; // 0x2800
     field public static final int USB_DATA_TRANSFER_RATE_20G = 20480; // 0x5000
     field public static final int USB_DATA_TRANSFER_RATE_40G = 40960; // 0xa000
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c10504d..c47e3b2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12873,14 +12873,14 @@
     method @NonNull public android.telephony.BarringInfo createLocationInfoSanitizedCopy();
   }
 
-  public final class CallAttributes implements android.os.Parcelable {
-    ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
-    method public int describeContents();
-    method @NonNull public android.telephony.CallQuality getCallQuality();
-    method public int getNetworkType();
-    method @NonNull public android.telephony.PreciseCallState getPreciseCallState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
+  @Deprecated public final class CallAttributes implements android.os.Parcelable {
+    ctor @Deprecated public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.telephony.CallQuality getCallQuality();
+    method @Deprecated public int getNetworkType();
+    method @Deprecated @NonNull public android.telephony.PreciseCallState getPreciseCallState();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
   }
 
   public final class CallForwardingInfo implements android.os.Parcelable {
@@ -12960,6 +12960,28 @@
     method @NonNull public android.telephony.CallQuality.Builder setUplinkCallQualityLevel(int);
   }
 
+  public final class CallState implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.telephony.CallQuality getCallQuality();
+    method public int getCallState();
+    method public int getImsCallServiceType();
+    method @Nullable public String getImsCallSessionId();
+    method public int getImsCallType();
+    method public int getNetworkType();
+    method public void writeToParcel(@Nullable android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallState> CREATOR;
+  }
+
+  public static final class CallState.Builder {
+    ctor public CallState.Builder(int);
+    method @NonNull public android.telephony.CallState build();
+    method @NonNull public android.telephony.CallState.Builder setCallQuality(@Nullable android.telephony.CallQuality);
+    method @NonNull public android.telephony.CallState.Builder setImsCallServiceType(int);
+    method @NonNull public android.telephony.CallState.Builder setImsCallSessionId(@Nullable String);
+    method @NonNull public android.telephony.CallState.Builder setImsCallType(int);
+    method @NonNull public android.telephony.CallState.Builder setNetworkType(int);
+  }
+
   public class CarrierConfigManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName();
     method @NonNull public static android.os.PersistableBundle getDefaultConfig();
@@ -13710,7 +13732,8 @@
   }
 
   public static interface TelephonyCallback.CallAttributesListener {
-    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List<android.telephony.CallState>);
   }
 
   public static interface TelephonyCallback.DataEnabledListener {
@@ -14811,6 +14834,7 @@
     field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
     field public static final int CALL_RESTRICT_CAUSE_NONE = 0; // 0x0
     field public static final int CALL_RESTRICT_CAUSE_RAT = 1; // 0x1
+    field public static final int CALL_TYPE_NONE = 0; // 0x0
     field public static final int CALL_TYPE_VIDEO_N_VOICE = 3; // 0x3
     field public static final int CALL_TYPE_VOICE = 2; // 0x2
     field public static final int CALL_TYPE_VOICE_N_VIDEO = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 725cef6..984e822 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1039,6 +1039,7 @@
     method @NonNull public static android.util.Pair<java.util.List<android.graphics.Typeface>,java.util.List<android.graphics.Typeface>> changeDefaultFontForTest(@NonNull java.util.List<android.graphics.Typeface>, @NonNull java.util.List<android.graphics.Typeface>);
     method @NonNull public static long[] deserializeFontMap(@NonNull java.nio.ByteBuffer, @NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws java.io.IOException;
     method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory();
+    method public void releaseNativeObjectForTest();
     method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException;
   }
 
@@ -2887,6 +2888,10 @@
     method @NonNull public android.view.Display.Mode.Builder setResolution(int, int);
   }
 
+  public final class DisplayShape implements android.os.Parcelable {
+    method @NonNull public static android.view.DisplayShape fromSpecString(@NonNull String, float, int, int);
+  }
+
   public class FocusFinder {
     method public static void sort(android.view.View[], int, int, android.view.ViewGroup, boolean);
   }
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 6d7a161..3a7d483 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -1128,12 +1128,10 @@
 
     /**
      * Callback called on timeout for {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
+     * See {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE} for more details.
      *
-     * TODO Implement it
-     * TODO Javadoc
-     *
-     * @param startId
-     * @hide
+     * @param startId the startId passed to {@link #onStartCommand(Intent, int, int)} when
+     * the service started.
      */
     public void onTimeout(int startId) {
     }
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 812f6b0..ed1f6a2 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -17,6 +17,7 @@
 package android.content.om;
 
 import android.annotation.NonNull;
+import android.annotation.NonUiContext;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -25,12 +26,16 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.content.om.OverlayManagerImpl;
+
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -76,6 +81,7 @@
 
     private final IOverlayManager mService;
     private final Context mContext;
+    private final OverlayManagerImpl mOverlayManagerImpl;
 
     /**
      * Pre R a {@link java.lang.SecurityException} would only be thrown by setEnabled APIs (e
@@ -117,6 +123,7 @@
     public OverlayManager(Context context, IOverlayManager service) {
         mContext = context;
         mService = service;
+        mOverlayManagerImpl = new OverlayManagerImpl(context);
     }
 
     /** @hide */
@@ -301,6 +308,17 @@
      * @hide
      */
     public void commit(@NonNull final OverlayManagerTransaction transaction) {
+        if (transaction.isSelfTargetingTransaction()
+                || mService == null
+                || mService.asBinder() == null) {
+            try {
+                commitSelfTarget(transaction);
+            } catch (PackageManager.NameNotFoundException | IOException e) {
+                throw new RuntimeException(e);
+            }
+            return;
+        }
+
         try {
             mService.commit(transaction);
         } catch (RemoteException e) {
@@ -332,4 +350,48 @@
             throw e;
         }
     }
+
+    /**
+     * Get a OverlayManagerTransaction.Builder to build out a overlay manager transaction.
+     *
+     * @return a builder of the overlay manager transaction.
+     * @hide
+     */
+    @NonNull
+    public OverlayManagerTransaction.Builder beginTransaction() {
+        return new OverlayManagerTransaction.Builder(this);
+    }
+
+    /**
+     * Commit the self-targeting transaction to register or unregister overlays.
+     *
+     * <p>Applications can request OverlayManager to register overlays and unregister the registered
+     * overlays via {@link OverlayManagerTransaction}.
+     *
+     * @throws IOException if there is a file operation error.
+     * @throws PackageManager.NameNotFoundException if the package name is not found.
+     * @hide
+     */
+    @NonUiContext
+    void commitSelfTarget(@NonNull final OverlayManagerTransaction transaction)
+            throws PackageManager.NameNotFoundException, IOException {
+        synchronized (mOverlayManagerImpl) {
+            mOverlayManagerImpl.commit(transaction);
+        }
+    }
+
+    /**
+     * Get the related information of overlays for {@code targetPackageName}.
+     *
+     * @param targetPackageName the target package name
+     * @return a list of overlay information
+     * @hide
+     */
+    @NonNull
+    @NonUiContext
+    public List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName) {
+        synchronized (mOverlayManagerImpl) {
+            return mOverlayManagerImpl.getOverlayInfosForTarget(targetPackageName);
+        }
+    }
 }
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
index 868dab2..42b3ef3 100644
--- a/core/java/android/content/om/OverlayManagerTransaction.java
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -20,19 +20,22 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.NonUiContext;
 import android.annotation.Nullable;
-import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * Container for a batch of requests to the OverlayManagerService.
@@ -53,13 +56,16 @@
     // TODO: remove @hide from this class when OverlayManager is added to the
     // SDK, but keep OverlayManagerTransaction.Request @hidden
     private final List<Request> mRequests;
+    private final OverlayManager mOverlayManager;
 
-    OverlayManagerTransaction(@NonNull final List<Request> requests) {
+    OverlayManagerTransaction(
+            @NonNull final List<Request> requests, @Nullable OverlayManager overlayManager) {
         checkNotNull(requests);
         if (requests.contains(null)) {
             throw new IllegalArgumentException("null request");
         }
         mRequests = requests;
+        mOverlayManager = overlayManager;
     }
 
     private OverlayManagerTransaction(@NonNull final Parcel source) {
@@ -72,6 +78,7 @@
             final Bundle extras = source.readBundle(null);
             mRequests.add(new Request(request, overlay, userId, extras));
         }
+        mOverlayManager = null;
     }
 
     @Override
@@ -156,6 +163,20 @@
      */
     public static class Builder {
         private final List<Request> mRequests = new ArrayList<>();
+        @Nullable private final OverlayManager mOverlayManager;
+
+        public Builder() {
+            mOverlayManager = null;
+        }
+
+        /**
+         * The transaction builder for self-targeting.
+         *
+         * @param overlayManager is not null if the transaction is for self-targeting.
+         */
+        Builder(@NonNull OverlayManager overlayManager) {
+            mOverlayManager = Objects.requireNonNull(overlayManager);
+        }
 
         /**
          * Request that an overlay package be enabled and change its loading
@@ -205,7 +226,10 @@
          *
          * @hide
          */
+        @NonNull
         public Builder registerFabricatedOverlay(@NonNull FabricatedOverlay overlay) {
+            Objects.requireNonNull(overlay);
+
             final Bundle extras = new Bundle();
             extras.putParcelable(Request.BUNDLE_FABRICATED_OVERLAY, overlay.mOverlay);
             mRequests.add(new Request(Request.TYPE_REGISTER_FABRICATED, overlay.getIdentifier(),
@@ -220,7 +244,10 @@
          *
          * @hide
          */
+        @NonNull
         public Builder unregisterFabricatedOverlay(@NonNull OverlayIdentifier overlay) {
+            Objects.requireNonNull(overlay);
+
             mRequests.add(new Request(Request.TYPE_UNREGISTER_FABRICATED, overlay,
                     UserHandle.USER_ALL));
             return this;
@@ -233,8 +260,9 @@
          * @see OverlayManager#commit
          * @return a new transaction
          */
+        @NonNull
         public OverlayManagerTransaction build() {
-            return new OverlayManagerTransaction(mRequests);
+            return new OverlayManagerTransaction(mRequests, mOverlayManager);
         }
     }
 
@@ -269,4 +297,23 @@
             return new OverlayManagerTransaction[size];
         }
     };
+
+    /**
+     * Commit the overlay manager transaction to register or unregister overlays for self-targeting.
+     *
+     * <p>Applications can register overlays and unregister the registered overlays via {@link
+     * OverlayManagerTransaction}.
+     *
+     * @throws IOException if there is a file operation error.
+     * @throws PackageManager.NameNotFoundException if the package name is not found.
+     * @hide
+     */
+    @NonUiContext
+    public void commit() throws PackageManager.NameNotFoundException, IOException {
+        mOverlayManager.commitSelfTarget(this);
+    }
+
+    boolean isSelfTargetingTransaction() {
+        return mOverlayManager != null;
+    }
 }
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 9e6cf62..7ea6733 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -366,24 +366,48 @@
     public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1 << 10;
 
     /**
-     * Foreground service type corresponding to {@code shortService} in
-     * the {@link android.R.attr#foregroundServiceType} attribute.
+     * A foreground service type for "short-lived" services, which corresponds to
+     * {@code shortService} in the {@link android.R.attr#foregroundServiceType} attribute in the
+     * manifest.
      *
-     * TODO Implement it
+     * <p>Unlike other foreground service types, this type is not associated with a specific use
+     * case, and it will not require any special permissions
+     * (besides {@link Manifest.permission#FOREGROUND_SERVICE}).
      *
-     * TODO Expand the javadoc
+     * However, this type has the following restrictions.
      *
-     * This type is not associated with specific use cases unlike other types, but this has
-     * unique restrictions.
      * <ul>
-     *     <li>Has a timeout
-     *     <li>Cannot start other foreground services from this
      *     <li>
+     *         The type has a 1 minute timeout.
+     *         A foreground service of this type must be stopped within the timeout by
+     *         {@link android.app.Service#stopSelf),
+     *         or {@link android.content.Context#stopService).
+     *         {@link android.app.Service#stopForeground) will also work, which will demote the
+     *         service to a "background" service, which will soon be stopped by the system.
+     *
+     *         <p>The system will <em>not</em> automatically stop it.
+     *
+     *         <p>If the service isn't stopped within the timeout,
+     *         {@link android.app.Service#onTimeout(int)} will be called.
+     *         If the service is still not stopped after the callback,
+     *         the app will be declared an ANR.
+     *
+     *     <li>
+     *         A foreground service of this type cannot be made "sticky"
+     *         (see {@link android.app.Service#START_STICKY}). That is, if an app is killed
+     *         due to a crash or out-of memory while it's running a short foregorund-service,
+     *         the system will not restart the service.
+     *     <li>
+     *         Other foreground services cannot be started from short foreground services.
+     *         Unlike other foreground service types, when an app is running in the background
+     *         while only having a "short" foreground service, it's not allowed to start
+     *         other foreground services, due to the restriction describe here:
+     *         <a href="/guide/components/foreground-services#background-start-restrictions>
+     *             Restrictions on background starts
+     *         </a>
      * </ul>
      *
-     * @see Service#onTimeout
-     *
-     * @hide
+     * @see android.app.Service#onTimeout(int)
      */
     public static final int FOREGROUND_SERVICE_TYPE_SHORT_SERVICE = 1 << 11;
 
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 51236fe3..248b5d0 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -122,10 +122,10 @@
     boolean isFunctionEnabled(String function);
 
     /* Sets the current USB function. */
-    void setCurrentFunctions(long functions);
+    void setCurrentFunctions(long functions, int operationId);
 
     /* Compatibility version of setCurrentFunctions(long). */
-    void setCurrentFunction(String function, boolean usbDataUnlocked);
+    void setCurrentFunction(String function, boolean usbDataUnlocked, int operationId);
 
     /* Gets the current USB functions. */
     long getCurrentFunctions();
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 342c336..7a8117c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
 import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -52,6 +53,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This class allows you to access the state of USB and communicate with USB devices.
@@ -95,7 +97,7 @@
      * If the sticky intent has not been found, that indicates USB is disconnected,
      * USB is not configued, MTP function is enabled, and all the other functions are disabled.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String ACTION_USB_STATE =
@@ -185,7 +187,7 @@
      * <p>For more information about communicating with USB accessory handshake, refer to
      * <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
      *
-     * {@hide}
+     * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @SystemApi
@@ -197,7 +199,7 @@
      * Boolean extra indicating whether USB is connected or disconnected.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_CONNECTED = "connected";
@@ -206,7 +208,7 @@
      * Boolean extra indicating whether USB is connected or disconnected as host.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_HOST_CONNECTED = "host_connected";
 
@@ -214,7 +216,7 @@
      * Boolean extra indicating whether USB is configured.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_CONFIGURED = "configured";
@@ -225,7 +227,7 @@
      * has explicitly asked for this data to be unlocked.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static final String USB_DATA_UNLOCKED = "unlocked";
@@ -234,7 +236,7 @@
      * A placeholder indicating that no USB function is being specified.
      * Used for compatibility with old init scripts to indicate no functions vs. charging function.
      *
-     * {@hide}
+     * @hide
      */
     @UnsupportedAppUsage
     public static final String USB_FUNCTION_NONE = "none";
@@ -243,7 +245,7 @@
      * Name of the adb USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_ADB = "adb";
 
@@ -251,7 +253,7 @@
      * Name of the RNDIS ethernet USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_FUNCTION_RNDIS = "rndis";
@@ -260,7 +262,7 @@
      * Name of the MTP USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_MTP = "mtp";
 
@@ -268,7 +270,7 @@
      * Name of the PTP USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_PTP = "ptp";
 
@@ -276,7 +278,7 @@
      * Name of the audio source USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
 
@@ -284,7 +286,7 @@
      * Name of the MIDI USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_MIDI = "midi";
 
@@ -292,7 +294,7 @@
      * Name of the Accessory USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_ACCESSORY = "accessory";
 
@@ -300,7 +302,7 @@
      * Name of the NCM USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_FUNCTION_NCM = "ncm";
@@ -308,32 +310,39 @@
     /**
      * Name of Gadget Hal Not Present;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_UNKNOWN = "unknown";
 
     /**
      * Name of the USB Gadget Hal Version v1.0;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_VERSION_1_0 = "V1_0";
 
     /**
      * Name of the USB Gadget Hal Version v1.1;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_VERSION_1_1 = "V1_1";
 
     /**
      * Name of the USB Gadget Hal Version v1.2;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_VERSION_1_2 = "V1_2";
 
     /**
+     * Name of the USB Gadget Hal Version v2.0;
+     *
+     * @hide
+     */
+    public static final String GADGET_HAL_VERSION_2_0 = "V2_0";
+
+    /**
      * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
      * containing the {@link UsbPort} object for the port.
      *
@@ -369,7 +378,7 @@
      * This is obtained with SystemClock.elapsedRealtime()
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_UEVENT_TIME =
@@ -383,7 +392,7 @@
      * between communicating with USB accessory handshake, refer to
      * <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_STRING_COUNT =
@@ -393,7 +402,7 @@
      * Boolean extra indicating whether got start accessory or not
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_START =
@@ -405,7 +414,7 @@
      * sending {@link #ACTION_USB_ACCESSORY_HANDSHAKE}.
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_HANDSHAKE_END =
@@ -439,7 +448,7 @@
     /**
      * The Value for USB gadget hal is not presented.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_NOT_SUPPORTED = -1;
@@ -447,7 +456,7 @@
     /**
      * Value for Gadget Hal Version v1.0.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_V1_0 = 10;
@@ -455,7 +464,7 @@
     /**
      * Value for Gadget Hal Version v1.1.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_V1_1 = 11;
@@ -463,15 +472,23 @@
     /**
      * Value for Gadget Hal Version v1.2.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_V1_2 = 12;
 
     /**
+     * Value for Gadget Hal Version v2.0.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int GADGET_HAL_V2_0 = 20;
+
+    /**
      * Value for USB_STATE is not configured.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1;
@@ -479,7 +496,7 @@
     /**
      * Value for USB Transfer Rate of Low Speed in Mbps (real value is 1.5Mbps).
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2;
@@ -487,7 +504,7 @@
     /**
      * Value for USB Transfer Rate of Full Speed in Mbps.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_FULL_SPEED = 12;
@@ -495,7 +512,7 @@
     /**
      * Value for USB Transfer Rate of High Speed in Mbps.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_HIGH_SPEED = 480;
@@ -503,7 +520,7 @@
     /**
      * Value for USB Transfer Rate of Super Speed in Mbps.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_5G = 5 * 1024;
@@ -511,7 +528,7 @@
     /**
      * Value for USB Transfer Rate of 10G.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_10G = 10 * 1024;
@@ -519,7 +536,7 @@
     /**
      * Value for USB Transfer Rate of 20G.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_20G = 20 * 1024;
@@ -527,7 +544,7 @@
     /**
      * Value for USB Transfer Rate of 40G.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
@@ -543,7 +560,7 @@
     /**
      * The Value for USB hal is not presented.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_NOT_SUPPORTED = -1;
@@ -551,7 +568,7 @@
     /**
      * Value for USB Hal Version v1.0.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_0 = 10;
@@ -559,7 +576,7 @@
     /**
      * Value for USB Hal Version v1.1.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_1 = 11;
@@ -567,7 +584,7 @@
     /**
      * Value for USB Hal Version v1.2.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_2 = 12;
@@ -575,7 +592,7 @@
     /**
      * Value for USB Hal Version v1.3.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_3 = 13;
@@ -590,63 +607,63 @@
 
     /**
      * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_NONE = 0;
 
     /**
      * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_MTP = GadgetFunction.MTP;
 
     /**
      * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_PTP = GadgetFunction.PTP;
 
     /**
      * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
 
     /**
      * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_MIDI = GadgetFunction.MIDI;
 
     /**
      * Code for the accessory usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;
 
     /**
      * Code for the audio source usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
 
     /**
      * Code for the adb usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_ADB = GadgetFunction.ADB;
 
     /**
      * Code for the ncm source usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_NCM = 1 << 10;
@@ -656,6 +673,11 @@
 
     private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     static {
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MTP, FUNCTION_MTP);
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_PTP, FUNCTION_PTP);
@@ -687,6 +709,7 @@
             GADGET_HAL_V1_0,
             GADGET_HAL_V1_1,
             GADGET_HAL_V1_2,
+            GADGET_HAL_V2_0,
     })
     public @interface UsbGadgetHalVersion {}
 
@@ -705,7 +728,7 @@
     private final IUsbManager mService;
 
     /**
-     * {@hide}
+     * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UsbManager(Context context, IUsbManager service) {
@@ -816,7 +839,7 @@
      * {@link #FUNCTION_PTP} are supported.
      * @return A ParcelFileDescriptor holding the valid fd, or null if the fd was not found.
      *
-     * {@hide}
+     * @hide
      */
     public ParcelFileDescriptor getControlFd(long function) {
         try {
@@ -977,7 +1000,7 @@
      * Only system components can call this function.
      * @param device to request permissions for
      *
-     * {@hide}
+     * @hide
      */
     public void grantPermission(UsbDevice device) {
         grantPermission(device, Process.myUid());
@@ -989,7 +1012,7 @@
      * @param device to request permissions for
      * @uid uid to give permission
      *
-     * {@hide}
+     * @hide
      */
     public void grantPermission(UsbDevice device, int uid) {
         try {
@@ -1005,7 +1028,7 @@
      * @param device to request permissions for
      * @param packageName of package to grant permissions
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1030,7 +1053,7 @@
      * @param function name of the USB function
      * @return true if the USB function is enabled
      *
-     * {@hide}
+     * @hide
      */
     @Deprecated
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1062,14 +1085,17 @@
      * @param functions the USB function(s) to set, as a bitwise mask.
      *                  Must satisfy {@link UsbManager#areSettableFunctions}
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
     public void setCurrentFunctions(@UsbFunctionMode long functions) {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         try {
-            mService.setCurrentFunctions(functions);
+            mService.setCurrentFunctions(functions, operationId);
         } catch (RemoteException e) {
+            Log.e(TAG, "setCurrentFunctions: failed to call setCurrentFunctions. functions:"
+                        + functions + ", opId:" + operationId, e);
             throw e.rethrowFromSystemServer();
         }
     }
@@ -1081,14 +1107,17 @@
      * @param functions the USB function(s) to set.
      * @param usbDataUnlocked unused
 
-     * {@hide}
+     * @hide
      */
     @Deprecated
     @UnsupportedAppUsage
     public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         try {
-            mService.setCurrentFunction(functions, usbDataUnlocked);
+            mService.setCurrentFunction(functions, usbDataUnlocked, operationId);
         } catch (RemoteException e) {
+            Log.e(TAG, "setCurrentFunction: failed to call setCurrentFunction. functions:"
+                        + functions + ", opId:" + operationId, e);
             throw e.rethrowFromSystemServer();
         }
     }
@@ -1103,7 +1132,7 @@
      * @return The currently enabled functions, in a bitwise mask.
      * A zero mask indicates that the current function is the charging function.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1129,7 +1158,7 @@
      * @param functions functions to set, in a bitwise mask.
      *                  Must satisfy {@link UsbManager#areSettableFunctions}
      *
-     * {@hide}
+     * @hide
      */
     public void setScreenUnlockedFunctions(long functions) {
         try {
@@ -1145,7 +1174,7 @@
      * @return The currently set screen enabled functions.
      * A zero mask indicates that the screen unlocked functions feature is not enabled.
      *
-     * {@hide}
+     * @hide
      */
     public long getScreenUnlockedFunctions() {
         try {
@@ -1167,19 +1196,17 @@
      *
      * @return The value of currently USB Bandwidth.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(Manifest.permission.MANAGE_USB)
     public int getUsbBandwidthMbps() {
         int usbSpeed;
-
         try {
             usbSpeed = mService.getCurrentUsbSpeed();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-
         return usbSpeedToBandwidth(usbSpeed);
     }
 
@@ -1191,7 +1218,7 @@
      *
      * @return a integer {@code GADGET_HAL_*} represent hal version.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1211,7 +1238,7 @@
      *
      * @return a integer {@code USB_HAL_*} represent hal version.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1507,7 +1534,7 @@
      * @param usbDeviceConnectionHandler The component to handle usb connections,
      * {@code null} to unset.
      *
-     * {@hide}
+     * @hide
      */
     public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
         try {
@@ -1526,7 +1553,7 @@
      *
      * @return Whether the mask is settable.
      *
-     * {@hide}
+     * @hide
      */
     public static boolean areSettableFunctions(long functions) {
         return functions == FUNCTION_NONE
@@ -1540,7 +1567,7 @@
      *
      * @return String representation of given mask
      *
-     * {@hide}
+     * @hide
      */
     public static String usbFunctionsToString(long functions) {
         StringJoiner joiner = new StringJoiner(",");
@@ -1576,7 +1603,7 @@
      *
      * @return A mask of all valid functions in the string
      *
-     * {@hide}
+     * @hide
      */
     public static long usbFunctionsFromString(String functions) {
         if (functions == null || functions.equals(USB_FUNCTION_NONE)) {
@@ -1598,7 +1625,7 @@
      *
      * @return a value of USB bandwidth
      *
-     * {@hide}
+     * @hide
      */
     public static int usbSpeedToBandwidth(int speed) {
         switch (speed) {
@@ -1632,12 +1659,14 @@
      *
      * @return String representation of Usb Gadget Hal Version
      *
-     * {@hide}
+     * @hide
      */
     public static @NonNull String usbGadgetHalVersionToString(int version) {
         String halVersion;
 
-        if (version == GADGET_HAL_V1_2) {
+        if (version == GADGET_HAL_V2_0) {
+            halVersion = GADGET_HAL_VERSION_2_0;
+        } else if (version == GADGET_HAL_V1_2) {
             halVersion = GADGET_HAL_VERSION_1_2;
         } else if (version == GADGET_HAL_V1_1) {
             halVersion = GADGET_HAL_VERSION_1_1;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fb66cb9..872414a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,11 +70,14 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -98,6 +101,7 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 import android.view.BatchedInputEventReceiver.SimpleBatchedInputEventReceiver;
 import android.view.Choreographer;
@@ -158,6 +162,8 @@
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.util.RingBuffer;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -730,7 +736,6 @@
         @Override
         public final void initializeInternal(@NonNull IInputMethod.InitParams params) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
-            mConfigTracker.onInitialize(params.configChanges);
             mPrivOps.set(params.privilegedOperations);
             InputMethodPrivilegedOperationsRegistry.put(params.token, mPrivOps);
             mNavigationBarController.onNavButtonFlagsChanged(params.navigationBarFlags);
@@ -1601,6 +1606,8 @@
         mHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_hideNavBarForKeyboard);
 
+        initConfigurationTracker();
+
         // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
         // for update resources & configuration correctly when show soft input
         // in non-default display.
@@ -1656,6 +1663,36 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
+    private void initConfigurationTracker() {
+        final int flags = PackageManager.GET_META_DATA
+                | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        final ComponentName imeComponent = new ComponentName(
+                getPackageName(), getClass().getName());
+        final String imeId = imeComponent.flattenToShortString();
+        final ServiceInfo si;
+        try {
+            si = getPackageManager().getServiceInfo(imeComponent,
+                    PackageManager.ComponentInfoFlags.of(flags));
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.wtf(TAG, "Unable to find input method " + imeId, e);
+            return;
+        }
+        try (XmlResourceParser parser = si.loadXmlMetaData(getPackageManager(),
+                InputMethod.SERVICE_META_DATA);
+             TypedArray sa = getResources().obtainAttributes(Xml.asAttributeSet(parser),
+                     com.android.internal.R.styleable.InputMethod)) {
+            if (parser == null) {
+                throw new XmlPullParserException(
+                        "No " + InputMethod.SERVICE_META_DATA + " meta-data");
+            }
+            final int handledConfigChanges = sa.getInt(
+                    com.android.internal.R.styleable.InputMethod_configChanges, 0);
+            mConfigTracker.onInitialize(handledConfigChanges);
+        } catch (Exception e) {
+            Log.wtf(TAG, "Unable to load input method " + imeId, e);
+        }
+    }
+
     /**
      * This is a hook that subclasses can use to perform initialization of
      * their interface.  It is called for you prior to any of your UI objects
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e5c9adb..dded76c 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -26,7 +26,6 @@
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
-import android.telephony.Annotation.CallState;
 import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.Annotation.RadioPowerState;
@@ -726,7 +725,7 @@
      */
     @Deprecated
     @RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
-    public void onCallStateChanged(@CallState int state, String phoneNumber) {
+    public void onCallStateChanged(@Annotation.CallState int state, String phoneNumber) {
         // default implementation empty
     }
 
@@ -1569,12 +1568,48 @@
                     () -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state)));
         }
 
-        public void onCallAttributesChanged(CallAttributes callAttributes) {
+        public void onCallStatesChanged(List<CallState> callStateList) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
+            if (callStateList == null) return;
+            CallAttributes ca;
+            if (callStateList.isEmpty()) {
+                ca = new CallAttributes(
+                        new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+            } else {
+                int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                for (CallState cs : callStateList) {
+                    switch (cs.getCallClassification()) {
+                        case CallState.CALL_CLASSIFICATION_FOREGROUND:
+                            foregroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_BACKGROUND:
+                            backgroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_RINGING:
+                            ringingCallState = cs.getCallState();
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                ca = new CallAttributes(
+                        new PreciseCallState(
+                                ringingCallState, foregroundCallState, backgroundCallState,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        callStateList.get(0).getNetworkType(),
+                        callStateList.get(0).getCallQuality());
+            }
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> psl.onCallAttributesChanged(callAttributes)));
+                    () -> mExecutor.execute(
+                            () -> psl.onCallAttributesChanged(ca)));
         }
 
         public void onActiveDataSubIdChanged(int subId) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index e8960b8..257f3b7 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -27,6 +27,7 @@
 import android.os.Build;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IPhoneStateListener;
@@ -62,7 +63,7 @@
  * appropriate sub-interfaces.
  */
 public class TelephonyCallback {
-
+    private static final String LOG_TAG = "TelephonyCallback";
     /**
      * Experiment flag to set the per-pid registration limit for TelephonyCallback
      *
@@ -1332,7 +1333,9 @@
     @SystemApi
     public interface CallAttributesListener {
         /**
-         * Callback invoked when the call attributes changes on the registered subscription.
+         * Callback invoked when the call attributes changes on the active call on the registered
+         * subscription. If the user swaps between a foreground and background call the call
+         * attributes will be reported for the active call only.
          * Note, the registration subscription ID comes from {@link TelephonyManager} object
          * which registers TelephonyCallback by
          * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
@@ -1346,9 +1349,77 @@
          * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
          *
          * @param callAttributes the call attributes
+         * @deprecated Use onCallStatesChanged({@link List<CallState>}) to get each of call
+         *          state for all ongoing calls on the subscription.
          */
         @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
-        void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+        @Deprecated
+        default void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
+            Log.w(LOG_TAG, "onCallAttributesChanged(List<CallState>) should be "
+                    + "overridden.");
+        }
+
+        /**
+         * Callback invoked when the call attributes changes on the ongoing calls on the registered
+         * subscription. If there are 1 foreground and 1 background call, Two {@link CallState}
+         * will be passed.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers TelephonyCallback by
+         * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         * In the event that there are no active(state is not
+         * {@link PreciseCallState#PRECISE_CALL_STATE_IDLE}) calls, this API will report empty list.
+         *
+         * The calling app should have carrier privileges
+         * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+         * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+         *
+         * @param callStateList the list of call states for each ongoing call. If there are
+         *                           a active call and a holding call, 1 call attributes for
+         *                           {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}  and another
+         *                           for {@link PreciseCallState#PRECISE_CALL_STATE_HOLDING}
+         *                           will be in this list.
+         */
+        // Added as default for backward compatibility
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        default void onCallStatesChanged(@NonNull List<CallState> callStateList) {
+            if (callStateList.size() > 0) {
+                int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                for (CallState cs : callStateList) {
+                    switch (cs.getCallClassification()) {
+                        case CallState.CALL_CLASSIFICATION_FOREGROUND:
+                            foregroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_BACKGROUND:
+                            backgroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_RINGING:
+                            ringingCallState = cs.getCallState();
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                onCallAttributesChanged(new CallAttributes(
+                        new PreciseCallState(
+                                ringingCallState, foregroundCallState, backgroundCallState,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        callStateList.get(0).getNetworkType(),
+                        callStateList.get(0).getCallQuality()));
+            } else {
+                onCallAttributesChanged(new CallAttributes(
+                        new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()));
+            }
+        }
     }
 
     /**
@@ -1702,14 +1773,13 @@
                     () -> mExecutor.execute(() -> listener.onRadioPowerStateChanged(state)));
         }
 
-        public void onCallAttributesChanged(CallAttributes callAttributes) {
+        public void onCallStatesChanged(List<CallState> callStateList) {
             CallAttributesListener listener =
                     (CallAttributesListener) mTelephonyCallbackWeakRef.get();
             if (listener == null) return;
 
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> listener.onCallAttributesChanged(
-                            callAttributes)));
+                    () -> mExecutor.execute(() -> listener.onCallStatesChanged(callStateList)));
         }
 
         public void onActiveDataSubIdChanged(int subId) {
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index a3696e3..0a1538de 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -32,13 +32,13 @@
 import android.telephony.Annotation.DataActivityType;
 import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.Annotation.NetworkType;
-import android.telephony.Annotation.PreciseCallStates;
 import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsReasonInfo;
 import android.util.ArraySet;
 import android.util.Log;
@@ -741,17 +741,20 @@
      * @param slotIndex for which precise call state changed. Can be derived from subId except when
      * subId is invalid.
      * @param subId for which precise call state changed.
-     * @param ringCallPreciseState ringCall state.
-     * @param foregroundCallPreciseState foreground call state.
-     * @param backgroundCallPreciseState background call state.
+     * @param callStates Array of PreciseCallState of foreground, background & ringing calls.
+     * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for
+     *                   ringing, foreground & background calls.
+     * @param imsServiceTypes Array of IMS call service type for ringing, foreground &
+     *                        background calls.
+     * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls.
      */
     public void notifyPreciseCallState(int slotIndex, int subId,
-            @PreciseCallStates int ringCallPreciseState,
-            @PreciseCallStates int foregroundCallPreciseState,
-            @PreciseCallStates int backgroundCallPreciseState) {
+            @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds,
+            @Annotation.ImsCallServiceType int[] imsServiceTypes,
+            @Annotation.ImsCallType int[] imsCallTypes) {
         try {
-            sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
-                foregroundCallPreciseState, backgroundCallPreciseState);
+            sRegistry.notifyPreciseCallState(slotIndex, subId, callStates,
+                    imsCallIds, imsServiceTypes, imsCallTypes);
         } catch (RemoteException ex) {
             // system process is dead
             throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index fbca373..2745858 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1009,6 +1009,28 @@
     }
 
     /**
+     * Returns the {@link DisplayShape} which is based on display coordinates.
+     *
+     * To get the {@link DisplayShape} based on the window frame, use
+     * {@link WindowInsets#getDisplayShape()} instead.
+     *
+     * @see DisplayShape
+     */
+    @SuppressLint("VisiblySynchronized")
+    @NonNull
+    public DisplayShape getShape() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            final DisplayShape displayShape = mDisplayInfo.displayShape;
+            final @Surface.Rotation int rotation = getLocalRotation();
+            if (displayShape != null && rotation != mDisplayInfo.rotation) {
+                return displayShape.setRotation(rotation);
+            }
+            return displayShape;
+        }
+    }
+
+    /**
      * Gets the pixel format of the display.
      * @return One of the constants defined in {@link android.graphics.PixelFormat}.
      *
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 0ba3072..138017c 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -323,6 +323,9 @@
     @Surface.Rotation
     public int installOrientation;
 
+    @Nullable
+    public DisplayShape displayShape;
+
     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
         @Override
         public DisplayInfo createFromParcel(Parcel source) {
@@ -395,7 +398,8 @@
                 && brightnessMaximum == other.brightnessMaximum
                 && brightnessDefault == other.brightnessDefault
                 && Objects.equals(roundedCorners, other.roundedCorners)
-                && installOrientation == other.installOrientation;
+                && installOrientation == other.installOrientation
+                && Objects.equals(displayShape, other.displayShape);
     }
 
     @Override
@@ -448,6 +452,7 @@
         brightnessDefault = other.brightnessDefault;
         roundedCorners = other.roundedCorners;
         installOrientation = other.installOrientation;
+        displayShape = other.displayShape;
     }
 
     public void readFromParcel(Parcel source) {
@@ -506,6 +511,7 @@
             userDisabledHdrTypes[i] = source.readInt();
         }
         installOrientation = source.readInt();
+        displayShape = source.readTypedObject(DisplayShape.CREATOR);
     }
 
     @Override
@@ -562,6 +568,7 @@
             dest.writeInt(userDisabledHdrTypes[i]);
         }
         dest.writeInt(installOrientation);
+        dest.writeTypedObject(displayShape, flags);
     }
 
     @Override
diff --git a/core/java/android/view/DisplayShape.aidl b/core/java/android/view/DisplayShape.aidl
new file mode 100644
index 0000000..af8b417
--- /dev/null
+++ b/core/java/android/view/DisplayShape.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.view;
+
+parcelable DisplayShape;
diff --git a/core/java/android/view/DisplayShape.java b/core/java/android/view/DisplayShape.java
new file mode 100644
index 0000000..43bd773
--- /dev/null
+++ b/core/java/android/view/DisplayShape.java
@@ -0,0 +1,357 @@
+/*
+ * 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.view;
+
+import static android.view.Surface.ROTATION_0;
+
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DisplayUtils;
+import android.util.PathParser;
+import android.util.RotationUtils;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * A class representing the shape of a display. It provides a {@link Path} of the display shape of
+ * the display shape.
+ *
+ * {@link DisplayShape} is immutable.
+ */
+public final class DisplayShape implements Parcelable {
+
+    /** @hide */
+    public static final DisplayShape NONE = new DisplayShape("" /* displayShapeSpec */,
+            0 /* displayWidth */, 0 /* displayHeight */, 0 /* physicalPixelDisplaySizeRatio */,
+            0 /* rotation */);
+
+    /** @hide */
+    @VisibleForTesting
+    public final String mDisplayShapeSpec;
+    private final float mPhysicalPixelDisplaySizeRatio;
+    private final int mDisplayWidth;
+    private final int mDisplayHeight;
+    private final int mRotation;
+    private final int mOffsetX;
+    private final int mOffsetY;
+    private final float mScale;
+
+    private DisplayShape(@NonNull String displayShapeSpec, int displayWidth, int displayHeight,
+            float physicalPixelDisplaySizeRatio, int rotation) {
+        this(displayShapeSpec, displayWidth, displayHeight, physicalPixelDisplaySizeRatio,
+                rotation, 0, 0, 1f);
+    }
+
+    private DisplayShape(@NonNull String displayShapeSpec, int displayWidth, int displayHeight,
+            float physicalPixelDisplaySizeRatio, int rotation, int offsetX, int offsetY,
+            float scale) {
+        mDisplayShapeSpec = displayShapeSpec;
+        mDisplayWidth = displayWidth;
+        mDisplayHeight = displayHeight;
+        mPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio;
+        mRotation = rotation;
+        mOffsetX = offsetX;
+        mOffsetY = offsetY;
+        mScale = scale;
+    }
+
+    /**
+     * @hide
+     */
+    @NonNull
+    public static DisplayShape fromResources(
+            @NonNull Resources res, @NonNull String displayUniqueId, int physicalDisplayWidth,
+            int physicalDisplayHeight, int displayWidth, int displayHeight) {
+        final boolean isScreenRound = RoundedCorners.getBuiltInDisplayIsRound(res, displayUniqueId);
+        final String spec = getSpecString(res, displayUniqueId);
+        if (spec == null || spec.isEmpty()) {
+            return createDefaultDisplayShape(displayWidth, displayHeight, isScreenRound);
+        }
+        final float physicalPixelDisplaySizeRatio = DisplayUtils.getPhysicalPixelDisplaySizeRatio(
+                physicalDisplayWidth, physicalDisplayHeight, displayWidth, displayHeight);
+        return fromSpecString(spec, physicalPixelDisplaySizeRatio, displayWidth, displayHeight);
+    }
+
+    /**
+     * @hide
+     */
+    @NonNull
+    public static DisplayShape createDefaultDisplayShape(
+            int displayWidth, int displayHeight, boolean isScreenRound) {
+        return fromSpecString(createDefaultSpecString(displayWidth, displayHeight, isScreenRound),
+                1f, displayWidth, displayHeight);
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public static DisplayShape fromSpecString(@NonNull String spec,
+            float physicalPixelDisplaySizeRatio, int displayWidth, int displayHeight) {
+        return Cache.getDisplayShape(spec, physicalPixelDisplaySizeRatio, displayWidth,
+                    displayHeight);
+    }
+
+    private static String createDefaultSpecString(int displayWidth, int displayHeight,
+            boolean isCircular) {
+        final String spec;
+        if (isCircular) {
+            final float xRadius = displayWidth / 2f;
+            final float yRadius = displayHeight / 2f;
+            // Draw a circular display shape.
+            spec = "M0," + yRadius
+                    // Draw upper half circle with arcTo command.
+                    + " A" + xRadius + "," + yRadius + " 0 1,1 " + displayWidth + "," + yRadius
+                    // Draw lower half circle with arcTo command.
+                    + " A" + xRadius + "," + yRadius + " 0 1,1 0," + yRadius + " Z";
+        } else {
+            // Draw a rectangular display shape.
+            spec = "M0,0"
+                    // Draw top edge.
+                    + " L" + displayWidth + ",0"
+                    // Draw right edge.
+                    + " L" + displayWidth + "," + displayHeight
+                    // Draw bottom edge.
+                    + " L0," + displayHeight
+                    // Draw left edge by close command which draws a line from current position to
+                    // the initial points (0,0).
+                    + " Z";
+        }
+        return spec;
+    }
+
+    /**
+     * Gets the display shape svg spec string of a display which is determined by the given display
+     * unique id.
+     *
+     * Loads the default config {@link R.string#config_mainDisplayShape} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static String getSpecString(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_displayShapeArray);
+        final String spec;
+        if (index >= 0 && index < array.length()) {
+            spec = array.getString(index);
+        } else {
+            spec = res.getString(R.string.config_mainDisplayShape);
+        }
+        array.recycle();
+        return spec;
+    }
+
+    /**
+     * @hide
+     */
+    public DisplayShape setRotation(int rotation) {
+        return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, rotation, mOffsetX, mOffsetY, mScale);
+    }
+
+    /**
+     * @hide
+     */
+    public DisplayShape setOffset(int offsetX, int offsetY) {
+        return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, mRotation, offsetX, offsetY, mScale);
+    }
+
+    /**
+     * @hide
+     */
+    public DisplayShape setScale(float scale) {
+        return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, mRotation, mOffsetX, mOffsetY, scale);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, mRotation, mOffsetX, mOffsetY, mScale);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof DisplayShape) {
+            DisplayShape ds = (DisplayShape) o;
+            return Objects.equals(mDisplayShapeSpec, ds.mDisplayShapeSpec)
+                    && mDisplayWidth == ds.mDisplayWidth && mDisplayHeight == ds.mDisplayHeight
+                    && mPhysicalPixelDisplaySizeRatio == ds.mPhysicalPixelDisplaySizeRatio
+                    && mRotation == ds.mRotation && mOffsetX == ds.mOffsetX
+                    && mOffsetY == ds.mOffsetY && mScale == ds.mScale;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "DisplayShape{"
+                + " spec=" + mDisplayShapeSpec
+                + " displayWidth=" + mDisplayWidth
+                + " displayHeight=" + mDisplayHeight
+                + " physicalPixelDisplaySizeRatio=" + mPhysicalPixelDisplaySizeRatio
+                + " rotation=" + mRotation
+                + " offsetX=" + mOffsetX
+                + " offsetY=" + mOffsetY
+                + " scale=" + mScale + "}";
+    }
+
+    /**
+     * Returns a {@link Path} of the display shape.
+     *
+     * @return a {@link Path} of the display shape.
+     */
+    @NonNull
+    public Path getPath() {
+        return Cache.getPath(this);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mDisplayShapeSpec);
+        dest.writeInt(mDisplayWidth);
+        dest.writeInt(mDisplayHeight);
+        dest.writeFloat(mPhysicalPixelDisplaySizeRatio);
+        dest.writeInt(mRotation);
+        dest.writeInt(mOffsetX);
+        dest.writeInt(mOffsetY);
+        dest.writeFloat(mScale);
+    }
+
+    public static final @NonNull Creator<DisplayShape> CREATOR = new Creator<DisplayShape>() {
+        @Override
+        public DisplayShape createFromParcel(Parcel in) {
+            final String spec = in.readString8();
+            final int displayWidth = in.readInt();
+            final int displayHeight = in.readInt();
+            final float ratio = in.readFloat();
+            final int rotation = in.readInt();
+            final int offsetX = in.readInt();
+            final int offsetY = in.readInt();
+            final float scale = in.readFloat();
+            return new DisplayShape(spec, displayWidth, displayHeight, ratio, rotation, offsetX,
+                    offsetY, scale);
+        }
+
+        @Override
+        public DisplayShape[] newArray(int size) {
+            return new DisplayShape[size];
+        }
+    };
+
+    private static final class Cache {
+        private static final Object CACHE_LOCK = new Object();
+
+        @GuardedBy("CACHE_LOCK")
+        private static String sCachedSpec;
+        @GuardedBy("CACHE_LOCK")
+        private static int sCachedDisplayWidth;
+        @GuardedBy("CACHE_LOCK")
+        private static int sCachedDisplayHeight;
+        @GuardedBy("CACHE_LOCK")
+        private static float sCachedPhysicalPixelDisplaySizeRatio;
+        @GuardedBy("CACHE_LOCK")
+        private static DisplayShape sCachedDisplayShape;
+
+        @GuardedBy("CACHE_LOCK")
+        private static DisplayShape sCacheForPath;
+        @GuardedBy("CACHE_LOCK")
+        private static Path sCachedPath;
+
+        static DisplayShape getDisplayShape(String spec, float physicalPixelDisplaySizeRatio,
+                int displayWidth, int displayHeight) {
+            synchronized (CACHE_LOCK) {
+                if (spec.equals(sCachedSpec)
+                        && sCachedDisplayWidth == displayWidth
+                        && sCachedDisplayHeight == displayHeight
+                        && sCachedPhysicalPixelDisplaySizeRatio == physicalPixelDisplaySizeRatio) {
+                    return sCachedDisplayShape;
+                }
+            }
+
+            final DisplayShape shape = new DisplayShape(spec, displayWidth, displayHeight,
+                    physicalPixelDisplaySizeRatio, ROTATION_0);
+
+            synchronized (CACHE_LOCK) {
+                sCachedSpec = spec;
+                sCachedDisplayWidth = displayWidth;
+                sCachedDisplayHeight = displayHeight;
+                sCachedPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio;
+                sCachedDisplayShape = shape;
+            }
+            return shape;
+        }
+
+        static Path getPath(@NonNull DisplayShape shape) {
+            synchronized (CACHE_LOCK) {
+                if (shape.equals(sCacheForPath)) {
+                    return sCachedPath;
+                }
+            }
+
+            final Path path = PathParser.createPathFromPathData(shape.mDisplayShapeSpec);
+
+            if (!path.isEmpty()) {
+                final Matrix matrix = new Matrix();
+                if (shape.mRotation != ROTATION_0) {
+                    RotationUtils.transformPhysicalToLogicalCoordinates(
+                            shape.mRotation, shape.mDisplayWidth, shape.mDisplayHeight, matrix);
+                }
+                if (shape.mPhysicalPixelDisplaySizeRatio != 1f) {
+                    matrix.preScale(shape.mPhysicalPixelDisplaySizeRatio,
+                            shape.mPhysicalPixelDisplaySizeRatio);
+                }
+                if (shape.mOffsetX != 0 || shape.mOffsetY != 0) {
+                    matrix.postTranslate(shape.mOffsetX, shape.mOffsetY);
+                }
+                if (shape.mScale != 1f) {
+                    matrix.postScale(shape.mScale, shape.mScale);
+                }
+                path.transform(matrix);
+            }
+
+            synchronized (CACHE_LOCK) {
+                sCacheForPath = shape;
+                sCachedPath = path;
+            }
+            return path;
+        }
+    }
+}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index a8cc9b6..c56d618 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -197,6 +197,9 @@
     private PrivacyIndicatorBounds mPrivacyIndicatorBounds =
             new PrivacyIndicatorBounds();
 
+    /** The display shape */
+    private DisplayShape mDisplayShape = DisplayShape.NONE;
+
     public InsetsState() {
     }
 
@@ -271,6 +274,7 @@
                 alwaysConsumeSystemBars, calculateRelativeCutout(frame),
                 calculateRelativeRoundedCorners(frame),
                 calculateRelativePrivacyIndicatorBounds(frame),
+                calculateRelativeDisplayShape(frame),
                 compatInsetsTypes, (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
     }
 
@@ -335,6 +339,16 @@
         return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
     }
 
+    private DisplayShape calculateRelativeDisplayShape(Rect frame) {
+        if (mDisplayFrame.equals(frame)) {
+            return mDisplayShape;
+        }
+        if (frame == null) {
+            return DisplayShape.NONE;
+        }
+        return mDisplayShape.setOffset(-frame.left, -frame.top);
+    }
+
     public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
         Insets insets = Insets.NONE;
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -589,6 +603,14 @@
         return mPrivacyIndicatorBounds;
     }
 
+    public void setDisplayShape(DisplayShape displayShape) {
+        mDisplayShape = displayShape;
+    }
+
+    public DisplayShape getDisplayShape() {
+        return mDisplayShape;
+    }
+
     /**
      * Modifies the state of this class to exclude a certain type to make it ready for dispatching
      * to the client.
@@ -628,6 +650,7 @@
         mRoundedCorners = mRoundedCorners.scale(scale);
         mRoundedCornerFrame.scale(scale);
         mPrivacyIndicatorBounds = mPrivacyIndicatorBounds.scale(scale);
+        mDisplayShape = mDisplayShape.setScale(scale);
         for (int i = 0; i < SIZE; i++) {
             final InsetsSource source = mSources[i];
             if (source != null) {
@@ -650,6 +673,7 @@
         mRoundedCorners = other.getRoundedCorners();
         mRoundedCornerFrame.set(other.mRoundedCornerFrame);
         mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
+        mDisplayShape = other.getDisplayShape();
         if (copySources) {
             for (int i = 0; i < SIZE; i++) {
                 InsetsSource source = other.mSources[i];
@@ -675,6 +699,7 @@
         mRoundedCorners = other.getRoundedCorners();
         mRoundedCornerFrame.set(other.mRoundedCornerFrame);
         mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
+        mDisplayShape = other.getDisplayShape();
         final ArraySet<Integer> t = toInternalType(types);
         for (int i = t.size() - 1; i >= 0; i--) {
             final int type = t.valueAt(i);
@@ -807,6 +832,7 @@
         pw.println(newPrefix + "mRoundedCorners=" + mRoundedCorners);
         pw.println(newPrefix + "mRoundedCornerFrame=" + mRoundedCornerFrame);
         pw.println(newPrefix + "mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds);
+        pw.println(newPrefix + "mDisplayShape=" + mDisplayShape);
         for (int i = 0; i < SIZE; i++) {
             InsetsSource source = mSources[i];
             if (source == null) continue;
@@ -911,7 +937,8 @@
                 || !mDisplayCutout.equals(state.mDisplayCutout)
                 || !mRoundedCorners.equals(state.mRoundedCorners)
                 || !mRoundedCornerFrame.equals(state.mRoundedCornerFrame)
-                || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)) {
+                || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)
+                || !mDisplayShape.equals(state.mDisplayShape)) {
             return false;
         }
         for (int i = 0; i < SIZE; i++) {
@@ -941,7 +968,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources),
-                mRoundedCorners, mPrivacyIndicatorBounds, mRoundedCornerFrame);
+                mRoundedCorners, mPrivacyIndicatorBounds, mRoundedCornerFrame, mDisplayShape);
     }
 
     public InsetsState(Parcel in) {
@@ -961,6 +988,7 @@
         dest.writeTypedObject(mRoundedCorners, flags);
         mRoundedCornerFrame.writeToParcel(dest, flags);
         dest.writeTypedObject(mPrivacyIndicatorBounds, flags);
+        dest.writeTypedObject(mDisplayShape, flags);
     }
 
     public static final @NonNull Creator<InsetsState> CREATOR = new Creator<InsetsState>() {
@@ -981,6 +1009,7 @@
         mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
         mRoundedCornerFrame.readFromParcel(in);
         mPrivacyIndicatorBounds = in.readTypedObject(PrivacyIndicatorBounds.CREATOR);
+        mDisplayShape = in.readTypedObject(DisplayShape.CREATOR);
     }
 
     @Override
@@ -998,6 +1027,7 @@
                 + ", mRoundedCorners=" + mRoundedCorners
                 + "  mRoundedCornerFrame=" + mRoundedCornerFrame
                 + ", mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds
+                + ", mDisplayShape=" + mDisplayShape
                 + ", mSources= { " + joiner
                 + " }";
     }
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 03b25c2..8de15c1 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -42,7 +42,6 @@
 import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Rect;
-import android.util.SparseArray;
 import android.view.View.OnApplyWindowInsetsListener;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.inputmethod.EditorInfo;
@@ -83,6 +82,7 @@
     @Nullable private final DisplayCutout mDisplayCutout;
     @Nullable private final RoundedCorners mRoundedCorners;
     @Nullable private final PrivacyIndicatorBounds mPrivacyIndicatorBounds;
+    @Nullable private final DisplayShape mDisplayShape;
 
     /**
      * In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -115,24 +115,9 @@
     public static final @NonNull WindowInsets CONSUMED;
 
     static {
-        CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
-    }
-
-    /**
-     * Construct a new WindowInsets from individual insets.
-     *
-     * A {@code null} inset indicates that the respective inset is consumed.
-     *
-     * @hide
-     * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
-     */
-    @Deprecated
-    public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect, boolean isRound,
-            boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
-        this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
-                createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
-                isRound, alwaysConsumeSystemBars, displayCutout, null, null,
-                systemBars(), false /* compatIgnoreVisibility */);
+        CONSUMED = new WindowInsets(createCompatTypeMap(null), createCompatTypeMap(null),
+                createCompatVisibilityMap(createCompatTypeMap(null)), false, false, null, null,
+                null, null, systemBars(), false);
     }
 
     /**
@@ -154,6 +139,7 @@
             boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
             RoundedCorners roundedCorners,
             PrivacyIndicatorBounds privacyIndicatorBounds,
+            DisplayShape displayShape,
             @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
         mSystemWindowInsetsConsumed = typeInsetsMap == null;
         mTypeInsetsMap = mSystemWindowInsetsConsumed
@@ -177,6 +163,7 @@
 
         mRoundedCorners = roundedCorners;
         mPrivacyIndicatorBounds = privacyIndicatorBounds;
+        mDisplayShape = displayShape;
     }
 
     /**
@@ -191,6 +178,7 @@
                 src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
                 src.mRoundedCorners,
                 src.mPrivacyIndicatorBounds,
+                src.mDisplayShape,
                 src.mCompatInsetsTypes,
                 src.mCompatIgnoreVisibility);
     }
@@ -244,15 +232,18 @@
     @UnsupportedAppUsage
     public WindowInsets(Rect systemWindowInsets) {
         this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
-                null, null, systemBars(), false /* compatIgnoreVisibility */);
+                null, null, null, systemBars(), false /* compatIgnoreVisibility */);
     }
 
     /**
      * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
      * {@link Type#statusBars()} and {@link Type#navigationBars()}, depending on the
      * location of the inset.
+     *
+     * @hide
      */
-    private static Insets[] createCompatTypeMap(@Nullable Rect insets) {
+    @VisibleForTesting
+    public static Insets[] createCompatTypeMap(@Nullable Rect insets) {
         if (insets == null) {
             return null;
         }
@@ -271,6 +262,10 @@
                 Insets.of(insets.left, 0, insets.right, insets.bottom);
     }
 
+    /**
+     * @hide
+     */
+    @VisibleForTesting
     private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetsMap) {
         boolean[] typeVisibilityMap = new boolean[SIZE];
         if (typeInsetsMap == null) {
@@ -533,6 +528,17 @@
     }
 
     /**
+     * Returns the display shape in the coordinate space of the window.
+     *
+     * @return the display shape
+     * @see DisplayShape
+     */
+    @Nullable
+    public DisplayShape getDisplayShape() {
+        return mDisplayShape;
+    }
+
+    /**
      * Returns a copy of this WindowInsets with the cutout fully consumed.
      *
      * @return A modified copy of this WindowInsets
@@ -547,7 +553,7 @@
                 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                 mTypeVisibilityMap,
                 mIsRound, mAlwaysConsumeSystemBars,
-                null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds,
+                null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape,
                 mCompatInsetsTypes, mCompatIgnoreVisibility);
     }
 
@@ -602,7 +608,7 @@
                 // it.
                 (mCompatInsetsTypes & displayCutout()) != 0
                         ? null : displayCutoutCopyConstructorArgument(this),
-                mRoundedCorners, mPrivacyIndicatorBounds, mCompatInsetsTypes,
+                mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape, mCompatInsetsTypes,
                 mCompatIgnoreVisibility);
     }
 
@@ -911,6 +917,8 @@
         result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
                 + mPrivacyIndicatorBounds : "");
         result.append("\n    ");
+        result.append(mDisplayShape != null ? "displayShape=" + mDisplayShape : "");
+        result.append("\n    ");
         result.append("compatInsetsTypes=" + mCompatInsetsTypes);
         result.append("\n    ");
         result.append("compatIgnoreVisibility=" + mCompatIgnoreVisibility);
@@ -1018,6 +1026,7 @@
                 mPrivacyIndicatorBounds == null
                         ? null
                         : mPrivacyIndicatorBounds.inset(left, top, right, bottom),
+                mDisplayShape,
                 mCompatInsetsTypes, mCompatIgnoreVisibility);
     }
 
@@ -1037,7 +1046,8 @@
                 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
                 && Objects.equals(mDisplayCutout, that.mDisplayCutout)
                 && Objects.equals(mRoundedCorners, that.mRoundedCorners)
-                && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds);
+                && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds)
+                && Objects.equals(mDisplayShape, that.mDisplayShape);
     }
 
     @Override
@@ -1045,7 +1055,7 @@
         return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
                 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
                 mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
-                mDisplayCutoutConsumed, mPrivacyIndicatorBounds);
+                mDisplayCutoutConsumed, mPrivacyIndicatorBounds, mDisplayShape);
     }
 
 
@@ -1106,6 +1116,7 @@
 
         private DisplayCutout mDisplayCutout;
         private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
+        private DisplayShape mDisplayShape = DisplayShape.NONE;
 
         private boolean mIsRound;
         private boolean mAlwaysConsumeSystemBars;
@@ -1137,6 +1148,7 @@
             mIsRound = insets.mIsRound;
             mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
             mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
+            mDisplayShape = insets.mDisplayShape;
         }
 
         /**
@@ -1381,6 +1393,19 @@
             return this;
         }
 
+        /**
+         * Sets the display shape.
+         *
+         * @see #getDisplayShape().
+         * @param displayShape the display shape.
+         * @return itself.
+         */
+        @NonNull
+        public Builder setDisplayShape(@NonNull DisplayShape displayShape) {
+            mDisplayShape = displayShape;
+            return this;
+        }
+
         /** @hide */
         @NonNull
         public Builder setRound(boolean round) {
@@ -1405,7 +1430,8 @@
             return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
                     mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
                     mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
-                    mPrivacyIndicatorBounds, systemBars(), false /* compatIgnoreVisibility */);
+                    mPrivacyIndicatorBounds, mDisplayShape, systemBars(),
+                    false /* compatIgnoreVisibility */);
         }
     }
 
diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
index 1e3714e..8cb568d 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
@@ -40,7 +40,6 @@
     parcelable InitParams {
         IBinder token;
         IInputMethodPrivilegedOperations privilegedOperations;
-        int configChanges;
         int navigationBarFlags;
     }
 
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 4b1753a..9cb2e68 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -17,7 +17,7 @@
 package com.android.internal.telephony;
 
 import android.telephony.BarringInfo;
-import android.telephony.CallAttributes;
+import android.telephony.CallState;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
@@ -62,7 +62,7 @@
     void onPhoneCapabilityChanged(in PhoneCapability capability);
     void onActiveDataSubIdChanged(in int subId);
     void onRadioPowerStateChanged(in int state);
-    void onCallAttributesChanged(in CallAttributes callAttributes);
+    void onCallStatesChanged(in List<CallState> callStateList);
     @SuppressWarnings(value={"untyped-collection"})
     void onEmergencyNumberListChanged(in Map emergencyNumberList);
     void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index c7fa757..7ba2686 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -66,8 +66,8 @@
     void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
-    void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
-            int foregroundCallState, int backgroundCallState);
+    void notifyPreciseCallState(int phoneId, int subId, in int[] callStates, in String[] imsCallIds,
+            in int[] imsCallServiceTypes, in int[] imsCallTypes);
     void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
             int preciseDisconnectCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6460007..eb70344 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1705,8 +1705,7 @@
         -->
         <flag name="systemExempted" value="0x400" />
         <!-- "Short service" foreground service type. See
-           TODO: Change it to a real link
-           {@code android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
+           {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
            for more details.
         -->
         <flag name="shortService" value="0x800" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9c2643b..2ab5b75 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5985,4 +5985,35 @@
     <string-array translatable="false" name="config_fontManagerServiceCerts">
     </string-array>
 
+    <!-- A string config in svg path format for the main display shape.
+         (@see https://www.w3.org/TR/SVG/paths.html#PathData).
+
+         This config must be set unless:
+         1. {@link Configuration#isScreenRound} is true which means the display shape is circular
+            and the system will auto-generate a circular shape.
+         2. The display has no rounded corner and the system will auto-generate a rectangular shape.
+         (@see DisplayShape#createDefaultDisplayShape)
+
+         Note: If the display supports multiple resolutions, please define the path config based on
+         the highest resolution so that it can be scaled correctly in each resolution. -->
+    <string name="config_mainDisplayShape" translatable="false"></string>
+
+    <!-- A string config in svg path format for the secondary display shape.
+         (@see https://www.w3.org/TR/SVG/paths.html#PathData).
+
+         This config must be set unless:
+         1. {@link Configuration#isScreenRound} is true which means the display shape is circular
+            and the system will auto-generate a circular shape.
+         2. The display has no rounded corner and the system will auto-generate a rectangular shape.
+         (@see DisplayShape#createDefaultDisplayShape)
+
+         Note: If the display supports multiple resolutions, please define the path config based on
+         the highest resolution so that it can be scaled correctly in each resolution. -->
+    <string name="config_secondaryDisplayShape" translatable="false"></string>
+
+    <!-- The display shape config for each display in a multi-display device. -->
+    <string-array name="config_displayShapeArray" translatable="false">
+        <item>@string/config_mainDisplayShape</item>
+        <item>@string/config_secondaryDisplayShape</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd93932..168806a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4915,4 +4915,8 @@
   <java-symbol type="dimen" name="status_bar_height_default" />
 
   <java-symbol type="string" name="default_card_name"/>
+
+  <java-symbol type="string" name="config_mainDisplayShape"/>
+  <java-symbol type="string" name="config_secondaryDisplayShape"/>
+  <java-symbol type="array" name="config_displayShapeArray" />
 </resources>
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index a528c19..6bf8f56 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -203,16 +203,22 @@
                 fallbackMap);
         SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
         Map<String, Typeface> copiedFontMap = new ArrayMap<>();
-        Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
-                copiedFontMap);
-        assertEquals(systemFontMap.size(), copiedFontMap.size());
-        for (String key : systemFontMap.keySet()) {
-            assertTrue(copiedFontMap.containsKey(key));
-            Typeface original = systemFontMap.get(key);
-            Typeface copied = copiedFontMap.get(key);
-            assertEquals(original.getStyle(), copied.getStyle());
-            assertEquals(original.getWeight(), copied.getWeight());
-            assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+        try {
+            Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
+                    copiedFontMap);
+            assertEquals(systemFontMap.size(), copiedFontMap.size());
+            for (String key : systemFontMap.keySet()) {
+                assertTrue(copiedFontMap.containsKey(key));
+                Typeface original = systemFontMap.get(key);
+                Typeface copied = copiedFontMap.get(key);
+                assertEquals(original.getStyle(), copied.getStyle());
+                assertEquals(original.getWeight(), copied.getWeight());
+                assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+            }
+        } finally {
+            for (Typeface typeface : copiedFontMap.values()) {
+                typeface.releaseNativeObjectForTest();
+            }
         }
     }
 
diff --git a/core/tests/coretests/src/android/view/DisplayShapeTest.java b/core/tests/coretests/src/android/view/DisplayShapeTest.java
new file mode 100644
index 0000000..77dd8bd
--- /dev/null
+++ b/core/tests/coretests/src/android/view/DisplayShapeTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.view;
+
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link DisplayShape}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayShapeTest {
+    // Rectangle with w=100, height=200
+    private static final String SPEC_RECTANGULAR_SHAPE = "M0,0 L100,0 L100,200 L0,200 Z";
+
+    @Test
+    public void testGetPath() {
+        final DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 100f, 200f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testDefaultShape_screenIsRound() {
+        final DisplayShape displayShape = DisplayShape.createDefaultDisplayShape(100, 100, true);
+
+        // A circle with radius = 50.
+        final String expect = "M0,50.0 A50.0,50.0 0 1,1 100,50.0 A50.0,50.0 0 1,1 0,50.0 Z";
+        assertEquals(displayShape.mDisplayShapeSpec, expect);
+    }
+
+    @Test
+    public void testDefaultShape_screenIsNotRound() {
+        final DisplayShape displayShape = DisplayShape.createDefaultDisplayShape(100, 200, false);
+
+        // A rectangle with width/height = 100/200.
+        final String expect = "M0,0 L100,0 L100,200 L0,200 Z";
+        assertEquals(displayShape.mDisplayShapeSpec, expect);
+    }
+
+    @Test
+    public void testFromSpecString_cache() {
+        final DisplayShape cached = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        assertThat(DisplayShape.fromSpecString(SPEC_RECTANGULAR_SHAPE, 1f, 100, 200),
+                sameInstance(cached));
+    }
+
+    @Test
+    public void testGetPath_cache() {
+        final Path cached = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200).getPath();
+        assertThat(DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200).getPath(),
+                sameInstance(cached));
+    }
+
+    @Test
+    public void testRotate_90() {
+        DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        displayShape = displayShape.setRotation(ROTATION_90);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 200f, 100f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testRotate_270() {
+        DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        displayShape = displayShape.setRotation(ROTATION_270);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 200f, 100f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testOffset() {
+        DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        displayShape = displayShape.setOffset(-10, -20);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(-10f, -20f, 90f, 180f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testPhysicalPixelDisplaySizeRatio() {
+        final DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 0.5f, 100, 200);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 50f, 100f);
+        assertEquals(actualRect, expectRect);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index be9da11..6a96f28 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -517,6 +517,19 @@
                 windowInsets.getRoundedCorner(POSITION_BOTTOM_LEFT));
     }
 
+    @Test
+    public void testCalculateRelativeDisplayShape() {
+        mState.setDisplayFrame(new Rect(0, 0, 200, 400));
+        mState.setDisplayShape(DisplayShape.createDefaultDisplayShape(200, 400, false));
+        WindowInsets windowInsets = mState.calculateInsets(new Rect(10, 20, 200, 400), null, false,
+                false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+                WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+
+        final DisplayShape expect =
+                DisplayShape.createDefaultDisplayShape(200, 400, false).setOffset(-10, -20);
+        assertEquals(expect, windowInsets.getDisplayShape());
+    }
+
     private void assertEqualsAndHashCode() {
         assertEquals(mState, mState2);
         assertEquals(mState.hashCode(), mState2.hashCode());
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index dd9634b..4fed396 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -39,13 +39,16 @@
 
     @Test
     public void systemWindowInsets_afterConsuming_isConsumed() {
-        assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, false, false, null)
+        assertTrue(new WindowInsets(WindowInsets.createCompatTypeMap(new Rect(1, 2, 3, 4)), null,
+                null, false, false, null, null, null, null,
+                WindowInsets.Type.systemBars(), false)
                 .consumeSystemWindowInsets().isConsumed());
     }
 
     @Test
     public void multiNullConstructor_isConsumed() {
-        assertTrue(new WindowInsets((Rect) null, null, false, false, null).isConsumed());
+        assertTrue(new WindowInsets(null, null, null, false, false, null, null, null, null,
+                WindowInsets.Type.systemBars(), false).isConsumed());
     }
 
     @Test
@@ -61,7 +64,8 @@
         WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
         WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
         WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
-                null, null, systemBars(), true /* compatIgnoreVisibility */);
+                null, null, DisplayShape.NONE, systemBars(),
+                true /* compatIgnoreVisibility */);
         assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index d10f173..4d4ec35 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -168,7 +168,8 @@
     }
 
     private WindowInsets insetsWith(Insets content, DisplayCutout cutout) {
-        return new WindowInsets(content.toRect(), null, false, false, cutout);
+        return new WindowInsets(WindowInsets.createCompatTypeMap(content.toRect()), null, null,
+                false, false, cutout, null, null, null, WindowInsets.Type.systemBars(), false);
     }
 
     private ViewGroup createViewGroupWithId(int id) {
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 215b60e..a43e225 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -371,6 +371,10 @@
 # key 413 "KEY_DIGITS"
 # key 414 "KEY_TEEN"
 # key 415 "KEY_TWEN"
+# key 418 "KEY_ZOOM_IN"
+key 418   ZOOM_IN
+# key 419 "KEY_ZOOM_OUT"
+key 419   ZOOM_OUT
 key 528 FOCUS
 
 key 429   CONTACTS
diff --git a/graphics/java/android/graphics/PathIterator.java b/graphics/java/android/graphics/PathIterator.java
index 33b9a47..bfda690 100644
--- a/graphics/java/android/graphics/PathIterator.java
+++ b/graphics/java/android/graphics/PathIterator.java
@@ -281,7 +281,7 @@
             return mConicWeight;
         }
 
-        public Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
+        Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
             mVerb = verb;
             mPoints = points;
             mConicWeight = conicWeight;
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 3b7d0e1..9fb627f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1207,6 +1207,7 @@
      * It is safe to call this method twice or more on the same instance.
      * @hide
      */
+    @TestApi
     public void releaseNativeObjectForTest() {
         mCleaner.run();
     }
@@ -1294,6 +1295,13 @@
     /**
      * Deserialize the font mapping from the serialized byte buffer.
      *
+     * <p>Warning: the given {@code buffer} must outlive generated Typeface
+     * objects in {@code out}. In production code, this is guaranteed by
+     * storing the buffer in {@link #sSystemFontMapBuffer}.
+     * If you call this method in a test, please make sure to destroy the
+     * generated Typeface objects by calling
+     * {@link #releaseNativeObjectForTest()}.
+     *
      * @hide
      */
     @TestApi
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
old mode 100755
new mode 100644
index c0fa63a..15aaae2
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -18,6 +18,7 @@
 
 #include "android-base/errors.h"
 #include "android-base/logging.h"
+#include "android-base/utf8.h"
 
 namespace android {
 
@@ -84,7 +85,7 @@
   }
 
   std::string overlay_path(loaded_idmap->OverlayApkPath());
-  auto fd = unique_fd(::open(overlay_path.c_str(), O_RDONLY|O_CLOEXEC));
+  auto fd = unique_fd(base::utf8::open(overlay_path.c_str(), O_RDONLY | O_CLOEXEC));
   std::unique_ptr<AssetsProvider> overlay_assets;
   if (IsFabricatedOverlay(fd)) {
     // Fabricated overlays do not contain resource definitions. All of the overlay resource values
@@ -92,7 +93,7 @@
     overlay_assets = EmptyAssetsProvider::Create(std::move(overlay_path));
   } else {
     // The overlay should be an APK.
-    overlay_assets = ZipAssetsProvider::Create(std::move(fd), std::move(overlay_path), flags);
+    overlay_assets = ZipAssetsProvider::Create(std::move(overlay_path), flags, std::move(fd));
   }
   if (overlay_assets == nullptr) {
     return {};
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index c3d153d..cc7e871 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -374,7 +374,7 @@
         const std::string name = ToFormattedResourceString(*res_name);
         output.append(base::StringPrintf(
             "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
-            name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
+            name.c_str(), info->name.data(), info->actor.data(), info->policy_flags));
       }
     }
   }
@@ -1356,21 +1356,22 @@
 
 void AssetManager2::RebuildFilterList() {
   for (PackageGroup& group : package_groups_) {
-    for (ConfiguredPackage& impl : group.packages_) {
-      impl.filtered_configs_.clear();
-
+    for (ConfiguredPackage& package : group.packages_) {
+      package.filtered_configs_.forEachItem([](auto, auto& fcg) { fcg.type_entries.clear(); });
       // Create the filters here.
-      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
+      package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
         FilteredConfigGroup* group = nullptr;
         for (const auto& type_entry : type_spec.type_entries) {
           if (type_entry.config.match(configuration_)) {
             if (!group) {
-              group = &impl.filtered_configs_.editItemAt(type_id - 1);
+              group = &package.filtered_configs_.editItemAt(type_id - 1);
             }
             group->type_entries.push_back(&type_entry);
           }
         }
       });
+      package.filtered_configs_.trimBuckets(
+          [](const auto& fcg) { return fcg.type_entries.empty(); });
     }
   }
 }
@@ -1411,30 +1412,34 @@
 std::unique_ptr<Theme> AssetManager2::NewTheme() {
   constexpr size_t kInitialReserveSize = 32;
   auto theme = std::unique_ptr<Theme>(new Theme(this));
+  theme->keys_.reserve(kInitialReserveSize);
   theme->entries_.reserve(kInitialReserveSize);
   return theme;
 }
 
+void AssetManager2::ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
+                                   package_property_t excluded_property_flags) const {
+  for (const PackageGroup& package_group : package_groups_) {
+    const auto loaded_package = package_group.packages_.front().loaded_package_;
+    if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U
+        && !func(loaded_package->GetPackageName(),
+                 package_group.dynamic_ref_table->mAssignedPackageId)) {
+      return;
+    }
+  }
+}
+
 Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
 }
 
 Theme::~Theme() = default;
 
 struct Theme::Entry {
-  uint32_t attr_res_id;
   ApkAssetsCookie cookie;
   uint32_t type_spec_flags;
   Res_value value;
 };
 
-namespace {
-struct ThemeEntryKeyComparer {
-  bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept {
-    return entry.attr_res_id < attr_res_id;
-  }
-};
-} // namespace
-
 base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
   ATRACE_NAME("Theme::ApplyStyle");
 
@@ -1463,18 +1468,20 @@
       continue;
     }
 
-    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
-                                     ThemeEntryKeyComparer{});
-    if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
+    const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), attr_res_id);
+    const auto entry_it = entries_.begin() + (key_it - keys_.begin());
+    if (key_it != keys_.end() && *key_it == attr_res_id) {
       if (is_undefined) {
         // DATA_NULL_UNDEFINED clears the value of the attribute in the theme only when `force` is
-        /// true.
+        // true.
+        keys_.erase(key_it);
         entries_.erase(entry_it);
       } else if (force) {
-        *entry_it = Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
+        *entry_it = Entry{it->cookie, (*bag)->type_spec_flags, it->value};
       }
     } else {
-      entries_.insert(entry_it, Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value});
+      keys_.insert(key_it, attr_res_id);
+      entries_.insert(entry_it, Entry{it->cookie, (*bag)->type_spec_flags, it->value});
     }
   }
   return {};
@@ -1485,6 +1492,7 @@
   ATRACE_NAME("Theme::Rebase");
   // Reset the entries without changing the vector capacity to prevent reallocations during
   // ApplyStyle.
+  keys_.clear();
   entries_.clear();
   asset_manager_ = am;
   for (size_t i = 0; i < style_count; i++) {
@@ -1493,16 +1501,14 @@
 }
 
 std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
-
   constexpr const uint32_t kMaxIterations = 20;
   uint32_t type_spec_flags = 0u;
   for (uint32_t i = 0; i <= kMaxIterations; i++) {
-    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), resid,
-                                     ThemeEntryKeyComparer{});
-    if (entry_it == entries_.end() || entry_it->attr_res_id != resid) {
+    const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), resid);
+    if (key_it == keys_.end() || *key_it != resid) {
       return std::nullopt;
     }
-
+    const auto entry_it = entries_.begin() + (key_it - keys_.begin());
     type_spec_flags |= entry_it->type_spec_flags;
     if (entry_it->value.dataType == Res_value::TYPE_ATTRIBUTE) {
       resid = entry_it->value.data;
@@ -1536,6 +1542,7 @@
 }
 
 void Theme::Clear() {
+  keys_.clear();
   entries_.clear();
 }
 
@@ -1547,11 +1554,12 @@
   type_spec_flags_ = source.type_spec_flags_;
 
   if (asset_manager_ == source.asset_manager_) {
+    keys_ = source.keys_;
     entries_ = source.entries_;
   } else {
-    std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
-    typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
-    std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
+    std::unordered_map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
+    using SourceToDestinationRuntimePackageMap = std::unordered_map<int, int>;
+    std::unordered_map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
 
     // Determine which ApkAssets are loaded in both theme AssetManagers.
     const auto src_assets = source.asset_manager_->GetApkAssets();
@@ -1579,15 +1587,17 @@
         }
 
         src_to_dest_asset_cookies.insert(std::make_pair(i, j));
-        src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
+        src_asset_cookie_id_map.insert(std::make_pair(i, std::move(package_map)));
         break;
       }
     }
 
     // Reset the data in the destination theme.
+    keys_.clear();
     entries_.clear();
 
-    for (const auto& entry : source.entries_) {
+    for (size_t i = 0, size = source.entries_.size(); i != size; ++i) {
+      const auto& entry = source.entries_[i];
       bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
                            || entry.value.dataType == Res_value::TYPE_REFERENCE
                            || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
@@ -1627,13 +1637,15 @@
         }
       }
 
+      const auto source_res_id = source.keys_[i];
+
       // The package id of the attribute needs to be rewritten to the package id of the
       // attribute in the destination.
-      int attribute_dest_package_id = get_package_id(entry.attr_res_id);
+      int attribute_dest_package_id = get_package_id(source_res_id);
       if (attribute_dest_package_id != 0x01) {
         // Find the cookie of the attribute resource id in the source AssetManager
         base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
-            source.asset_manager_->FindEntry(entry.attr_res_id, 0 /* density_override */ ,
+            source.asset_manager_->FindEntry(source_res_id, 0 /* density_override */ ,
                                              true /* stop_at_first_match */,
                                              true /* ignore_configuration */);
         if (UNLIKELY(IsIOError(attribute_entry_result))) {
@@ -1657,16 +1669,15 @@
         attribute_dest_package_id = attribute_dest_package->second;
       }
 
-      auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(entry.attr_res_id),
-                                     get_entry_id(entry.attr_res_id));
-      Theme::Entry new_entry{dest_attr_id, data_dest_cookie, entry.type_spec_flags,
-                                            Res_value{.dataType = entry.value.dataType,
-                                                      .data = attribute_data}};
-
+      auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(source_res_id),
+                                     get_entry_id(source_res_id));
+      const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), dest_attr_id);
+      const auto entry_it = entries_.begin() + (key_it - keys_.begin());
       // Since the entries were cleared, the attribute resource id has yet been mapped to any value.
-      auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), dest_attr_id,
-                                       ThemeEntryKeyComparer{});
-      entries_.insert(entry_it, new_entry);
+      keys_.insert(key_it, dest_attr_id);
+      entries_.insert(entry_it, Entry{data_dest_cookie, entry.type_spec_flags,
+                                      Res_value{.dataType = entry.value.dataType,
+                                                .data = attribute_data}});
     }
   }
   return {};
@@ -1674,9 +1685,11 @@
 
 void Theme::Dump() const {
   LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
-  for (auto& entry : entries_) {
+  for (size_t i = 0, size = keys_.size(); i != size; ++i) {
+    auto res_id = keys_[i];
+    const auto& entry = entries_[i];
     LOG(INFO) << base::StringPrintf("  entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
-                                    entry.attr_res_id, entry.value.data, entry.value.dataType,
+                                    res_id, entry.value.data, entry.value.dataType,
                                     entry.cookie);
   }
 }
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index 80e5607..b9264c5 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -92,21 +92,27 @@
       last_mod_time_(last_mod_time) {}
 
 std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
-                                                             package_property_t flags) {
+                                                             package_property_t flags,
+                                                             base::unique_fd fd) {
+  const auto released_fd = fd.ok() ? fd.release() : -1;
   ZipArchiveHandle handle;
-  if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
+  if (int32_t result = released_fd < 0 ? OpenArchive(path.c_str(), &handle)
+                                       : OpenArchiveFd(released_fd, path.c_str(), &handle)) {
     LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
     CloseArchive(handle);
     return {};
   }
 
   struct stat sb{.st_mtime = -1};
-  if (stat(path.c_str(), &sb) < 0) {
-    // Stat requires execute permissions on all directories path to the file. If the process does
-    // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
-    // always have to return true.
-    LOG(WARNING) << "Failed to stat file '" << path << "': "
-                 << base::SystemErrorCodeToString(errno);
+  // Skip all up-to-date checks if the file won't ever change.
+  if (!isReadonlyFilesystem(path.c_str())) {
+    if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) {
+      // Stat requires execute permissions on all directories path to the file. If the process does
+      // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+      // always have to return true.
+      LOG(WARNING) << "Failed to stat file '" << path << "': "
+                   << base::SystemErrorCodeToString(errno);
+    }
   }
 
   return std::unique_ptr<ZipAssetsProvider>(
@@ -133,12 +139,15 @@
   }
 
   struct stat sb{.st_mtime = -1};
-  if (fstat(released_fd, &sb) < 0) {
-    // Stat requires execute permissions on all directories path to the file. If the process does
-    // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
-    // always have to return true.
-    LOG(WARNING) << "Failed to fstat file '" << friendly_name << "': "
-                 << base::SystemErrorCodeToString(errno);
+  // Skip all up-to-date checks if the file won't ever change.
+  if (!isReadonlyFilesystem(released_fd)) {
+    if (fstat(released_fd, &sb) < 0) {
+      // Stat requires execute permissions on all directories path to the file. If the process does
+      // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+      // always have to return true.
+      LOG(WARNING) << "Failed to fstat file '" << friendly_name
+                   << "': " << base::SystemErrorCodeToString(errno);
+    }
   }
 
   return std::unique_ptr<ZipAssetsProvider>(
@@ -275,6 +284,9 @@
 }
 
 bool ZipAssetsProvider::IsUpToDate() const {
+  if (last_mod_time_ == -1) {
+    return true;
+  }
   struct stat sb{};
   if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) {
     // If fstat fails on the zip archive, return true so the zip archive the resource system does
@@ -288,7 +300,7 @@
     : dir_(std::forward<std::string>(path)), last_mod_time_(last_mod_time) {}
 
 std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) {
-  struct stat sb{};
+  struct stat sb;
   const int result = stat(path.c_str(), &sb);
   if (result == -1) {
     LOG(ERROR) << "Failed to find directory '" << path << "'.";
@@ -304,8 +316,9 @@
     path += OS_PATH_SEPARATOR;
   }
 
-  return std::unique_ptr<DirectoryAssetsProvider>(new DirectoryAssetsProvider(std::move(path),
-                                                                              sb.st_mtime));
+  const bool isReadonly = isReadonlyFilesystem(path.c_str());
+  return std::unique_ptr<DirectoryAssetsProvider>(
+      new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime));
 }
 
 std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path,
@@ -335,7 +348,10 @@
 }
 
 bool DirectoryAssetsProvider::IsUpToDate() const {
-  struct stat sb{};
+  if (last_mod_time_ == -1) {
+    return true;
+  }
+  struct stat sb;
   if (stat(dir_.c_str(), &sb) < 0) {
     // If stat fails on the zip archive, return true so the zip archive the resource system does
     // attempt to refresh the ApkAsset.
@@ -431,4 +447,4 @@
   return true;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 386f718..c0fdfe2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -645,16 +645,16 @@
         }
 
         std::string name;
-        util::ReadUtf16StringFromDevice(overlayable->name, arraysize(overlayable->name), &name);
+        util::ReadUtf16StringFromDevice(overlayable->name, std::size(overlayable->name), &name);
         std::string actor;
-        util::ReadUtf16StringFromDevice(overlayable->actor, arraysize(overlayable->actor), &actor);
-
-        if (loaded_package->overlayable_map_.find(name) !=
-            loaded_package->overlayable_map_.end()) {
-          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'.";
+        util::ReadUtf16StringFromDevice(overlayable->actor, std::size(overlayable->actor), &actor);
+        auto [name_to_actor_it, inserted] =
+            loaded_package->overlayable_map_.emplace(std::move(name), std::move(actor));
+        if (!inserted) {
+          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '"
+                     << name_to_actor_it->first << "'.";
           return {};
         }
-        loaded_package->overlayable_map_.emplace(name, actor);
 
         // Iterate over the overlayable policy chunks contained within the overlayable chunk data
         ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
@@ -669,7 +669,6 @@
                 LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
                 return {};
               }
-
               if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
                   < dtohl(policy_header->entry_count)) {
                 LOG(ERROR) <<  "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
@@ -691,8 +690,8 @@
 
               // Add the pairing of overlayable properties and resource ids to the package
               OverlayableInfo overlayable_info {
-                .name = name,
-                .actor = actor,
+                .name = name_to_actor_it->first,
+                .actor = name_to_actor_it->second,
                 .policy_flags = policy_header->policy_flags
               };
               loaded_package->overlayable_infos_.emplace_back(std::move(overlayable_info), std::move(ids));
@@ -736,6 +735,7 @@
         const auto entry_end = entry_begin + dtohl(lib_alias->count);
         std::unordered_set<uint32_t> finalized_ids;
         finalized_ids.reserve(entry_end - entry_begin);
+        loaded_package->alias_id_map_.reserve(entry_end - entry_begin);
         for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
           if (!entry_iter) {
             LOG(ERROR) << "NULL ResTable_staged_alias_entry record??";
@@ -749,13 +749,20 @@
           }
 
           auto staged_id = dtohl(entry_iter->stagedResId);
-          auto [_, success] = loaded_package->alias_id_map_.emplace(staged_id, finalized_id);
-          if (!success) {
+          loaded_package->alias_id_map_.emplace_back(staged_id, finalized_id);
+        }
+
+        std::sort(loaded_package->alias_id_map_.begin(), loaded_package->alias_id_map_.end(),
+            [](auto&& l, auto&& r) { return l.first < r.first; });
+        const auto duplicate_it =
+            std::adjacent_find(loaded_package->alias_id_map_.begin(),
+                               loaded_package->alias_id_map_.end(),
+                               [](auto&& l, auto&& r) { return l.first == r.first; });
+          if (duplicate_it != loaded_package->alias_id_map_.end()) {
             LOG(ERROR) << StringPrintf("Repeated staged resource id '%08x' in staged aliases.",
-                                       staged_id);
+                                       duplicate_it->first);
             return {};
           }
-        }
       } break;
 
       default:
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index e9aaedc..e4d1218 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -17,6 +17,7 @@
 #ifndef ANDROIDFW_ASSETMANAGER2_H_
 #define ANDROIDFW_ASSETMANAGER2_H_
 
+#include "android-base/function_ref.h"
 #include "android-base/macros.h"
 
 #include <array>
@@ -320,17 +321,8 @@
   // Creates a new Theme from this AssetManager.
   std::unique_ptr<Theme> NewTheme();
 
-  void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func,
-                      package_property_t excluded_property_flags = 0U) const {
-    for (const PackageGroup& package_group : package_groups_) {
-      const auto loaded_package = package_group.packages_.front().loaded_package_;
-      if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U
-          && !func(loaded_package->GetPackageName(),
-                   package_group.dynamic_ref_table->mAssignedPackageId)) {
-        return;
-      }
-    }
-  }
+  void ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
+                      package_property_t excluded_property_flags = 0U) const;
 
   void DumpToLog() const;
 
@@ -571,6 +563,7 @@
   AssetManager2* asset_manager_ = nullptr;
   uint32_t type_spec_flags_ = 0u;
 
+  std::vector<uint32_t> keys_;
   std::vector<Entry> entries_;
 };
 
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index af6e7f4..7891194 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -80,8 +80,8 @@
 
 // Supplies assets from a zip archive.
 struct ZipAssetsProvider : public AssetsProvider {
-  static std::unique_ptr<ZipAssetsProvider> Create(std::string path,
-                                                   package_property_t flags);
+  static std::unique_ptr<ZipAssetsProvider> Create(std::string path, package_property_t flags,
+                                                   base::unique_fd fd = {});
 
   static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
                                                    std::string friendly_name,
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index 05a2c4d..ca0a9ed 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -17,6 +17,7 @@
 #ifndef __BYTE_BUCKET_ARRAY_H
 #define __BYTE_BUCKET_ARRAY_H
 
+#include <algorithm>
 #include <cstdint>
 #include <cstring>
 
@@ -36,15 +37,11 @@
   }
 
   ~ByteBucketArray() {
-    clear();
+    deleteBuckets();
   }
 
   void clear() {
-    for (size_t i = 0; i < kNumBuckets; i++) {
-      if (buckets_[i] != NULL) {
-        delete[] buckets_[i];
-      }
-    }
+    deleteBuckets();
     memset(buckets_, 0, sizeof(buckets_));
   }
 
@@ -59,7 +56,7 @@
 
     uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
     T* bucket = buckets_[bucket_index];
-    if (bucket == NULL) {
+    if (bucket == nullptr) {
       return default_;
     }
     return bucket[0x0f & static_cast<uint8_t>(index)];
@@ -70,9 +67,9 @@
                           << ") with size=" << size();
 
     uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
-    T* bucket = buckets_[bucket_index];
-    if (bucket == NULL) {
-      bucket = buckets_[bucket_index] = new T[kBucketSize]();
+    T*& bucket = buckets_[bucket_index];
+    if (bucket == nullptr) {
+      bucket = new T[kBucketSize]();
     }
     return bucket[0x0f & static_cast<uint8_t>(index)];
   }
@@ -86,9 +83,42 @@
     return true;
   }
 
+  template <class Func>
+  void forEachItem(Func f) {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      const auto bucket = buckets_[i];
+      if (bucket != nullptr) {
+        for (size_t j = 0; j < kBucketSize; j++) {
+          f((i << 4) | j, bucket[j]);
+        }
+      }
+    }
+  }
+
+  template <class Func>
+  void trimBuckets(Func isEmptyFunc) {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      const auto bucket = buckets_[i];
+      if (bucket != nullptr) {
+        if (std::all_of(bucket, bucket + kBucketSize, isEmptyFunc)) {
+          delete[] bucket;
+          buckets_[i] = nullptr;
+        }
+      }
+    }
+  }
+
  private:
   enum { kNumBuckets = 16, kBucketSize = 16 };
 
+  void deleteBuckets() {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      if (buckets_[i] != nullptr) {
+        delete[] buckets_[i];
+      }
+    }
+  }
+
   T* buckets_[kNumBuckets];
   static inline const T default_ = {};
 };
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 79d96282..4d12885 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -99,8 +99,8 @@
 };
 
 struct OverlayableInfo {
-  std::string name;
-  std::string actor;
+  std::string_view name;
+  std::string_view actor;
   uint32_t policy_flags;
 };
 
@@ -275,7 +275,7 @@
     return overlayable_map_;
   }
 
-  const std::map<uint32_t, uint32_t>& GetAliasResourceIdMap() const {
+  const std::vector<std::pair<uint32_t, uint32_t>>& GetAliasResourceIdMap() const {
     return alias_id_map_;
   }
 
@@ -295,8 +295,8 @@
   std::unordered_map<uint8_t, TypeSpec> type_specs_;
   ByteBucketArray<uint32_t> resource_ids_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
-  std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
-  std::map<uint32_t, uint32_t> alias_id_map_;
+  std::vector<std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+  std::vector<std::pair<uint32_t, uint32_t>> alias_id_map_;
 
   // A map of overlayable name to actor
   std::unordered_map<std::string, std::string> overlayable_map_;
diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h
index 5a5a0e2..d40d24e 100644
--- a/libs/androidfw/include/androidfw/misc.h
+++ b/libs/androidfw/include/androidfw/misc.h
@@ -44,6 +44,10 @@
 /* get the file's modification date; returns -1 w/errno set on failure */
 time_t getFileModDate(const char* fileName);
 
+// Check if |path| or |fd| resides on a readonly filesystem.
+bool isReadonlyFilesystem(const char* path);
+bool isReadonlyFilesystem(int fd);
+
 }; // namespace android
 
 #endif // _LIBS_ANDROID_FW_MISC_H
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index 5285420..7af5066 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -21,12 +21,17 @@
 //
 #include <androidfw/misc.h>
 
-#include <sys/stat.h>
-#include <cstring>
-#include <errno.h>
-#include <cstdio>
+#include "android-base/logging.h"
 
-using namespace android;
+#ifndef _WIN32
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#endif  // _WIN32
+
+#include <cstring>
+#include <cstdio>
+#include <errno.h>
+#include <sys/stat.h>
 
 namespace android {
 
@@ -41,8 +46,7 @@
         if (errno == ENOENT || errno == ENOTDIR)
             return kFileTypeNonexistent;
         else {
-            fprintf(stderr, "getFileType got errno=%d on '%s'\n",
-                errno, fileName);
+            PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed";
             return kFileTypeUnknown;
         }
     } else {
@@ -82,4 +86,32 @@
     return sb.st_mtime;
 }
 
+#ifdef _WIN32
+// No need to implement these for Windows, the functions only matter on a device.
+bool isReadonlyFilesystem(const char*) {
+    return false;
+}
+bool isReadonlyFilesystem(int) {
+    return false;
+}
+#else   // _WIN32
+bool isReadonlyFilesystem(const char* path) {
+    struct statfs sfs;
+    if (::statfs(path, &sfs)) {
+        PLOG(ERROR) << "isReadonlyFilesystem(): statfs(" << path << ") failed";
+        return false;
+    }
+    return (sfs.f_flags & ST_RDONLY) != 0;
+}
+
+bool isReadonlyFilesystem(int fd) {
+    struct statfs sfs;
+    if (::fstatfs(fd, &sfs)) {
+        PLOG(ERROR) << "isReadonlyFilesystem(): fstatfs(" << fd << ") failed";
+        return false;
+    }
+    return (sfs.f_flags & ST_RDONLY) != 0;
+}
+#endif  // _WIN32
+
 }; // namespace android
diff --git a/libs/androidfw/tests/ByteBucketArray_test.cpp b/libs/androidfw/tests/ByteBucketArray_test.cpp
index 5d464c7..9c36cfb 100644
--- a/libs/androidfw/tests/ByteBucketArray_test.cpp
+++ b/libs/androidfw/tests/ByteBucketArray_test.cpp
@@ -52,4 +52,57 @@
   }
 }
 
+TEST(ByteBucketArrayTest, TestForEach) {
+  ByteBucketArray<int> bba;
+  ASSERT_TRUE(bba.set(0, 1));
+  ASSERT_TRUE(bba.set(10, 2));
+  ASSERT_TRUE(bba.set(26, 3));
+  ASSERT_TRUE(bba.set(129, 4));
+  ASSERT_TRUE(bba.set(234, 5));
+
+  int count = 0;
+  bba.forEachItem([&count](auto i, auto val) {
+    ++count;
+    switch (i) {
+      case 0:
+        EXPECT_EQ(1, val);
+        break;
+      case 10:
+        EXPECT_EQ(2, val);
+        break;
+      case 26:
+        EXPECT_EQ(3, val);
+        break;
+      case 129:
+        EXPECT_EQ(4, val);
+        break;
+      case 234:
+        EXPECT_EQ(5, val);
+        break;
+      default:
+        EXPECT_EQ(0, val);
+        break;
+    }
+  });
+  ASSERT_EQ(4 * 16, count);
+}
+
+TEST(ByteBucketArrayTest, TestTrimBuckets) {
+  ByteBucketArray<int> bba;
+  ASSERT_TRUE(bba.set(0, 1));
+  ASSERT_TRUE(bba.set(255, 2));
+  {
+    bba.trimBuckets([](auto val) { return val < 2; });
+    int count = 0;
+    bba.forEachItem([&count](auto, auto) { ++count; });
+    ASSERT_EQ(1 * 16, count);
+  }
+  {
+    bba.trimBuckets([](auto val) { return val < 3; });
+    int count = 0;
+    bba.forEachItem([&count](auto, auto) { ++count; });
+    ASSERT_EQ(0, count);
+  }
+}
+
 }  // namespace android
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 68880bd..59024e7 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -489,24 +489,10 @@
                         Integer algorithmId = entry.getKey();
                         byte[] contentDigest = entry.getValue();
 
-                        // TODO(b/259348134): consider refactoring the following to a helper method
-                        switch (algorithmId) {
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
-                                pw.print("CHUNKED_SHA256:");
-                                break;
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
-                                pw.print("CHUNKED_SHA512:");
-                                break;
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
-                                pw.print("VERITY_CHUNKED_SHA256:");
-                                break;
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
-                                pw.print("SHA256:");
-                                break;
-                            default:
-                                pw.print("UNKNOWN_ALGO_ID(" + algorithmId + "):");
-                        }
+                        pw.print(translateContentDigestAlgorithmIdToString(algorithmId));
+                        pw.print(":");
                         pw.print(HexEncoding.encodeToString(contentDigest, false));
+                        pw.print("\n");
                     }
                 }
 
@@ -533,31 +519,13 @@
                             pw.println("ERROR: Failed to compute package content digest for "
                                     + origPackageFilepath);
                         } else {
-                            // TODO(b/259348134): consider refactoring this to a helper method
                             for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) {
                                 Integer algorithmId = entry.getKey();
                                 byte[] contentDigest = entry.getValue();
-                                pw.print("|--> Pre-installed package content digest algorithm: ");
-                                switch (algorithmId) {
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
-                                        pw.print("CHUNKED_SHA256");
-                                        break;
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
-                                        pw.print("CHUNKED_SHA512");
-                                        break;
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
-                                        pw.print("VERITY_CHUNKED_SHA256");
-                                        break;
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
-                                        pw.print("SHA256");
-                                        break;
-                                    default:
-                                        pw.print("UNKNOWN");
-                                }
-                                pw.print("\n");
-                                pw.print("|--> Pre-installed package content digest: ");
-                                pw.print(HexEncoding.encodeToString(contentDigest, false));
-                                pw.print("\n");
+                                pw.println("|--> Pre-installed package content digest: "
+                                        + HexEncoding.encodeToString(contentDigest, false));
+                                pw.println("|--> Pre-installed package content digest algorithm: "
+                                        + translateContentDigestAlgorithmIdToString(algorithmId));
                             }
                         }
                     }
@@ -739,7 +707,6 @@
                         pw.print(packageName + ","
                                 + packageInfo.getLongVersionCode() + ",");
                         printPackageMeasurements(packageInfo, pw);
-                        pw.print("\n");
 
                         if (verbose) {
                             ModuleInfo moduleInfo;
@@ -802,7 +769,6 @@
                             pw.print(packageInfo.packageName + ",");
                             pw.print(packageInfo.getLongVersionCode() + ",");
                             printPackageMeasurements(packageInfo, pw);
-                            pw.print("\n");
 
                             if (verbose) {
                                 printModuleDetails(module, pw);
@@ -858,7 +824,6 @@
                         pw.print(packageInfo.packageName + ",");
                         pw.print(packageInfo.getLongVersionCode() + ",");
                         printPackageMeasurements(packageInfo, pw);
-                        pw.print("\n");
 
                         if (verbose) {
                             printAppDetails(packageInfo, printLibraries, pw);
@@ -1079,6 +1044,21 @@
         FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
     }
 
+    private String translateContentDigestAlgorithmIdToString(int algorithmId) {
+        switch (algorithmId) {
+            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
+                return "CHUNKED_SHA256";
+            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
+                return "CHUNKED_SHA512";
+            case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
+                return "VERITY_CHUNKED_SHA256";
+            case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
+                return "SHA256";
+            default:
+                return "UNKNOWN_ALGO_ID(" + algorithmId + ")";
+        }
+    }
+
     @NonNull
     private List<PackageInfo> getCurrentInstalledApexs() {
         List<PackageInfo> results = new ArrayList<>();
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index b56d1fc..b4ab254 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -447,6 +447,13 @@
                 thread.start();
                 break;
             case LEVEL_FACTORY_RESET:
+                // Before the completion of Reboot, if any crash happens then PackageWatchdog
+                // escalates to next level i.e. factory reset, as they happen in separate threads.
+                // Adding a check to prevent factory reset to execute before above reboot completes.
+                // Note: this reboot property is not persistent resets after reboot is completed.
+                if (isRebootPropertySet()) {
+                    break;
+                }
                 SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
                 runnable = new Runnable() {
                     @Override
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index ca86021c..bd90d85 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -52,8 +52,8 @@
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.BarringInfo;
-import android.telephony.CallAttributes;
 import android.telephony.CallQuality;
+import android.telephony.CallState;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.CellSignalStrength;
@@ -82,6 +82,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsReasonInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -349,9 +350,9 @@
 
     private CallQuality[] mCallQuality;
 
-    private CallAttributes[] mCallAttributes;
+    private ArrayList<List<CallState>> mCallStateLists;
 
-    // network type of the call associated with the mCallAttributes and mCallQuality
+    // network type of the call associated with the mCallStateLists and mCallQuality
     private int[] mCallNetworkType;
 
     private int[] mSrvccState;
@@ -687,7 +688,6 @@
             mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones);
             mCallQuality = copyOf(mCallQuality, mNumPhones);
             mCallNetworkType = copyOf(mCallNetworkType, mNumPhones);
-            mCallAttributes = copyOf(mCallAttributes, mNumPhones);
             mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
             mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
             mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
@@ -707,6 +707,7 @@
                 cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
                 cutListToSize(mCarrierPrivilegeStates, mNumPhones);
                 cutListToSize(mCarrierServiceStates, mNumPhones);
+                cutListToSize(mCallStateLists, mNumPhones);
                 return;
             }
 
@@ -730,8 +731,7 @@
                 mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
                 mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
                 mCallQuality[i] = createCallQuality();
-                mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
-                        TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+                mCallStateLists.add(i, new ArrayList<>());
                 mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
                 mPreciseCallState[i] = createPreciseCallState();
                 mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -799,7 +799,7 @@
         mCallPreciseDisconnectCause = new int[numPhones];
         mCallQuality = new CallQuality[numPhones];
         mCallNetworkType = new int[numPhones];
-        mCallAttributes = new CallAttributes[numPhones];
+        mCallStateLists = new ArrayList<>();
         mPreciseDataConnectionStates = new ArrayList<>();
         mCellInfo = new ArrayList<>(numPhones);
         mImsReasonInfo = new ArrayList<>();
@@ -837,8 +837,7 @@
             mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
             mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
             mCallQuality[i] = createCallQuality();
-            mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
-                    TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+            mCallStateLists.add(i, new ArrayList<>());
             mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             mPreciseCallState[i] = createPreciseCallState();
             mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -1336,7 +1335,7 @@
                 }
                 if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) {
                     try {
-                        r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]);
+                        r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId));
                     } catch (RemoteException ex) {
                         remove(r.binder);
                     }
@@ -2171,11 +2170,30 @@
         }
     }
 
-    public void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
-                                       int foregroundCallState, int backgroundCallState) {
+    /**
+     * Send a notification to registrants that the precise call state has changed.
+     *
+     * @param phoneId the phoneId carrying the data connection
+     * @param subId the subscriptionId for the data connection
+     * @param callStates Array of PreciseCallState of foreground, background & ringing calls.
+     * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId()} for
+     *                   ringing, foreground & background calls.
+     * @param imsServiceTypes Array of IMS call service type for ringing, foreground &
+     *                        background calls.
+     * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls.
+     */
+    public void notifyPreciseCallState(int phoneId, int subId,
+            @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds,
+            @Annotation.ImsCallServiceType int[] imsServiceTypes,
+            @Annotation.ImsCallType int[] imsCallTypes) {
         if (!checkNotifyPermission("notifyPreciseCallState()")) {
             return;
         }
+
+        int ringingCallState = callStates[CallState.CALL_CLASSIFICATION_RINGING];
+        int foregroundCallState = callStates[CallState.CALL_CLASSIFICATION_FOREGROUND];
+        int backgroundCallState = callStates[CallState.CALL_CLASSIFICATION_BACKGROUND];
+
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mRingingCallState[phoneId] = ringingCallState;
@@ -2186,11 +2204,11 @@
                         backgroundCallState,
                         DisconnectCause.NOT_VALID,
                         PreciseDisconnectCause.NOT_VALID);
-                boolean notifyCallAttributes = true;
+                boolean notifyCallState = true;
                 if (mCallQuality == null) {
                     log("notifyPreciseCallState: mCallQuality is null, "
                             + "skipping call attributes");
-                    notifyCallAttributes = false;
+                    notifyCallState = false;
                 } else {
                     // If the precise call state is no longer active, reset the call network type
                     // and call quality.
@@ -2199,8 +2217,65 @@
                         mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
                         mCallQuality[phoneId] = createCallQuality();
                     }
-                    mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
-                            mCallNetworkType[phoneId], mCallQuality[phoneId]);
+                    mCallStateLists.get(phoneId).clear();
+                    if (foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+                            && foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+                        CallQuality callQuality = mCallQuality[phoneId];
+                        CallState.Builder builder = new CallState.Builder(
+                                callStates[CallState.CALL_CLASSIFICATION_FOREGROUND])
+                                .setNetworkType(mCallNetworkType[phoneId])
+                                .setCallQuality(callQuality)
+                                .setCallClassification(
+                                        CallState.CALL_CLASSIFICATION_FOREGROUND);
+                        if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+                            builder = builder
+                                    .setImsCallSessionId(imsCallIds[
+                                            CallState.CALL_CLASSIFICATION_FOREGROUND])
+                                    .setImsCallServiceType(imsServiceTypes[
+                                            CallState.CALL_CLASSIFICATION_FOREGROUND])
+                                    .setImsCallType(imsCallTypes[
+                                            CallState.CALL_CLASSIFICATION_FOREGROUND]);
+                        }
+                        mCallStateLists.get(phoneId).add(builder.build());
+                    }
+                    if (backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+                            && backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+                        CallState.Builder builder = new CallState.Builder(
+                                callStates[CallState.CALL_CLASSIFICATION_BACKGROUND])
+                                .setNetworkType(mCallNetworkType[phoneId])
+                                .setCallQuality(createCallQuality())
+                                .setCallClassification(
+                                        CallState.CALL_CLASSIFICATION_BACKGROUND);
+                        if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+                            builder = builder
+                                    .setImsCallSessionId(imsCallIds[
+                                            CallState.CALL_CLASSIFICATION_BACKGROUND])
+                                    .setImsCallServiceType(imsServiceTypes[
+                                            CallState.CALL_CLASSIFICATION_BACKGROUND])
+                                    .setImsCallType(imsCallTypes[
+                                            CallState.CALL_CLASSIFICATION_BACKGROUND]);
+                        }
+                        mCallStateLists.get(phoneId).add(builder.build());
+                    }
+                    if (ringingCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+                            && ringingCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+                        CallState.Builder builder = new CallState.Builder(
+                                callStates[CallState.CALL_CLASSIFICATION_RINGING])
+                                .setNetworkType(mCallNetworkType[phoneId])
+                                .setCallQuality(createCallQuality())
+                                .setCallClassification(
+                                        CallState.CALL_CLASSIFICATION_RINGING);
+                        if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+                            builder = builder
+                                    .setImsCallSessionId(imsCallIds[
+                                            CallState.CALL_CLASSIFICATION_RINGING])
+                                    .setImsCallServiceType(imsServiceTypes[
+                                            CallState.CALL_CLASSIFICATION_RINGING])
+                                    .setImsCallType(imsCallTypes[
+                                            CallState.CALL_CLASSIFICATION_RINGING]);
+                        }
+                        mCallStateLists.get(phoneId).add(builder.build());
+                    }
                 }
 
                 for (Record r : mRecords) {
@@ -2213,11 +2288,11 @@
                             mRemoveList.add(r.binder);
                         }
                     }
-                    if (notifyCallAttributes && r.matchTelephonyCallbackEvent(
+                    if (notifyCallState && r.matchTelephonyCallbackEvent(
                             TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r, subId, phoneId)) {
                         try {
-                            r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+                            r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2515,15 +2590,29 @@
                 // merge CallQuality with PreciseCallState and network type
                 mCallQuality[phoneId] = callQuality;
                 mCallNetworkType[phoneId] = callNetworkType;
-                mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
-                        callNetworkType, callQuality);
+                if (mCallStateLists.get(phoneId).size() > 0
+                        && mCallStateLists.get(phoneId).get(0).getCallState()
+                        == PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
+                    CallState prev = mCallStateLists.get(phoneId).remove(0);
+                    mCallStateLists.get(phoneId).add(
+                            0, new CallState.Builder(prev.getCallState())
+                                    .setNetworkType(callNetworkType)
+                                    .setCallQuality(callQuality)
+                                    .setCallClassification(prev.getCallClassification())
+                                    .setImsCallSessionId(prev.getImsCallSessionId())
+                                    .setImsCallServiceType(prev.getImsCallServiceType())
+                                    .setImsCallType(prev.getImsCallType()).build());
+                } else {
+                    log("There is no active call to report CallQaulity");
+                    return;
+                }
 
                 for (Record r : mRecords) {
                     if (r.matchTelephonyCallbackEvent(
                             TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r, subId, phoneId)) {
                         try {
-                            r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+                            r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2991,7 +3080,6 @@
                 pw.println("mSrvccState=" + mSrvccState[i]);
                 pw.println("mCallPreciseDisconnectCause=" + mCallPreciseDisconnectCause[i]);
                 pw.println("mCallQuality=" + mCallQuality[i]);
-                pw.println("mCallAttributes=" + mCallAttributes[i]);
                 pw.println("mCallNetworkType=" + mCallNetworkType[i]);
                 pw.println("mPreciseDataConnectionStates=" + mPreciseDataConnectionStates.get(i));
                 pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]);
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index b92c163..a954164 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -338,7 +338,18 @@
                                     + " and userId " + userId);
                             break;
                         }
+                        if (mHandler.hasMessages(CANCEL_GAME_LOADING_MODE)) {
+                            mHandler.removeMessages(CANCEL_GAME_LOADING_MODE);
+                        }
                         mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+                        if (isLoading) {
+                            int loadingBoostDuration = getLoadingBoostDuration(packageName, userId);
+                            loadingBoostDuration = loadingBoostDuration > 0 ? loadingBoostDuration
+                                    : LOADING_BOOST_MAX_DURATION;
+                            mHandler.sendMessageDelayed(
+                                    mHandler.obtainMessage(CANCEL_GAME_LOADING_MODE),
+                                    loadingBoostDuration);
+                        }
                     }
                     break;
                 }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index a0cbd7f..8811999 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -23,6 +23,7 @@
 import android.view.DisplayAddress;
 import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
+import android.view.DisplayShape;
 import android.view.RoundedCorners;
 import android.view.Surface;
 
@@ -316,6 +317,11 @@
     public RoundedCorners roundedCorners;
 
     /**
+     * The {@link RoundedCorners} if present or {@code null} otherwise.
+     */
+    public DisplayShape displayShape;
+
+    /**
      * The touch attachment, per {@link DisplayViewport#touch}.
      */
     public int touch;
@@ -451,7 +457,8 @@
                 || !BrightnessSynchronizer.floatEquals(brightnessDefault,
                 other.brightnessDefault)
                 || !Objects.equals(roundedCorners, other.roundedCorners)
-                || installOrientation != other.installOrientation) {
+                || installOrientation != other.installOrientation
+                || !Objects.equals(displayShape, other.displayShape)) {
             diff |= DIFF_OTHER;
         }
         return diff;
@@ -497,6 +504,7 @@
         brightnessDefault = other.brightnessDefault;
         roundedCorners = other.roundedCorners;
         installOrientation = other.installOrientation;
+        displayShape = other.displayShape;
     }
 
     // For debugging purposes
@@ -546,6 +554,9 @@
         }
         sb.append(flagsToString(flags));
         sb.append(", installOrientation ").append(installOrientation);
+        if (displayShape != null) {
+            sb.append(", displayShape ").append(displayShape);
+        }
         sb.append("}");
         return sb.toString();
     }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5a714f5..4bf1e98 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -38,6 +38,7 @@
 import android.view.DisplayAddress;
 import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
+import android.view.DisplayShape;
 import android.view.RoundedCorners;
 import android.view.SurfaceControl;
 
@@ -686,6 +687,9 @@
                         res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
                 mInfo.installOrientation = mStaticDisplayInfo.installOrientation;
 
+                mInfo.displayShape = DisplayShape.fromResources(
+                        res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
+
                 if (mStaticDisplayInfo.isInternal) {
                     mInfo.type = Display.TYPE_INTERNAL;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 26ac528..28bdce3 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -233,6 +233,7 @@
                 info.displayCutout = mOverrideDisplayInfo.displayCutout;
                 info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
                 info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
+                info.displayShape = mOverrideDisplayInfo.displayShape;
             }
             mInfo.set(info);
         }
@@ -437,6 +438,7 @@
             mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
             mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
             mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation;
+            mBaseDisplayInfo.displayShape = deviceInfo.displayShape;
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo.set(null);
         }
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index b0de844..0e11b53 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -29,6 +29,7 @@
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.Display;
+import android.view.DisplayShape;
 import android.view.Gravity;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -361,6 +362,8 @@
                 mInfo.state = mState;
                 // The display is trusted since it is created by system.
                 mInfo.flags |= FLAG_TRUSTED;
+                mInfo.displayShape =
+                        DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
             }
             return mInfo;
         }
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index a23a073..d0e518b 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -52,6 +52,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.view.Display;
+import android.view.DisplayShape;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -524,6 +525,9 @@
 
                 mInfo.ownerUid = mOwnerUid;
                 mInfo.ownerPackageName = mOwnerPackageName;
+
+                mInfo.displayShape =
+                        DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
             }
             return mInfo;
         }
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 146b003..c759d98 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -34,6 +34,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayAddress;
+import android.view.DisplayShape;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -655,6 +656,8 @@
                 mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
                 // The display is trusted since it is created by system.
                 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
+                mInfo.displayShape =
+                        DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
             }
             return mInfo;
         }
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 015e576..c53f1a5 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -110,11 +110,10 @@
 
     @AnyThread
     void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privilegedOperations,
-            int configChanges, @InputMethodNavButtonFlags int navigationBarFlags) {
+            @InputMethodNavButtonFlags int navigationBarFlags) {
         final IInputMethod.InitParams params = new IInputMethod.InitParams();
         params.token = token;
         params.privilegedOperations = privilegedOperations;
-        params.configChanges = configChanges;
         params.navigationBarFlags = navigationBarFlags;
         try {
             mTarget.initializeInternal(params);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 4d67311..079234c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -296,7 +296,7 @@
                     if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
                     final InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
                     mSupportsStylusHw = info.supportsStylusHandwriting();
-                    mService.initializeImeLocked(mCurMethod, mCurToken, info.getConfigChanges());
+                    mService.initializeImeLocked(mCurMethod, mCurToken);
                     mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
                     mService.reRequestCurrentClientSessionLocked();
                     mService.performOnCreateInlineSuggestionsRequestLocked();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8b083bd..080d582 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2692,14 +2692,13 @@
     }
 
     @GuardedBy("ImfLock.class")
-    void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token,
-            @android.content.pm.ActivityInfo.Config int configChanges) {
+    void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token) {
         if (DEBUG) {
             Slog.v(TAG, "Sending attach of token: " + token + " for display: "
                     + mCurTokenDisplayId);
         }
         inputMethod.initializeInternal(token, new InputMethodPrivilegedOperationsImpl(this, token),
-                configChanges, getInputMethodNavButtonFlagsLocked());
+                getInputMethodNavButtonFlagsLocked());
     }
 
     @AnyThread
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 02a57b2..b5c1206 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3358,13 +3358,13 @@
                     Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): no system user data");
                     return;
                 }
+                final int oldMainUserId = getMainUserIdUnchecked();
                 final int oldFlags = systemUserData.info.flags;
                 final int newFlags;
                 final String newUserType;
-                // TODO(b/256624031): Also handle FLAG_MAIN
                 if (newHeadlessSystemUserMode) {
                     newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
-                    newFlags = oldFlags & ~UserInfo.FLAG_FULL;
+                    newFlags = oldFlags & ~UserInfo.FLAG_FULL & ~UserInfo.FLAG_MAIN;
                 } else {
                     newUserType = UserManager.USER_TYPE_FULL_SYSTEM;
                     newFlags = oldFlags | UserInfo.FLAG_FULL;
@@ -3379,9 +3379,38 @@
                         + "%s, flags changed from %s to %s",
                         systemUserData.info.userType, newUserType,
                         UserInfo.flagsToString(oldFlags), UserInfo.flagsToString(newFlags));
+
                 systemUserData.info.userType = newUserType;
                 systemUserData.info.flags = newFlags;
                 writeUserLP(systemUserData);
+
+                // Switch the MainUser to a reasonable choice if needed.
+                // (But if there was no MainUser, we deliberately continue to have no MainUser.)
+                final UserData oldMain = getUserDataNoChecks(oldMainUserId);
+                if (newHeadlessSystemUserMode) {
+                    if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) != 0) {
+                        // System was MainUser. So we need a new choice for Main. Pick the oldest.
+                        // If no oldest, don't set any. Let the BootUserInitializer do that later.
+                        final UserInfo newMainUser = getEarliestCreatedFullUser();
+                        if (newMainUser != null) {
+                            Slogf.i(LOG_TAG, "Designating user " + newMainUser.id + " to be Main");
+                            newMainUser.flags |= UserInfo.FLAG_MAIN;
+                            writeUserLP(getUserDataNoChecks(newMainUser.id));
+                        }
+                    }
+                } else {
+                    // TODO(b/256624031): For now, we demand the Main user (if there is one) is
+                    //  always the system in non-HSUM. In the future, when we relax this, change how
+                    //  we handle MAIN.
+                    if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) == 0) {
+                        // Someone else was the MainUser; transfer it to System.
+                        Slogf.i(LOG_TAG, "Transferring Main to user 0 from " + oldMain.info.id);
+                        oldMain.info.flags &= ~UserInfo.FLAG_MAIN;
+                        systemUserData.info.flags |= UserInfo.FLAG_MAIN;
+                        writeUserLP(oldMain);
+                        writeUserLP(systemUserData);
+                    }
+                }
             }
         }
 
@@ -3658,8 +3687,10 @@
             // Add FLAG_MAIN
             if (isHeadlessSystemUserMode()) {
                 final UserInfo earliestCreatedUser = getEarliestCreatedFullUser();
-                earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
-                userIdsToWrite.add(earliestCreatedUser.id);
+                if (earliestCreatedUser != null) {
+                    earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
+                    userIdsToWrite.add(earliestCreatedUser.id);
+                }
             } else {
                 synchronized (mUsersLock) {
                     final UserData userData = mUsers.get(UserHandle.USER_SYSTEM);
@@ -3799,9 +3830,10 @@
         userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
     }
 
-    private UserInfo getEarliestCreatedFullUser() {
+    /** Returns the oldest Full Admin user, or null is if there none. */
+    private @Nullable UserInfo getEarliestCreatedFullUser() {
         final List<UserInfo> users = getUsersInternal(true, true, true);
-        UserInfo earliestUser = users.get(0);
+        UserInfo earliestUser = null;
         long earliestCreationTime = Long.MAX_VALUE;
         for (int i = 0; i < users.size(); i++) {
             final UserInfo info = users.get(i);
diff --git a/services/core/java/com/android/server/utils/Slogf.java b/services/core/java/com/android/server/utils/Slogf.java
index e88ac63..6efbd89 100644
--- a/services/core/java/com/android/server/utils/Slogf.java
+++ b/services/core/java/com/android/server/utils/Slogf.java
@@ -162,7 +162,7 @@
     }
 
     /**
-     * Logs a {@link Log.VEBOSE} message with an exception
+     * Logs a {@link Log.VEBOSE} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#VERBOSE} logging
      * is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -170,10 +170,10 @@
      * you're calling this method in a critical path, make sure to explicitly do the check before
      * calling it.
      */
-    public static void v(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void v(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.VERBOSE)) return;
 
-        v(tag, getMessage(format, args), exception);
+        v(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -192,7 +192,7 @@
     }
 
     /**
-     * Logs a {@link Log.DEBUG} message with an exception
+     * Logs a {@link Log.DEBUG} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#DEBUG} logging
      * is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -200,10 +200,10 @@
      * you're calling this method in a critical path, make sure to explicitly do the check before
      * calling it.
      */
-    public static void d(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void d(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.DEBUG)) return;
 
-        d(tag, getMessage(format, args), exception);
+        d(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -222,7 +222,7 @@
     }
 
     /**
-     * Logs a {@link Log.INFO} message with an exception
+     * Logs a {@link Log.INFO} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#INFO} logging
      * is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -230,10 +230,10 @@
      * you're calling this method in a critical path, make sure to explicitly do the check before
      * calling it.
      */
-    public static void i(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void i(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.INFO)) return;
 
-        i(tag, getMessage(format, args), exception);
+        i(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -252,7 +252,7 @@
     }
 
     /**
-     * Logs a {@link Log.WARN} message with an exception
+     * Logs a {@link Log.WARN} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
      * enabled for the given {@code tag}, but the compiler will still create an intermediate array
@@ -260,10 +260,10 @@
      * calling this method in a critical path, make sure to explicitly do the check before calling
      * it.
      */
-    public static void w(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void w(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.WARN)) return;
 
-        w(tag, getMessage(format, args), exception);
+        w(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -282,7 +282,7 @@
     }
 
     /**
-     * Logs a {@link Log.ERROR} message with an exception
+     * Logs a {@link Log.ERROR} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#ERROR} logging is
      * enabled for the given {@code tag}, but the compiler will still create an intermediate array
@@ -290,10 +290,10 @@
      * calling this method in a critical path, make sure to explicitly do the check before calling
      * it.
      */
-    public static void e(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void e(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.ERROR)) return;
 
-        e(tag, getMessage(format, args), exception);
+        e(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -304,11 +304,11 @@
     }
 
     /**
-     * Logs a {@code wtf} message with an exception.
+     * Logs a {@code wtf} message with a throwable.
      */
-    public static void wtf(String tag, Exception exception, String format,
+    public static void wtf(String tag, Throwable throwable, String format,
             @Nullable Object... args) {
-        wtf(tag, getMessage(format, args), exception);
+        wtf(tag, getMessage(format, args), throwable);
     }
 
     private static String getMessage(String format, @Nullable Object... args) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 530fa4d..12424c0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3317,9 +3317,17 @@
                 mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants,
                         resultTo.getUriPermissionsLocked());
             }
-            if (mForceSendResultForMediaProjection) {
-                resultTo.sendResult(this.getUid(), resultWho, requestCode, resultCode,
-                        resultData, resultGrants, true /* forceSendForMediaProjection */);
+            if (mForceSendResultForMediaProjection || resultTo.isState(RESUMED)) {
+                // Sending the result to the resultTo activity asynchronously to prevent the
+                // resultTo activity getting results before this Activity paused.
+                final ActivityRecord resultToActivity = resultTo;
+                mAtmService.mH.post(() -> {
+                    synchronized (mAtmService.mGlobalLock) {
+                        resultToActivity.sendResult(this.getUid(), resultWho, requestCode,
+                                resultCode, resultData, resultGrants,
+                                mForceSendResultForMediaProjection);
+                    }
+                });
             } else {
                 resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
             }
@@ -4630,7 +4638,7 @@
                 false /* forceSendForMediaProjection */);
     }
 
-    private void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
+    void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
             Intent data, NeededUriGrants dataGrants, boolean forceSendForMediaProjection) {
         if (callingUid > 0) {
             mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 5938e7f..0b16a4d 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -78,7 +78,6 @@
 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
-import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -2777,11 +2776,6 @@
                 errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity;
                 break;
             }
-            case EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT: {
-                errMsg = "Cannot embed activity across TaskFragments for result, resultTo: "
-                        + mStartActivity.resultTo;
-                break;
-            }
             default:
                 errMsg = "Unhandled embed result:" + result;
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9c920f53..d1122e1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -207,6 +207,7 @@
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.Gravity;
 import android.view.IDisplayWindowInsetsController;
 import android.view.ISystemGestureExclusionListener;
@@ -391,6 +392,10 @@
             mPrivacyIndicatorBoundsCache = new
             RotationCache<>(this::calculatePrivacyIndicatorBoundsForRotationUncached);
 
+    DisplayShape mInitialDisplayShape;
+    private final RotationCache<DisplayShape, DisplayShape> mDisplayShapeCache =
+            new RotationCache<>(this::calculateDisplayShapeForRotationUncached);
+
     /**
      * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
      * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -1095,7 +1100,8 @@
         mDisplayFrames = new DisplayFrames(mInsetsStateController.getRawInsetsState(),
                 mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
                 calculateRoundedCornersForRotation(mDisplayInfo.rotation),
-                calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
+                calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation),
+                calculateDisplayShapeForRotation(mDisplayInfo.rotation));
         initializeDisplayBaseInfo();
 
         mHoldScreenWakeLock = mWmService.mPowerManager.newWakeLock(
@@ -1969,8 +1975,9 @@
         final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
         final PrivacyIndicatorBounds indicatorBounds =
                 calculatePrivacyIndicatorBoundsForRotation(rotation);
+        final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
         final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(), info,
-                cutout, roundedCorners, indicatorBounds);
+                cutout, roundedCorners, indicatorBounds, displayShape);
         token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
     }
 
@@ -2178,6 +2185,7 @@
         // Update application display metrics.
         final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
         final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
+        final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
 
         final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
         mDisplayInfo.rotation = rotation;
@@ -2194,6 +2202,7 @@
         }
         mDisplayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
         mDisplayInfo.roundedCorners = roundedCorners;
+        mDisplayInfo.displayShape = displayShape;
         mDisplayInfo.getAppMetrics(mDisplayMetrics);
         if (mDisplayScalingDisabled) {
             mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
@@ -2280,6 +2289,23 @@
         return bounds.rotate(rotation);
     }
 
+    DisplayShape calculateDisplayShapeForRotation(int rotation) {
+        return mDisplayShapeCache.getOrCompute(mInitialDisplayShape, rotation);
+    }
+
+    private DisplayShape calculateDisplayShapeForRotationUncached(
+            DisplayShape displayShape, int rotation) {
+        if (displayShape == null) {
+            return DisplayShape.NONE;
+        }
+
+        if (rotation == ROTATION_0) {
+            return displayShape;
+        }
+
+        return displayShape.setRotation(rotation);
+    }
+
     /**
      * Compute display info and configuration according to the given rotation without changing
      * current display.
@@ -2781,7 +2807,8 @@
         return displayFrames.update(rotation, w, h,
                 calculateDisplayCutoutForRotation(rotation),
                 calculateRoundedCornersForRotation(rotation),
-                calculatePrivacyIndicatorBoundsForRotation(rotation));
+                calculatePrivacyIndicatorBoundsForRotation(rotation),
+                calculateDisplayShapeForRotation(rotation));
     }
 
     @Override
@@ -2821,6 +2848,7 @@
         mInitialRoundedCorners = mDisplayInfo.roundedCorners;
         mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds(new Rect[4],
                 mDisplayInfo.rotation);
+        mInitialDisplayShape = mDisplayInfo.displayShape;
         final Display.Mode maxDisplayMode =
                 DisplayUtils.getMaximumResolutionDisplayMode(mDisplayInfo.supportedModes);
         mPhysicalDisplaySize = new Point(
@@ -2848,6 +2876,7 @@
                 ? DisplayCutout.NO_CUTOUT : mDisplayInfo.displayCutout;
         final String newUniqueId = mDisplayInfo.uniqueId;
         final RoundedCorners newRoundedCorners = mDisplayInfo.roundedCorners;
+        final DisplayShape newDisplayShape = mDisplayInfo.displayShape;
 
         final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
                 || mInitialDisplayHeight != newHeight
@@ -2855,7 +2884,8 @@
                 || mInitialPhysicalXDpi != newXDpi
                 || mInitialPhysicalYDpi != newYDpi
                 || !Objects.equals(mInitialDisplayCutout, newCutout)
-                || !Objects.equals(mInitialRoundedCorners, newRoundedCorners);
+                || !Objects.equals(mInitialRoundedCorners, newRoundedCorners)
+                || !Objects.equals(mInitialDisplayShape, newDisplayShape);
         final boolean physicalDisplayChanged = !newUniqueId.equals(mCurrentUniqueDisplayId);
 
         if (displayMetricsChanged || physicalDisplayChanged) {
@@ -2893,6 +2923,7 @@
             mInitialPhysicalYDpi = newYDpi;
             mInitialDisplayCutout = newCutout;
             mInitialRoundedCorners = newRoundedCorners;
+            mInitialDisplayShape = newDisplayShape;
             mCurrentUniqueDisplayId = newUniqueId;
             reconfigureDisplayLocked();
 
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 33641f7..e984456 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -26,6 +26,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.InsetsState;
 import android.view.PrivacyIndicatorBounds;
 import android.view.RoundedCorners;
@@ -56,10 +57,11 @@
     public int mRotation;
 
     public DisplayFrames(InsetsState insetsState, DisplayInfo info, DisplayCutout cutout,
-            RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds) {
+            RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds,
+            DisplayShape displayShape) {
         mInsetsState = insetsState;
         update(info.rotation, info.logicalWidth, info.logicalHeight, cutout, roundedCorners,
-                indicatorBounds);
+                indicatorBounds, displayShape);
     }
 
     DisplayFrames() {
@@ -73,7 +75,8 @@
      */
     public boolean update(int rotation, int w, int h, @NonNull DisplayCutout displayCutout,
             @NonNull RoundedCorners roundedCorners,
-            @NonNull PrivacyIndicatorBounds indicatorBounds) {
+            @NonNull PrivacyIndicatorBounds indicatorBounds,
+            @NonNull DisplayShape displayShape) {
         final InsetsState state = mInsetsState;
         final Rect safe = mDisplayCutoutSafe;
         if (mRotation == rotation && mWidth == w && mHeight == h
@@ -91,6 +94,7 @@
         state.setDisplayCutout(displayCutout);
         state.setRoundedCorners(roundedCorners);
         state.setPrivacyIndicatorBounds(indicatorBounds);
+        state.setDisplayShape(displayShape);
         state.getDisplayCutoutSafe(safe);
         if (safe.left > unrestricted.left) {
             state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 91cb037..d3a3cf5 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -172,13 +172,6 @@
      * indicate that an Activity can't be embedded because the Activity is started on a new task.
      */
     static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
-    /**
-     * An embedding check result of
-     * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
-     * indicate that an Activity can't be embedded because the Activity is started on a new
-     * TaskFragment, e.g. start an Activity on a new TaskFragment for result.
-     */
-    static final int EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT = 4;
 
     /**
      * Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
@@ -189,7 +182,6 @@
             EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
             EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
             EMBEDDING_DISALLOWED_NEW_TASK,
-            EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
     })
     @interface EmbeddingCheckResult {}
 
@@ -616,14 +608,6 @@
             return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
         }
 
-        // Cannot embed activity across TaskFragments for activity result.
-        // If the activity that started for result is finishing, it's likely that this start mode
-        // is used to place an activity in the same task. Since the finishing activity won't be
-        // able to get the results, so it's OK to embed in a different TaskFragment.
-        if (a.resultTo != null && !a.resultTo.finishing && a.resultTo.getTaskFragment() != this) {
-            return EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
-        }
-
         return EMBEDDING_ALLOWED;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 51fa851..e7c384b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -252,6 +252,7 @@
         noteBoot(4);
         assertTrue(RescueParty.isRebootPropertySet());
 
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
         noteBoot(5);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -276,6 +277,7 @@
         noteAppCrash(4, true);
         assertTrue(RescueParty.isRebootPropertySet());
 
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
         noteAppCrash(5, true);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -429,6 +431,27 @@
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
             noteBoot(i + 1);
         }
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        noteBoot(LEVEL_FACTORY_RESET + 1);
+        assertTrue(RescueParty.isAttemptingFactoryReset());
+        assertTrue(RescueParty.isFactoryResetPropertySet());
+    }
+
+    @Test
+    public void testIsAttemptingFactoryResetOnlyAfterRebootCompleted() {
+        for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
+            noteBoot(i + 1);
+        }
+        int mitigationCount = LEVEL_FACTORY_RESET + 1;
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        noteBoot(mitigationCount++);
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        noteBoot(mitigationCount++);
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        noteBoot(mitigationCount++);
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        noteBoot(mitigationCount + 1);
         assertTrue(RescueParty.isAttemptingFactoryReset());
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index dc77762..8d2e1ec 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -17,6 +17,7 @@
 package com.android.server.app;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.app.GameManagerService.CANCEL_GAME_LOADING_MODE;
 import static com.android.server.app.GameManagerService.WRITE_SETTINGS;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -1454,7 +1455,58 @@
         verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
     }
 
-    private void setGameState(boolean isLoading) {
+    @Test
+    public void testSetGameStateLoading_withNoDeviceConfig() {
+        mockDeviceConfigNone();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(
+                mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_1),
+                GameManager.GAME_MODE_PERFORMANCE);
+        int testMode = GameState.MODE_GAMEPLAY_INTERRUPTIBLE;
+        int testLabel = 99;
+        int testQuality = 123;
+        GameState gameState = new GameState(true, testMode, testLabel, testQuality);
+        assertEquals(testMode, gameState.getMode());
+        assertEquals(testLabel, gameState.getLabel());
+        assertEquals(testQuality, gameState.getQuality());
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        reset(mMockPowerManager);
+        assertTrue(
+                gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        verify(mMockPowerManager, never()).setPowerMode(Mode.GAME_LOADING, false);
+        mTestLooper.moveTimeForward(GameManagerService.LOADING_BOOST_MAX_DURATION);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+    }
+
+    @Test
+    public void testSetGameStateLoading_withDeviceConfig() {
+        String configString = "mode=2,loadingBoost=2000";
+        when(DeviceConfig.getProperty(anyString(), anyString()))
+                .thenReturn(configString);
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(
+                mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        GameState gameState = new GameState(true, GameState.MODE_GAMEPLAY_INTERRUPTIBLE, 99, 123);
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        verify(mMockPowerManager, never()).setPowerMode(Mode.GAME_LOADING, false);
+        reset(mMockPowerManager);
+        assertTrue(
+                gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        mTestLooper.moveTimeForward(2000);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+    }
+
+    @Test
+    public void testSetGameStateNotLoading() {
         mockDeviceConfigNone();
         mockModifyGameModeGranted();
         GameManagerService gameManagerService =
@@ -1462,27 +1514,19 @@
         startUser(gameManagerService, USER_ID_1);
         gameManagerService.setGameMode(
                 mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
-        int testMode = GameState.MODE_NONE;
+        int testMode = GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE;
         int testLabel = 99;
         int testQuality = 123;
-        GameState gameState = new GameState(isLoading, testMode, testLabel, testQuality);
-        assertEquals(isLoading, gameState.isLoading());
+        GameState gameState = new GameState(false, testMode, testLabel, testQuality);
+        assertFalse(gameState.isLoading());
         assertEquals(testMode, gameState.getMode());
         assertEquals(testLabel, gameState.getLabel());
         assertEquals(testQuality, gameState.getQuality());
         gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
         mTestLooper.dispatchAll();
-        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, isLoading);
-    }
-
-    @Test
-    public void testSetGameStateLoading() {
-        setGameState(true);
-    }
-
-    @Test
-    public void testSetGameStateNotLoading() {
-        setGameState(false);
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+        assertFalse(
+                gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
     }
 
     private List<String> readGameModeInterventionList() throws Exception {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index d41ac70..395e6ac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -161,6 +161,10 @@
         when(mMockedResources.getIntArray(
                 com.android.internal.R.array.config_autoBrightnessLevels))
                 .thenReturn(new int[]{});
+        when(mMockedResources.obtainTypedArray(R.array.config_displayShapeArray))
+                .thenReturn(mockArray);
+        when(mMockedResources.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray))
+                .thenReturn(mockArray);
     }
 
     @After
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
index ae25c1b..cb59d37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
@@ -44,7 +44,7 @@
 
     private MockitoSession mSession;
 
-    private final Exception mException = new Exception("D'OH!");
+    private final Throwable mThrowable = new Throwable("D'OH!");
 
     @Before
     public void setup() {
@@ -78,10 +78,10 @@
     }
 
     @Test
-    public void testV_msgAndException() {
-        Slogf.v(TAG, "msg", mException);
+    public void testV_msgAndThrowable() {
+        Slogf.v(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.v(TAG, "msg", mException));
+        verify(()-> Slog.v(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -103,12 +103,12 @@
     }
 
     @Test
-    public void testV_msgFormattedWithException_enabled() {
+    public void testV_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.VERBOSE);
 
-        Slogf.v(TAG, mException, "msg in a %s", "bottle");
+        Slogf.v(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.v(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.v(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
@@ -128,10 +128,10 @@
     }
 
     @Test
-    public void testD_msgAndException() {
-        Slogf.d(TAG, "msg", mException);
+    public void testD_msgAndThrowable() {
+        Slogf.d(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.d(TAG, "msg", mException));
+        verify(()-> Slog.d(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -153,19 +153,19 @@
     }
 
     @Test
-    public void testD_msgFormattedWithException_enabled() {
+    public void testD_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.DEBUG);
 
-        Slogf.d(TAG, mException, "msg in a %s", "bottle");
+        Slogf.d(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.d(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.d(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testD_msgFormattedWithException_disabled() {
         disableLogging(Log.DEBUG);
 
-        Slogf.d(TAG, mException, "msg in a %s", "bottle");
+        Slogf.d(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.d(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -178,10 +178,10 @@
     }
 
     @Test
-    public void testI_msgAndException() {
-        Slogf.i(TAG, "msg", mException);
+    public void testI_msgAndThrowable() {
+        Slogf.i(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.i(TAG, "msg", mException));
+        verify(()-> Slog.i(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -203,19 +203,19 @@
     }
 
     @Test
-    public void testI_msgFormattedWithException_enabled() {
+    public void testI_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.INFO);
 
-        Slogf.i(TAG, mException, "msg in a %s", "bottle");
+        Slogf.i(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.i(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.i(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testI_msgFormattedWithException_disabled() {
         disableLogging(Log.INFO);
 
-        Slogf.i(TAG, mException, "msg in a %s", "bottle");
+        Slogf.i(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.i(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -228,17 +228,17 @@
     }
 
     @Test
-    public void testW_msgAndException() {
-        Slogf.w(TAG, "msg", mException);
+    public void testW_msgAndThrowable() {
+        Slogf.w(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.w(TAG, "msg", mException));
+        verify(()-> Slog.w(TAG, "msg", mThrowable));
     }
 
     @Test
-    public void testW_exception() {
-        Slogf.w(TAG, mException);
+    public void testW_Throwable() {
+        Slogf.w(TAG, mThrowable);
 
-        verify(()-> Slog.w(TAG, mException));
+        verify(()-> Slog.w(TAG, mThrowable));
     }
 
     @Test
@@ -260,19 +260,19 @@
     }
 
     @Test
-    public void testW_msgFormattedWithException_enabled() {
+    public void testW_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.WARN);
 
-        Slogf.w(TAG, mException, "msg in a %s", "bottle");
+        Slogf.w(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.w(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.w(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testW_msgFormattedWithException_disabled() {
         disableLogging(Log.WARN);
 
-        Slogf.w(TAG, mException, "msg in a %s", "bottle");
+        Slogf.w(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.w(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -285,10 +285,10 @@
     }
 
     @Test
-    public void testE_msgAndException() {
-        Slogf.e(TAG, "msg", mException);
+    public void testE_msgAndThrowable() {
+        Slogf.e(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.e(TAG, "msg", mException));
+        verify(()-> Slog.e(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -310,19 +310,19 @@
     }
 
     @Test
-    public void testE_msgFormattedWithException_enabled() {
+    public void testE_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.ERROR);
 
-        Slogf.e(TAG, mException, "msg in a %s", "bottle");
+        Slogf.e(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.e(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.e(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testE_msgFormattedWithException_disabled() {
         disableLogging(Log.ERROR);
 
-        Slogf.e(TAG, mException, "msg in a %s", "bottle");
+        Slogf.e(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.e(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -335,17 +335,17 @@
     }
 
     @Test
-    public void testWtf_msgAndException() {
-        Slogf.wtf(TAG, "msg", mException);
+    public void testWtf_msgAndThrowable() {
+        Slogf.wtf(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.wtf(TAG, "msg", mException));
+        verify(()-> Slog.wtf(TAG, "msg", mThrowable));
     }
 
     @Test
-    public void testWtf_exception() {
-        Slogf.wtf(TAG, mException);
+    public void testWtf_Throwable() {
+        Slogf.wtf(TAG, mThrowable);
 
-        verify(()-> Slog.wtf(TAG, mException));
+        verify(()-> Slog.wtf(TAG, mThrowable));
     }
 
     @Test
@@ -377,10 +377,10 @@
     }
 
     @Test
-    public void testWtf_msgFormattedWithException() {
-        Slogf.wtf(TAG, mException, "msg in a %s", "bottle");
+    public void testWtf_msgFormattedWithThrowable() {
+        Slogf.wtf(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.wtf(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.wtf(TAG, "msg in a bottle", mThrowable));
     }
 
     private void enableLogging(@Log.Level int level) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 1ab7d7e..a410eed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1206,6 +1206,25 @@
         }
     }
 
+    @Test
+    public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() {
+        final Task task = new TaskBuilder(mSupervisor).build();
+        final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task);
+        final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task);
+        final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity();
+        final ActivityRecord targetActivity = taskFragment2.getTopMostActivity();
+        resultToActivity.setState(RESUMED, "test");
+        targetActivity.setState(RESUMED, "test");
+        targetActivity.resultTo = resultToActivity;
+
+        clearInvocations(mAtm.getLifecycleManager());
+        targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
+        waitUntilHandlersIdle();
+
+        verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null),
+                anyBoolean());
+    }
+
     /**
      * Verify that complete finish request for non-finishing activity is invalid.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 70b68c7..6733470 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -133,8 +133,8 @@
         final RoundedCorners roundedCorners = mHasRoundedCorners
                 ? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
                 : RoundedCorners.NO_ROUNDED_CORNERS;
-        return new DisplayFrames(insetsState, info,
-                info.displayCutout, roundedCorners, new PrivacyIndicatorBounds());
+        return new DisplayFrames(insetsState, info, info.displayCutout, roundedCorners,
+                new PrivacyIndicatorBounds(), info.displayShape);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index d99946f..10f2270 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -58,6 +58,7 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.InsetsSource;
 import android.view.InsetsState;
 import android.view.PrivacyIndicatorBounds;
@@ -321,7 +322,8 @@
         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         mImeWindow.mAboveInsetsState.set(state);
         mDisplayContent.mDisplayFrames = new DisplayFrames(
-                state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
+                state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(),
+                DisplayShape.NONE);
 
         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
         mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 4e796c5..8fda191 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -24,7 +24,6 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.os.Process.FIRST_APPLICATION_UID;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -33,9 +32,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
-import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
-import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -475,23 +472,6 @@
         doReturn(true).when(taskFragment).smallerThanMinDimension(any());
         assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
                 taskFragment.isAllowedToEmbedActivity(activity));
-
-        // Not allow to start activity across TaskFragments for result.
-        final TaskFragment newTaskFragment = new TaskFragmentBuilder(mAtm)
-                .setParentTask(taskFragment.getTask())
-                .build();
-        final ActivityRecord newActivity = new ActivityBuilder(mAtm)
-                .setUid(FIRST_APPLICATION_UID)
-                .build();
-        doReturn(true).when(newTaskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt());
-        doReturn(false).when(newTaskFragment).smallerThanMinDimension(any());
-        newActivity.resultTo = activity;
-        assertEquals(EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
-                newTaskFragment.isAllowedToEmbedActivity(newActivity));
-
-        // Allow embedding if the resultTo activity is finishing.
-        activity.finishing = true;
-        assertEquals(EMBEDDING_ALLOWED, newTaskFragment.isAllowedToEmbedActivity(newActivity));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index aab70b5..94b5b93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -54,6 +54,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.Gravity;
 import android.view.InsetsState;
 import android.view.PrivacyIndicatorBounds;
@@ -165,7 +166,8 @@
         final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
         final DisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
         final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(),
-                info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
+                info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(),
+                DisplayShape.NONE);
         wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config);
 
         // Check that the wallpaper has the same frame in landscape than in portrait
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 52cfe25..133f924 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -33,5 +33,6 @@
         "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.usb.gadget-V1.1-java",
         "android.hardware.usb.gadget-V1.2-java",
+        "android.hardware.usb.gadget-V1-java",
     ],
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1c081c1..ffdb07b 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -44,6 +44,7 @@
 import android.debug.AdbNotifications;
 import android.debug.AdbTransportType;
 import android.debug.IAdbTransport;
+import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbConfiguration;
@@ -54,9 +55,7 @@
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
-import android.hardware.usb.gadget.V1_0.IUsbGadget;
 import android.hardware.usb.gadget.V1_0.Status;
-import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
 import android.hardware.usb.gadget.V1_2.UsbSpeed;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
@@ -88,9 +87,12 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.usb.hal.gadget.UsbGadgetHal;
+import com.android.server.usb.hal.gadget.UsbGadgetHalInstance;
 import com.android.server.utils.EventLogger;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -106,6 +108,7 @@
 import java.util.NoSuchElementException;
 import java.util.Scanner;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -216,6 +219,13 @@
 
     private static EventLogger sEventLogger;
 
+    private UsbGadgetHal mUsbGadgetHal;
+
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     static {
         sDenyInterfaces = new HashSet<>();
         sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
@@ -298,15 +308,11 @@
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
         initRndisAddress();
 
+        int operationId = sUsbOperationCount.incrementAndGet();
         boolean halNotPresent = false;
-        try {
-            IUsbGadget.getService(true);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
-        } catch (NoSuchElementException e) {
-            halNotPresent = true;
-            Slog.i(TAG, "USB GADGET HAL not present in the device", e);
-        }
+
+        mUsbGadgetHal = UsbGadgetHalInstance.getInstance(this, null);
+        Slog.d(TAG, "getInstance done");
 
         mControlFds = new HashMap<>();
         FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
@@ -320,7 +326,7 @@
         }
         mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);
 
-        if (halNotPresent) {
+        if (mUsbGadgetHal == null) {
             /**
              * Initialze the legacy UsbHandler
              */
@@ -334,6 +340,8 @@
                     alsaManager, permissionManager);
         }
 
+        mHandler.handlerInitDone(operationId);
+
         if (nativeIsStartRequested()) {
             if (DEBUG) Slog.d(TAG, "accessory attached at boot");
             startAccessoryMode();
@@ -455,6 +463,8 @@
     private void startAccessoryMode() {
         if (!mHasUsbAccessory) return;
 
+        int operationId = sUsbOperationCount.incrementAndGet();
+
         mAccessoryStrings = nativeGetAccessoryStrings();
         boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
         // don't start accessory mode if our mandatory strings have not been set
@@ -475,7 +485,7 @@
                     ACCESSORY_REQUEST_TIMEOUT);
             mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_HANDSHAKE_TIMEOUT),
                     ACCESSORY_HANDSHAKE_TIMEOUT);
-            setCurrentFunctions(functions);
+            setCurrentFunctions(functions, operationId);
         }
     }
 
@@ -504,6 +514,20 @@
         }
     }
 
+    public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+        Slog.println(priority, TAG, msg);
+        if (pw != null) {
+            pw.println(msg);
+        }
+    }
+
+    public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
+        Slog.e(TAG, msg, e);
+        if (pw != null) {
+            pw.println(msg + e);
+        }
+    }
+
     abstract static class UsbHandler extends Handler {
 
         // current USB state
@@ -608,6 +632,19 @@
             sendMessage(m);
         }
 
+        public boolean sendMessage(int what) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            return sendMessageDelayed(m,0);
+        }
+
+        public void sendMessage(int what, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = operationId;
+            sendMessage(m);
+        }
+
         public void sendMessage(int what, Object arg) {
             removeMessages(what);
             Message m = Message.obtain(this, what);
@@ -615,6 +652,22 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, Object arg, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg;
+            m.arg1 = operationId;
+            sendMessage(m);
+        }
+
+        public void sendMessage(int what, boolean arg, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = (arg ? 1 : 0);
+            m.arg2 = operationId;
+            sendMessage(m);
+        }
+
         public void sendMessage(int what, Object arg, boolean arg1) {
             removeMessages(what);
             Message m = Message.obtain(this, what);
@@ -623,6 +676,15 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, long arg, boolean arg1, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg;
+            m.arg1 = (arg1 ? 1 : 0);
+            m.arg2 = operationId;
+            sendMessage(m);
+        }
+
         public void sendMessage(int what, boolean arg1, boolean arg2) {
             removeMessages(what);
             Message m = Message.obtain(this, what);
@@ -680,7 +742,7 @@
             sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
         }
 
-        private void setAdbEnabled(boolean enable) {
+        private void setAdbEnabled(boolean enable, int operationId) {
             if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
 
             if (enable) {
@@ -689,7 +751,7 @@
                 setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, "");
             }
 
-            setEnabledFunctions(mCurrentFunctions, true);
+            setEnabledFunctions(mCurrentFunctions, true, operationId);
             updateAdbNotification(false);
         }
 
@@ -701,6 +763,8 @@
         private void updateCurrentAccessory() {
             // We are entering accessory mode if we have received a request from the host
             // and the request has not timed out yet.
+            int operationId = sUsbOperationCount.incrementAndGet();
+
             boolean enteringAccessoryMode = hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT);
 
             if (mConfigured && enteringAccessoryMode) {
@@ -732,18 +796,18 @@
                 }
             } else {
                 if (!enteringAccessoryMode) {
-                    notifyAccessoryModeExit();
+                    notifyAccessoryModeExit(operationId);
                 } else if (DEBUG) {
                     Slog.v(TAG, "Debouncing accessory mode exit");
                 }
             }
         }
 
-        private void notifyAccessoryModeExit() {
+        private void notifyAccessoryModeExit(int operationId) {
             // make sure accessory mode is off
             // and restore default functions
             Slog.d(TAG, "exited USB accessory mode");
-            setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+            setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
 
             if (mCurrentAccessory != null) {
                 if (mBootCompleted) {
@@ -869,8 +933,8 @@
                     mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
         }
 
-        private void setScreenUnlockedFunctions() {
-            setEnabledFunctions(mScreenUnlockedFunctions, false);
+        private void setScreenUnlockedFunctions(int operationId) {
+            setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
         }
 
         private static class AdbTransport extends IAdbTransport.Stub {
@@ -883,7 +947,8 @@
             @Override
             public void onAdbEnabled(boolean enabled, byte transportType) {
                 if (transportType == AdbTransportType.USB) {
-                    mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+                    int operationId = sUsbOperationCount.incrementAndGet();
+                    mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
                 }
             }
         }
@@ -906,6 +971,7 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_UPDATE_STATE:
+                    int operationId = sUsbOperationCount.incrementAndGet();
                     mConnected = (msg.arg1 == 1);
                     mConfigured = (msg.arg2 == 1);
 
@@ -923,9 +989,9 @@
                             // restore defaults when USB is disconnected
                             if (!mScreenLocked
                                     && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
-                                setScreenUnlockedFunctions();
+                                setScreenUnlockedFunctions(operationId);
                             } else {
-                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                             }
                         }
                         updateUsbFunctions();
@@ -1036,13 +1102,15 @@
                     updateUsbNotification(false);
                     break;
                 case MSG_ENABLE_ADB:
-                    setAdbEnabled(msg.arg1 == 1);
+                    setAdbEnabled(msg.arg1 == 1, msg.arg2);
                     break;
                 case MSG_SET_CURRENT_FUNCTIONS:
                     long functions = (Long) msg.obj;
-                    setEnabledFunctions(functions, false);
+                    operationId = (int) msg.arg1;
+                    setEnabledFunctions(functions, false, operationId);
                     break;
                 case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     mScreenUnlockedFunctions = (Long) msg.obj;
                     if (mSettings != null) {
                         SharedPreferences.Editor editor = mSettings.edit();
@@ -1053,12 +1121,13 @@
                     }
                     if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
                         // If the screen is unlocked, also set current functions.
-                        setScreenUnlockedFunctions();
+                        setScreenUnlockedFunctions(operationId);
                     } else {
-                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                     }
                     break;
                 case MSG_UPDATE_SCREEN_LOCK:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (msg.arg1 == 1 == mScreenLocked) {
                         break;
                     }
@@ -1068,23 +1137,25 @@
                     }
                     if (mScreenLocked) {
                         if (!mConnected) {
-                            setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                            setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                         }
                     } else {
                         if (mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE
                                 && mCurrentFunctions == UsbManager.FUNCTION_NONE) {
                             // Set the screen unlocked functions if current function is charging.
-                            setScreenUnlockedFunctions();
+                            setScreenUnlockedFunctions(operationId);
                         }
                     }
                     break;
                 case MSG_UPDATE_USER_RESTRICTIONS:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     // Restart the USB stack if USB transfer is enabled but no longer allowed.
                     if (isUsbDataTransferActive(mCurrentFunctions) && !isUsbTransferAllowed()) {
-                        setEnabledFunctions(UsbManager.FUNCTION_NONE, true);
+                        setEnabledFunctions(UsbManager.FUNCTION_NONE, true, operationId);
                     }
                     break;
                 case MSG_SYSTEM_READY:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     mNotificationManager = (NotificationManager)
                             mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
@@ -1102,17 +1173,19 @@
                                         NotificationManager.IMPORTANCE_HIGH));
                     }
                     mSystemReady = true;
-                    finishBoot();
+                    finishBoot(operationId);
                     break;
                 case MSG_LOCALE_CHANGED:
                     updateAdbNotification(true);
                     updateUsbNotification(true);
                     break;
                 case MSG_BOOT_COMPLETED:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     mBootCompleted = true;
-                    finishBoot();
+                    finishBoot(operationId);
                     break;
                 case MSG_USER_SWITCHED: {
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (mCurrentUser != msg.arg1) {
                         if (DEBUG) {
                             Slog.v(TAG, "Current user switched to " + msg.arg1);
@@ -1125,16 +1198,18 @@
                                     mSettings.getString(String.format(Locale.ENGLISH,
                                             UNLOCKED_CONFIG_PREF, mCurrentUser), ""));
                         }
-                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                     }
                     break;
                 }
                 case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (DEBUG) {
-                        Slog.v(TAG, "Accessory mode enter timeout: " + mConnected);
+                        Slog.v(TAG, "Accessory mode enter timeout: " + mConnected
+                                    + " ,operationId: " + operationId);
                     }
                     if (!mConnected || (mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) == 0) {
-                        notifyAccessoryModeExit();
+                        notifyAccessoryModeExit(operationId);
                     }
                     break;
                 }
@@ -1157,7 +1232,9 @@
             }
         }
 
-        protected void finishBoot() {
+        public abstract void handlerInitDone(int operationId);
+
+        protected void finishBoot(int operationId) {
             if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
                 if (mPendingBootBroadcast) {
                     updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
@@ -1165,9 +1242,9 @@
                 }
                 if (!mScreenLocked
                         && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
-                    setScreenUnlockedFunctions();
+                    setScreenUnlockedFunctions(operationId);
                 } else {
-                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                 }
                 if (mCurrentAccessory != null) {
                     mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -1507,7 +1584,8 @@
         /**
          * Evaluates USB function policies and applies the change accordingly.
          */
-        protected abstract void setEnabledFunctions(long functions, boolean forceRestart);
+        protected abstract void setEnabledFunctions(long functions,
+                boolean forceRestart, int operationId);
 
         public void setAccessoryUEventTime(long accessoryConnectionStartTime) {
             mAccessoryConnectionStartTime = accessoryConnectionStartTime;
@@ -1522,6 +1600,11 @@
             mSendStringCount = 0;
             mStartAccessory = false;
         }
+
+        public abstract void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions);
+
+        public abstract void getUsbSpeedCb(int speed);
     }
 
     private static final class UsbHandlerLegacy extends UsbHandler {
@@ -1540,6 +1623,11 @@
         private String mCurrentFunctionsStr;
         private boolean mUsbDataUnlocked;
 
+        /**
+         * Keeps track of the latest setCurrentUsbFunctions request number.
+         */
+        private int mCurrentRequest = 0;
+
         UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
                 UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
             super(looper, context, deviceManager, alsaManager, permissionManager);
@@ -1573,6 +1661,10 @@
             }
         }
 
+        @Override
+        public void handlerInitDone(int operationId) {
+        }
+
         private void readOemUsbOverrideConfig(Context context) {
             String[] configList = context.getResources().getStringArray(
                     com.android.internal.R.array.config_oemUsbModeOverride);
@@ -1675,11 +1767,14 @@
         }
 
         @Override
-        protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
+        protected void setEnabledFunctions(long usbFunctions,
+                boolean forceRestart, int operationId) {
             boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
             if (DEBUG) {
-                Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions + ", "
-                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+                Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions +
+                        " ,forceRestart=" + forceRestart +
+                        " ,usbDataUnlocked=" + usbDataUnlocked +
+                        " ,operationId=" + operationId);
             }
 
             if (usbDataUnlocked != mUsbDataUnlocked) {
@@ -1775,7 +1870,6 @@
                     || !mCurrentFunctionsStr.equals(functions)
                     || !mCurrentFunctionsApplied
                     || forceRestart) {
-                Slog.i(TAG, "Setting USB config to " + functions);
                 mCurrentFunctionsStr = functions;
                 mCurrentOemFunctions = oemFunctions;
                 mCurrentFunctionsApplied = false;
@@ -1871,15 +1965,18 @@
             if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
             return true;
         }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed){
+        }
     }
 
-    private static final class UsbHandlerHal extends UsbHandler {
-
-        /**
-         * Proxy object for the usb gadget hal daemon.
-         */
-        @GuardedBy("mGadgetProxyLock")
-        private IUsbGadget mGadgetProxy;
+    private final class UsbHandlerHal extends UsbHandler {
 
         private final Object mGadgetProxyLock = new Object();
 
@@ -1926,33 +2023,20 @@
         UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
                 UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
             super(looper, context, deviceManager, alsaManager, permissionManager);
+            int operationId = sUsbOperationCount.incrementAndGet();
             try {
-                ServiceNotification serviceNotification = new ServiceNotification();
-
-                boolean ret = IServiceManager.getService()
-                        .registerForNotifications(GADGET_HAL_FQ_NAME, "", serviceNotification);
-                if (!ret) {
-                    Slog.e(TAG, "Failed to register usb gadget service start notification");
-                    return;
-                }
 
                 synchronized (mGadgetProxyLock) {
-                    mGadgetProxy = IUsbGadget.getService(true);
-                    mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
-                            USB_GADGET_HAL_DEATH_COOKIE);
                     mCurrentFunctions = UsbManager.FUNCTION_NONE;
                     mCurrentUsbFunctionsRequested = true;
                     mUsbSpeed = UsbSpeed.UNKNOWN;
                     mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
-                    mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+                    updateUsbGadgetHalVersion();
                 }
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
-                updateUsbGadgetHalVersion();
             } catch (NoSuchElementException e) {
                 Slog.e(TAG, "Usb gadget hal not found", e);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Usb Gadget hal not responding", e);
             } catch (Exception e) {
                 Slog.e(TAG, "Error initializing UsbHandler", e);
             }
@@ -1965,7 +2049,7 @@
                 if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
                     Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie);
                     synchronized (mGadgetProxyLock) {
-                        mGadgetProxy = null;
+                        mUsbGadgetHal = null;
                     }
                 }
             }
@@ -1988,18 +2072,22 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_SET_CHARGING_FUNCTIONS:
-                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                    int operationId = sUsbOperationCount.incrementAndGet();
+                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                     break;
                 case MSG_SET_FUNCTIONS_TIMEOUT:
-                    Slog.e(TAG, "Set functions timed out! no reply from usb hal");
+                    operationId = sUsbOperationCount.incrementAndGet();
+                    Slog.e(TAG, "Set functions timed out! no reply from usb hal"
+                                + " ,operationId:" + operationId);
                     if (msg.arg1 != 1) {
                         // Set this since default function may be selected from Developer options
-                        setEnabledFunctions(mScreenUnlockedFunctions, false);
+                        setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
                     }
                     break;
                 case MSG_GET_CURRENT_USB_FUNCTIONS:
                     Slog.i(TAG, "processing MSG_GET_CURRENT_USB_FUNCTIONS");
                     mCurrentUsbFunctionsReceived = true;
+                    operationId = msg.arg2;
 
                     if (mCurrentUsbFunctionsRequested) {
                         Slog.i(TAG, "updating mCurrentFunctions");
@@ -2009,91 +2097,71 @@
                                 "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
                         mCurrentFunctionsApplied = msg.arg1 == 1;
                     }
-                    finishBoot();
+                    finishBoot(operationId);
                     break;
                 case MSG_FUNCTION_SWITCH_TIMEOUT:
                     /**
                      * Dont force to default when the configuration is already set to default.
                      */
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (msg.arg1 != 1) {
                         // Set this since default function may be selected from Developer options
-                        setEnabledFunctions(mScreenUnlockedFunctions, false);
+                        setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
                     }
                     break;
                 case MSG_GADGET_HAL_REGISTERED:
                     boolean preexisting = msg.arg1 == 1;
+                    operationId = sUsbOperationCount.incrementAndGet();
                     synchronized (mGadgetProxyLock) {
                         try {
-                            mGadgetProxy = IUsbGadget.getService();
-                            mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
-                                    USB_GADGET_HAL_DEATH_COOKIE);
+                            mUsbGadgetHal = UsbGadgetHalInstance.getInstance(mUsbDeviceManager,
+                                    null);
                             if (!mCurrentFunctionsApplied && !preexisting) {
-                                setEnabledFunctions(mCurrentFunctions, false);
+                                setEnabledFunctions(mCurrentFunctions, false, operationId);
                             }
                         } catch (NoSuchElementException e) {
                             Slog.e(TAG, "Usb gadget hal not found", e);
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "Usb Gadget hal not responding", e);
                         }
                     }
                     break;
                 case MSG_RESET_USB_GADGET:
                     synchronized (mGadgetProxyLock) {
-                        if (mGadgetProxy == null) {
-                            Slog.e(TAG, "reset Usb Gadget mGadgetProxy is null");
+                        if (mUsbGadgetHal == null) {
+                            Slog.e(TAG, "reset Usb Gadget mUsbGadgetHal is null");
                             break;
                         }
 
                         try {
-                            android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxy =
-                                    android.hardware.usb.gadget.V1_1.IUsbGadget
-                                            .castFrom(mGadgetProxy);
-                            gadgetProxy.reset();
-                        } catch (RemoteException e) {
+                            mUsbGadgetHal.reset();
+                        } catch (Exception e) {
                             Slog.e(TAG, "reset Usb Gadget failed", e);
                         }
                     }
                     break;
                 case MSG_UPDATE_USB_SPEED:
-                    synchronized (mGadgetProxyLock) {
-                        if (mGadgetProxy == null) {
-                            Slog.e(TAG, "mGadgetProxy is null");
-                            break;
-                        }
+                    operationId = sUsbOperationCount.incrementAndGet();
+                    if (mUsbGadgetHal == null) {
+                        Slog.e(TAG, "mGadgetHal is null, operationId:" + operationId);
+                        break;
+                    }
 
-                        try {
-                            android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
-                                    android.hardware.usb.gadget.V1_2.IUsbGadget
-                                            .castFrom(mGadgetProxy);
-                            if (gadgetProxy != null) {
-                                gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
-                            }
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "get UsbSpeed failed", e);
-                        }
+                    try {
+                        mUsbGadgetHal.getUsbSpeed(operationId);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "get UsbSpeed failed", e);
                     }
                     break;
                 case MSG_UPDATE_HAL_VERSION:
-                    synchronized (mGadgetProxyLock) {
-                        if (mGadgetProxy == null) {
-                            Slog.e(TAG, "mGadgetProxy is null");
-                            break;
+                    if (mUsbGadgetHal == null) {
+                        Slog.e(TAG, "mUsbGadgetHal is null");
+                        break;
+                    }
+                    else {
+                        try {
+                            mCurrentGadgetHalVersion = mUsbGadgetHal.getGadgetHalVersion();
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "update Usb gadget version failed", e);
                         }
-
-                        android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
-                                android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
-                        if (gadgetProxy == null) {
-                            android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxyV1By1 =
-                                    android.hardware.usb.gadget.V1_1.IUsbGadget
-                                            .castFrom(mGadgetProxy);
-                            if (gadgetProxyV1By1 == null) {
-                                mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
-                                break;
-                            }
-                            mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_1;
-                            break;
-                        }
-                        mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_2;
                     }
                     break;
                 default:
@@ -2101,56 +2169,31 @@
             }
         }
 
-        private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
-            int mRequest;
-            long mFunctions;
-            boolean mChargingFunctions;
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
 
-            UsbGadgetCallback() {
+            if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
+                  || (mFunctions != functions)) {
+                return;
             }
 
-            UsbGadgetCallback(int request, long functions,
-                    boolean chargingFunctions) {
-                mRequest = request;
-                mFunctions = functions;
-                mChargingFunctions = chargingFunctions;
-            }
-
-            @Override
-            public void setCurrentUsbFunctionsCb(long functions,
-                    int status) {
-                /**
-                 * Callback called for a previous setCurrenUsbFunction
-                 */
-                if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
-                        || (mFunctions != functions)) {
-                    return;
-                }
-
-                removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
-                Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
-                if (status == Status.SUCCESS) {
-                    mCurrentFunctionsApplied = true;
-                } else if (!mChargingFunctions) {
-                    Slog.e(TAG, "Setting default fuctions");
-                    sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
-                }
-            }
-
-            @Override
-            public void getCurrentUsbFunctionsCb(long functions,
-                    int status) {
-                sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
-                        status == Status.FUNCTIONS_APPLIED);
-            }
-
-            @Override
-            public void getUsbSpeedCb(int speed) {
-                mUsbSpeed = speed;
+            removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+            Slog.i(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
+            if (status == Status.SUCCESS) {
+                mCurrentFunctionsApplied = true;
+            } else if (!mChargingFunctions) {
+                Slog.e(TAG, "Setting default fuctions");
+                sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
             }
         }
 
-        private void setUsbConfig(long config, boolean chargingFunctions) {
+        @Override
+        public void getUsbSpeedCb(int speed) {
+            mUsbSpeed = speed;
+        }
+
+        private void setUsbConfig(long config, boolean chargingFunctions, int operationId) {
             if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
             /**
              * Cancel any ongoing requests, if present.
@@ -2160,8 +2203,8 @@
             removeMessages(MSG_SET_CHARGING_FUNCTIONS);
 
             synchronized (mGadgetProxyLock) {
-                if (mGadgetProxy == null) {
-                    Slog.e(TAG, "setUsbConfig mGadgetProxy is null");
+                if (mUsbGadgetHal == null) {
+                    Slog.e(TAG, "setUsbConfig mUsbGadgetHal is null");
                     return;
                 }
                 try {
@@ -2178,10 +2221,9 @@
                         LocalServices.getService(AdbManagerInternal.class)
                                 .stopAdbdForTransport(AdbTransportType.USB);
                     }
-                    UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
-                            config, chargingFunctions);
-                    mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback,
-                            SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS);
+                    mUsbGadgetHal.setCurrentUsbFunctions(mCurrentRequest,
+                            config, chargingFunctions,
+                            SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS, operationId);
                     sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions,
                             SET_FUNCTIONS_TIMEOUT_MS);
                     if (mConnected) {
@@ -2190,17 +2232,19 @@
                                 SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS);
                     }
                     if (DEBUG) Slog.d(TAG, "timeout message queued");
-                } catch (RemoteException e) {
+                } catch (Exception e) {//RemoteException e) {
                     Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e);
                 }
             }
         }
 
         @Override
-        protected void setEnabledFunctions(long functions, boolean forceRestart) {
+        protected void setEnabledFunctions(long functions, boolean forceRestart, int operationId) {
             if (DEBUG) {
-                Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
-                        + "forceRestart=" + forceRestart);
+                Slog.d(TAG, "setEnabledFunctionsi " +
+                        "functions=" + functions +
+                        ", forceRestart=" + forceRestart +
+                        ", operationId=" + operationId);
             }
             if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
                 if ((functions & UsbManager.FUNCTION_NCM) != 0) {
@@ -2221,7 +2265,7 @@
                 functions = getAppliedFunctions(functions);
 
                 // Set the new USB configuration.
-                setUsbConfig(functions, chargingFunctions);
+                setUsbConfig(functions, chargingFunctions, operationId);
 
                 if (mBootCompleted && isUsbDataTransferActive(functions)) {
                     // Start up dependent services.
@@ -2229,6 +2273,11 @@
                 }
             }
         }
+
+        @Override
+        public void handlerInitDone(int operationId) {
+            mUsbGadgetHal.getCurrentUsbFunctions(operationId);
+        }
     }
 
     /* returns the currently attached USB accessory */
@@ -2270,6 +2319,21 @@
         return mHandler.getGadgetHalVersion();
     }
 
+    public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
+        mHandler.setCurrentUsbFunctionsCb(functions, status,
+                    mRequest, mFunctions, mChargingFunctions);
+    }
+
+    public void getCurrentUsbFunctionsCb(long functions, int status) {
+        mHandler.sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
+                    status == Status.FUNCTIONS_APPLIED);
+    }
+
+    public void getUsbSpeedCb(int speed) {
+        mHandler.getUsbSpeedCb(speed);
+    }
+
     /**
      * Returns a dup of the control file descriptor for the given function.
      */
@@ -2295,7 +2359,7 @@
      *
      * @param functions The functions to set, or empty to set the charging function.
      */
-    public void setCurrentFunctions(long functions) {
+    public void setCurrentFunctions(long functions, int operationId) {
         if (DEBUG) {
             Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
         }
@@ -2312,7 +2376,7 @@
         } else if (functions == UsbManager.FUNCTION_ACCESSORY) {
             MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
         }
-        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
+        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, operationId);
     }
 
     /**
@@ -2340,7 +2404,8 @@
     }
 
     private void onAdbEnabled(boolean enabled) {
-        mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+        int operationId = sUsbOperationCount.incrementAndGet();
+        mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
     }
 
     /**
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index d821dee..d09f729 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -622,16 +622,16 @@
     }
 
     @Override
-    public void setCurrentFunctions(long functions) {
+    public void setCurrentFunctions(long functions, int operationId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
         Preconditions.checkState(mDeviceManager != null);
-        mDeviceManager.setCurrentFunctions(functions);
+        mDeviceManager.setCurrentFunctions(functions, operationId);
     }
 
     @Override
-    public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
-        setCurrentFunctions(UsbManager.usbFunctionsFromString(functions));
+    public void setCurrentFunction(String functions, boolean usbDataUnlocked, int operationId) {
+        setCurrentFunctions(UsbManager.usbFunctionsFromString(functions), operationId);
     }
 
     @Override
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
new file mode 100644
index 0000000..bdfe60a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
@@ -0,0 +1,220 @@
+/*
+ * 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 com.android.server.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_V2_0;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.IUsbGadget;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+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.UsbDeviceManager;
+
+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 UsbGadgetAidl implements UsbGadgetHal {
+    private static final String TAG = UsbGadgetAidl.class.getSimpleName();
+    private static final String USB_GADGET_AIDL_SERVICE = IUsbGadget.DESCRIPTOR + "/default";
+    // Proxy object for the usb gadget hal daemon.
+    @GuardedBy("mGadgetProxyLock")
+    private IUsbGadget mGadgetProxy;
+    private final UsbDeviceManager mDeviceManager;
+    public final IndentingPrintWriter mPw;
+    // Mutex for all mutable shared state.
+    private final Object mGadgetProxyLock = new Object();
+    // Callback when the UsbDevice status is changed by the kernel.
+    private UsbGadgetCallback mUsbGadgetCallback;
+
+    public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+        synchronized (mGadgetProxyLock) {
+            if (mGadgetProxy == null) {
+                throw new RemoteException("IUsb not initialized yet");
+            }
+        }
+        Slog.i(TAG, "USB Gadget HAL AIDL version: GADGET_HAL_V2_0");
+        return GADGET_HAL_V2_0;
+    }
+
+    @Override
+    public void systemReady() {
+    }
+
+    public void serviceDied() {
+        logAndPrint(Log.ERROR, mPw, "Usb Gadget AIDL hal service died");
+        synchronized (mGadgetProxyLock) {
+            mGadgetProxy = null;
+        }
+        connectToProxy(null);
+    }
+
+    private void connectToProxy(IndentingPrintWriter pw) {
+        synchronized (mGadgetProxyLock) {
+            if (mGadgetProxy != null) {
+                return;
+            }
+
+            try {
+                mGadgetProxy = IUsbGadget.Stub.asInterface(
+                        ServiceManager.waitForService(USB_GADGET_AIDL_SERVICE));
+            } catch (NoSuchElementException e) {
+                logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+                        + " Did the service fail to start?", e);
+            }
+        }
+    }
+
+    static boolean isServicePresent(IndentingPrintWriter pw) {
+        try {
+            return ServiceManager.isDeclared(USB_GADGET_AIDL_SERVICE);
+        } catch (NoSuchElementException e) {
+            logAndPrintException(pw, "connectToProxy: usb gadget Aidl hal service not found.", e);
+        }
+
+        return false;
+    }
+
+    public UsbGadgetAidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+        mDeviceManager = Objects.requireNonNull(deviceManager);
+        mPw = pw;
+        connectToProxy(mPw);
+    }
+
+    @Override
+    public void getCurrentUsbFunctions(long operationId) {
+        synchronized (mGadgetProxyLock) {
+            try {
+                mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback(), operationId);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw,
+                        "RemoteException while calling getCurrentUsbFunctions"
+                        + ", opID:" + operationId, e);
+                return;
+            }
+        }
+    }
+
+    @Override
+    public void getUsbSpeed(long operationId) {
+        try {
+            synchronized (mGadgetProxyLock) {
+                mGadgetProxy.getUsbSpeed(new UsbGadgetCallback(), operationId);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getUsbSpeed"
+                    + ", opID:" + operationId, e);
+            return;
+        }
+    }
+
+    @Override
+    public void reset() {
+        try {
+            synchronized (mGadgetProxyLock) {
+                mGadgetProxy.reset();
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getUsbSpeed", e);
+            return;
+        }
+    }
+
+    @Override
+    public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+            boolean mChargingFunctions, int timeout, long operationId) {
+        try {
+            mUsbGadgetCallback = new UsbGadgetCallback(mRequest,
+                                      mFunctions, mChargingFunctions);
+            synchronized (mGadgetProxyLock) {
+                mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback,
+                        timeout, operationId);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling setCurrentUsbFunctions: "
+                    + "mRequest=" + mRequest
+                    + ", mFunctions=" + mFunctions
+                    + ", mChargingFunctions=" + mChargingFunctions
+                    + ", timeout=" + timeout
+                    + ", opID:" + operationId, e);
+            return;
+        }
+    }
+
+    private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+        public int mRequest;
+        public long mFunctions;
+        public boolean mChargingFunctions;
+
+        UsbGadgetCallback() {
+        }
+
+        UsbGadgetCallback(int request, long functions,
+                boolean chargingFunctions) {
+            mRequest = request;
+            mFunctions = functions;
+            mChargingFunctions = chargingFunctions;
+        }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                int status, long transactionId) {
+            mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+                    mRequest, mFunctions, mChargingFunctions);
+        }
+
+        @Override
+        public void getCurrentUsbFunctionsCb(long functions,
+                int status, long transactionId) {
+            mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed, long transactionId) {
+            mDeviceManager.getUsbSpeedCb(speed);
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return IUsbGadgetCallback.HASH;
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return IUsbGadgetCallback.VERSION;
+        }
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
new file mode 100644
index 0000000..267247b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
@@ -0,0 +1,138 @@
+/*
+ * 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 com.android.server.usb.hal.gadget;
+
+import android.annotation.IntDef;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+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 UsbGadgetHal {
+    /**
+     * 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();
+
+    /**
+     * This function is used to query the USB functions included in the
+     * current USB configuration.
+     *
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void getCurrentUsbFunctions(long transactionId);
+
+    /**
+     * The function is used to query current USB speed.
+     *
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void getUsbSpeed(long transactionId);
+
+    /**
+     * This function is used to reset USB gadget driver.
+     * Performs USB data connection reset. The connection will disconnect and
+     * reconnect.
+     */
+    public void reset();
+
+    /**
+     * Invoked to query the version of current gadget hal implementation.
+     */
+    public @UsbHalVersion int getGadgetHalVersion() throws RemoteException;
+
+    /**
+     * This function is used to set the current USB gadget configuration.
+     * The USB gadget needs to be torn down if a USB configuration is already
+     * active.
+     *
+     * @param functions list of functions defined by GadgetFunction to be
+     *                  included in the gadget composition.
+     * @param timeout The maximum time (in milliseconds) within which the
+     *                IUsbGadgetCallback needs to be returned.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void setCurrentUsbFunctions(int request, long functions,
+        boolean chargingFunctions, int timeout, long transactionId);
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
new file mode 100644
index 0000000..d268315
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
@@ -0,0 +1,48 @@
+/*
+ * 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 com.android.server.usb.hal.gadget;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.hal.gadget.UsbGadgetHidl;
+import com.android.server.usb.hal.gadget.UsbGadgetAidl;
+import com.android.server.usb.UsbDeviceManager;
+
+import android.util.Log;
+/**
+ * Helper class that queries the underlying hal layer to populate UsbPortHal instance.
+ */
+public final class UsbGadgetHalInstance {
+
+    public static UsbGadgetHal getInstance(UsbDeviceManager deviceManager,
+            IndentingPrintWriter pw) {
+
+        logAndPrint(Log.DEBUG, pw, "Querying USB Gadget HAL version");
+        if (UsbGadgetAidl.isServicePresent(null)) {
+            logAndPrint(Log.INFO, pw, "USB Gadget HAL AIDL present");
+            return new UsbGadgetAidl(deviceManager, pw);
+        }
+        if (UsbGadgetHidl.isServicePresent(null)) {
+            logAndPrint(Log.INFO, pw, "USB Gadget HAL HIDL present");
+            return new UsbGadgetHidl(deviceManager, pw);
+        }
+
+        logAndPrint(Log.ERROR, pw, "USB Gadget HAL AIDL/HIDL not present");
+        return null;
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
new file mode 100644
index 0000000..3e5ecc5
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
@@ -0,0 +1,261 @@
+/*
+ * 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 com.android.server.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_NOT_SUPPORTED;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_0;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_1;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_2;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.V1_0.Status;
+import android.hardware.usb.gadget.V1_0.IUsbGadget;
+import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
+import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+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 com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+/**
+ *
+ */
+public final class UsbGadgetHidl implements UsbGadgetHal {
+    // Cookie sent for usb gadget hal death notification.
+    private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000;
+    // Proxy object for the usb gadget hal daemon.
+    @GuardedBy("mGadgetProxyLock")
+    private IUsbGadget mGadgetProxy;
+    private UsbDeviceManager mDeviceManager;
+    private final IndentingPrintWriter mPw;
+    // Mutex for all mutable shared state.
+    private final Object mGadgetProxyLock = new Object();
+    private UsbGadgetCallback mUsbGadgetCallback;
+
+    public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+        int version;
+        synchronized(mGadgetProxyLock) {
+            if (mGadgetProxy == null) {
+                throw new RemoteException("IUsbGadget not initialized yet");
+            }
+            if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                version = UsbManager.GADGET_HAL_V1_2;
+            } else if (android.hardware.usb.gadget.V1_1.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                version = UsbManager.GADGET_HAL_V1_1;
+            } else {
+                version = UsbManager.GADGET_HAL_V1_0;
+            }
+            logAndPrint(Log.INFO, mPw, "USB Gadget HAL HIDL version: " + version);
+            return version;
+        }
+    }
+
+    final class DeathRecipient implements IHwBinder.DeathRecipient {
+        private final IndentingPrintWriter mPw;
+
+        DeathRecipient(IndentingPrintWriter pw) {
+            mPw = pw;
+        }
+
+        @Override
+        public void serviceDied(long cookie) {
+            if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
+                logAndPrint(Log.ERROR, mPw, "Usb Gadget hal service died cookie: " + cookie);
+                synchronized (mGadgetProxyLock) {
+                    mGadgetProxy = null;
+                }
+            }
+        }
+    }
+
+    final class ServiceNotification extends IServiceNotification.Stub {
+        @Override
+        public void onRegistration(String fqName, String name, boolean preexisting) {
+            logAndPrint(Log.INFO, mPw, "Usb gadget hal service started " + fqName + " " + name);
+            connectToProxy(null);
+        }
+    }
+
+    private void connectToProxy(IndentingPrintWriter pw) {
+        synchronized (mGadgetProxyLock) {
+            if (mGadgetProxy != null) {
+                return;
+            }
+
+            try {
+                mGadgetProxy = IUsbGadget.getService();
+                mGadgetProxy.linkToDeath(new DeathRecipient(pw), USB_GADGET_HAL_DEATH_COOKIE);
+            } catch (NoSuchElementException e) {
+                logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+                        + " Did the service fail to start?", e);
+            } catch (RemoteException e) {
+                logAndPrintException(pw, "connectToProxy: usb gadget hal service not responding"
+                        , e);
+            }
+        }
+    }
+
+    @Override
+    public void systemReady() {
+    }
+
+    static boolean isServicePresent(IndentingPrintWriter pw) {
+        try {
+            IUsbGadget.getService(true);
+        } catch (NoSuchElementException e) {
+            logAndPrintException(pw, "connectToProxy: usb gadget hidl hal service not found.", e);
+            return false;
+        } catch (RemoteException e) {
+            logAndPrintException(pw, "IUSBGadget hal service present but failed to get service", e);
+        }
+
+        return true;
+    }
+
+    public UsbGadgetHidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+        mDeviceManager = Objects.requireNonNull(deviceManager);
+        mPw = pw;
+        try {
+            ServiceNotification serviceNotification = new ServiceNotification();
+
+            boolean ret = IServiceManager.getService()
+                    .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
+                            "", serviceNotification);
+            if (!ret) {
+                logAndPrint(Log.ERROR, pw, "Failed to register service start notification");
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(pw, "Failed to register service start notification", e);
+            return;
+        }
+        connectToProxy(mPw);
+    }
+
+    @Override
+    public void getCurrentUsbFunctions(long transactionId) {
+        try {
+            synchronized(mGadgetProxyLock) {
+                mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getCurrentUsbFunctions", e);
+            return;
+        }
+    }
+
+    @Override
+    public void getUsbSpeed(long transactionId) {
+        try {
+            synchronized(mGadgetProxyLock) {
+                if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                    android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+                    android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+                    gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
+                }
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw, "get UsbSpeed failed", e);
+        }
+    }
+
+    @Override
+    public void reset() {
+        try {
+            synchronized(mGadgetProxyLock) {
+                if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                    android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+                    android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+                    gadgetProxy.reset();
+                }
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getUsbSpeed", e);
+            return;
+        }
+    }
+
+    @Override
+    public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+            boolean mChargingFunctions, int timeout, long operationId) {
+        try {
+            mUsbGadgetCallback = new UsbGadgetCallback(null, mRequest,
+                                      mFunctions, mChargingFunctions);
+            synchronized(mGadgetProxyLock) {
+                mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback, timeout);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling setCurrentUsbFunctions"
+                    + " mRequest = " + mRequest
+                    + ", mFunctions = " + mFunctions
+                    + ", timeout = " + timeout
+                    + ", mChargingFunctions = " + mChargingFunctions
+                    + ", operationId =" + operationId, e);
+            return;
+        }
+    }
+
+    private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+        public int mRequest;
+        public long mFunctions;
+        public boolean mChargingFunctions;
+
+        UsbGadgetCallback() {
+        }
+        UsbGadgetCallback(IndentingPrintWriter pw, int request,
+                long functions, boolean chargingFunctions) {
+            mRequest = request;
+            mFunctions = functions;
+            mChargingFunctions = chargingFunctions;
+        }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                int status) {
+            mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+                    mRequest, mFunctions, mChargingFunctions);
+        }
+
+        @Override
+        public void getCurrentUsbFunctionsCb(long functions,
+                int status) {
+            mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed) {
+            mDeviceManager.getUsbSpeedCb(speed);
+        }
+    }
+}
+
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 86b98f1..2435243 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -5,6 +5,7 @@
 import android.net.NetworkCapabilities;
 import android.telecom.Connection;
 import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsCallProfile;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -494,7 +495,7 @@
             PreciseCallState.PRECISE_CALL_STATE_HOLDING,
             PreciseCallState.PRECISE_CALL_STATE_DIALING,
             PreciseCallState.PRECISE_CALL_STATE_ALERTING,
-            PreciseCallState. PRECISE_CALL_STATE_INCOMING,
+            PreciseCallState.PRECISE_CALL_STATE_INCOMING,
             PreciseCallState.PRECISE_CALL_STATE_WAITING,
             PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
             PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
@@ -727,6 +728,36 @@
     })
     public @interface ValidationStatus {}
 
+    /**
+     * IMS call Service types
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "SERVICE_TYPE_" }, value = {
+            ImsCallProfile.SERVICE_TYPE_NONE,
+            ImsCallProfile.SERVICE_TYPE_NORMAL,
+            ImsCallProfile.SERVICE_TYPE_EMERGENCY,
+    })
+    public @interface ImsCallServiceType {}
+
+    /**
+     * IMS call types
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "CALL_TYPE_" }, value = {
+            ImsCallProfile.CALL_TYPE_NONE,
+            ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO,
+            ImsCallProfile.CALL_TYPE_VOICE,
+            ImsCallProfile.CALL_TYPE_VIDEO_N_VOICE,
+            ImsCallProfile.CALL_TYPE_VT,
+            ImsCallProfile.CALL_TYPE_VT_TX,
+            ImsCallProfile.CALL_TYPE_VT_RX,
+            ImsCallProfile.CALL_TYPE_VT_NODIR,
+            ImsCallProfile.CALL_TYPE_VS,
+            ImsCallProfile.CALL_TYPE_VS_TX,
+            ImsCallProfile.CALL_TYPE_VS_RX,
+    })
+    public @interface ImsCallType {}
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index b7bef39..1dc64a9 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -29,8 +29,10 @@
  * Contains information about a call's attributes as passed up from the HAL. If there are multiple
  * ongoing calls, the CallAttributes will pertain to the call in the foreground.
  * @hide
+ * @deprecated use {@link CallState} for call information for each call.
  */
 @SystemApi
+@Deprecated
 public final class CallAttributes implements Parcelable {
     private PreciseCallState mPreciseCallState;
     @NetworkType
diff --git a/telephony/java/android/telephony/CallState.aidl b/telephony/java/android/telephony/CallState.aidl
new file mode 100644
index 0000000..dd5af8e
--- /dev/null
+++ b/telephony/java/android/telephony/CallState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+parcelable CallState;
+
diff --git a/telephony/java/android/telephony/CallState.java b/telephony/java/android/telephony/CallState.java
new file mode 100644
index 0000000..51ecfb0
--- /dev/null
+++ b/telephony/java/android/telephony/CallState.java
@@ -0,0 +1,409 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Annotation.ImsCallServiceType;
+import android.telephony.Annotation.ImsCallType;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseCallStates;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsCallSession;
+
+import java.util.Objects;
+
+/**
+ * Contains information about various states for a call.
+ * @hide
+ */
+@SystemApi
+public final class CallState implements Parcelable {
+
+    /**
+     * Call classifications are just used for backward compatibility of deprecated API {@link
+     * TelephonyCallback#CallAttributesListener#onCallAttributesChanged}, Since these will be
+     * removed when the deprecated API is removed, they should not be opened.
+     */
+    /**
+     * Call classification is not valid. It should not be opened.
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_UNKNOWN = -1;
+
+    /**
+     * Call classification indicating foreground call
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_RINGING = 0;
+
+    /**
+     * Call classification indicating background call
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_FOREGROUND = 1;
+
+    /**
+     * Call classification indicating ringing call
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_BACKGROUND = 2;
+
+    /**
+     * Call classification Max value.
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_MAX = CALL_CLASSIFICATION_BACKGROUND + 1;
+
+    @PreciseCallStates
+    private final int mPreciseCallState;
+
+    @NetworkType
+    private final int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints
+    private final CallQuality mCallQuality;
+
+    private final int mCallClassification;
+    /**
+     * IMS call session ID. {@link ImsCallSession#getCallId()}
+     */
+    @Nullable
+    private String mImsCallId;
+
+    /**
+     * IMS call service type of this call
+     */
+    @ImsCallServiceType
+    private int mImsCallServiceType;
+
+    /**
+     * IMS call type of this call.
+     */
+    @ImsCallType
+    private int mImsCallType;
+
+    /**
+     * Constructor of CallAttributes
+     *
+     * @param callState call state defined in {@link PreciseCallState}
+     * @param networkType network type for this call attributes
+     * @param callQuality call quality for this call attributes, only CallState in
+     *                    {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call
+     *                    quality.
+     * @param callClassification call classification
+     * @param imsCallId IMS call session ID for this call attributes
+     * @param imsCallServiceType IMS call service type for this call attributes
+     * @param imsCallType IMS call type for this call attributes
+     */
+    private CallState(@PreciseCallStates int callState, @NetworkType int networkType,
+            @NonNull CallQuality callQuality, int callClassification, @Nullable String imsCallId,
+            @ImsCallServiceType int imsCallServiceType, @ImsCallType int imsCallType) {
+        this.mPreciseCallState = callState;
+        this.mNetworkType = networkType;
+        this.mCallQuality = callQuality;
+        this.mCallClassification = callClassification;
+        this.mImsCallId = imsCallId;
+        this.mImsCallServiceType = imsCallServiceType;
+        this.mImsCallType = imsCallType;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType
+                + " mCallQuality=" + mCallQuality + " mCallClassification" + mCallClassification
+                + " mImsCallId=" + mImsCallId + " mImsCallServiceType=" + mImsCallServiceType
+                + " mImsCallType=" + mImsCallType;
+    }
+
+    private CallState(Parcel in) {
+        this.mPreciseCallState = in.readInt();
+        this.mNetworkType = in.readInt();
+        this.mCallQuality = in.readParcelable(
+                CallQuality.class.getClassLoader(), CallQuality.class);
+        this.mCallClassification = in.readInt();
+        this.mImsCallId = in.readString();
+        this.mImsCallServiceType = in.readInt();
+        this.mImsCallType = in.readInt();
+    }
+
+    // getters
+    /**
+     * Returns the precise call state of the call.
+     */
+    @PreciseCallStates
+    public int getCallState() {
+        return mPreciseCallState;
+    }
+
+    /**
+     * Returns the {@link TelephonyManager#NetworkType} of the call.
+     *
+     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+     * @see TelephonyManager#NETWORK_TYPE_GPRS
+     * @see TelephonyManager#NETWORK_TYPE_EDGE
+     * @see TelephonyManager#NETWORK_TYPE_UMTS
+     * @see TelephonyManager#NETWORK_TYPE_CDMA
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+     * @see TelephonyManager#NETWORK_TYPE_1xRTT
+     * @see TelephonyManager#NETWORK_TYPE_HSDPA
+     * @see TelephonyManager#NETWORK_TYPE_HSUPA
+     * @see TelephonyManager#NETWORK_TYPE_HSPA
+     * @see TelephonyManager#NETWORK_TYPE_IDEN
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+     * @see TelephonyManager#NETWORK_TYPE_LTE
+     * @see TelephonyManager#NETWORK_TYPE_EHRPD
+     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     * @see TelephonyManager#NETWORK_TYPE_GSM
+     * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA
+     * @see TelephonyManager#NETWORK_TYPE_IWLAN
+     * @see TelephonyManager#NETWORK_TYPE_LTE_CA
+     * @see TelephonyManager#NETWORK_TYPE_NR
+     */
+    @NetworkType
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * Returns the {#link CallQuality} of the call.
+     * @return call quality for this call attributes, only CallState in {@link
+     *         PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call quality. It will be
+     *         null for the call which is not in {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}.
+     */
+    @Nullable
+    public CallQuality getCallQuality() {
+        return mCallQuality;
+    }
+
+    /**
+     * Returns the call classification.
+     * @hide
+     */
+    public int getCallClassification() {
+        return mCallClassification;
+    }
+
+    /**
+     * Returns the IMS call session ID.
+     */
+    @Nullable
+    public String getImsCallSessionId() {
+        return mImsCallId;
+    }
+
+    /**
+     * Returns the IMS call service type.
+     */
+    @ImsCallServiceType
+    public int getImsCallServiceType() {
+        return mImsCallServiceType;
+    }
+
+    /**
+     * Returns the IMS call type.
+     */
+    @ImsCallType
+    public int getImsCallType() {
+        return mImsCallType;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality, mCallClassification,
+                mImsCallId, mImsCallServiceType, mImsCallType);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (o == null || !(o instanceof CallState) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        CallState s = (CallState) o;
+
+        return (mPreciseCallState == s.mPreciseCallState
+                && mNetworkType == s.mNetworkType
+                && Objects.equals(mCallQuality, s.mCallQuality)
+                && mCallClassification == s.mCallClassification
+                && Objects.equals(mImsCallId, s.mImsCallId)
+                && mImsCallType == s.mImsCallType
+                && mImsCallServiceType == s.mImsCallServiceType);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(@Nullable Parcel dest, int flags) {
+        dest.writeInt(mPreciseCallState);
+        dest.writeInt(mNetworkType);
+        dest.writeParcelable(mCallQuality, flags);
+        dest.writeInt(mCallClassification);
+        dest.writeString(mImsCallId);
+        dest.writeInt(mImsCallServiceType);
+        dest.writeInt(mImsCallType);
+    }
+
+    public static final @NonNull Creator<CallState> CREATOR = new Creator() {
+        public CallState createFromParcel(Parcel in) {
+            return new CallState(in);
+        }
+
+        public CallState[] newArray(int size) {
+            return new CallState[size];
+        }
+    };
+
+    /**
+     * Builder of {@link CallState}
+     *
+     * <p>The example below shows how you might create a new {@code CallState}:
+     *
+     * <pre><code>
+     *
+     * CallState = new CallState.Builder()
+     *     .setCallState(3)
+     *     .setNetworkType({@link TelephonyManager#NETWORK_TYPE_LTE})
+     *     .setCallQuality({@link CallQuality})
+     *     .setImsCallSessionId({@link String})
+     *     .setImsCallServiceType({@link ImsCallProfile#SERVICE_TYPE_NORMAL})
+     *     .setImsCallType({@link ImsCallProfile#CALL_TYPE_VOICE})
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        private @PreciseCallStates int mPreciseCallState;
+        private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        private CallQuality mCallQuality = null;
+        private int mCallClassification = CALL_CLASSIFICATION_UNKNOWN;
+        private String mImsCallId;
+        private @ImsCallServiceType int mImsCallServiceType = ImsCallProfile.SERVICE_TYPE_NONE;
+        private @ImsCallType int mImsCallType = ImsCallProfile.CALL_TYPE_NONE;
+
+
+        /**
+         * Default constructor for the Builder.
+         */
+        public Builder(@PreciseCallStates int preciseCallState) {
+            mPreciseCallState = preciseCallState;
+        }
+
+        /**
+         * Set network type of this call.
+         *
+         * @param networkType the transport type.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setNetworkType(@NetworkType int networkType) {
+            this.mNetworkType = networkType;
+            return this;
+        }
+
+        /**
+         * Set the call quality {@link CallQuality} of this call.
+         *
+         * @param callQuality call quality of active call.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setCallQuality(@Nullable CallQuality callQuality) {
+            this.mCallQuality = callQuality;
+            return this;
+        }
+
+        /**
+         * Set call classification for this call.
+         *
+         * @param classification call classification type defined in this class.
+         * @return The same instance of the builder.
+         * @hide
+         */
+        @NonNull
+        public CallState.Builder setCallClassification(int classification) {
+            this.mCallClassification = classification;
+            return this;
+        }
+
+        /**
+         * Set IMS call session ID of this call.
+         *
+         * @param imsCallId  IMS call session ID.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setImsCallSessionId(@Nullable String imsCallId) {
+            this.mImsCallId = imsCallId;
+            return this;
+        }
+
+        /**
+         * Set IMS call service type of this call.
+         *
+         * @param serviceType IMS call service type defined in {@link ImsCallProfile}.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setImsCallServiceType(@ImsCallServiceType int serviceType) {
+            this.mImsCallServiceType = serviceType;
+            return this;
+        }
+
+        /**
+         * Set IMS call type of this call.
+         *
+         * @param callType IMS call type defined in {@link ImsCallProfile}.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setImsCallType(@ImsCallType int callType) {
+            this.mImsCallType = callType;
+            return this;
+        }
+
+        /**
+         * Build the {@link CallState}
+         *
+         * @return the {@link CallState} object
+         */
+        @NonNull
+        public CallState build() {
+            return new CallState(
+                    mPreciseCallState,
+                    mNetworkType,
+                    mCallQuality,
+                    mCallClassification,
+                    mImsCallId,
+                    mImsCallServiceType,
+                    mImsCallType);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index e6d7df3..1ea7fdc 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -78,8 +78,9 @@
     public static final int SERVICE_TYPE_EMERGENCY = 2;
 
     /**
-     * Call types
+     * Call type none
      */
+    public static final int CALL_TYPE_NONE = 0;
     /**
      * IMSPhone to support IR.92 & IR.94 (voice + video upgrade/downgrade)
      */
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index d133f6f..e2099e6 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -24,12 +24,15 @@
 
 import android.content.Context;
 import android.hardware.usb.UsbManager;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * Unit tests lib for {@link android.hardware.usb.UsbManager}.
  */
@@ -42,6 +45,11 @@
     private UsbManager mUsbManagerMock;
     @Mock private android.hardware.usb.IUsbManager mMockUsbService;
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     public UsbManagerTestLib(Context context) {
         MockitoAnnotations.initMocks(this);
         mContext = context;
@@ -82,10 +90,11 @@
     }
 
     private void testSetCurrentFunctionsMock_Matched(long functions) {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         try {
             setCurrentFunctions(functions);
 
-            verify(mMockUsbService).setCurrentFunctions(eq(functions));
+            verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
         } catch (RemoteException remEx) {
             Log.w(TAG, "RemoteException");
         }
@@ -106,9 +115,10 @@
     }
 
     public void testSetCurrentFunctionsEx(long functions) throws Exception {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         setCurrentFunctions(functions);
 
-        verify(mMockUsbService).setCurrentFunctions(eq(functions));
+        verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
     }
 
     public void testGetCurrentFunctions_shouldMatched() {
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 86bcb72..4103ca7 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -98,7 +98,7 @@
         }
 
         @Override
-        protected void setEnabledFunctions(long functions, boolean force) {
+        protected void setEnabledFunctions(long functions, boolean force, int operationId) {
             mCurrentFunctions = functions;
         }
 
@@ -134,6 +134,20 @@
         protected void sendStickyBroadcast(Intent intent) {
             mBroadcastedIntent = intent;
         }
+
+        @Override
+        public void handlerInitDone(int operationId) {
+        }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed){
+        }
+
     }
 
     @Before