Merge "Don't remove bubbless onClearAll or onNotifClick"
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index 4ffcf8a..4b4fb96 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -80,27 +80,22 @@
     }
 
     /**
-     * Add the specified package to the power save whitelist.
-     *
-     * @return true if the package was successfully added to the whitelist
+     * Add the specified package to the permanent power save whitelist.
      */
     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
-    public boolean addToWhitelist(@NonNull String packageName) {
-        return addToWhitelist(Collections.singletonList(packageName)) == 1;
+    public void addToWhitelist(@NonNull String packageName) {
+        addToWhitelist(Collections.singletonList(packageName));
     }
 
     /**
-     * Add the specified packages to the power save whitelist.
-     *
-     * @return the number of packages that were successfully added to the whitelist
+     * Add the specified packages to the permanent power save whitelist.
      */
     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
-    public int addToWhitelist(@NonNull List<String> packageNames) {
+    public void addToWhitelist(@NonNull List<String> packageNames) {
         try {
-            return mService.addPowerSaveWhitelistApps(packageNames);
+            mService.addPowerSaveWhitelistApps(packageNames);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
-            return 0;
         }
     }
 
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index d2d942a..dc72d6d 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -85,6 +85,7 @@
     /**
      * Checks if an app has been idle for a while and filters out apps that are excluded.
      * It returns false if the current system state allows all apps to be considered active.
+     * This happens if the device is plugged in or otherwise temporarily allowed to make exceptions.
      * Called by interface impls.
      */
     boolean isAppIdleFiltered(String packageName, int appId, int userId,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index b516279..e4c6b52 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -37,8 +37,6 @@
 import android.app.job.JobWorkItem;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -57,7 +55,6 @@
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -90,7 +87,6 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.compat.PlatformCompat;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
 import com.android.server.job.controllers.BackgroundJobsController;
@@ -155,16 +151,6 @@
     /** The maximum number of jobs that we allow an unprivileged app to schedule */
     private static final int MAX_JOBS_PER_APP = 100;
 
-    /**
-     * {@link #schedule(JobInfo)}, {@link #scheduleAsPackage(JobInfo, String, int, String)}, and
-     * {@link #enqueue(JobInfo, JobWorkItem)} will throw a {@link IllegalStateException} if the app
-     * calls the APIs too frequently.
-     */
-    @ChangeId
-    // This means the change will be enabled for target SDK larger than 29 (Q), meaning R and up.
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
-    protected static final long CRASH_ON_EXCEEDED_LIMIT = 144363383L;
-
     @VisibleForTesting
     public static Clock sSystemClock = Clock.systemUTC();
 
@@ -264,7 +250,6 @@
 
     private final CountQuotaTracker mQuotaTracker;
     private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()";
-    private final PlatformCompat mPlatformCompat;
 
     /**
      * Queue of pending jobs. The JobServiceContext class will receive jobs from this list
@@ -986,9 +971,7 @@
                 Slog.e(TAG, userId + "-" + pkg + " has called schedule() too many times");
                 mAppStandbyInternal.restrictApp(
                         pkg, userId, UsageStatsManager.REASON_SUB_RESTRICT_BUGGY);
-                if (mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION
-                        && mPlatformCompat.isChangeEnabledByPackageName(
-                                CRASH_ON_EXCEEDED_LIMIT, pkg, userId)) {
+                if (mConstants.API_QUOTA_SCHEDULE_THROW_EXCEPTION) {
                     final boolean isDebuggable;
                     synchronized (mLock) {
                         if (!mDebuggableApps.containsKey(packageName)) {
@@ -1370,8 +1353,6 @@
         // Set up the app standby bucketing tracker
         mStandbyTracker = new StandbyTracker();
         mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
-        mPlatformCompat =
-                (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
         mQuotaTracker = new CountQuotaTracker(context, Categorizer.SINGLE_CATEGORIZER);
         mQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY,
                 mConstants.API_QUOTA_SCHEDULE_COUNT,
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index f1bfa04..e343478 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -48,6 +48,7 @@
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
 
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
 
 import android.annotation.NonNull;
@@ -71,9 +72,8 @@
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
 import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkRequest;
 import android.net.NetworkScoreManager;
+import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Build;
 import android.os.Environment;
@@ -285,6 +285,7 @@
     long mInitialForegroundServiceStartTimeoutMillis;
 
     private volatile boolean mAppIdleEnabled;
+    private boolean mIsCharging;
     private boolean mSystemServicesReady = false;
     // There was a system update, defaults need to be initialized after services are ready
     private boolean mPendingInitializeDefaults;
@@ -360,6 +361,11 @@
         mHandler = new AppStandbyHandler(mInjector.getLooper());
         mPackageManager = mContext.getPackageManager();
 
+        DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver();
+        IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
+        deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
+        mContext.registerReceiver(deviceStateReceiver, deviceStates);
+
         synchronized (mAppIdleLock) {
             mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
                     mInjector.elapsedRealtime());
@@ -417,6 +423,8 @@
             if (mPendingOneTimeCheckIdleStates) {
                 postOneTimeCheckIdleStates();
             }
+        } else if (phase == PHASE_BOOT_COMPLETED) {
+            setChargingState(mInjector.isCharging());
         }
     }
 
@@ -515,6 +523,16 @@
                 appUsage.bucketingReason, false);
     }
 
+    @VisibleForTesting
+    void setChargingState(boolean isCharging) {
+        synchronized (mAppIdleLock) {
+            if (mIsCharging != isCharging) {
+                if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
+                mIsCharging = isCharging;
+            }
+        }
+    }
+
     @Override
     public void postCheckIdleStates(int userId) {
         mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
@@ -977,6 +995,11 @@
         if (isAppSpecial(packageName, appId, userId)) {
             return false;
         } else {
+            synchronized (mAppIdleLock) {
+                if (!mAppIdleEnabled || mIsCharging) {
+                    return false;
+                }
+            }
             return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
         }
     }
@@ -1543,6 +1566,8 @@
 
         pw.println();
         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
+        pw.print(" mIsCharging=");
+        pw.print(mIsCharging);
         pw.println();
         pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
         pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
@@ -1560,6 +1585,7 @@
         private final Looper mLooper;
         private IDeviceIdleController mDeviceIdleController;
         private IBatteryStats mBatteryStats;
+        private BatteryManager mBatteryManager;
         private PackageManagerInternal mPackageManagerInternal;
         private DisplayManager mDisplayManager;
         private PowerManager mPowerManager;
@@ -1593,6 +1619,7 @@
                 mDisplayManager = (DisplayManager) mContext.getSystemService(
                         Context.DISPLAY_SERVICE);
                 mPowerManager = mContext.getSystemService(PowerManager.class);
+                mBatteryManager = mContext.getSystemService(BatteryManager.class);
 
                 final ActivityManager activityManager =
                         (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1630,6 +1657,10 @@
             return buildFlag && runtimeFlag;
         }
 
+        boolean isCharging() {
+            return mBatteryManager.isCharging();
+        }
+
         boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
             return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
         }
@@ -1766,15 +1797,19 @@
         }
     };
 
-    private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build();
-
-    private final ConnectivityManager.NetworkCallback mNetworkCallback
-            = new ConnectivityManager.NetworkCallback() {
+    private class DeviceStateReceiver extends BroadcastReceiver {
         @Override
-        public void onAvailable(Network network) {
-            mConnectivityManager.unregisterNetworkCallback(this);
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case BatteryManager.ACTION_CHARGING:
+                    setChargingState(true);
+                    break;
+                case BatteryManager.ACTION_DISCHARGING:
+                    setChargingState(false);
+                    break;
+            }
         }
-    };
+    }
 
     private final DisplayManager.DisplayListener mDisplayListener
             = new DisplayManager.DisplayListener() {
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 1f9f18c..c0f84a0 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -20,6 +20,7 @@
 
 apex_defaults {
     native_shared_libs: [
+        "libstatspull",
         "libstats_jni",
     ],
     // binaries: ["vold"],
@@ -28,6 +29,7 @@
         "service-statsd",
     ],
     // prebuilts: ["my_prebuilt"],
+    compile_multilib: "both",
     name: "com.android.os.statsd-defaults",
     key: "com.android.os.statsd.key",
     certificate: ":com.android.os.statsd.certificate",
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 7c93bc7..4ccdd7e 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -38,6 +38,10 @@
         },
         ndk: {
             enabled: true,
+            apex_available: [
+                "com.android.os.statsd",
+            ],
         }
-    }
+
+    },
 }
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 63a853a..ab669d4 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_visibility: [ ":__pkg__" ]
+}
+
 genrule {
     name: "statslog-statsd-java-gen",
     tools: ["stats-log-api-gen"],
@@ -25,6 +29,9 @@
     srcs: [
         ":statslog-statsd-java-gen",
     ],
+    visibility: [
+        "//cts/hostsidetests/statsd/apps:__subpackages__",
+    ]
 }
 
 filegroup {
@@ -34,6 +41,9 @@
         ":framework-statsd-aidl-sources",
         ":statslog-statsd-java-gen",
     ],
+    visibility: [
+        "//frameworks/base", // For the "global" stubs.
+    ],
 }
 
 java_defaults {
@@ -139,6 +149,10 @@
         "framework-statsd-defaults",
     ],
     srcs: [ ":framework-statsd-stubs-srcs-publicapi" ],
+    visibility: [
+        "//frameworks/base", // Framework
+        "//frameworks/base/apex/statsd", // statsd apex
+    ]
 }
 
 java_library {
@@ -147,6 +161,10 @@
         "framework-statsd-defaults",
     ],
     srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
+    visibility: [
+        "//frameworks/base", // Framework
+        "//frameworks/base/apex/statsd", // statsd apex
+    ]
 }
 
 java_library {
@@ -155,4 +173,9 @@
         "framework-statsd-defaults",
     ],
     srcs: [ ":framework-statsd-stubs-srcs-module_libs_api" ],
+    visibility: [
+        "//frameworks/base", // Framework
+        "//frameworks/base/apex/statsd", // statsd apex
+        "//frameworks/opt/net/wifi/service" // wifi service
+    ]
 }
diff --git a/api/current.txt b/api/current.txt
index ac52e58..4887c66 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12703,8 +12703,7 @@
 
   public class Resources {
     ctor @Deprecated public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
-    method public void addLoader(@NonNull android.content.res.loader.ResourcesLoader);
-    method public void clearLoaders();
+    method public void addLoaders(@NonNull android.content.res.loader.ResourcesLoader...);
     method public final void finishPreloading();
     method public final void flushLayoutCache();
     method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimRes @AnimatorRes int) throws android.content.res.Resources.NotFoundException;
@@ -12731,7 +12730,6 @@
     method @NonNull public int[] getIntArray(@ArrayRes int) throws android.content.res.Resources.NotFoundException;
     method public int getInteger(@IntegerRes int) throws android.content.res.Resources.NotFoundException;
     method @NonNull public android.content.res.XmlResourceParser getLayout(@LayoutRes int) throws android.content.res.Resources.NotFoundException;
-    method @NonNull public java.util.List<android.content.res.loader.ResourcesLoader> getLoaders();
     method @Deprecated public android.graphics.Movie getMovie(@RawRes int) throws android.content.res.Resources.NotFoundException;
     method @NonNull public String getQuantityString(@PluralsRes int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
     method @NonNull public String getQuantityString(@PluralsRes int, int) throws android.content.res.Resources.NotFoundException;
@@ -12759,8 +12757,7 @@
     method public android.content.res.AssetFileDescriptor openRawResourceFd(@RawRes int) throws android.content.res.Resources.NotFoundException;
     method public void parseBundleExtra(String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
     method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void removeLoader(@NonNull android.content.res.loader.ResourcesLoader);
-    method public void setLoaders(@NonNull java.util.List<android.content.res.loader.ResourcesLoader>);
+    method public void removeLoaders(@NonNull android.content.res.loader.ResourcesLoader...);
     method @Deprecated public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
     field @AnyRes public static final int ID_NULL = 0; // 0x0
   }
@@ -45514,7 +45511,7 @@
     field public static final int DIRECTION_INCOMING = 0; // 0x0
     field public static final int DIRECTION_OUTGOING = 1; // 0x1
     field public static final int DIRECTION_UNKNOWN = -1; // 0xffffffff
-    field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
+    field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
     field public static final int PROPERTY_CONFERENCE = 1; // 0x1
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
@@ -45603,7 +45600,8 @@
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
     method public final int getConnectionProperties();
-    method public final long getConnectionTime();
+    method public final long getConnectionStartElapsedRealtimeMillis();
+    method @IntRange(from=0) public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
@@ -45633,8 +45631,9 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConnectionCapabilities(int);
     method public final void setConnectionProperties(int);
-    method public final void setConnectionStartElapsedRealTime(long);
-    method public final void setConnectionTime(long);
+    method @Deprecated public final void setConnectionStartElapsedRealTime(long);
+    method public final void setConnectionStartElapsedRealtimeMillis(long);
+    method public final void setConnectionTime(@IntRange(from=0) long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
     method public final void setExtras(@Nullable android.os.Bundle);
@@ -45794,7 +45793,7 @@
     field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
     field public static final String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
     field public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
-    field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
+    field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
@@ -47133,6 +47132,19 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ClosedSubscriberGroupInfo> CREATOR;
   }
 
+  public final class DisplayInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getNetworkType();
+    method public int getOverrideNetworkType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DisplayInfo> CREATOR;
+    field public static final int OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO = 2; // 0x2
+    field public static final int OVERRIDE_NETWORK_TYPE_LTE_CA = 1; // 0x1
+    field public static final int OVERRIDE_NETWORK_TYPE_NONE = 0; // 0x0
+    field public static final int OVERRIDE_NETWORK_TYPE_NR_NSA = 3; // 0x3
+    field public static final int OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE = 4; // 0x4
+  }
+
   public class IccOpenLogicalChannelResponse implements android.os.Parcelable {
     method public int describeContents();
     method public int getChannel();
@@ -47389,6 +47401,7 @@
     method public void onDataActivity(int);
     method public void onDataConnectionStateChanged(int);
     method public void onDataConnectionStateChanged(int, int);
+    method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.DisplayInfo);
     method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
     method public void onMessageWaitingIndicatorChanged(boolean);
     method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
@@ -47406,6 +47419,7 @@
     field public static final int LISTEN_CELL_LOCATION = 16; // 0x10
     field public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
     field public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
+    field public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
     field public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
     field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
     field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
diff --git a/api/system-current.txt b/api/system-current.txt
index b07066d..0fd8a20 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8839,8 +8839,8 @@
   }
 
   public class PowerWhitelistManager {
-    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean addToWhitelist(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public int addToWhitelist(@NonNull java.util.List<java.lang.String>);
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
     method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
     method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
     field public static final int EVENT_MMS = 2; // 0x2
@@ -10854,27 +10854,26 @@
   public abstract class Conference extends android.telecom.Conferenceable {
     method @Deprecated public final android.telecom.AudioState getAudioState();
     method @Deprecated public final long getConnectTimeMillis();
-    method public final long getConnectionStartElapsedRealTime();
     method public android.telecom.Connection getPrimaryConnection();
     method @NonNull public final String getTelecomCallId();
     method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
-    method public final void setAddress(@NonNull android.net.Uri, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setAddress(@NonNull android.net.Uri, int);
     method public final void setCallerDisplayName(@NonNull String, int);
-    method public void setConferenceState(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setConferenceState(boolean);
     method @Deprecated public final void setConnectTimeMillis(long);
   }
 
   public abstract class Connection extends android.telecom.Conferenceable {
     method @Deprecated public final android.telecom.AudioState getAudioState();
-    method public final long getConnectElapsedTimeMillis();
-    method public final long getConnectTimeMillis();
+    method @IntRange(from=0) public final long getConnectTimeMillis();
+    method public final long getConnectionStartElapsedRealtimeMillis();
     method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
     method @Nullable public final String getTelecomCallId();
     method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
     method public final void resetConnectionTime();
     method public void setCallDirection(int);
-    method public final void setConnectTimeMillis(long);
-    method public final void setConnectionStartElapsedRealTime(long);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectionStartElapsedRealtimeMillis(long);
     method public void setPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
     method public void setTelecomCallId(@NonNull String);
     field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
@@ -11033,7 +11032,7 @@
   }
 
   public static class PhoneAccount.Builder {
-    method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
   }
 
   public class PhoneAccountSuggestionService extends android.app.Service {
@@ -11108,7 +11107,7 @@
     method public int getCallState();
     method public android.telecom.PhoneAccountHandle getConnectionManager();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle);
     method @Deprecated public android.content.ComponentName getDefaultPhoneApp();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String);
@@ -12572,6 +12571,7 @@
     method public void notifyDataActivityChanged(int, int);
     method public void notifyDataConnectionForSubscriber(int, int, int, @Nullable android.telephony.PreciseDataConnectionState);
     method public void notifyDisconnectCause(int, int, int, int);
+    method public void notifyDisplayInfoChanged(int, int, @NonNull android.telephony.DisplayInfo);
     method public void notifyEmergencyNumberList(int, int);
     method public void notifyImsDisconnectCause(int, @NonNull android.telephony.ims.ImsReasonInfo);
     method public void notifyMessageWaitingChanged(int, int, boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index 84fd6f4..4c8bb02 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2451,8 +2451,8 @@
   }
 
   public class PowerWhitelistManager {
-    method @RequiresPermission("android.permission.DEVICE_POWER") public boolean addToWhitelist(@NonNull String);
-    method @RequiresPermission("android.permission.DEVICE_POWER") public int addToWhitelist(@NonNull java.util.List<java.lang.String>);
+    method @RequiresPermission("android.permission.DEVICE_POWER") public void addToWhitelist(@NonNull String);
+    method @RequiresPermission("android.permission.DEVICE_POWER") public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
     method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public void whitelistAppTemporarily(@NonNull String, long);
     method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
     field public static final int EVENT_MMS = 2; // 0x2
@@ -3441,23 +3441,22 @@
   }
 
   public abstract class Conference extends android.telecom.Conferenceable {
-    method public final long getConnectionStartElapsedRealTime();
     method public android.telecom.Connection getPrimaryConnection();
     method @NonNull public final String getTelecomCallId();
-    method public final void setAddress(@NonNull android.net.Uri, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setAddress(@NonNull android.net.Uri, int);
     method public final void setCallerDisplayName(@NonNull String, int);
-    method public void setConferenceState(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setConferenceState(boolean);
   }
 
   public abstract class Connection extends android.telecom.Conferenceable {
-    method public final long getConnectElapsedTimeMillis();
-    method public final long getConnectTimeMillis();
+    method @IntRange(from=0) public final long getConnectTimeMillis();
+    method public final long getConnectionStartElapsedRealtimeMillis();
     method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
     method @Nullable public final String getTelecomCallId();
     method public final void resetConnectionTime();
     method public void setCallDirection(int);
-    method public final void setConnectTimeMillis(long);
-    method public final void setConnectionStartElapsedRealTime(long);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectionStartElapsedRealtimeMillis(long);
     method public void setPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
     method public void setTelecomCallId(@NonNull String);
     field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
@@ -3489,7 +3488,7 @@
   }
 
   public static class PhoneAccount.Builder {
-    method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
   }
 
   public class PhoneAccountSuggestionService extends android.app.Service {
@@ -3503,7 +3502,7 @@
   public class TelecomManager {
     method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
-    method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(int);
+    method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
     field public static final int TTY_MODE_FULL = 1; // 0x1
@@ -3721,6 +3720,7 @@
     method public void notifyDataActivityChanged(int, int);
     method public void notifyDataConnectionForSubscriber(int, int, int, @Nullable android.telephony.PreciseDataConnectionState);
     method public void notifyDisconnectCause(int, int, int, int);
+    method public void notifyDisplayInfoChanged(int, int, @NonNull android.telephony.DisplayInfo);
     method public void notifyEmergencyNumberList(int, int);
     method public void notifyImsDisconnectCause(int, @NonNull android.telephony.ims.ImsReasonInfo);
     method public void notifyMessageWaitingChanged(int, int, boolean);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index dc11013..4a5a23a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4718,15 +4718,40 @@
     public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
 
     /**
-     * Keyguard features that when set on a managed profile that doesn't have its own challenge will
-     * affect the profile's parent user. These can also be set on the managed profile's parent
+     * Keyguard features that when set on a non-organization-owned managed profile that doesn't
+     * have its own challenge will affect the profile's parent user. These can also be set on the
+     * managed profile's parent {@link DevicePolicyManager} instance to explicitly control the
+     * parent user.
+     *
+     * <p>
+     * Organization-owned managed profile supports disabling additional keyguard features on the
+     * parent user as defined in {@link #ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY}.
+     *
+     * @hide
+     */
+    public static final int NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
+            | DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS;
+
+    /**
+     * Keyguard features that when set by the profile owner of an organization-owned managed
+     * profile will affect the profile's parent user if set on the managed profile's parent
      * {@link DevicePolicyManager} instance.
      *
      * @hide
      */
+    public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY =
+            KEYGUARD_DISABLE_SECURE_CAMERA;
+
+    /**
+     * Keyguard features that when set on a normal or organization-owned managed profile, have
+     * the potential to affect the profile's parent user.
+     *
+     * @hide
+     */
     public static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
-            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
-            | DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS;
+            DevicePolicyManager.NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER
+                    | DevicePolicyManager.ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY;
 
     /**
      * @deprecated This method does not actually modify the storage encryption of the device.
@@ -6115,11 +6140,20 @@
      * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} which affects notifications generated
      * by applications in the managed profile.
      * </ul>
+     * <p>
+     * From version {@link android.os.Build.VERSION_CODES#R} the profile owner of an
+     * organization-owned managed profile can set:
+     * <ul>
+     * <li>{@link #KEYGUARD_DISABLE_SECURE_CAMERA} which affects the parent user when called on the
+     * parent profile.
+     * </ul>
      * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT},
-     * {@link #KEYGUARD_DISABLE_FACE} and {@link #KEYGUARD_DISABLE_IRIS} can also be
-     * set on the {@link DevicePolicyManager} instance returned by
-     * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
-     * profile.
+     * {@link #KEYGUARD_DISABLE_FACE}, {@link #KEYGUARD_DISABLE_IRIS} and
+     * {@link #KEYGUARD_DISABLE_SECURE_CAMERA} can also be set on the {@link DevicePolicyManager}
+     * instance returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+     * restrictions on the parent profile. {@link #KEYGUARD_DISABLE_SECURE_CAMERA} can only be set
+     * on the parent profile instance if the calling device admin is the profile owner of an
+     * organization-owned managed profile.
      * <p>
      * Requests to disable other features on a managed profile will be ignored.
      * <p>
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 5668944..2c701b4 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -599,7 +599,8 @@
     /**
      * Returns whether the specified app is currently considered inactive. This will be true if the
      * app hasn't been used directly or indirectly for a period of time defined by the system. This
-     * could be of the order of several hours or days.
+     * could be of the order of several hours or days. Apps are not considered inactive when the
+     * device is charging.
      * @param packageName The package name of the app to query
      * @return whether the app is currently considered inactive
      */
diff --git a/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java b/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java
index 475f019..9d37299 100644
--- a/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java
+++ b/core/java/android/content/integrity/InstallerAllowedByManifestFormula.java
@@ -16,6 +16,10 @@
 
 package android.content.integrity;
 
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
 import java.util.Map;
 
 /**
@@ -25,7 +29,29 @@
  *
  * @hide
  */
-public class InstallerAllowedByManifestFormula extends IntegrityFormula {
+public class InstallerAllowedByManifestFormula extends IntegrityFormula implements Parcelable {
+
+    public static final String INSTALLER_CERTIFICATE_NOT_EVALUATED = "";
+
+    public InstallerAllowedByManifestFormula() {
+    }
+
+    private InstallerAllowedByManifestFormula(Parcel in) {
+    }
+
+    @NonNull
+    public static final Creator<InstallerAllowedByManifestFormula> CREATOR =
+            new Creator<InstallerAllowedByManifestFormula>() {
+                @Override
+                public InstallerAllowedByManifestFormula createFromParcel(Parcel in) {
+                    return new InstallerAllowedByManifestFormula(in);
+                }
+
+                @Override
+                public InstallerAllowedByManifestFormula[] newArray(int size) {
+                    return new InstallerAllowedByManifestFormula[size];
+                }
+            };
 
     @Override
     public int getTag() {
@@ -54,10 +80,30 @@
     private static boolean installerInAllowedInstallersFromManifest(
             AppInstallMetadata appInstallMetadata,
             Map<String, String> allowedInstallersAndCertificates) {
-        return allowedInstallersAndCertificates.containsKey(appInstallMetadata.getInstallerName())
-                && appInstallMetadata.getInstallerCertificates()
-                .contains(
-                        allowedInstallersAndCertificates
-                        .get(appInstallMetadata.getInstallerName()));
+        String installerPackage = appInstallMetadata.getInstallerName();
+
+        if (!allowedInstallersAndCertificates.containsKey(installerPackage)) {
+            return false;
+        }
+
+        // If certificate is not specified in the manifest, we do not check it.
+        if (!allowedInstallersAndCertificates.get(installerPackage)
+                .equals(INSTALLER_CERTIFICATE_NOT_EVALUATED)) {
+            return appInstallMetadata.getInstallerCertificates()
+                    .contains(
+                            allowedInstallersAndCertificates
+                                    .get(appInstallMetadata.getInstallerName()));
+        }
+
+        return true;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
     }
 }
diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java
index ac4c907..c5e5c8a 100644
--- a/core/java/android/content/integrity/IntegrityFormula.java
+++ b/core/java/android/content/integrity/IntegrityFormula.java
@@ -214,6 +214,8 @@
                 return LongAtomicFormula.CREATOR.createFromParcel(in);
             case BOOLEAN_ATOMIC_FORMULA_TAG:
                 return BooleanAtomicFormula.CREATOR.createFromParcel(in);
+            case INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG:
+                return InstallerAllowedByManifestFormula.CREATOR.createFromParcel(in);
             default:
                 throw new IllegalArgumentException("Unknown formula tag " + tag);
         }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 471e83c..cb809da 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -62,6 +62,7 @@
 import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
@@ -112,7 +113,7 @@
     static final String TAG = "Resources";
 
     private static final Object sSync = new Object();
-    private final Object mLock = new Object();
+    private final Object mUpdateLock = new Object();
 
     // Used by BridgeResources in layoutlib
     @UnsupportedAppUsage
@@ -139,6 +140,7 @@
     @UnsupportedAppUsage
     final ClassLoader mClassLoader;
 
+    @GuardedBy("mUpdateLock")
     private UpdateCallbacks mCallbacks = null;
 
     /**
@@ -2375,6 +2377,7 @@
      *
      * <p>Loaders are listed in increasing precedence order. A loader will override the resources
      * and assets of loaders listed before itself.
+     * @hide
      */
     @NonNull
     public List<ResourcesLoader> getLoaders() {
@@ -2382,87 +2385,81 @@
     }
 
     /**
-     * Appends a loader to the end of the loader list. If the loader is already present in the
-     * loader list, the list will not be modified.
-     *
-     * @param loader the loader to add
-     */
-    public void addLoader(@NonNull ResourcesLoader loader) {
-        synchronized (mLock) {
-            checkCallbacksRegistered();
-
-            final List<ResourcesLoader> loaders = new ArrayList<>(
-                    mResourcesImpl.getAssets().getLoaders());
-            if (loaders.contains(loader)) {
-                return;
-            }
-
-            loaders.add(loader);
-            mCallbacks.onLoadersChanged(this, loaders);
-            loader.registerOnProvidersChangedCallback(this, mCallbacks);
-        }
-    }
-
-    /**
-     * Removes a loader from the loaders. If the loader is not present in the loader list, the list
+     * Adds a loader to the list of loaders. If the loader is already present in the list, the list
      * will not be modified.
      *
-     * @param loader the loader to remove
+     * @param loaders the loaders to add
      */
-    public void removeLoader(@NonNull ResourcesLoader loader) {
-        synchronized (mLock) {
+    public void addLoaders(@NonNull ResourcesLoader... loaders) {
+        synchronized (mUpdateLock) {
             checkCallbacksRegistered();
+            final List<ResourcesLoader> newLoaders =
+                    new ArrayList<>(mResourcesImpl.getAssets().getLoaders());
+            final ArraySet<ResourcesLoader> loaderSet = new ArraySet<>(newLoaders);
 
-            final List<ResourcesLoader> loaders = new ArrayList<>(
-                    mResourcesImpl.getAssets().getLoaders());
-            if (!loaders.remove(loader)) {
+            for (int i = 0; i < loaders.length; i++) {
+                final ResourcesLoader loader = loaders[i];
+                if (!loaderSet.contains(loader)) {
+                    newLoaders.add(loader);
+                }
+            }
+
+            if (loaderSet.size() == newLoaders.size()) {
                 return;
             }
 
-            mCallbacks.onLoadersChanged(this, loaders);
-            loader.unregisterOnProvidersChangedCallback(this);
+            mCallbacks.onLoadersChanged(this, newLoaders);
+            for (int i = loaderSet.size(), n = newLoaders.size(); i < n; i++) {
+                newLoaders.get(i).registerOnProvidersChangedCallback(this, mCallbacks);
+            }
         }
     }
 
     /**
-     * Sets the list of loaders.
+     * Removes loaders from the list of loaders. If the loader is not present in the list, the list
+     * will not be modified.
      *
-     * @param loaders the new loaders
+     * @param loaders the loaders to remove
      */
-    public void setLoaders(@NonNull List<ResourcesLoader> loaders) {
-        synchronized (mLock) {
+    public void removeLoaders(@NonNull ResourcesLoader... loaders) {
+        synchronized (mUpdateLock) {
             checkCallbacksRegistered();
-
+            final ArraySet<ResourcesLoader> removedLoaders = new ArraySet<>(loaders);
+            final List<ResourcesLoader> newLoaders = new ArrayList<>();
             final List<ResourcesLoader> oldLoaders = mResourcesImpl.getAssets().getLoaders();
-            int index = 0;
-            boolean modified = loaders.size() != oldLoaders.size();
-            final ArraySet<ResourcesLoader> seenLoaders = new ArraySet<>();
-            for (final ResourcesLoader loader : loaders) {
-                if (!seenLoaders.add(loader)) {
-                    throw new IllegalArgumentException("Loader " + loader + " present twice");
-                }
 
-                if (!modified && oldLoaders.get(index++) != loader) {
-                    modified = true;
+            for (int i = 0, n = oldLoaders.size(); i < n; i++) {
+                final ResourcesLoader loader = oldLoaders.get(i);
+                if (!removedLoaders.contains(loader)) {
+                    newLoaders.add(loader);
                 }
             }
 
-            if (!modified) {
+            if (oldLoaders.size() == newLoaders.size()) {
                 return;
             }
 
-            mCallbacks.onLoadersChanged(this, loaders);
-            for (int i = 0, n = oldLoaders.size(); i < n; i++) {
-                oldLoaders.get(i).unregisterOnProvidersChangedCallback(this);
-            }
-            for (ResourcesLoader newLoader : loaders) {
-                newLoader.registerOnProvidersChangedCallback(this, mCallbacks);
+            mCallbacks.onLoadersChanged(this, newLoaders);
+            for (int i = 0; i < loaders.length; i++) {
+                loaders[i].unregisterOnProvidersChangedCallback(this);
             }
         }
     }
 
-    /** Removes all {@link ResourcesLoader ResourcesLoader(s)}. */
+    /**
+     * Removes all {@link ResourcesLoader ResourcesLoader(s)}.
+     * @hide
+     */
+    @VisibleForTesting
     public void clearLoaders() {
-        setLoaders(Collections.emptyList());
+        synchronized (mUpdateLock) {
+            checkCallbacksRegistered();
+            final List<ResourcesLoader> newLoaders = Collections.emptyList();
+            final List<ResourcesLoader> oldLoaders = mResourcesImpl.getAssets().getLoaders();
+            mCallbacks.onLoadersChanged(this, newLoaders);
+            for (ResourcesLoader loader : oldLoaders) {
+                loader.unregisterOnProvidersChangedCallback(this);
+            }
+        }
     }
 }
diff --git a/core/java/android/content/res/loader/ResourcesLoader.java b/core/java/android/content/res/loader/ResourcesLoader.java
index 69dacee..58fec60 100644
--- a/core/java/android/content/res/loader/ResourcesLoader.java
+++ b/core/java/android/content/res/loader/ResourcesLoader.java
@@ -40,8 +40,8 @@
  * of {@link ResourcesProvider ResourcesProvider(s)} a loader contains propagates to all Resources
  * objects that use the loader.
  *
- * <p>Loaders retrieved with {@link Resources#getLoaders()} are listed in increasing precedence
- * order. A loader will override the resources and assets of loaders listed before itself.
+ * <p>Loaders must be added to Resources objects in increasing precedence order. A loader will
+ * override the resources and assets of loaders added before itself.
  *
  * <p>Providers retrieved with {@link #getProviders()} are listed in increasing precedence order. A
  * provider will override the resources and assets of providers listed before itself.
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 09ec6c3..d83715c 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -51,7 +51,7 @@
  *
  * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
  * transport mode security associations and apply them to individual sockets. Applications looking
- * to create a VPN should use {@link VpnService}.
+ * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}.
  *
  * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
  *     Internet Protocol</a>
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e65bd9f..d273500 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -301,6 +301,13 @@
     public static final int LISTEN_USER_MOBILE_DATA_STATE                  = 0x00080000;
 
     /**
+     *  Listen for display info changed event.
+     *
+     *  @see #onDisplayInfoChanged
+     */
+    public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
+
+    /**
      *  Listen for changes to the phone capability.
      *
      *  @see #onPhoneCapabilityChanged
@@ -848,6 +855,21 @@
     }
 
     /**
+     * Callback invoked when the display info has changed on the registered subscription.
+     * <p> The {@link DisplayInfo} contains status information shown to the user based on
+     * carrier policy.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @param displayInfo The display information.
+     */
+    @RequiresPermission((android.Manifest.permission.READ_PHONE_STATE))
+    public void onDisplayInfoChanged(@NonNull DisplayInfo displayInfo) {
+        // default implementation empty
+    }
+
+    /**
      * Callback invoked when the current emergency number list has changed on the registered
      * subscription.
      * Note, the registration subId comes from {@link TelephonyManager} object which registers
@@ -1226,6 +1248,15 @@
                             () -> psl.onUserMobileDataStateChanged(enabled)));
         }
 
+        public void onDisplayInfoChanged(DisplayInfo displayInfo) {
+            PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
+            if (psl == null) return;
+
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(
+                            () -> psl.onDisplayInfoChanged(displayInfo)));
+        }
+
         public void onOemHookRawEvent(byte[] rawData) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 4024db1..2c077bb 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -589,6 +589,24 @@
     }
 
     /**
+     * Notify display info changed.
+     *
+     * @param slotIndex The SIM slot index for which display info has changed. Can be
+     * derived from {@code subscriptionId} except when {@code subscriptionId} is invalid, such as
+     * when the device is in emergency-only mode.
+     * @param subscriptionId Subscription id for which display network info has changed.
+     * @param displayInfo The display info.
+     */
+    public void notifyDisplayInfoChanged(int slotIndex, int subscriptionId,
+                                         @NonNull DisplayInfo displayInfo) {
+        try {
+            sRegistry.notifyDisplayInfoChanged(slotIndex, subscriptionId, displayInfo);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
      * Notify IMS call disconnect causes which contains {@link android.telephony.ims.ImsReasonInfo}.
      *
      * @param subId for which ims call disconnect.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 2548068..9cd6050e 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -882,6 +882,9 @@
         } else {
             hideDirectly(types);
         }
+        if (mViewRoot.mView == null) {
+            return;
+        }
         mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation);
         mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
             @Override
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 0f50596f..3d5dfbb 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -21,6 +21,7 @@
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.DisplayInfo;
 import android.telephony.PhoneCapability;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
@@ -54,6 +55,7 @@
     void onOemHookRawEvent(in byte[] rawData);
     void onCarrierNetworkChange(in boolean active);
     void onUserMobileDataStateChanged(in boolean enabled);
+    void onDisplayInfoChanged(in DisplayInfo displayInfo);
     void onPhoneCapabilityChanged(in PhoneCapability capability);
     void onActiveDataSubIdChanged(in int subId);
     void onRadioPowerStateChanged(in int state);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 47752c5..520ffc9 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -23,6 +23,7 @@
 import android.telephony.CallQuality;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
+import android.telephony.DisplayInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
@@ -87,6 +88,7 @@
     void notifyOpportunisticSubscriptionInfoChanged();
     void notifyCarrierNetworkChange(in boolean active);
     void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
+    void notifyDisplayInfoChanged(int slotIndex, int subId, in DisplayInfo displayInfo);
     void notifyPhoneCapabilityChanged(in PhoneCapability capability);
     void notifyActiveDataSubIdChanged(int activeDataSubId);
     void notifyRadioPowerStateChanged(in int phoneId, in int subId, in int state);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index bf4cdee..03676dd 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -428,7 +428,7 @@
         (section).args = "dropbox --proto system_app_wtf"
     ];
 
-    optional android.service.dropbox.DropBoxManagerServiceDumpProto dropbox_system_server_crashes = 3037 [
+    optional android.service.dropbox.DropBoxManagerServiceDumpProto dropbox_system_server_crash = 3037 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "dropbox --proto system_server_crash"
     ];
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
index 34ed90a..e1af962 100644
--- a/core/proto/android/stats/mediametrics/mediametrics.proto
+++ b/core/proto/android/stats/mediametrics/mediametrics.proto
@@ -154,6 +154,8 @@
     optional int64 latency_avg = 18;
     optional int64 latency_count = 19;
     optional int64 latency_unknown = 20;
+    optional int32 queue_input_buffer_error = 21;
+    optional int32 queue_secure_input_buffer_error = 22;
 }
 
 /**
diff --git a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/DirectoryAssetsProviderTest.kt b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/DirectoryAssetsProviderTest.kt
index 9e94bdc..afe9d7f 100644
--- a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/DirectoryAssetsProviderTest.kt
+++ b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/DirectoryAssetsProviderTest.kt
@@ -44,7 +44,7 @@
         testDir = context.filesDir.resolve("DirectoryAssetsProvider_${testName.methodName}")
         assetsProvider = DirectoryAssetsProvider(testDir)
         loader = ResourcesLoader()
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
     }
 
     @After
diff --git a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderAssetsTest.kt b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderAssetsTest.kt
index e3ba93d..da5092d 100644
--- a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderAssetsTest.kt
+++ b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderAssetsTest.kt
@@ -119,7 +119,7 @@
 
         val loader = ResourcesLoader()
         loader.providers = listOf(one, two)
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
 
         assertOpenedAsset()
         inOrder(two.assetsProvider, one.assetsProvider).apply {
@@ -149,7 +149,7 @@
         val loader2 = ResourcesLoader()
         loader2.addProvider(two)
 
-        resources.loaders = listOf(loader1, loader2)
+        resources.addLoaders(loader1, loader2)
 
         assertOpenedAsset()
         inOrder(two.assetsProvider, one.assetsProvider).apply {
@@ -170,7 +170,7 @@
         val loader = ResourcesLoader()
         val one = ResourcesProvider.empty(assetsProvider1)
         val two = ResourcesProvider.empty(assetsProvider2)
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.providers = listOf(one, two)
 
         assertOpenedAsset()
@@ -186,7 +186,7 @@
         val loader = ResourcesLoader()
         val one = ResourcesProvider.empty(assetsProvider1)
         val two = ResourcesProvider.empty(assetsProvider2)
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.providers = listOf(one, two)
 
         assertOpenedAsset()
@@ -202,7 +202,7 @@
         val loader = ResourcesLoader()
         val one = ResourcesProvider.empty(assetsProvider1)
         val two = ResourcesProvider.empty(assetsProvider2)
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.providers = listOf(one, two)
 
         assertOpenedAsset()
diff --git a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderValuesTest.kt b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderValuesTest.kt
index 0cc56d7..16eafcd 100644
--- a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderValuesTest.kt
+++ b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderValuesTest.kt
@@ -192,13 +192,13 @@
     }
 
     @Test
-    fun addMultipleProviders() {
+    fun addProvidersRepeatedly() {
         val originalValue = getValue()
         val testOne = openOne()
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.addProvider(testOne)
         assertEquals(valueOne, getValue())
 
@@ -213,25 +213,25 @@
     }
 
     @Test
-    fun addMultipleLoaders() {
+    fun addLoadersRepeatedly() {
         val originalValue = getValue()
         val testOne = openOne()
         val testTwo = openTwo()
         val loader1 = ResourcesLoader()
         val loader2 = ResourcesLoader()
 
-        resources.addLoader(loader1)
+        resources.addLoaders(loader1)
         loader1.addProvider(testOne)
         assertEquals(valueOne, getValue())
 
-        resources.addLoader(loader2)
+        resources.addLoaders(loader2)
         loader2.addProvider(testTwo)
         assertEquals(valueTwo, getValue())
 
-        resources.removeLoader(loader1)
+        resources.removeLoaders(loader1)
         assertEquals(valueTwo, getValue())
 
-        resources.removeLoader(loader2)
+        resources.removeLoaders(loader2)
         assertEquals(originalValue, getValue())
     }
 
@@ -242,7 +242,7 @@
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.providers = listOf(testOne, testTwo)
         assertEquals(valueTwo, getValue())
 
@@ -254,20 +254,20 @@
     }
 
     @Test
-    fun setMultipleLoaders() {
+    fun addMultipleLoaders() {
         val originalValue = getValue()
         val loader1 = ResourcesLoader()
         loader1.addProvider(openOne())
         val loader2 = ResourcesLoader()
         loader2.addProvider(openTwo())
 
-        resources.loaders = listOf(loader1, loader2)
+        resources.addLoaders(loader1, loader2)
         assertEquals(valueTwo, getValue())
 
-        resources.removeLoader(loader2)
+        resources.removeLoaders(loader2)
         assertEquals(valueOne, getValue())
 
-        resources.loaders = Collections.emptyList()
+        resources.removeLoaders(loader1)
         assertEquals(originalValue, getValue())
     }
 
@@ -291,7 +291,7 @@
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.addProvider(testOne)
         loader.addProvider(testTwo)
         loader.addProvider(testOne)
@@ -308,9 +308,9 @@
         val loader2 = ResourcesLoader()
         loader2.addProvider(openTwo())
 
-        resources.addLoader(loader1)
-        resources.addLoader(loader2)
-        resources.addLoader(loader1)
+        resources.addLoaders(loader1)
+        resources.addLoaders(loader2)
+        resources.addLoaders(loader1)
 
         assertEquals(2, resources.loaders.size)
         assertEquals(resources.loaders[0], loader1)
@@ -323,7 +323,7 @@
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.addProvider(testOne)
         loader.addProvider(testTwo)
 
@@ -341,12 +341,16 @@
         val loader2 = ResourcesLoader()
         loader2.addProvider(openTwo())
 
-        resources.loaders = listOf(loader1, loader2)
-        resources.removeLoader(loader1)
-        resources.removeLoader(loader1)
+        resources.addLoaders(loader1, loader2)
+        resources.removeLoaders(loader1)
+        resources.removeLoaders(loader1)
 
         assertEquals(1, resources.loaders.size)
         assertEquals(resources.loaders[0], loader2)
+
+        resources.removeLoaders(loader2, loader2)
+
+        assertEquals(0, resources.loaders.size)
     }
 
     @Test
@@ -355,7 +359,7 @@
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.providers = listOf(testOne, testTwo)
         loader.providers = listOf(testOne, testTwo)
 
@@ -365,14 +369,14 @@
     }
 
     @Test
-    fun repeatedSetLoaders() {
+    fun repeatedAddMultipleLoaders() {
         val loader1 = ResourcesLoader()
         loader1.addProvider(openOne())
         val loader2 = ResourcesLoader()
         loader2.addProvider(openTwo())
 
-        resources.loaders = listOf(loader1, loader2)
-        resources.loaders = listOf(loader1, loader2)
+        resources.addLoaders(loader1, loader2)
+        resources.addLoaders(loader1, loader2)
 
         assertEquals(2, resources.loaders.size)
         assertEquals(resources.loaders[0], loader1)
@@ -386,7 +390,7 @@
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.addProvider(testOne)
         loader.addProvider(testTwo)
         assertEquals(valueTwo, getValue())
@@ -414,20 +418,20 @@
         val loader2 = ResourcesLoader()
         loader2.addProvider(testTwo)
 
-        resources.addLoader(loader1)
-        resources.addLoader(loader2)
+        resources.addLoaders(loader1)
+        resources.addLoaders(loader2)
         assertEquals(valueTwo, getValue())
 
-        resources.removeLoader(loader1)
+        resources.removeLoaders(loader1)
         assertEquals(valueTwo, getValue())
 
-        resources.addLoader(loader1)
+        resources.addLoaders(loader1)
         assertEquals(valueOne, getValue())
 
-        resources.removeLoader(loader2)
+        resources.removeLoaders(loader2)
         assertEquals(valueOne, getValue())
 
-        resources.removeLoader(loader1)
+        resources.removeLoaders(loader1)
         assertEquals(originalValue, getValue())
     }
 
@@ -444,10 +448,11 @@
         val loader2 = ResourcesLoader()
         loader2.providers = listOf(testThree, testFour)
 
-        resources.loaders = listOf(loader1, loader2)
+        resources.addLoaders(loader1, loader2)
         assertEquals(valueFour, getValue())
 
-        resources.loaders = listOf(loader2, loader1)
+        resources.removeLoaders(loader1)
+        resources.addLoaders(loader1)
         assertEquals(valueTwo, getValue())
 
         loader1.removeProvider(testTwo)
@@ -471,7 +476,7 @@
         val loader2 = ResourcesLoader()
         loader2.addProvider(openTwo())
 
-        resources.loaders = listOf(loader1)
+        resources.addLoaders(loader1)
         assertEquals(valueOne, getValue())
 
         // The child context should include the loaders of the original context.
@@ -479,12 +484,12 @@
         assertEquals(valueOne, getValue(childContext))
 
         // Changing the loaders of the child context should not affect the original context.
-        childContext.resources.loaders = listOf(loader1, loader2)
+        childContext.resources.addLoaders(loader2)
         assertEquals(valueOne, getValue())
         assertEquals(valueTwo, getValue(childContext))
 
         // Changing the loaders of the original context should not affect the child context.
-        resources.removeLoader(loader1)
+        resources.removeLoaders(loader1)
         assertEquals(originalValue, getValue())
         assertEquals(valueTwo, getValue(childContext))
 
@@ -506,7 +511,7 @@
         val testTwo = openTwo()
         val loader = ResourcesLoader()
 
-        resources.addLoader(loader)
+        resources.addLoaders(loader)
         loader.addProvider(testOne)
         assertEquals(valueOne, getValue())
 
@@ -527,7 +532,7 @@
         assertEquals(originalValue, getValue())
         assertEquals(originalValue, getValue(childContext2))
 
-        childContext2.resources.addLoader(loader)
+        childContext2.resources.addLoaders(loader)
         assertEquals(originalValue, getValue())
         assertEquals(valueTwo, getValue(childContext))
         assertEquals(valueTwo, getValue(childContext2))
@@ -539,7 +544,7 @@
         loader.addProvider(openOne())
 
         val applicationContext = context.applicationContext
-        applicationContext.resources.addLoader(loader)
+        applicationContext.resources.addLoaders(loader)
         assertEquals(valueOne, getValue(applicationContext))
 
         val activity = mTestActivityRule.launchActivity(Intent())
@@ -556,7 +561,7 @@
         loader2.addProvider(openTwo())
 
         val applicationContext = context.applicationContext
-        applicationContext.resources.addLoader(loader1)
+        applicationContext.resources.addLoaders(loader1)
         assertEquals(valueOne, getValue(applicationContext))
 
         var token: IBinder? = null
@@ -569,7 +574,7 @@
             assertEquals(valueOne, getValue(applicationContext))
             assertEquals(valueOne, getValue(activity))
 
-            activity.resources.addLoader(loader2)
+            activity.resources.addLoaders(loader2)
             assertEquals(valueOne, getValue(applicationContext))
             assertEquals(valueTwo, getValue(activity))
 
@@ -598,10 +603,11 @@
         loader2.addProvider(provider1)
         loader2.addProvider(openTwo())
 
-        resources.loaders = listOf(loader1, loader2)
+        resources.addLoaders(loader1, loader2)
         assertEquals(valueTwo, getValue())
 
-        resources.loaders = listOf(loader2, loader1)
+        resources.removeLoaders(loader1)
+        resources.addLoaders(loader1)
         assertEquals(valueOne, getValue())
 
         assertEquals(2, resources.assets.apkAssets.count { apkAssets -> apkAssets.isForLoader })
diff --git a/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java b/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java
index c897ace..693d4ca 100644
--- a/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/InstallerAllowedByManifestFormulaTest.java
@@ -16,15 +16,20 @@
 
 package android.content.integrity;
 
+import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableMap;
 
-import org.testng.annotations.Test;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 import java.util.Arrays;
 import java.util.Collections;
 
+@RunWith(JUnit4.class)
 public class InstallerAllowedByManifestFormulaTest {
 
     private static final InstallerAllowedByManifestFormula
@@ -70,7 +75,7 @@
     }
 
     @Test
-    public void testFormulaMatches_certificateNotInManifest() {
+    public void testFormulaMatches_certificateDoesNotMatchManifest() {
         AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
                 .setInstallerName("installer1")
                 .setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert"))
@@ -92,6 +97,19 @@
         assertThat(FORMULA.matches(appInstallMetadata)).isTrue();
     }
 
+    @Test
+    public void testFormulaMatches_certificateNotSpecifiedInManifest() {
+        AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
+                .setInstallerName("installer1")
+                .setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert"))
+                .setAllowedInstallersAndCert(ImmutableMap.of(
+                        "installer1", INSTALLER_CERTIFICATE_NOT_EVALUATED,
+                        "installer2", "installer_cert1"
+                )).build();
+
+        assertThat(FORMULA.matches(appInstallMetadata)).isTrue();
+    }
+
     /** Returns a builder with all fields filled with some dummy data. */
     private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
         return new AppInstallMetadata.Builder()
diff --git a/packages/PrintSpooler/res/values-ja/donottranslate.xml b/packages/PrintSpooler/res/values-ja/donottranslate.xml
index d334ddd..6a0f768 100644
--- a/packages/PrintSpooler/res/values-ja/donottranslate.xml
+++ b/packages/PrintSpooler/res/values-ja/donottranslate.xml
@@ -16,7 +16,7 @@
 
 <resources>
 
-    <string name="mediasize_default">JIS_B5</string>
+    <string name="mediasize_default">ISO_A4</string>
     <string name="mediasize_standard">@string/mediasize_standard_japan</string>
 
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 45705b7..1e39954 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -226,6 +226,10 @@
         mIconView.update(this);
     }
 
+    void setInflated(boolean inflated) {
+        mInflated = inflated;
+    }
+
     /**
      * Set visibility of bubble in the expanded state.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 05838ab..762e5f2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -749,7 +749,8 @@
     }
 
     void promoteBubbleFromOverflow(Bubble bubble) {
-        mBubbleData.promoteBubbleFromOverflow(bubble);
+        bubble.setInflateSynchronously(mInflateSynchronously);
+        mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 673121f..8a5aad8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -199,16 +199,21 @@
         dispatchPendingChanges();
     }
 
-    public void promoteBubbleFromOverflow(Bubble bubble) {
+    public void promoteBubbleFromOverflow(Bubble bubble, BubbleStackView stack,
+            BubbleIconFactory factory) {
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "promoteBubbleFromOverflow: " + bubble);
         }
-        mOverflowBubbles.remove(bubble);
-        doAdd(bubble);
-        setSelectedBubbleInternal(bubble);
+
         // Preserve new order for next repack, which sorts by last updated time.
         bubble.markUpdatedAt(mTimeSource.currentTimeMillis());
-        trim();
+        setSelectedBubbleInternal(bubble);
+        mOverflowBubbles.remove(bubble);
+
+        bubble.inflate(
+                b -> notificationEntryUpdated(bubble, /* suppressFlyout */
+                        false, /* showInShade */ true),
+                mContext, stack, factory);
         dispatchPendingChanges();
     }
 
@@ -445,6 +450,10 @@
             mOverflowBubbles.add(0, bubbleToRemove);
             if (mOverflowBubbles.size() == mMaxOverflowBubbles + 1) {
                 // Remove oldest bubble.
+                if (DEBUG_BUBBLE_DATA) {
+                    Log.d(TAG, "Overflow full. Remove bubble: " + mOverflowBubbles.get(
+                            mOverflowBubbles.size() - 1));
+                }
                 mOverflowBubbles.remove(mOverflowBubbles.size() - 1);
             }
         }
@@ -511,7 +520,7 @@
         if (Objects.equals(bubble, mSelectedBubble)) {
             return;
         }
-        if (bubble != null && !mBubbles.contains(bubble)) {
+        if (bubble != null && !mBubbles.contains(bubble) && !mOverflowBubbles.contains(bubble)) {
             Log.e(TAG, "Cannot select bubble which doesn't exist!"
                     + " (" + bubble + ") bubbles=" + mBubbles);
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index bce172b..acaf271 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -795,6 +795,7 @@
         if (removedIndex >= 0) {
             mBubbleContainer.removeViewAt(removedIndex);
             bubble.cleanupExpandedState();
+            bubble.setInflated(false);
             logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
         } else {
             Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index c987620..9540f43 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1556,16 +1556,16 @@
         }
 
         Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels");
-        switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
-            case AppOpsManager.MODE_DEFAULT:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
-                break;
-            case AppOpsManager.MODE_ALLOWED:
-                return;
-            default:
-                throw new SecurityException("Request to ignore AppOps for non-legacy API");
+
+        // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system
+        // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS
+        // permission or is the System Server.
+        if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow(
+                TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
+            return;
         }
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
     }
 
     private void createOrUpdateTransform(
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 75e310d..b5b22f1 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1300,13 +1300,6 @@
                     vol.state = newState;
                     onVolumeStateChangedLocked(vol, oldState, newState);
                 }
-                try {
-                    if (vol.type == VolumeInfo.TYPE_PRIVATE && state == VolumeInfo.STATE_MOUNTED) {
-                        mInstaller.onPrivateVolumeMounted(vol.getFsUuid());
-                    }
-                } catch (Installer.InstallerException e) {
-                    Slog.i(TAG, "Failed when private volume mounted " + vol, e);
-                }
             }
         }
 
@@ -3110,6 +3103,15 @@
 
         try {
             mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
+            // After preparing user storage, we should check if we should mount data mirror again,
+            // and we do it for user 0 only as we only need to do once for all users.
+            if (volumeUuid != null) {
+                final StorageManager storage = mContext.getSystemService(StorageManager.class);
+                VolumeInfo info = storage.findVolumeByUuid(volumeUuid);
+                if (info != null && userId == 0 && info.type == VolumeInfo.TYPE_PRIVATE) {
+                    mInstaller.tryMountDataMirror(volumeUuid);
+                }
+            }
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 0e5a6bb..f85fc28 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -61,6 +61,7 @@
 import android.telephony.CellSignalStrengthWcdma;
 import android.telephony.DataFailCause;
 import android.telephony.DisconnectCause;
+import android.telephony.DisplayInfo;
 import android.telephony.LocationAccessPolicy;
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneStateListener;
@@ -205,6 +206,8 @@
 
     private boolean[] mUserMobileDataState;
 
+    private DisplayInfo[] mDisplayInfos;
+
     private SignalStrength[] mSignalStrength;
 
     private boolean[] mMessageWaiting;
@@ -284,7 +287,8 @@
     static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
                         | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
-                        | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
+                        | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
+                        | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
 
     static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_PRECISE_CALL_STATE
@@ -443,6 +447,7 @@
         mCallAttributes = copyOf(mCallAttributes, mNumPhones);
         mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
         mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
+        mDisplayInfos = copyOf(mDisplayInfos, mNumPhones);
 
         // ds -> ss switch.
         if (mNumPhones < oldNumPhones) {
@@ -482,6 +487,7 @@
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
             mBarringInfo.add(i, new BarringInfo());
+            mDisplayInfos[i] = null;
         }
     }
 
@@ -540,6 +546,7 @@
         mOutgoingCallEmergencyNumber = new EmergencyNumber[numPhones];
         mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
         mBarringInfo = new ArrayList<>();
+        mDisplayInfos = new DisplayInfo[numPhones];
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -568,6 +575,7 @@
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mPreciseDataConnectionStates.add(new HashMap<Integer, PreciseDataConnectionState>());
             mBarringInfo.add(i, new BarringInfo());
+            mDisplayInfos[i] = null;
         }
 
         mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -978,6 +986,15 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+                        try {
+                            if (mDisplayInfos[phoneId] != null) {
+                                r.callback.onDisplayInfoChanged(mDisplayInfos[phoneId]);
+                            }
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                     if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
                         try {
                             r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
@@ -1501,6 +1518,45 @@
         }
     }
 
+    /**
+     * Notify display network info changed.
+     *
+     * @param phoneId Phone id
+     * @param subId Subscription id
+     * @param displayInfo Display network info
+     *
+     * @see PhoneStateListener#onDisplayInfoChanged(DisplayInfo)
+     */
+    public void notifyDisplayInfoChanged(int phoneId, int subId,
+                                         @NonNull DisplayInfo displayInfo) {
+        if (!checkNotifyPermission("notifyDisplayInfoChanged()")) {
+            return;
+        }
+        if (VDBG) {
+            log("notifyDisplayInfoChanged: PhoneId=" + phoneId
+                    + " subId=" + subId + " displayInfo=" + displayInfo);
+        }
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                if (mDisplayInfos[phoneId] != null) {
+                    mDisplayInfos[phoneId] = displayInfo;
+                    for (Record r : mRecords) {
+                        if (r.matchPhoneStateListenerEvent(
+                                PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+                                && idMatch(r.subId, subId, phoneId)) {
+                            try {
+                                r.callback.onDisplayInfoChanged(displayInfo);
+                            } catch (RemoteException ex) {
+                                mRemoveList.add(r.binder);
+                            }
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     public void notifyCallForwardingChanged(boolean cfi) {
         notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cfi);
     }
@@ -2730,6 +2786,20 @@
             }
         }
 
+        if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+            try {
+                if (VDBG) {
+                    log("checkPossibleMissNotify: onDisplayInfoChanged phoneId="
+                            + phoneId + " dpi=" + mDisplayInfos[phoneId]);
+                }
+                if (mDisplayInfos[phoneId] != null) {
+                    r.callback.onDisplayInfoChanged(mDisplayInfos[phoneId]);
+                }
+            } catch (RemoteException ex) {
+                mRemoveList.add(r.binder);
+            }
+        }
+
         if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
             try {
                 if (VDBG) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 06561f5..3ffe1be 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -56,7 +56,6 @@
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
 import static android.content.Intent.EXTRA_REPLACING;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
-import static android.os.Process.STATSD_UID;
 
 import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
 
@@ -411,9 +410,9 @@
                     Slog.e(TAG, "Bad app ops settings", e);
                 }
                 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
+                        KEY_TOP_STATE_SETTLE_TIME, 5 * 1000L);
                 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
+                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 5 * 1000L);
                 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
                         KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
             }
@@ -1890,9 +1889,9 @@
 
         ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
         boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
-        boolean isCallerStatsCollector = Binder.getCallingUid() == STATSD_UID;
+        boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
 
-        if (!isCallerStatsCollector && !isCallerInstrumented) {
+        if (!isCallerSystem && !isCallerInstrumented) {
             mHandler.post(() -> callback.sendResult(new Bundle()));
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index cb88c4e..1a68f1b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -48,8 +48,12 @@
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
 import android.net.INetworkManagementEventObserver;
+import android.net.Ikev2VpnProfile;
 import android.net.IpPrefix;
 import android.net.IpSecManager;
+import android.net.IpSecManager.IpSecTunnelInterface;
+import android.net.IpSecManager.UdpEncapsulationSocket;
+import android.net.IpSecTransform;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.LocalSocket;
@@ -65,6 +69,12 @@
 import android.net.UidRange;
 import android.net.VpnManager;
 import android.net.VpnService;
+import android.net.ipsec.ike.ChildSessionCallback;
+import android.net.ipsec.ike.ChildSessionConfiguration;
+import android.net.ipsec.ike.ChildSessionParams;
+import android.net.ipsec.ike.IkeSession;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.IkeSessionParams;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -113,6 +123,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -122,6 +133,9 @@
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -176,14 +190,14 @@
 
     private final Context mContext;
     private final NetworkInfo mNetworkInfo;
-    private String mPackage;
+    @VisibleForTesting protected String mPackage;
     private int mOwnerUID;
     private boolean mIsPackageTargetingAtLeastQ;
     private String mInterface;
     private Connection mConnection;
 
     /** Tracks the runners for all VPN types managed by the platform (eg. LegacyVpn, PlatformVpn) */
-    private VpnRunner mVpnRunner;
+    @VisibleForTesting protected VpnRunner mVpnRunner;
 
     private PendingIntent mStatusIntent;
     private volatile boolean mEnableTeardown = true;
@@ -196,6 +210,7 @@
     @VisibleForTesting
     protected final NetworkCapabilities mNetworkCapabilities;
     private final SystemServices mSystemServices;
+    private final Ikev2SessionCreator mIkev2SessionCreator;
 
     /**
      * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
@@ -238,17 +253,20 @@
 
     public Vpn(Looper looper, Context context, INetworkManagementService netService,
             @UserIdInt int userHandle) {
-        this(looper, context, netService, userHandle, new SystemServices(context));
+        this(looper, context, netService, userHandle,
+                new SystemServices(context), new Ikev2SessionCreator());
     }
 
     @VisibleForTesting
     protected Vpn(Looper looper, Context context, INetworkManagementService netService,
-            int userHandle, SystemServices systemServices) {
+            int userHandle, SystemServices systemServices,
+            Ikev2SessionCreator ikev2SessionCreator) {
         mContext = context;
         mNetd = netService;
         mUserHandle = userHandle;
         mLooper = looper;
         mSystemServices = systemServices;
+        mIkev2SessionCreator = ikev2SessionCreator;
 
         mPackage = VpnConfig.LEGACY_VPN;
         mOwnerUID = getAppUid(mPackage, mUserHandle);
@@ -749,8 +767,9 @@
 
     private boolean isCurrentPreparedPackage(String packageName) {
         // We can't just check that packageName matches mPackage, because if the app was uninstalled
-        // and reinstalled it will no longer be prepared. Instead check the UID.
-        return getAppUid(packageName, mUserHandle) == mOwnerUID;
+        // and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
+        // calling package may not be the same as the prepared package. Check both UID and package.
+        return getAppUid(packageName, mUserHandle) == mOwnerUID && mPackage.equals(packageName);
     }
 
     /** Prepare the VPN for the given package. Does not perform permission checks. */
@@ -979,7 +998,11 @@
         }
         lp.setDomains(buffer.toString().trim());
 
-        // TODO: Stop setting the MTU in jniCreate and set it here.
+        if (mConfig.mtu > 0) {
+            lp.setMtu(mConfig.mtu);
+        }
+
+        // TODO: Stop setting the MTU in jniCreate
 
         return lp;
     }
@@ -2004,30 +2027,369 @@
         protected abstract void exit();
     }
 
-    private class IkeV2VpnRunner extends VpnRunner {
-        private static final String TAG = "IkeV2VpnRunner";
+    interface IkeV2VpnRunnerCallback {
+        void onDefaultNetworkChanged(@NonNull Network network);
 
-        private final IpSecManager mIpSecManager;
-        private final VpnProfile mProfile;
+        void onChildOpened(
+                @NonNull Network network, @NonNull ChildSessionConfiguration childConfig);
 
-        IkeV2VpnRunner(VpnProfile profile) {
+        void onChildTransformCreated(
+                @NonNull Network network, @NonNull IpSecTransform transform, int direction);
+
+        void onSessionLost(@NonNull Network network);
+    }
+
+    /**
+     * Internal class managing IKEv2/IPsec VPN connectivity
+     *
+     * <p>The IKEv2 VPN will listen to, and run based on the lifecycle of Android's default Network.
+     * As a new default is selected, old IKE sessions will be torn down, and a new one will be
+     * started.
+     *
+     * <p>This class uses locking minimally - the Vpn instance lock is only ever held when fields of
+     * the outer class are modified. As such, care must be taken to ensure that no calls are added
+     * that might modify the outer class' state without acquiring a lock.
+     *
+     * <p>The overall structure of the Ikev2VpnRunner is as follows:
+     *
+     * <ol>
+     *   <li>Upon startup, a NetworkRequest is registered with ConnectivityManager. This is called
+     *       any time a new default network is selected
+     *   <li>When a new default is connected, an IKE session is started on that Network. If there
+     *       were any existing IKE sessions on other Networks, they are torn down before starting
+     *       the new IKE session
+     *   <li>Upon establishment, the onChildTransformCreated() callback is called twice, one for
+     *       each direction, and finally onChildOpened() is called
+     *   <li>Upon the onChildOpened() call, the VPN is fully set up.
+     *   <li>Subsequent Network changes result in new onDefaultNetworkChanged() callbacks. See (2).
+     * </ol>
+     */
+    class IkeV2VpnRunner extends VpnRunner implements IkeV2VpnRunnerCallback {
+        @NonNull private static final String TAG = "IkeV2VpnRunner";
+
+        @NonNull private final IpSecManager mIpSecManager;
+        @NonNull private final Ikev2VpnProfile mProfile;
+        @NonNull private final ConnectivityManager.NetworkCallback mNetworkCallback;
+
+        /**
+         * Executor upon which ALL callbacks must be run.
+         *
+         * <p>This executor MUST be a single threaded executor, in order to ensure the consistency
+         * of the mutable Ikev2VpnRunner fields. The Ikev2VpnRunner is built mostly lock-free by
+         * virtue of everything being serialized on this executor.
+         */
+        @NonNull private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+        /** Signal to ensure shutdown is honored even if a new Network is connected. */
+        private boolean mIsRunning = true;
+
+        @Nullable private UdpEncapsulationSocket mEncapSocket;
+        @Nullable private IpSecTunnelInterface mTunnelIface;
+        @Nullable private IkeSession mSession;
+        @Nullable private Network mActiveNetwork;
+
+        IkeV2VpnRunner(@NonNull Ikev2VpnProfile profile) {
             super(TAG);
             mProfile = profile;
-
-            // TODO: move this to startVpnRunnerPrivileged()
-            mConfig = new VpnConfig();
-            mIpSecManager = mContext.getSystemService(IpSecManager.class);
+            mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
+            mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this);
         }
 
         @Override
         public void run() {
-            // TODO: Build IKE config, start IKE session
+            // Explicitly use only the network that ConnectivityService thinks is the "best." In
+            // other words, only ever use the currently selected default network. This does mean
+            // that in both onLost() and onConnected(), any old sessions MUST be torn down. This
+            // does NOT include VPNs.
+            final ConnectivityManager cm = ConnectivityManager.from(mContext);
+            cm.requestNetwork(cm.getDefaultRequest(), mNetworkCallback);
+        }
+
+        private boolean isActiveNetwork(@Nullable Network network) {
+            return Objects.equals(mActiveNetwork, network) && mIsRunning;
+        }
+
+        /**
+         * Called when an IKE Child session has been opened, signalling completion of the startup.
+         *
+         * <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor
+         * thread in order to ensure consistency of the Ikev2VpnRunner fields.
+         */
+        public void onChildOpened(
+                @NonNull Network network, @NonNull ChildSessionConfiguration childConfig) {
+            if (!isActiveNetwork(network)) {
+                Log.d(TAG, "onOpened called for obsolete network " + network);
+
+                // Do nothing; this signals that either: (1) a new/better Network was found,
+                // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
+                // IKE session was already shut down (exited, or an error was encountered somewhere
+                // else). In both cases, all resources and sessions are torn down via
+                // resetIkeState().
+                return;
+            }
+
+            try {
+                final String interfaceName = mTunnelIface.getInterfaceName();
+                final int maxMtu = mProfile.getMaxMtu();
+                final List<LinkAddress> internalAddresses = childConfig.getInternalAddresses();
+
+                final Collection<RouteInfo> newRoutes = VpnIkev2Utils.getRoutesFromTrafficSelectors(
+                        childConfig.getOutboundTrafficSelectors());
+                for (final LinkAddress address : internalAddresses) {
+                    mTunnelIface.addAddress(address.getAddress(), address.getPrefixLength());
+                }
+
+                final NetworkAgent networkAgent;
+                final LinkProperties lp;
+
+                synchronized (Vpn.this) {
+                    mInterface = interfaceName;
+                    mConfig.mtu = maxMtu;
+                    mConfig.interfaze = mInterface;
+
+                    mConfig.addresses.clear();
+                    mConfig.addresses.addAll(internalAddresses);
+
+                    mConfig.routes.clear();
+                    mConfig.routes.addAll(newRoutes);
+
+                    // TODO: Add DNS servers from negotiation
+
+                    networkAgent = mNetworkAgent;
+
+                    // The below must be done atomically with the mConfig update, otherwise
+                    // isRunningLocked() will be racy.
+                    if (networkAgent == null) {
+                        if (isSettingsVpnLocked()) {
+                            prepareStatusIntent();
+                        }
+                        agentConnect();
+                        return; // Link properties are already sent.
+                    }
+
+                    lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked
+                }
+
+                networkAgent.sendLinkProperties(lp);
+            } catch (Exception e) {
+                Log.d(TAG, "Error in ChildOpened for network " + network, e);
+                onSessionLost(network);
+            }
+        }
+
+        /**
+         * Called when an IPsec transform has been created, and should be applied.
+         *
+         * <p>This method is called multiple times over the lifetime of an IkeSession (or default
+         * network), and is MUST always be called on the mExecutor thread in order to ensure
+         * consistency of the Ikev2VpnRunner fields.
+         */
+        public void onChildTransformCreated(
+                @NonNull Network network, @NonNull IpSecTransform transform, int direction) {
+            if (!isActiveNetwork(network)) {
+                Log.d(TAG, "ChildTransformCreated for obsolete network " + network);
+
+                // Do nothing; this signals that either: (1) a new/better Network was found,
+                // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
+                // IKE session was already shut down (exited, or an error was encountered somewhere
+                // else). In both cases, all resources and sessions are torn down via
+                // resetIkeState().
+                return;
+            }
+
+            try {
+                // Transforms do not need to be persisted; the IkeSession will keep
+                // them alive for us
+                mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform);
+            } catch (IOException e) {
+                Log.d(TAG, "Transform application failed for network " + network, e);
+                onSessionLost(network);
+            }
+        }
+
+        /**
+         * Called when a new default network is connected.
+         *
+         * <p>The Ikev2VpnRunner will unconditionally switch to the new network, killing the old IKE
+         * state in the process, and starting a new IkeSession instance.
+         *
+         * <p>This method is called multiple times over the lifetime of the Ikev2VpnRunner, and is
+         * called on the ConnectivityService thread. Thus, the actual work MUST be proxied to the
+         * mExecutor thread in order to ensure consistency of the Ikev2VpnRunner fields.
+         */
+        public void onDefaultNetworkChanged(@NonNull Network network) {
+            Log.d(TAG, "Starting IKEv2/IPsec session on new network: " + network);
+
+            // Proxy to the Ikev2VpnRunner (single-thread) executor to ensure consistency in lieu
+            // of locking.
+            mExecutor.execute(() -> {
+                try {
+                    if (!mIsRunning) {
+                        Log.d(TAG, "onDefaultNetworkChanged after exit");
+                        return; // VPN has been shut down.
+                    }
+
+                    // Without MOBIKE, we have no way to seamlessly migrate. Close on old
+                    // (non-default) network, and start the new one.
+                    resetIkeState();
+                    mActiveNetwork = network;
+
+                    // TODO(b/149356682): Update this based on new IKE API
+                    mEncapSocket = mIpSecManager.openUdpEncapsulationSocket();
+
+                    // TODO(b/149356682): Update this based on new IKE API
+                    final IkeSessionParams ikeSessionParams =
+                            VpnIkev2Utils.buildIkeSessionParams(mProfile, mEncapSocket);
+                    final ChildSessionParams childSessionParams =
+                            VpnIkev2Utils.buildChildSessionParams();
+
+                    // TODO: Remove the need for adding two unused addresses with
+                    // IPsec tunnels.
+                    mTunnelIface =
+                            mIpSecManager.createIpSecTunnelInterface(
+                                    ikeSessionParams.getServerAddress() /* unused */,
+                                    ikeSessionParams.getServerAddress() /* unused */,
+                                    network);
+                    mNetd.setInterfaceUp(mTunnelIface.getInterfaceName());
+
+                    // Socket must be bound to prevent network switches from causing
+                    // the IKE teardown to fail/timeout.
+                    // TODO(b/149356682): Update this based on new IKE API
+                    network.bindSocket(mEncapSocket.getFileDescriptor());
+
+                    mSession = mIkev2SessionCreator.createIkeSession(
+                            mContext,
+                            ikeSessionParams,
+                            childSessionParams,
+                            mExecutor,
+                            new VpnIkev2Utils.IkeSessionCallbackImpl(
+                                    TAG, IkeV2VpnRunner.this, network),
+                            new VpnIkev2Utils.ChildSessionCallbackImpl(
+                                    TAG, IkeV2VpnRunner.this, network));
+                    Log.d(TAG, "Ike Session started for network " + network);
+                } catch (Exception e) {
+                    Log.i(TAG, "Setup failed for network " + network + ". Aborting", e);
+                    onSessionLost(network);
+                }
+            });
+        }
+
+        /**
+         * Handles loss of a session
+         *
+         * <p>The loss of a session might be due to an onLost() call, the IKE session getting torn
+         * down for any reason, or an error in updating state (transform application, VPN setup)
+         *
+         * <p>This method MUST always be called on the mExecutor thread in order to ensure
+         * consistency of the Ikev2VpnRunner fields.
+         */
+        public void onSessionLost(@NonNull Network network) {
+            if (!isActiveNetwork(network)) {
+                Log.d(TAG, "onSessionLost() called for obsolete network " + network);
+
+                // Do nothing; this signals that either: (1) a new/better Network was found,
+                // and the Ikev2VpnRunner has switched to it in onDefaultNetworkChanged, or (2) this
+                // IKE session was already shut down (exited, or an error was encountered somewhere
+                // else). In both cases, all resources and sessions are torn down via
+                // onSessionLost() and resetIkeState().
+                return;
+            }
+
+            mActiveNetwork = null;
+
+            // Close all obsolete state, but keep VPN alive incase a usable network comes up.
+            // (Mirrors VpnService behavior)
+            Log.d(TAG, "Resetting state for network: " + network);
+
+            synchronized (Vpn.this) {
+                // Since this method handles non-fatal errors only, set mInterface to null to
+                // prevent the NetworkManagementEventObserver from killing this VPN based on the
+                // interface going down (which we expect).
+                mInterface = null;
+                mConfig.interfaze = null;
+
+                // Set as unroutable to prevent traffic leaking while the interface is down.
+                if (mConfig != null && mConfig.routes != null) {
+                    final List<RouteInfo> oldRoutes = new ArrayList<>(mConfig.routes);
+
+                    mConfig.routes.clear();
+                    for (final RouteInfo route : oldRoutes) {
+                        mConfig.routes.add(new RouteInfo(route.getDestination(), RTN_UNREACHABLE));
+                    }
+                    if (mNetworkAgent != null) {
+                        mNetworkAgent.sendLinkProperties(makeLinkProperties());
+                    }
+                }
+            }
+
+            resetIkeState();
+        }
+
+        /**
+         * Cleans up all IKE state
+         *
+         * <p>This method MUST always be called on the mExecutor thread in order to ensure
+         * consistency of the Ikev2VpnRunner fields.
+         */
+        private void resetIkeState() {
+            if (mTunnelIface != null) {
+                // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
+                mTunnelIface.close();
+                mTunnelIface = null;
+            }
+            if (mSession != null) {
+                mSession.kill(); // Kill here to make sure all resources are released immediately
+                mSession = null;
+            }
+
+            // TODO(b/149356682): Update this based on new IKE API
+            if (mEncapSocket != null) {
+                try {
+                    mEncapSocket.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "Failed to close encap socket", e);
+                }
+                mEncapSocket = null;
+            }
+        }
+
+        /**
+         * Triggers cleanup of outer class' state
+         *
+         * <p>Can be called from any thread, as it does not mutate state in the Ikev2VpnRunner.
+         */
+        private void cleanupVpnState() {
+            synchronized (Vpn.this) {
+                agentDisconnect();
+            }
+        }
+
+        /**
+         * Cleans up all Ikev2VpnRunner internal state
+         *
+         * <p>This method MUST always be called on the mExecutor thread in order to ensure
+         * consistency of the Ikev2VpnRunner fields.
+         */
+        private void shutdownVpnRunner() {
+            mActiveNetwork = null;
+            mIsRunning = false;
+
+            resetIkeState();
+
+            final ConnectivityManager cm = ConnectivityManager.from(mContext);
+            cm.unregisterNetworkCallback(mNetworkCallback);
+
+            mExecutor.shutdown();
         }
 
         @Override
         public void exit() {
-            // TODO: Teardown IKE session & any resources.
-            agentDisconnect();
+            // Cleanup outer class' state immediately, otherwise race conditions may ensue.
+            cleanupVpnState();
+
+            mExecutor.execute(() -> {
+                shutdownVpnRunner();
+            });
         }
     }
 
@@ -2488,12 +2850,46 @@
                         throw new IllegalArgumentException("No profile found for " + packageName);
                     }
 
-                    startVpnProfilePrivileged(profile);
+                    startVpnProfilePrivileged(profile, packageName);
                 });
     }
 
-    private void startVpnProfilePrivileged(@NonNull VpnProfile profile) {
-        // TODO: Start PlatformVpnRunner
+    private void startVpnProfilePrivileged(
+            @NonNull VpnProfile profile, @NonNull String packageName) {
+        // Ensure that no other previous instance is running.
+        if (mVpnRunner != null) {
+            mVpnRunner.exit();
+            mVpnRunner = null;
+        }
+        updateState(DetailedState.CONNECTING, "startPlatformVpn");
+
+        try {
+            // Build basic config
+            mConfig = new VpnConfig();
+            mConfig.user = packageName;
+            mConfig.isMetered = profile.isMetered;
+            mConfig.startTime = SystemClock.elapsedRealtime();
+            mConfig.proxyInfo = profile.proxy;
+
+            switch (profile.type) {
+                case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
+                case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
+                case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
+                    mVpnRunner = new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile));
+                    mVpnRunner.start();
+                    break;
+                default:
+                    updateState(DetailedState.FAILED, "Invalid platform VPN type");
+                    Log.d(TAG, "Unknown VPN profile type: " + profile.type);
+                    break;
+            }
+        } catch (IOException | GeneralSecurityException e) {
+            // Reset mConfig
+            mConfig = null;
+
+            updateState(DetailedState.FAILED, "VPN startup failed");
+            throw new IllegalArgumentException("VPN startup failed", e);
+        }
     }
 
     /**
@@ -2507,13 +2903,37 @@
     public synchronized void stopVpnProfile(@NonNull String packageName) {
         checkNotNull(packageName, "No package name provided");
 
-        // To stop the VPN profile, the caller must be the current prepared package. Otherwise,
-        // the app is not prepared, and we can just return.
-        if (!isCurrentPreparedPackage(packageName)) {
-            // TODO: Also check to make sure that the running VPN is a VPN profile.
+        // To stop the VPN profile, the caller must be the current prepared package and must be
+        // running an Ikev2VpnProfile.
+        if (!isCurrentPreparedPackage(packageName) && mVpnRunner instanceof IkeV2VpnRunner) {
             return;
         }
 
         prepareInternal(VpnConfig.LEGACY_VPN);
     }
+
+    /**
+     * Proxy to allow testing
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static class Ikev2SessionCreator {
+        /** Creates a IKE session */
+        public IkeSession createIkeSession(
+                @NonNull Context context,
+                @NonNull IkeSessionParams ikeSessionParams,
+                @NonNull ChildSessionParams firstChildSessionParams,
+                @NonNull Executor userCbExecutor,
+                @NonNull IkeSessionCallback ikeSessionCallback,
+                @NonNull ChildSessionCallback firstChildSessionCallback) {
+            return new IkeSession(
+                    context,
+                    ikeSessionParams,
+                    firstChildSessionParams,
+                    userCbExecutor,
+                    ikeSessionCallback,
+                    firstChildSessionCallback);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
new file mode 100644
index 0000000..33fc32b
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2020 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.connectivity;
+
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_1024_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
+
+import android.annotation.NonNull;
+import android.net.Ikev2VpnProfile;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpSecManager.UdpEncapsulationSocket;
+import android.net.IpSecTransform;
+import android.net.Network;
+import android.net.RouteInfo;
+import android.net.eap.EapSessionConfig;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.ChildSessionCallback;
+import android.net.ipsec.ike.ChildSessionConfiguration;
+import android.net.ipsec.ike.ChildSessionParams;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeIdentification;
+import android.net.ipsec.ike.IkeIpv4AddrIdentification;
+import android.net.ipsec.ike.IkeIpv6AddrIdentification;
+import android.net.ipsec.ike.IkeKeyIdIdentification;
+import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.ipsec.ike.IkeSessionConfiguration;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.util.IpRange;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.internal.net.VpnProfile;
+import com.android.internal.util.HexDump;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Utility class to build and convert IKEv2/IPsec parameters.
+ *
+ * @hide
+ */
+public class VpnIkev2Utils {
+    static IkeSessionParams buildIkeSessionParams(
+            @NonNull Ikev2VpnProfile profile, @NonNull UdpEncapsulationSocket socket) {
+        // TODO(b/149356682): Update this based on new IKE API. Only numeric addresses supported
+        //                    until then. All others throw IAE (caught by caller).
+        final InetAddress serverAddr = InetAddresses.parseNumericAddress(profile.getServerAddr());
+        final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
+        final IkeIdentification remoteId = parseIkeIdentification(profile.getServerAddr());
+
+        // TODO(b/149356682): Update this based on new IKE API.
+        final IkeSessionParams.Builder ikeOptionsBuilder =
+                new IkeSessionParams.Builder()
+                        .setServerAddress(serverAddr)
+                        .setUdpEncapsulationSocket(socket)
+                        .setLocalIdentification(localId)
+                        .setRemoteIdentification(remoteId);
+        setIkeAuth(profile, ikeOptionsBuilder);
+
+        for (final IkeSaProposal ikeProposal : getIkeSaProposals()) {
+            ikeOptionsBuilder.addSaProposal(ikeProposal);
+        }
+
+        return ikeOptionsBuilder.build();
+    }
+
+    static ChildSessionParams buildChildSessionParams() {
+        final TunnelModeChildSessionParams.Builder childOptionsBuilder =
+                new TunnelModeChildSessionParams.Builder();
+
+        for (final ChildSaProposal childProposal : getChildSaProposals()) {
+            childOptionsBuilder.addSaProposal(childProposal);
+        }
+
+        childOptionsBuilder.addInternalAddressRequest(OsConstants.AF_INET);
+        childOptionsBuilder.addInternalAddressRequest(OsConstants.AF_INET6);
+        childOptionsBuilder.addInternalDnsServerRequest(OsConstants.AF_INET);
+        childOptionsBuilder.addInternalDnsServerRequest(OsConstants.AF_INET6);
+
+        return childOptionsBuilder.build();
+    }
+
+    private static void setIkeAuth(
+            @NonNull Ikev2VpnProfile profile, @NonNull IkeSessionParams.Builder builder) {
+        switch (profile.getType()) {
+            case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
+                final EapSessionConfig eapConfig =
+                        new EapSessionConfig.Builder()
+                                .setEapMsChapV2Config(profile.getUsername(), profile.getPassword())
+                                .build();
+                builder.setAuthEap(profile.getServerRootCaCert(), eapConfig);
+                break;
+            case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
+                builder.setAuthPsk(profile.getPresharedKey());
+                break;
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
+                builder.setAuthDigitalSignature(
+                        profile.getServerRootCaCert(),
+                        profile.getUserCert(),
+                        profile.getRsaPrivateKey());
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown auth method set");
+        }
+    }
+
+    private static List<IkeSaProposal> getIkeSaProposals() {
+        // TODO: filter this based on allowedAlgorithms
+        final List<IkeSaProposal> proposals = new ArrayList<>();
+
+        // Encryption Algorithms: Currently only AES_CBC is supported.
+        final IkeSaProposal.Builder normalModeBuilder = new IkeSaProposal.Builder();
+
+        // Currently only AES_CBC is supported.
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256);
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192);
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128);
+
+        // Authentication/Integrity Algorithms
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+
+        // Add AEAD options
+        final IkeSaProposal.Builder aeadBuilder = new IkeSaProposal.Builder();
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128);
+
+        // Add dh, prf for both builders
+        for (final IkeSaProposal.Builder builder : Arrays.asList(normalModeBuilder, aeadBuilder)) {
+            builder.addDhGroup(DH_GROUP_2048_BIT_MODP);
+            builder.addDhGroup(DH_GROUP_1024_BIT_MODP);
+            builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC);
+            builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
+        }
+
+        proposals.add(normalModeBuilder.build());
+        proposals.add(aeadBuilder.build());
+        return proposals;
+    }
+
+    private static List<ChildSaProposal> getChildSaProposals() {
+        // TODO: filter this based on allowedAlgorithms
+        final List<ChildSaProposal> proposals = new ArrayList<>();
+
+        // Add non-AEAD options
+        final ChildSaProposal.Builder normalModeBuilder = new ChildSaProposal.Builder();
+
+        // Encryption Algorithms: Currently only AES_CBC is supported.
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256);
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192);
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128);
+
+        // Authentication/Integrity Algorithms
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA1_96);
+
+        // Add AEAD options
+        final ChildSaProposal.Builder aeadBuilder = new ChildSaProposal.Builder();
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128);
+
+        proposals.add(normalModeBuilder.build());
+        proposals.add(aeadBuilder.build());
+        return proposals;
+    }
+
+    static class IkeSessionCallbackImpl implements IkeSessionCallback {
+        private final String mTag;
+        private final Vpn.IkeV2VpnRunnerCallback mCallback;
+        private final Network mNetwork;
+
+        IkeSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
+            mTag = tag;
+            mCallback = callback;
+            mNetwork = network;
+        }
+
+        @Override
+        public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
+            Log.d(mTag, "IkeOpened for network " + mNetwork);
+            // Nothing to do here.
+        }
+
+        @Override
+        public void onClosed() {
+            Log.d(mTag, "IkeClosed for network " + mNetwork);
+            mCallback.onSessionLost(mNetwork); // Server requested session closure. Retry?
+        }
+
+        @Override
+        public void onClosedExceptionally(@NonNull IkeException exception) {
+            Log.d(mTag, "IkeClosedExceptionally for network " + mNetwork, exception);
+            mCallback.onSessionLost(mNetwork);
+        }
+
+        @Override
+        public void onError(@NonNull IkeProtocolException exception) {
+            Log.d(mTag, "IkeError for network " + mNetwork, exception);
+            // Non-fatal, log and continue.
+        }
+    }
+
+    static class ChildSessionCallbackImpl implements ChildSessionCallback {
+        private final String mTag;
+        private final Vpn.IkeV2VpnRunnerCallback mCallback;
+        private final Network mNetwork;
+
+        ChildSessionCallbackImpl(String tag, Vpn.IkeV2VpnRunnerCallback callback, Network network) {
+            mTag = tag;
+            mCallback = callback;
+            mNetwork = network;
+        }
+
+        @Override
+        public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
+            Log.d(mTag, "ChildOpened for network " + mNetwork);
+            mCallback.onChildOpened(mNetwork, childConfig);
+        }
+
+        @Override
+        public void onClosed() {
+            Log.d(mTag, "ChildClosed for network " + mNetwork);
+            mCallback.onSessionLost(mNetwork);
+        }
+
+        @Override
+        public void onClosedExceptionally(@NonNull IkeException exception) {
+            Log.d(mTag, "ChildClosedExceptionally for network " + mNetwork, exception);
+            mCallback.onSessionLost(mNetwork);
+        }
+
+        @Override
+        public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
+            Log.d(mTag, "ChildTransformCreated; Direction: " + direction + "; network " + mNetwork);
+            mCallback.onChildTransformCreated(mNetwork, transform, direction);
+        }
+
+        @Override
+        public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) {
+            // Nothing to be done; no references to the IpSecTransform are held by the
+            // Ikev2VpnRunner (or this callback class), and this transform will be closed by the
+            // IKE library.
+            Log.d(mTag,
+                    "ChildTransformDeleted; Direction: " + direction + "; for network " + mNetwork);
+        }
+    }
+
+    static class Ikev2VpnNetworkCallback extends NetworkCallback {
+        private final String mTag;
+        private final Vpn.IkeV2VpnRunnerCallback mCallback;
+
+        Ikev2VpnNetworkCallback(String tag, Vpn.IkeV2VpnRunnerCallback callback) {
+            mTag = tag;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onAvailable(@NonNull Network network) {
+            Log.d(mTag, "Starting IKEv2/IPsec session on new network: " + network);
+            mCallback.onDefaultNetworkChanged(network);
+        }
+
+        @Override
+        public void onLost(@NonNull Network network) {
+            Log.d(mTag, "Tearing down; lost network: " + network);
+            mCallback.onSessionLost(network);
+        }
+    }
+
+    /**
+     * Identity parsing logic using similar logic to open source implementations of IKEv2
+     *
+     * <p>This method does NOT support using type-prefixes (eg 'fqdn:' or 'keyid'), or ASN.1 encoded
+     * identities.
+     */
+    private static IkeIdentification parseIkeIdentification(@NonNull String identityStr) {
+        // TODO: Add identity formatting to public API javadocs.
+        if (identityStr.contains("@")) {
+            if (identityStr.startsWith("@#")) {
+                // KEY_ID
+                final String hexStr = identityStr.substring(2);
+                return new IkeKeyIdIdentification(HexDump.hexStringToByteArray(hexStr));
+            } else if (identityStr.startsWith("@@")) {
+                // RFC822 (USER_FQDN)
+                return new IkeRfc822AddrIdentification(identityStr.substring(2));
+            } else if (identityStr.startsWith("@")) {
+                // FQDN
+                return new IkeFqdnIdentification(identityStr.substring(1));
+            } else {
+                // RFC822 (USER_FQDN)
+                return new IkeRfc822AddrIdentification(identityStr);
+            }
+        } else if (InetAddresses.isNumericAddress(identityStr)) {
+            final InetAddress addr = InetAddresses.parseNumericAddress(identityStr);
+            if (addr instanceof Inet4Address) {
+                // IPv4
+                return new IkeIpv4AddrIdentification((Inet4Address) addr);
+            } else if (addr instanceof Inet6Address) {
+                // IPv6
+                return new IkeIpv6AddrIdentification((Inet6Address) addr);
+            } else {
+                throw new IllegalArgumentException("IP version not supported");
+            }
+        } else {
+            if (identityStr.contains(":")) {
+                // KEY_ID
+                return new IkeKeyIdIdentification(identityStr.getBytes());
+            } else {
+                // FQDN
+                return new IkeFqdnIdentification(identityStr);
+            }
+        }
+    }
+
+    static Collection<RouteInfo> getRoutesFromTrafficSelectors(
+            List<IkeTrafficSelector> trafficSelectors) {
+        final HashSet<RouteInfo> routes = new HashSet<>();
+
+        for (final IkeTrafficSelector selector : trafficSelectors) {
+            for (final IpPrefix prefix :
+                    new IpRange(selector.startingAddress, selector.endingAddress).asIpPrefixes()) {
+                routes.add(new RouteInfo(prefix, null));
+            }
+        }
+
+        return routes;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 68ced79..b9a30bb 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS;
 import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE;
 import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS;
+import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED;
 import static android.content.integrity.IntegrityUtils.getHexDigest;
 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
 
@@ -95,7 +96,7 @@
      * This string will be used as the "installer" for formula evaluation when the app is being
      * installed via ADB.
      */
-    private static final String ADB_INSTALLER = "adb";
+    public static final String ADB_INSTALLER = "adb";
 
     private static final String TAG = "AppIntegrityManagerServiceImpl";
 
@@ -106,8 +107,6 @@
     private static final String ALLOWED_INSTALLER_DELIMITER = ",";
     private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|";
 
-    private static final String INSTALLER_CERT_NOT_APPLICABLE = "";
-
     // Access to files inside mRulesDir is protected by mRulesLock;
     private final Context mContext;
     private final Handler mHandler;
@@ -282,15 +281,16 @@
             builder.setInstallerName(getPackageNameNormalized(installerPackageName));
             builder.setInstallerCertificates(installerCertificates);
             builder.setIsPreInstalled(isSystemApp(packageName));
+            builder.setAllowedInstallersAndCert(getAllowedInstallers(packageInfo));
 
             AppInstallMetadata appInstallMetadata = builder.build();
-            Map<String, String> allowedInstallers = getAllowedInstallers(packageInfo);
 
             Slog.i(
                     TAG,
-                    "To be verified: " + appInstallMetadata + " installers " + allowedInstallers);
+                    "To be verified: " + appInstallMetadata + " installers " + getAllowedInstallers(
+                            packageInfo));
             IntegrityCheckResult result =
-                    mEvaluationEngine.evaluate(appInstallMetadata, allowedInstallers);
+                    mEvaluationEngine.evaluate(appInstallMetadata);
             Slog.i(
                     TAG,
                     "Integrity check result: "
@@ -449,9 +449,9 @@
                         String packageName = getPackageNameNormalized(packageAndCert[0]);
                         String cert = packageAndCert[1];
                         packageCertMap.put(packageName, cert);
-                    } else if (packageAndCert.length == 1
-                            && packageAndCert[0].equals(ADB_INSTALLER)) {
-                        packageCertMap.put(ADB_INSTALLER, INSTALLER_CERT_NOT_APPLICABLE);
+                    } else if (packageAndCert.length == 1) {
+                        packageCertMap.put(getPackageNameNormalized(packageAndCert[0]),
+                                INSTALLER_CERTIFICATE_NOT_EVALUATED);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index 79e69e1..61da45d 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -17,9 +17,6 @@
 package com.android.server.integrity.engine;
 
 import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.IntegrityFormula;
 import android.content.integrity.Rule;
 import android.util.Slog;
 
@@ -28,10 +25,8 @@
 import com.android.server.integrity.model.IntegrityCheckResult;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.Optional;
 
 /**
  * The engine used to evaluate rules against app installs.
@@ -69,16 +64,15 @@
      * @return result of the integrity check
      */
     public IntegrityCheckResult evaluate(
-            AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallers) {
+            AppInstallMetadata appInstallMetadata) {
         List<Rule> rules = loadRules(appInstallMetadata);
-        allowedInstallersRule(allowedInstallers).ifPresent(rules::add);
         return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
     }
 
     private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
         if (!mIntegrityFileManager.initialized()) {
-            Slog.w(TAG, "Integrity rule files are not available. Evaluating only manifest rules.");
-            return new ArrayList<>();
+            Slog.w(TAG, "Integrity rule files are not available.");
+            return Collections.emptyList();
         }
 
         try {
@@ -88,41 +82,4 @@
             return new ArrayList<>();
         }
     }
-
-    private static Optional<Rule> allowedInstallersRule(Map<String, String> allowedInstallers) {
-        if (allowedInstallers.isEmpty()) {
-            return Optional.empty();
-        }
-
-        List<IntegrityFormula> formulas = new ArrayList<>(allowedInstallers.size());
-        allowedInstallers.forEach(
-                (installer, cert) -> {
-                    formulas.add(allowedInstallerFormula(installer, cert));
-                });
-
-        // We need this special case since OR-formulas require at least two operands.
-        IntegrityFormula allInstallersFormula =
-                formulas.size() == 1
-                        ? formulas.get(0)
-                        : new CompoundFormula(CompoundFormula.OR, formulas);
-
-        return Optional.of(
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.NOT, Arrays.asList(allInstallersFormula)),
-                        Rule.DENY));
-    }
-
-    private static IntegrityFormula allowedInstallerFormula(String installer, String cert) {
-        return new CompoundFormula(
-                CompoundFormula.AND,
-                Arrays.asList(
-                        new AtomicFormula.StringAtomicFormula(
-                                AtomicFormula.INSTALLER_NAME,
-                                installer,
-                                /* isHashedValue= */ false),
-                        new AtomicFormula.StringAtomicFormula(
-                                AtomicFormula.INSTALLER_CERTIFICATE, cert, /* isHashedValue= */
-                                false)));
-    }
 }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b98bb08..8ad3e9d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -611,10 +611,10 @@
     /**
      * Bind mount private volume CE and DE mirror storage.
      */
-    public void onPrivateVolumeMounted(String volumeUuid) throws InstallerException {
+    public void tryMountDataMirror(String volumeUuid) throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            mInstalld.onPrivateVolumeMounted(volumeUuid);
+            mInstalld.tryMountDataMirror(volumeUuid);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2c85d06..064fd3f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4600,7 +4600,7 @@
         synchronized (mLock) {
             final AndroidPackage p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
-                PackageSetting ps = getPackageSetting(p.getPackageName());
+                PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return -1;
                 }
@@ -5924,7 +5924,10 @@
      */
     @Override
     public String[] getPackagesForUid(int uid) {
-        final int callingUid = Binder.getCallingUid();
+        return getPackagesForUidInternal(uid, Binder.getCallingUid());
+    }
+
+    private String[] getPackagesForUidInternal(int uid, int callingUid) {
         final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
         final int userId = UserHandle.getUserId(uid);
         final int appId = UserHandle.getAppId(uid);
@@ -17380,6 +17383,13 @@
 
     @GuardedBy("mLock")
     private String resolveInternalPackageNameLPr(String packageName, long versionCode) {
+        final int callingUid = Binder.getCallingUid();
+        return resolveInternalPackageNameInternalLocked(packageName, versionCode,
+                callingUid);
+    }
+
+    private String resolveInternalPackageNameInternalLocked(
+            String packageName, long versionCode, int callingUid) {
         // Handle renamed packages
         String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
         packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
@@ -17393,12 +17403,12 @@
 
         // Figure out which lib versions the caller can see
         LongSparseLongArray versionsCallerCanSee = null;
-        final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+        final int callingAppId = UserHandle.getAppId(callingUid);
         if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
                 && callingAppId != Process.ROOT_UID) {
             versionsCallerCanSee = new LongSparseLongArray();
             String libName = versionedLib.valueAt(0).getName();
-            String[] uidPackages = getPackagesForUid(Binder.getCallingUid());
+            String[] uidPackages = getPackagesForUidInternal(callingUid, callingUid);
             if (uidPackages != null) {
                 for (String uidPackage : uidPackages) {
                     PackageSetting ps = mSettings.getPackageLPr(uidPackage);
@@ -23003,7 +23013,7 @@
         @Override
         public AndroidPackage getPackage(int uid) {
             synchronized (mLock) {
-                final String[] packageNames = getPackagesForUid(uid);
+                final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
                 AndroidPackage pkg = null;
                 final int numPackages = packageNames == null ? 0 : packageNames.length;
                 for (int i = 0; pkg == null && i < numPackages; i++) {
@@ -24017,9 +24027,13 @@
 
     @Nullable
     public PackageSetting getPackageSetting(String packageName) {
+        return getPackageSettingInternal(packageName, Binder.getCallingUid());
+    }
+
+    private PackageSetting getPackageSettingInternal(String packageName, int callingUid) {
         synchronized (mLock) {
-            packageName = resolveInternalPackageNameLPr(
-                    packageName, PackageManager.VERSION_CODE_HIGHEST);
+            packageName = resolveInternalPackageNameInternalLocked(
+                    packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
             return mSettings.mPackages.get(packageName);
         }
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e469067..aa5dafc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -57,6 +57,7 @@
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
+import static android.app.admin.DevicePolicyManager.NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
@@ -522,7 +523,8 @@
 
     /** Keyguard features that are allowed to be set on a managed profile */
     private static final int PROFILE_KEYGUARD_FEATURES =
-            PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
+            NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER
+                    | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
 
     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
 
@@ -8168,16 +8170,20 @@
         }
         Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
-        if (isManagedProfile(userHandle)) {
-            if (parent) {
-                which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
-            } else {
-                which = which & PROFILE_KEYGUARD_FEATURES;
-            }
-        }
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES, parent);
+            if (isManagedProfile(userHandle)) {
+                if (parent) {
+                    if (isProfileOwnerOfOrganizationOwnedDevice(ap)) {
+                        which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+                    } else {
+                        which = which & NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+                    }
+                } else {
+                    which = which & PROFILE_KEYGUARD_FEATURES;
+                }
+            }
             if (ap.disabledKeyguardFeatures != which) {
                 ap.disabledKeyguardFeatures = which;
                 saveSettingsLocked(userHandle);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index c8673f8..a904b42 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -322,7 +322,8 @@
     private void updateDefaultDialer(@NonNull UserData userData) {
         TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
         String defaultDialer = telecomManager != null
-                ? telecomManager.getDefaultDialerPackage(userData.getUserId()) : null;
+                ? telecomManager.getDefaultDialerPackage(
+                        new UserHandle(userData.getUserId())) : null;
         userData.setDefaultDialer(defaultDialer);
     }
 
diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/DummyAppTwoCerts.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/DummyAppTwoCerts.apk
new file mode 100644
index 0000000..9161d86
--- /dev/null
+++ b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/DummyAppTwoCerts.apk
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f2f8ad1..8f70cca 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2188,6 +2188,42 @@
         assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
     }
 
+    public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+
+        dpm.setKeyguardDisabledFeatures(admin1, DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        assertThat(dpm.getKeyguardDisabledFeatures(admin1)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+    }
+
+    public void testSetKeyguardDisabledFeaturesWithPO() throws Exception {
+        setupProfileOwner();
+
+        dpm.setKeyguardDisabledFeatures(admin1, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+        assertThat(dpm.getKeyguardDisabledFeatures(admin1)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+    }
+
+    public void testSetKeyguardDisabledFeaturesWithPOOfOrganizationOwnedDevice()
+            throws Exception {
+        final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
+        final int MANAGED_PROFILE_ADMIN_UID =
+                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+
+        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+        parentDpm.setKeyguardDisabledFeatures(admin1,
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        assertThat(parentDpm.getKeyguardDisabledFeatures(admin1)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+    }
+
     public void testSetApplicationHiddenWithDO() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 8dae48c..0d4c6e8 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -19,6 +19,7 @@
 import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS;
 import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE;
 import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS;
+import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED;
 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE;
 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_UID;
@@ -39,6 +40,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -65,6 +68,7 @@
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.testutils.TestUtils;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -76,8 +80,9 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -87,6 +92,9 @@
     private static final String TEST_APP_PATH =
             "/data/local/tmp/AppIntegrityManagerServiceTestApp.apk";
 
+    private static final String TEST_APP_TWO_CERT_PATH =
+            "AppIntegrityManagerServiceImplTest/DummyAppTwoCerts.apk";
+
     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
     private static final String VERSION = "version";
     private static final String TEST_FRAMEWORK_PACKAGE = "com.android.frameworks.servicestests";
@@ -105,6 +113,11 @@
     private static final String INSTALLER_SHA256 =
             "30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227";
 
+    private static final String DUMMY_APP_TWO_CERTS_CERT_1 =
+            "C0369C2A1096632429DFA8433068AECEAD00BAC337CA92A175036D39CC9AFE94";
+    private static final String DUMMY_APP_TWO_CERTS_CERT_2 =
+            "94366E0A80F3A3F0D8171A15760B88E228CD6E1101F0414C98878724FBE70147";
+
     private static final String PLAY_STORE_PKG = "com.android.vending";
     private static final String ADB_INSTALLER = "adb";
     private static final String PLAY_STORE_CERT = "play_store_cert";
@@ -128,6 +141,7 @@
 
     private PackageManager mSpyPackageManager;
     private File mTestApk;
+    private File mTestApkTwoCerts;
 
     private final Context mRealContext = InstrumentationRegistry.getTargetContext();
     // under test
@@ -136,6 +150,10 @@
     @Before
     public void setup() throws Exception {
         mTestApk = new File(TEST_APP_PATH);
+        mTestApkTwoCerts = File.createTempFile("AppIntegrity", ".apk");
+        try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_TWO_CERT_PATH)) {
+            Files.copy(inputStream, mTestApkTwoCerts.toPath(), REPLACE_EXISTING);
+        }
 
         mService =
                 new AppIntegrityManagerServiceImpl(
@@ -154,6 +172,11 @@
         when(mIntegrityFileManager.initialized()).thenReturn(true);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        mTestApkTwoCerts.delete();
+    }
+
     @Test
     public void updateRuleSet_notAuthorized() throws Exception {
         makeUsSystemApp();
@@ -268,20 +291,16 @@
         verify(mMockContext)
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent();
-        when(mRuleEvaluationEngine.evaluate(any(), any())).thenReturn(IntegrityCheckResult.allow());
+        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
 
         ArgumentCaptor<AppInstallMetadata> metadataCaptor =
                 ArgumentCaptor.forClass(AppInstallMetadata.class);
-        Map<String, String> allowedInstallers = new HashMap<>();
-        ArgumentCaptor<Map<String, String>> allowedInstallersCaptor =
-                ArgumentCaptor.forClass(allowedInstallers.getClass());
         verify(mRuleEvaluationEngine)
-                .evaluate(metadataCaptor.capture(), allowedInstallersCaptor.capture());
+                .evaluate(metadataCaptor.capture());
         AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
-        allowedInstallers = allowedInstallersCaptor.getValue();
         assertEquals(PACKAGE_NAME, appInstallMetadata.getPackageName());
         assertThat(appInstallMetadata.getAppCertificates()).containsExactly(APP_CERT);
         assertEquals(INSTALLER_SHA256, appInstallMetadata.getInstallerName());
@@ -289,9 +308,34 @@
         assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
         assertFalse(appInstallMetadata.isPreInstalled());
         // These are hardcoded in the test apk android manifest
+        Map<String, String> allowedInstallers =
+                appInstallMetadata.getAllowedInstallersAndCertificates();
         assertEquals(2, allowedInstallers.size());
         assertEquals(PLAY_STORE_CERT, allowedInstallers.get(PLAY_STORE_PKG));
-        assertEquals(ADB_CERT, allowedInstallers.get(ADB_INSTALLER));
+        assertEquals(INSTALLER_CERTIFICATE_NOT_EVALUATED, allowedInstallers.get(ADB_INSTALLER));
+    }
+
+    @Test
+    public void handleBroadcast_correctArgs_multipleCerts() throws Exception {
+        whitelistUsAsRuleProvider();
+        makeUsSystemApp();
+        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mMockContext)
+                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
+        Intent intent = makeVerificationIntent();
+        intent.setDataAndType(Uri.fromFile(mTestApkTwoCerts), PACKAGE_MIME_TYPE);
+        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
+
+        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
+        runJobInHandler();
+
+        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
+                ArgumentCaptor.forClass(AppInstallMetadata.class);
+        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
+        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
+        assertThat(appInstallMetadata.getAppCertificates()).containsExactly(
+                DUMMY_APP_TWO_CERTS_CERT_1, DUMMY_APP_TWO_CERTS_CERT_2);
     }
 
     @Test
@@ -303,7 +347,7 @@
         verify(mMockContext)
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent();
-        when(mRuleEvaluationEngine.evaluate(any(), any())).thenReturn(IntegrityCheckResult.allow());
+        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
@@ -321,7 +365,7 @@
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         verify(mMockContext)
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        when(mRuleEvaluationEngine.evaluate(any(), any()))
+        when(mRuleEvaluationEngine.evaluate(any()))
                 .thenReturn(
                         IntegrityCheckResult.deny(
                                 Arrays.asList(
@@ -349,7 +393,7 @@
         verify(mMockContext)
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent();
-        when(mRuleEvaluationEngine.evaluate(any(), any())).thenReturn(IntegrityCheckResult.allow());
+        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
         runJobInHandler();
@@ -377,7 +421,7 @@
         verify(mMockContext, atLeastOnce())
                 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
         Intent intent = makeVerificationIntent(TEST_FRAMEWORK_PACKAGE);
-        when(mRuleEvaluationEngine.evaluate(any(), any()))
+        when(mRuleEvaluationEngine.evaluate(any()))
                 .thenReturn(IntegrityCheckResult.deny(/* rule= */ null));
 
         broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
index b0b9596..0488745 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
@@ -22,6 +22,8 @@
 import static org.mockito.Mockito.when;
 
 import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.IntegrityFormula;
+import android.content.integrity.Rule;
 
 import com.android.server.integrity.IntegrityFileManager;
 import com.android.server.integrity.model.IntegrityCheckResult;
@@ -33,7 +35,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -60,13 +61,14 @@
 
         mEngine = new RuleEvaluationEngine(mIntegrityFileManager);
 
-        when(mIntegrityFileManager.readRules(any())).thenReturn(new ArrayList<>());
+        when(mIntegrityFileManager.readRules(any())).thenReturn(Collections.singletonList(new Rule(
+                IntegrityFormula.Installer.notAllowedByManifest(), Rule.DENY)));
+
+        when(mIntegrityFileManager.initialized()).thenReturn(true);
     }
 
     @Test
     public void testAllowedInstallers_empty() {
-        Map<String, String> allowedInstallers = Collections.emptyMap();
-
         AppInstallMetadata appInstallMetadata1 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_1)
@@ -83,11 +85,11 @@
                         .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                         .build();
 
-        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-        assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
     }
 
@@ -100,32 +102,36 @@
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_1)
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
 
         AppInstallMetadata appInstallMetadata2 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(RANDOM_INSTALLER)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.DENY);
 
         AppInstallMetadata appInstallMetadata3 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_1)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.DENY);
 
         AppInstallMetadata appInstallMetadata4 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_1)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.DENY);
     }
 
@@ -138,57 +144,37 @@
         AppInstallMetadata appInstallMetadata1 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_1)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
 
         AppInstallMetadata appInstallMetadata2 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_2)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
 
         AppInstallMetadata appInstallMetadata3 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_1)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.DENY);
 
         AppInstallMetadata appInstallMetadata4 =
                 getAppInstallMetadataBuilder()
                         .setInstallerName(INSTALLER_2)
+                        .setAllowedInstallersAndCert(allowedInstallers)
                         .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                         .build();
-        assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.DENY);
-    }
-
-    @Test
-    public void manifestBasedRuleEvaluationWorksEvenWhenIntegrityFilesAreUnavailable() {
-        when(mIntegrityFileManager.initialized()).thenReturn(false);
-
-        Map<String, String> allowedInstallers =
-                Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT);
-
-        AppInstallMetadata appInstallMetadata1 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(INSTALLER_1)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect())
-                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
-
-        AppInstallMetadata appInstallMetadata2 =
-                getAppInstallMetadataBuilder()
-                        .setInstallerName(RANDOM_INSTALLER)
-                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
-                        .build();
-        assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect())
+        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
                 .isEqualTo(IntegrityCheckResult.Effect.DENY);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 498d888..6769faa 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -142,7 +142,8 @@
         when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
         when(mContext.getSystemServiceName(TelecomManager.class)).thenReturn(
                 Context.TELECOM_SERVICE);
-        when(mTelecomManager.getDefaultDialerPackage(anyInt())).thenReturn(TEST_PKG_NAME);
+        when(mTelecomManager.getDefaultDialerPackage(any(UserHandle.class)))
+                .thenReturn(TEST_PKG_NAME);
 
         when(mExecutorService.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(
                 TimeUnit.class))).thenReturn(mScheduledFuture);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index e768205..9e57763 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -145,6 +145,7 @@
     static class MyInjector extends AppStandbyController.Injector {
         long mElapsedRealtime;
         boolean mIsAppIdleEnabled = true;
+        boolean mIsCharging;
         List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
         boolean mDisplayOn;
         DisplayManager.DisplayListener mDisplayListener;
@@ -179,6 +180,11 @@
         }
 
         @Override
+        boolean isCharging() {
+            return mIsCharging;
+        }
+
+        @Override
         boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
             return mPowerSaveWhitelistExceptIdle.contains(packageName);
         }
@@ -281,6 +287,13 @@
         } catch (PackageManager.NameNotFoundException nnfe) {}
     }
 
+    private void setChargingState(AppStandbyController controller, boolean charging) {
+        mInjector.mIsCharging = charging;
+        if (controller != null) {
+            controller.setChargingState(charging);
+        }
+    }
+
     private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
         mInjector.mIsAppIdleEnabled = enabled;
         if (controller != null) {
@@ -297,6 +310,7 @@
         controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
         mInjector.setDisplayOn(false);
         mInjector.setDisplayOn(true);
+        setChargingState(controller, false);
         controller.checkIdleStates(USER_ID);
         assertNotEquals(STANDBY_BUCKET_EXEMPTED,
                 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
@@ -324,6 +338,46 @@
                         mInjector.mElapsedRealtime, false));
     }
 
+    @Test
+    public void testIsAppIdle_Charging() throws Exception {
+        setChargingState(mController, false);
+        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+                REASON_MAIN_FORCED_BY_SYSTEM);
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+        setChargingState(mController, true);
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+        assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+        assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+        setChargingState(mController, false);
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+    }
+
+    @Test
+    public void testIsAppIdle_Enabled() throws Exception {
+        setChargingState(mController, false);
+        setAppIdleEnabled(mController, true);
+        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+                REASON_MAIN_FORCED_BY_SYSTEM);
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+        setAppIdleEnabled(mController, false);
+        assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+        assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+
+        setAppIdleEnabled(mController, true);
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
+        assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
+    }
+
     private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
         mInjector.mElapsedRealtime = elapsedTime;
         controller.checkIdleStates(USER_ID);
diff --git a/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
index f5dbf43..98572d4 100644
--- a/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
@@ -22,7 +22,7 @@
     <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
 
     <application android:hasCode="false">
-        <meta-data android:name="allowed-installers" android:value="com.android.vending|play_store_cert,adb|"/>
+        <meta-data android:name="allowed-installers" android:value="com.android.vending|play_store_cert,adb"/>
     </application>
 </manifest>
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index ec99f36..52213d8 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -17,6 +17,7 @@
 package android.telecom;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -458,8 +459,14 @@
         /** Call supports the deflect feature. */
         public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000;
 
+        /**
+         * Call supports adding participants to the call via
+         * {@link #addConferenceParticipants(List)}.
+         * @hide
+         */
+        public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
         //******************************************************************************************
-        // Next CAPABILITY value: 0x02000000
+        // Next CAPABILITY value: 0x04000000
         //******************************************************************************************
 
         /**
@@ -539,7 +546,7 @@
          *
          * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING
          */
-        public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
+        public static final int PROPERTY_ASSISTED_DIALING = 0x00000200;
 
         /**
          * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the
@@ -689,6 +696,9 @@
             if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
                 builder.append(" CAPABILITY_SUPPORT_DEFLECT");
             }
+            if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
+                builder.append(" CAPABILITY_ADD_PARTICIPANT");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -744,7 +754,7 @@
             if (hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
                 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
             }
-            if (hasProperty(properties, PROPERTY_ASSISTED_DIALING_USED)) {
+            if (hasProperty(properties, PROPERTY_ASSISTED_DIALING)) {
                 builder.append(" PROPERTY_ASSISTED_DIALING_USED");
             }
             if (hasProperty(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
@@ -1703,6 +1713,17 @@
     }
 
     /**
+     * Pulls participants to existing call by forming a conference call.
+     * See {@link Details#CAPABILITY_ADD_PARTICIPANT}.
+     *
+     * @param participants participants to be pulled to existing call.
+     * @hide
+     */
+    public void addConferenceParticipants(@NonNull List<Uri> participants) {
+        mInCallAdapter.addConferenceParticipants(mTelecomCallId, participants);
+    }
+
+    /**
      * Initiates a request to the {@link ConnectionService} to pull an external call to the local
      * device.
      * <p>
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 56acdff..f019a9d 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,8 +16,13 @@
 
 package android.telecom;
 
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.net.Uri;
@@ -319,6 +324,13 @@
     public void onConnectionAdded(Connection connection) {}
 
     /**
+     * Notifies the {@link Conference} of a request to add a new participants to the conference call
+     * @param participants that will be added to this conference call
+     * @hide
+     */
+    public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
+
+    /**
      * Notifies this Conference, which is in {@code STATE_RINGING}, of
      * a request to accept.
      * For managed {@link ConnectionService}s, this will be called when the user answers a call via
@@ -625,12 +637,12 @@
      * Should be specified in wall-clock time returned by {@link System#currentTimeMillis()}.
      * <p>
      * When setting the connection time, you should always set the connection elapsed time via
-     * {@link #setConnectionStartElapsedRealTime(long)} to ensure the duration is reflected.
+     * {@link #setConnectionStartElapsedRealtimeMillis(long)} to ensure the duration is reflected.
      *
      * @param connectionTimeMillis The connection time, in milliseconds, as returned by
      *                             {@link System#currentTimeMillis()}.
      */
-    public final void setConnectionTime(long connectionTimeMillis) {
+    public final void setConnectionTime(@IntRange(from = 0) long connectionTimeMillis) {
         mConnectTimeMillis = connectionTimeMillis;
     }
 
@@ -646,8 +658,28 @@
      *
      * @param connectionStartElapsedRealTime The connection time, as measured by
      * {@link SystemClock#elapsedRealtime()}.
+     * @deprecated use {@link #setConnectionStartElapsedRealtimeMillis(long)} instead.
      */
+    @Deprecated
     public final void setConnectionStartElapsedRealTime(long connectionStartElapsedRealTime) {
+        setConnectionStartElapsedRealtimeMillis(connectionStartElapsedRealTime);
+    }
+
+    /**
+     * Sets the start time of the {@link Conference} which is the basis for the determining the
+     * duration of the {@link Conference}.
+     * <p>
+     * You should use a value returned by {@link SystemClock#elapsedRealtime()} to ensure that time
+     * zone changes do not impact the conference duration.
+     * <p>
+     * When setting this, you should also set the connection time via
+     * {@link #setConnectionTime(long)}.
+     *
+     * @param connectionStartElapsedRealTime The connection time, as measured by
+     * {@link SystemClock#elapsedRealtime()}.
+     */
+    public final void setConnectionStartElapsedRealtimeMillis(
+            @ElapsedRealtimeLong long connectionStartElapsedRealTime) {
         mConnectionStartElapsedRealTime = connectionStartElapsedRealTime;
     }
 
@@ -668,7 +700,7 @@
      *
      * @return The time at which the {@code Conference} was connected.
      */
-    public final long getConnectionTime() {
+    public final @IntRange(from = 0) long getConnectionTime() {
         return mConnectTimeMillis;
     }
 
@@ -685,11 +717,8 @@
      * has no general use other than to the Telephony framework.
      *
      * @return The elapsed time at which the {@link Conference} was connected.
-     * @hide
      */
-    @SystemApi
-    @TestApi
-    public final long getConnectionStartElapsedRealTime() {
+    public final @ElapsedRealtimeLong long getConnectionStartElapsedRealtimeMillis() {
         return mConnectionStartElapsedRealTime;
     }
 
@@ -987,6 +1016,7 @@
      */
     @SystemApi
     @TestApi
+    @RequiresPermission(MODIFY_PHONE_STATE)
     public void setConferenceState(boolean isConference) {
         for (Listener l : mListeners) {
             l.onConferenceStateChanged(this, isConference);
@@ -1007,6 +1037,7 @@
      */
     @SystemApi
     @TestApi
+    @RequiresPermission(MODIFY_PHONE_STATE)
     public final void setAddress(@NonNull Uri address,
             @TelecomManager.Presentation int presentation) {
         Log.d(this, "setAddress %s", address);
@@ -1113,12 +1144,52 @@
     }
 
     /**
-     * Sends an event associated with this {@code Conference} with associated event extras to the
-     * {@link InCallService} (note: this is identical in concept to
-     * {@link Connection#sendConnectionEvent(String, Bundle)}).
-     * @see Connection#sendConnectionEvent(String, Bundle)
+     * Sends an event associated with this {@link Conference} with associated event extras to the
+     * {@link InCallService}.
+     * <p>
+     * Connection events are used to communicate point in time information from a
+     * {@link ConnectionService} to an {@link InCallService} implementation.  An example of a
+     * custom connection event includes notifying the UI when a WIFI call has been handed over to
+     * LTE, which the InCall UI might use to inform the user that billing charges may apply.  The
+     * Android Telephony framework will send the {@link Connection#EVENT_MERGE_COMPLETE}
+     * connection event when a call to {@link Call#mergeConference()} has completed successfully.
+     * <p>
+     * Events are exposed to {@link InCallService} implementations via
+     * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+     * <p>
+     * No assumptions should be made as to how an In-Call UI or service will handle these events.
+     * The {@link ConnectionService} must assume that the In-Call UI could even chose to ignore
+     * some events altogether.
+     * <p>
+     * Events should be fully qualified (e.g. {@code com.example.event.MY_EVENT}) to avoid
+     * conflicts between {@link ConnectionService} implementations.  Further, custom
+     * {@link ConnectionService} implementations shall not re-purpose events in the
+     * {@code android.*} namespace, nor shall they define new event types in this namespace.  When
+     * defining a custom event type, ensure the contents of the extras {@link Bundle} is clearly
+     * defined.  Extra keys for this bundle should be named similar to the event type (e.g.
+     * {@code com.example.extra.MY_EXTRA}).
+     * <p>
+     * When defining events and the associated extras, it is important to keep their behavior
+     * consistent when the associated {@link ConnectionService} is updated.  Support for deprecated
+     * events/extras should me maintained to ensure backwards compatibility with older
+     * {@link InCallService} implementations which were built to support the older behavior.
+     * <p>
+     * Expected connection events from the Telephony stack are:
+     * <p>
+     * <ul>
+     *      <li>{@link Connection#EVENT_CALL_HOLD_FAILED} with {@code null} {@code extras} when the
+     *      {@link Conference} could not be held.</li>
+     *      <li>{@link Connection#EVENT_MERGE_START} with {@code null} {@code extras} when a new
+     *      call is being merged into the conference.</li>
+     *      <li>{@link Connection#EVENT_MERGE_COMPLETE} with {@code null} {@code extras} a new call
+     *      has completed being merged into the conference.</li>
+     *      <li>{@link Connection#EVENT_CALL_MERGE_FAILED} with {@code null} {@code extras} a new
+     *      call has failed to merge into the conference (the dialer app can determine which call
+     *      failed to merge based on the fact that the call still exists outside of the conference
+     *      at the end of the merge process).</li>
+     * </ul>
      *
-     * @param event The connection event.
+     * @param event The conference event.
      * @param extras Optional bundle containing extra information associated with the event.
      */
     public void sendConferenceEvent(@NonNull String event, @Nullable Bundle extras) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8049459..3b0ba25 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -16,9 +16,14 @@
 
 package android.telecom;
 
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+
+import android.annotation.ElapsedRealtimeLong;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.Notification;
@@ -376,8 +381,14 @@
     /** Call supports the deflect feature. */
     public static final int CAPABILITY_SUPPORT_DEFLECT = 0x02000000;
 
+    /**
+     * When set, indicates that this {@link Connection} supports initiation of a conference call
+     * by directly adding participants using {@link #onAddConferenceParticipants(List)}.
+     * @hide
+     */
+    public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000;
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x04000000
+    // Next CAPABILITY value: 0x08000000
     //**********************************************************************************************
 
     /**
@@ -474,7 +485,7 @@
      *
      * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING
      */
-    public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
+    public static final int PROPERTY_ASSISTED_DIALING = 1 << 9;
 
     /**
      * Set by the framework to indicate that the network has identified a Connection as an emergency
@@ -953,7 +964,9 @@
         if ((capabilities & CAPABILITY_SUPPORT_DEFLECT) == CAPABILITY_SUPPORT_DEFLECT) {
             builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def");
         }
-
+        if ((capabilities & CAPABILITY_ADD_PARTICIPANT) == CAPABILITY_ADD_PARTICIPANT) {
+            builder.append(isLong ? " CAPABILITY_ADD_PARTICIPANT" : " add_participant");
+        }
         builder.append("]");
         return builder.toString();
     }
@@ -2109,19 +2122,24 @@
      */
     @SystemApi
     @TestApi
-    public final long getConnectTimeMillis() {
+    public final @IntRange(from = 0) long getConnectTimeMillis() {
         return mConnectTimeMillis;
     }
 
     /**
      * Retrieves the connection start time of the {@link Connection}, if specified.  A value of
      * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
-     * start time of the conference.
+     * start time of the connection.
      * <p>
      * Based on the value of {@link SystemClock#elapsedRealtime()}, which ensures that wall-clock
      * changes do not impact the call duration.
      * <p>
      * Used internally in Telephony when migrating conference participant data for IMS conferences.
+     * <p>
+     * The value returned is the same one set using
+     * {@link #setConnectionStartElapsedRealtimeMillis(long)}.  This value is never updated from
+     * the Telecom framework, so no permission enforcement occurs when retrieving the value with
+     * this method.
      *
      * @return The time at which the {@link Connection} was connected.
      *
@@ -2129,7 +2147,7 @@
      */
     @SystemApi
     @TestApi
-    public final long getConnectElapsedTimeMillis() {
+    public final @ElapsedRealtimeLong long getConnectionStartElapsedRealtimeMillis() {
         return mConnectElapsedTimeMillis;
     }
 
@@ -2550,6 +2568,9 @@
      * Sets the time at which a call became active on this Connection. This is set only
      * when a conference call becomes active on this connection.
      * <p>
+     * This time corresponds to the date/time of connection and is stored in the call log in
+     * {@link android.provider.CallLog.Calls#DATE}.
+     * <p>
      * Used by telephony to maintain calls associated with an IMS Conference.
      *
      * @param connectTimeMillis The connection time, in milliseconds.  Should be set using a value
@@ -2559,7 +2580,8 @@
      */
     @SystemApi
     @TestApi
-    public final void setConnectTimeMillis(long connectTimeMillis) {
+    @RequiresPermission(MODIFY_PHONE_STATE)
+    public final void setConnectTimeMillis(@IntRange(from = 0) long connectTimeMillis) {
         mConnectTimeMillis = connectTimeMillis;
     }
 
@@ -2567,15 +2589,23 @@
      * Sets the time at which a call became active on this Connection. This is set only
      * when a conference call becomes active on this connection.
      * <p>
+     * This time is used to establish the duration of a call.  It uses
+     * {@link SystemClock#elapsedRealtime()} to ensure that the call duration is not impacted by
+     * time zone changes during a call.  The difference between the current
+     * {@link SystemClock#elapsedRealtime()} and the value set at the connection start time is used
+     * to populate {@link android.provider.CallLog.Calls#DURATION} in the call log.
+     * <p>
      * Used by telephony to maintain calls associated with an IMS Conference.
+     *
      * @param connectElapsedTimeMillis The connection time, in milliseconds.  Stored in the format
      *                              {@link SystemClock#elapsedRealtime()}.
-     *
      * @hide
      */
     @SystemApi
     @TestApi
-    public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) {
+    @RequiresPermission(MODIFY_PHONE_STATE)
+    public final void setConnectionStartElapsedRealtimeMillis(
+            @ElapsedRealtimeLong long connectElapsedTimeMillis) {
         mConnectElapsedTimeMillis = connectElapsedTimeMillis;
     }
 
@@ -2953,6 +2983,14 @@
     public void onSeparate() {}
 
     /**
+     * Supports initiation of a conference call by directly adding participants to an ongoing call.
+     *
+     * @param participants with which conference call will be formed.
+     * @hide
+     */
+    public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
+
+    /**
      * Notifies this Connection of a request to abort.
      */
     public void onAbort() {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 00c2918..2aea723 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
@@ -142,6 +141,7 @@
     private static final String SESSION_SPLIT_CONFERENCE = "CS.sFC";
     private static final String SESSION_MERGE_CONFERENCE = "CS.mC";
     private static final String SESSION_SWAP_CONFERENCE = "CS.sC";
+    private static final String SESSION_ADD_PARTICIPANT = "CS.aP";
     private static final String SESSION_POST_DIAL_CONT = "CS.oPDC";
     private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
     private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
@@ -195,6 +195,7 @@
     private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
     private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
     private static final int MSG_REJECT_WITH_REASON = 38;
+    private static final int MSG_ADD_PARTICIPANT = 39;
 
     private static Connection sNullConnection;
 
@@ -627,6 +628,21 @@
         }
 
         @Override
+        public void addConferenceParticipants(String callId, List<Uri> participants,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_ADD_PARTICIPANT);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = participants;
+                args.arg3 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_ADD_PARTICIPANT, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void onPostDialContinue(String callId, boolean proceed, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_POST_DIAL_CONT);
             try {
@@ -1224,6 +1240,19 @@
                     }
                     break;
                 }
+                case MSG_ADD_PARTICIPANT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        Log.continueSession((Session) args.arg3,
+                                SESSION_HANDLER + SESSION_ADD_PARTICIPANT);
+                        addConferenceParticipants((String) args.arg1, (List<Uri>)args.arg2);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
+
                 case MSG_ON_POST_DIAL_CONTINUE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
@@ -1778,7 +1807,7 @@
                         null : conference.getVideoProvider().getInterface(),
                 conference.getVideoState(),
                 conference.getConnectTimeMillis(),
-                conference.getConnectionStartElapsedRealTime(),
+                conference.getConnectionStartElapsedRealtimeMillis(),
                 conference.getStatusHints(),
                 conference.getExtras(),
                 conference.getAddress(),
@@ -1884,7 +1913,7 @@
                         connection.isRingbackRequested(),
                         connection.getAudioModeIsVoip(),
                         connection.getConnectTimeMillis(),
-                        connection.getConnectElapsedTimeMillis(),
+                        connection.getConnectionStartElapsedRealtimeMillis(),
                         connection.getStatusHints(),
                         connection.getDisconnectCause(),
                         createIdList(connection.getConferenceables()),
@@ -2152,6 +2181,17 @@
         }
     }
 
+    private void addConferenceParticipants(String callId, List<Uri> participants) {
+        Log.d(this, "addConferenceParticipants(%s)", callId);
+        if (mConnectionById.containsKey(callId)) {
+            findConnectionForAction(callId, "addConferenceParticipants")
+                    .onAddConferenceParticipants(participants);
+        } else {
+            findConferenceForAction(callId, "addConferenceParticipants")
+                    .onAddConferenceParticipants(participants);
+        }
+    }
+
     /**
      * Notifies a {@link Connection} of a request to pull an external call.
      *
@@ -2374,7 +2414,7 @@
                             null : conference.getVideoProvider().getInterface(),
                     conference.getVideoState(),
                     conference.getConnectTimeMillis(),
-                    conference.getConnectionStartElapsedRealTime(),
+                    conference.getConnectionStartElapsedRealtimeMillis(),
                     conference.getStatusHints(),
                     conference.getExtras(),
                     conference.getAddress(),
@@ -2465,7 +2505,7 @@
                     connection.isRingbackRequested(),
                     connection.getAudioModeIsVoip(),
                     connection.getConnectTimeMillis(),
-                    connection.getConnectElapsedTimeMillis(),
+                    connection.getConnectionStartElapsedRealtimeMillis(),
                     connection.getStatusHints(),
                     connection.getDisconnectCause(),
                     emptyList,
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 594c1eb..9d291740 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -283,6 +283,20 @@
     }
 
     /**
+     * Instructs Telecom to pull participants to existing call
+     *
+     * @param callId The unique ID of the call.
+     * @param participants participants to be pulled to existing call.
+     */
+    public void addConferenceParticipants(String callId, List<Uri> participants) {
+        try {
+            mAdapter.addConferenceParticipants(callId, participants);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+
+    /**
      * Instructs Telecom to split the specified call from any conference call with which it may be
      * connected.
      *
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index f00432b..4e6e1a5 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -16,7 +16,10 @@
 
 package android.telecom;
 
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.Intent;
@@ -614,7 +617,8 @@
          * time. By default, there is no group Id for a {@link PhoneAccount} (an empty String). Only
          * grouped {@link PhoneAccount}s with the same {@link ConnectionService} can be replaced.
          * <p>
-         * Note: This is an API specific to the Telephony stack.
+         * Note: This is an API specific to the Telephony stack; the group Id will be ignored for
+         * callers not holding the correct permission.
          *
          * @param groupId The group Id of the {@link PhoneAccount} that will replace any other
          * registered {@link PhoneAccount} in Telecom with the same Group Id.
@@ -623,6 +627,7 @@
          */
         @SystemApi
         @TestApi
+        @RequiresPermission(MODIFY_PHONE_STATE)
         public @NonNull Builder setGroupId(@NonNull String groupId) {
             if (groupId != null) {
                 mGroupId = groupId;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index a28cc4f..5d7d649 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -819,8 +819,8 @@
      * automatically add dialing prefixes when placing international calls.
      * <p>
      * Setting this extra on the outgoing call extras will cause the
-     * {@link Connection#PROPERTY_ASSISTED_DIALING_USED} property and
-     * {@link Call.Details#PROPERTY_ASSISTED_DIALING_USED} property to be set on the
+     * {@link Connection#PROPERTY_ASSISTED_DIALING} property and
+     * {@link Call.Details#PROPERTY_ASSISTED_DIALING} property to be set on the
      * {@link Connection}/{@link Call} in question.  When the call is logged to the call log, the
      * {@link android.provider.CallLog.Calls#FEATURES_ASSISTED_DIALING_USED} call feature is set to
      * indicate that assisted dialing was used for the call.
@@ -1412,7 +1412,7 @@
     /**
      * Used to determine the currently selected default dialer package for a specific user.
      *
-     * @param userId the user id to query the default dialer package for.
+     * @param userHandle the user id to query the default dialer package for.
      * @return package name for the default dialer package or null if no package has been
      *         selected as the default dialer.
      * @hide
@@ -1420,10 +1420,11 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
-    public @Nullable String getDefaultDialerPackage(int userId) {
+    public @Nullable String getDefaultDialerPackage(@NonNull UserHandle userHandle) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getDefaultDialerPackageForUser(userId);
+                return getTelecomService().getDefaultDialerPackageForUser(
+                        userHandle.getIdentifier());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException attempting to get the default dialer package name.", e);
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 4249dff..a397d77 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -104,6 +104,9 @@
 
     void swapConference(String conferenceCallId, in Session.Info sessionInfo);
 
+    void addConferenceParticipants(String CallId, in List<Uri> participants,
+    in Session.Info sessionInfo);
+
     void onPostDialContinue(String callId, boolean proceed, in Session.Info sessionInfo);
 
     void pullExternalCall(String callId, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index eb2d714..9beff22 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -67,6 +67,8 @@
 
     void swapConference(String callId);
 
+    void addConferenceParticipants(String callId, in List<Uri> participants);
+
     void turnOnProximitySensor();
 
     void turnOffProximitySensor(boolean screenOnImmediately);
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index d2a5905..a27c480 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -661,4 +661,16 @@
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Skip464XlatStatus {}
+
+    /**
+     * Override network type
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "OVERRIDE_NETWORK_TYPE_", value = {
+            DisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+            DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA,
+            DisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO,
+            DisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA,
+            DisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE})
+    public @interface OverrideNetworkType {}
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ebb53c5..51b4a31 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1090,6 +1090,14 @@
             "support_adhoc_conference_calls_bool";
 
     /**
+     * Determines whether conference participants can be added to existing call.  When {@code true},
+     * adding conference participants to existing call is supported, {@code false otherwise}.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL =
+            "support_add_conference_participants_bool";
+
+    /**
      * Determines whether conference calls are supported by a carrier.  When {@code true},
      * conference calling is supported, {@code false otherwise}.
      */
@@ -4004,6 +4012,7 @@
         sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
         sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true);
diff --git a/telephony/java/android/telephony/DisplayInfo.aidl b/telephony/java/android/telephony/DisplayInfo.aidl
new file mode 100644
index 0000000..861b0fe
--- /dev/null
+++ b/telephony/java/android/telephony/DisplayInfo.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2020 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 DisplayInfo;
diff --git a/telephony/java/android/telephony/DisplayInfo.java b/telephony/java/android/telephony/DisplayInfo.java
new file mode 100644
index 0000000..d54bcf9
--- /dev/null
+++ b/telephony/java/android/telephony/DisplayInfo.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2020 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.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.OverrideNetworkType;
+
+import java.util.Objects;
+
+/**
+ * DisplayInfo contains telephony-related information used for display purposes only. This
+ * information is provided in accordance with carrier policy and branding preferences; it is not
+ * necessarily a precise or accurate representation of the current state and should be treated
+ * accordingly.
+ */
+public final class DisplayInfo implements Parcelable {
+    /**
+     * No override. {@link #getNetworkType()} should be used for display network
+     * type.
+     */
+    public static final int OVERRIDE_NETWORK_TYPE_NONE = 0;
+
+    /**
+     * Override network type when the device is connected to
+     * {@link TelephonyManager#NETWORK_TYPE_LTE} cellular network and is using carrier aggregation.
+     */
+    public static final int OVERRIDE_NETWORK_TYPE_LTE_CA = 1;
+
+    /**
+     * Override network type when the device is connected to advanced pro
+     * {@link TelephonyManager#NETWORK_TYPE_LTE} cellular network.
+     */
+    public static final int OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO = 2;
+
+    /**
+     * Override network type when the device is connected to
+     * {@link TelephonyManager#NETWORK_TYPE_LTE} network and has E-UTRA-NR Dual Connectivity(EN-DC)
+     * capability or is currently connected to the secondary
+     * {@link TelephonyManager#NETWORK_TYPE_NR} cellular network.
+     */
+    public static final int OVERRIDE_NETWORK_TYPE_NR_NSA = 3;
+
+    /**
+     * Override network type when the device is connected to
+     * {@link TelephonyManager#NETWORK_TYPE_LTE} network and has E-UTRA-NR Dual Connectivity(EN-DC)
+     * capability or is currently connected to the secondary
+     * {@link TelephonyManager#NETWORK_TYPE_NR} cellular network on millimeter wave bands.
+     *
+     * @see AccessNetworkConstants.NgranBands#FREQUENCY_RANGE_GROUP_2
+     */
+    public static final int OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE = 4;
+
+    @NetworkType
+    private final  int mNetworkType;
+
+    @OverrideNetworkType
+    private final  int mOverrideNetworkType;
+
+    /**
+     * Constructor
+     *
+     * @param networkType Current packet-switching cellular network type
+     * @param overrideNetworkType The override network type
+     *
+     * @hide
+     */
+    public DisplayInfo(@NetworkType int networkType, @OverrideNetworkType int overrideNetworkType) {
+        mNetworkType = networkType;
+        mOverrideNetworkType = overrideNetworkType;
+    }
+
+    /** @hide */
+    public DisplayInfo(Parcel p) {
+        mNetworkType = p.readInt();
+        mOverrideNetworkType = p.readInt();
+    }
+
+    /**
+     * Get current packet-switching cellular network type. This is the actual network type the
+     * device is camped on.
+     *
+     * @return The network type.
+     */
+    @NetworkType
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * Get the override network type. Note the override network type is for market branding
+     * or visualization purposes only. It cannot be treated as the actual network type device is
+     * camped on.
+     *
+     * @return The override network type.
+     */
+    @OverrideNetworkType
+    public int getOverrideNetworkType() {
+        return mOverrideNetworkType;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mNetworkType);
+        dest.writeInt(mOverrideNetworkType);
+    }
+
+    public static final @NonNull Parcelable.Creator<DisplayInfo> CREATOR =
+            new Parcelable.Creator<DisplayInfo>() {
+                @Override
+                public DisplayInfo createFromParcel(Parcel source) {
+                    return new DisplayInfo(source);
+                }
+
+                @Override
+                public DisplayInfo[] newArray(int size) {
+                    return new DisplayInfo[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DisplayInfo that = (DisplayInfo) o;
+        return mNetworkType == that.mNetworkType
+                && mOverrideNetworkType == that.mOverrideNetworkType;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mNetworkType, mOverrideNetworkType);
+    }
+
+    private static String overrideNetworkTypeToString(@OverrideNetworkType int type) {
+        switch (type) {
+            case OVERRIDE_NETWORK_TYPE_NONE: return "NONE";
+            case OVERRIDE_NETWORK_TYPE_LTE_CA: return "LTE_CA";
+            case OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO: return "LTE_ADV_PRO";
+            case OVERRIDE_NETWORK_TYPE_NR_NSA: return "NR_NSA";
+            case OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE: return "NR_NSA_MMWAVE";
+            default: return "UNKNOWN";
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "DisplayInfo {network=" + TelephonyManager.getNetworkTypeName(mNetworkType)
+                + ", override=" + overrideNetworkTypeToString(mOverrideNetworkType);
+    }
+}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 155c61f..eb78529 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -148,6 +148,7 @@
     @Mock private AppOpsManager mAppOps;
     @Mock private NotificationManager mNotificationManager;
     @Mock private Vpn.SystemServices mSystemServices;
+    @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
     @Mock private ConnectivityManager mConnectivityManager;
     @Mock private KeyStore mKeyStore;
     private final VpnProfile mVpnProfile = new VpnProfile("key");
@@ -867,7 +868,8 @@
      * Mock some methods of vpn object.
      */
     private Vpn createVpn(@UserIdInt int userId) {
-        return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
+        return new Vpn(Looper.myLooper(), mContext, mNetService,
+                userId, mSystemServices, mIkev2SessionCreator);
     }
 
     private static void assertBlocked(Vpn vpn, int... uids) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b6f4490..f693315 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -28,6 +28,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.ActivityManager;
@@ -1621,11 +1622,13 @@
          * @param wifiConfiguration WifiConfiguration object corresponding to the network
          *                          user selected.
          */
+        @SuppressLint("CallbackMethodName")
         default void select(@NonNull WifiConfiguration wifiConfiguration) {}
 
         /**
          * User rejected the app's request.
          */
+        @SuppressLint("CallbackMethodName")
         default void reject() {}
     }