Merge "Replace withCleanCallingIdentity with [clear|restore]CallingIdentity"
diff --git a/Android.bp b/Android.bp
index 36c2fa8..2316823 100644
--- a/Android.bp
+++ b/Android.bp
@@ -295,6 +295,7 @@
     srcs: [
         // Java/AIDL sources under frameworks/base
         ":framework-blobstore-sources",
+        ":framework-connectivity-sources", // framework-connectivity is not yet a module
         ":framework-core-sources",
         ":framework-drm-sources",
         ":framework-graphics-sources",
@@ -481,6 +482,7 @@
         "android.hardware.vibrator-V1.1-java",
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
+        "android.security.apc-java",
         "android.system.keystore2-java",
         "android.system.suspend.control.internal-java",
         "devicepolicyprotosnano",
diff --git a/core/api/current.txt b/core/api/current.txt
index 8681d41..2e821b3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -23898,7 +23898,9 @@
     field public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
     field public static final String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
     field public static final String COLUMN_APP_LINK_TEXT = "app_link_text";
+    field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
     field public static final String COLUMN_BROWSABLE = "browsable";
+    field public static final String COLUMN_CHANNEL_LIST_ID = "channel_list_id";
     field public static final String COLUMN_DESCRIPTION = "description";
     field public static final String COLUMN_DISPLAY_NAME = "display_name";
     field public static final String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -23913,6 +23915,8 @@
     field public static final String COLUMN_LOCKED = "locked";
     field public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
     field public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final String COLUMN_REMOTE_CONTROL_KEY_PRESET_NUMBER = "remote_control_key_preset_number";
+    field public static final String COLUMN_SCRAMBLED = "scrambled";
     field public static final String COLUMN_SEARCHABLE = "searchable";
     field public static final String COLUMN_SERVICE_ID = "service_id";
     field public static final String COLUMN_SERVICE_TYPE = "service_type";
@@ -23921,6 +23925,7 @@
     field public static final String COLUMN_TYPE = "type";
     field public static final String COLUMN_VERSION_NUMBER = "version_number";
     field public static final String COLUMN_VIDEO_FORMAT = "video_format";
+    field public static final String COLUMN_VIDEO_RESOLUTION = "video_resolution";
     field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
     field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
     field public static final android.net.Uri CONTENT_URI;
@@ -38773,6 +38778,7 @@
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 16384; // 0x4000
+    field public static final int CAPABILITY_CALL_COMPOSER = 32768; // 0x8000
     field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
     field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
@@ -39030,14 +39036,19 @@
     field public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
     field public static final String EXTRA_DISCONNECT_CAUSE = "android.telecom.extra.DISCONNECT_CAUSE";
     field public static final String EXTRA_HANDLE = "android.telecom.extra.HANDLE";
+    field public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
     field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
     field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
+    field public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
     field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
     field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
+    field public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
     field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
     field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
+    field public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
     field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
     field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
@@ -39053,6 +39064,8 @@
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final int PRIORITY_NORMAL = 0; // 0x0
+    field public static final int PRIORITY_URGENT = 1; // 0x1
   }
 
   public class VideoProfile implements android.os.Parcelable {
@@ -39356,6 +39369,7 @@
     field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
     field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
     field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
+    field public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING = "call_composer_picture_server_url_string";
     field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
     field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string";
     field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool";
@@ -39545,6 +39559,7 @@
     field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
     field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
     field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+    field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
     field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
     field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
@@ -41880,6 +41895,7 @@
 
   public static class MmTelFeature.MmTelCapabilities {
     method public final boolean isCapable(int);
+    field public static final int CAPABILITY_TYPE_CALL_COMPOSER = 16; // 0x10
     field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
     field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
     field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
@@ -44631,7 +44647,7 @@
     field public static final java.util.regex.Pattern DOMAIN_NAME;
     field public static final java.util.regex.Pattern EMAIL_ADDRESS;
     field @Deprecated public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
-    field public static final java.util.regex.Pattern IP_ADDRESS;
+    field @Deprecated public static final java.util.regex.Pattern IP_ADDRESS;
     field public static final java.util.regex.Pattern PHONE;
     field @Deprecated public static final java.util.regex.Pattern TOP_LEVEL_DOMAIN;
     field @Deprecated public static final String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cc819fa..85186dd 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10494,6 +10494,35 @@
 
 package android.telephony.data {
 
+  public final class ApnThrottleStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getApnType();
+    method public int getRetryType();
+    method public int getSlotIndex();
+    method public long getThrottleExpiryTimeMillis();
+    method public int getThrottleType();
+    method public int getTransportType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ApnThrottleStatus> CREATOR;
+    field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3
+    field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2
+    field public static final int RETRY_TYPE_NONE = 1; // 0x1
+    field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2
+    field public static final int THROTTLE_TYPE_NONE = 1; // 0x1
+  }
+
+  public static final class ApnThrottleStatus.Builder {
+    ctor public ApnThrottleStatus.Builder();
+    method @NonNull public android.telephony.data.ApnThrottleStatus build();
+    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setApnType(int);
+    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setNoThrottle();
+    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setRetryType(int);
+    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setSlotIndex(int);
+    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setThrottleExpiryTimeMillis(long);
+    method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setTransportType(int);
+    field public static final long NO_THROTTLE_EXPIRY_TIME = -1L; // 0xffffffffffffffffL
+  }
+
   public final class DataCallResponse implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
@@ -10510,7 +10539,7 @@
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
     method public int getPduSessionId();
     method public int getProtocolType();
-    method public long getRetryIntervalMillis();
+    method public long getRetryDurationMillis();
     method @Deprecated public int getSuggestedRetryTime();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -10524,7 +10553,7 @@
     field public static final int LINK_STATUS_INACTIVE = 0; // 0x0
     field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff
     field public static final int PDU_SESSION_ID_NOT_SET = 0; // 0x0
-    field public static final int RETRY_INTERVAL_UNDEFINED = -1; // 0xffffffff
+    field public static final int RETRY_DURATION_UNDEFINED = -1; // 0xffffffff
   }
 
   public static final class DataCallResponse.Builder {
@@ -10544,7 +10573,7 @@
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
-    method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryIntervalMillis(long);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
     method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
   }
 
@@ -10611,6 +10640,7 @@
     method public abstract void close();
     method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback);
     method public final int getSlotIndex();
+    method public final void notifyApnUnthrottled(@NonNull String);
     method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
     method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback);
     method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
@@ -10621,6 +10651,7 @@
   }
 
   public class DataServiceCallback {
+    method public void onApnUnthrottled(@NonNull String);
     method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>);
     method public void onDeactivateDataCallComplete(int);
     method public void onHandoverCancelled(int);
@@ -10646,6 +10677,7 @@
     ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int);
     method public abstract void close();
     method public final int getSlotIndex();
+    method public void reportApnThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ApnThrottleStatus>);
     method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
   }
 
@@ -11031,6 +11063,7 @@
     method public boolean getCallExtraBoolean(String, boolean);
     method public int getCallExtraInt(String);
     method public int getCallExtraInt(String, int);
+    method @Nullable public <T extends android.os.Parcelable> T getCallExtraParcelable(@Nullable String);
     method public android.os.Bundle getCallExtras();
     method public int getCallType();
     method public static int getCallTypeFromVideoState(int);
@@ -11053,6 +11086,7 @@
     method public void setCallExtra(String, String);
     method public void setCallExtraBoolean(String, boolean);
     method public void setCallExtraInt(String, int);
+    method public void setCallExtraParcelable(@NonNull String, @NonNull android.os.Parcelable);
     method public void setCallRestrictCause(int);
     method public void setCallerNumberVerificationStatus(int);
     method public void setEmergencyCallRouting(int);
@@ -11087,6 +11121,7 @@
     field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE";
     field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
     field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+    field public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT";
     field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
     field public static final String EXTRA_CNA = "cna";
     field public static final String EXTRA_CNAP = "cnap";
@@ -11096,8 +11131,11 @@
     field public static final String EXTRA_EMERGENCY_CALL = "e_call";
     field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER";
     field public static final String EXTRA_IS_CALL_PULL = "CallPull";
+    field public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION";
     field public static final String EXTRA_OI = "oi";
     field public static final String EXTRA_OIR = "oir";
+    field public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
+    field public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY";
     field public static final String EXTRA_REMOTE_URI = "remote_uri";
     field public static final String EXTRA_USSD = "ussd";
     field public static final int OIR_DEFAULT = 0; // 0x0
@@ -11105,6 +11143,8 @@
     field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1
     field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final int PRIORITY_NORMAL = 0; // 0x0
+    field public static final int PRIORITY_URGENT = 1; // 0x1
     field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2
     field public static final int SERVICE_TYPE_NONE = 0; // 0x0
     field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1
@@ -11126,7 +11166,9 @@
     method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
     method public void callSessionInitiated(android.telephony.ims.ImsCallProfile);
-    method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
+    method @Deprecated public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
+    method public void callSessionInitiating(@NonNull android.telephony.ims.ImsCallProfile);
+    method public void callSessionInitiatingFailed(@NonNull android.telephony.ims.ImsReasonInfo);
     method public void callSessionInviteParticipantsRequestDelivered();
     method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
     method @Deprecated public void callSessionMayHandover(int, int);
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index af74b03..5dc6e60 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -16,16 +16,23 @@
 package android.accounts;
 
 import android.app.Activity;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.widget.TextView;
-import android.widget.LinearLayout;
-import android.view.View;
-import android.view.LayoutInflater;
+import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
 import com.android.internal.R;
 
 import java.io.IOException;
@@ -42,11 +49,15 @@
     private Account mAccount;
     private String mAuthTokenType;
     private int mUid;
+    private int mCallingUid;
     private Bundle mResultBundle = null;
     protected LayoutInflater mInflater;
 
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        getWindow().addSystemFlags(
+                android.view.WindowManager.LayoutParams
+                        .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         setContentView(R.layout.grant_credentials_permission);
         setTitle(R.string.grant_permissions_header_text);
 
@@ -74,6 +85,20 @@
             return;
         }
 
+        try {
+            IBinder activityToken = getActivityToken();
+            mCallingUid = ActivityTaskManager.getService().getLaunchedFromUid(activityToken);
+        } catch (RemoteException re) {
+            // Couldn't figure out caller details
+            Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
+        }
+
+        if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) && mCallingUid != mUid) {
+            setResult(Activity.RESULT_CANCELED);
+            finish();
+            return;
+        }
+
         String accountTypeLabel;
         try {
             accountTypeLabel = getAccountLabel(mAccount);
diff --git a/core/java/android/app/people/OWNERS b/core/java/android/app/people/OWNERS
new file mode 100644
index 0000000..7371a88
--- /dev/null
+++ b/core/java/android/app/people/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 978868
+
+danningc@google.com
+juliacr@google.com
\ No newline at end of file
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index bd1eea5..46be548 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -153,6 +153,7 @@
      */
     public static final String EXTRA_PKG = "pkg";
     /**
+     * @Deprecated provider pkg is now being extracted in SlicePermissionActivity
      * @hide
      */
     public static final String EXTRA_PROVIDER_PKG = "provider_pkg";
diff --git a/core/java/android/content/pm/LAUNCHER_OWNERS b/core/java/android/content/pm/LAUNCHER_OWNERS
new file mode 100644
index 0000000..400836f
--- /dev/null
+++ b/core/java/android/content/pm/LAUNCHER_OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+omakoto@google.com
+sunnygoyal@google.com
+mett@google.com
+jonmiranda@google.com
+pinyaoting@google.com
diff --git a/core/java/android/content/pm/SHORTCUT_OWNERS b/core/java/android/content/pm/SHORTCUT_OWNERS
new file mode 100644
index 0000000..3688d5a
--- /dev/null
+++ b/core/java/android/content/pm/SHORTCUT_OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+omakoto@google.com
+yamasani@google.com
+sunnygoyal@google.com
+mett@google.com
+pinyaoting@google.com
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9fa5b20..8ea540c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -61,6 +61,7 @@
 import android.util.Log;
 import android.util.SparseIntArray;
 
+import com.android.connectivity.aidl.INetworkAgent;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
@@ -3299,9 +3300,9 @@
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
             android.Manifest.permission.NETWORK_FACTORY})
-    public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+    public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkAgentConfig config) {
-        return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
+        return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
     }
 
     /**
@@ -3312,10 +3313,10 @@
     @RequiresPermission(anyOf = {
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
             android.Manifest.permission.NETWORK_FACTORY})
-    public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+    public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
         try {
-            return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId);
+            return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 95a2f2e..cbb1197 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -37,6 +37,7 @@
 import android.os.PersistableBundle;
 import android.os.ResultReceiver;
 
+import com.android.connectivity.aidl.INetworkAgent;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
@@ -164,7 +165,7 @@
 
     void declareNetworkRequestUnfulfillable(in NetworkRequest request);
 
-    Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+    Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp,
             in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
             in int factorySerialNumber);
 
diff --git a/core/java/android/net/NattKeepalivePacketData.aidl b/core/java/android/net/NattKeepalivePacketData.aidl
new file mode 100644
index 0000000..af644b5
--- /dev/null
+++ b/core/java/android/net/NattKeepalivePacketData.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 perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+@JavaOnlyStableParcelable parcelable NattKeepalivePacketData;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 6780167..4166c2c 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -29,11 +29,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Messenger;
+import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.connectivity.aidl.INetworkAgent;
+import com.android.connectivity.aidl.INetworkAgentRegistry;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
 import java.lang.annotation.Retention;
@@ -94,12 +95,18 @@
     @Nullable
     private volatile Network mNetwork;
 
+    @Nullable
+    private volatile INetworkAgentRegistry mRegistry;
+
+    private interface RegistryAction {
+        void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException;
+    }
+
     private final Handler mHandler;
-    private volatile AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
-    private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
+    private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>();
     private volatile long mLastBwRefreshTime = 0;
     private static final long BW_REFRESH_MIN_WIN_MS = 500;
     private boolean mBandwidthUpdateScheduled = false;
@@ -329,6 +336,17 @@
      */
     public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
 
+    /**
+     * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection.
+     * obj = INetworkAgentRegistry
+     */
+    private static final int EVENT_AGENT_CONNECTED = BASE + 18;
+
+    /**
+     * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected.
+     */
+    private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
+
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
         // The subtype can be changed with (TODO) setLegacySubtype, but it starts
         // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -402,36 +420,33 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
-                    if (mAsyncChannel != null) {
+                case EVENT_AGENT_CONNECTED: {
+                    if (mRegistry != null) {
                         log("Received new connection while already connected!");
                     } else {
                         if (VDBG) log("NetworkAgent fully connected");
-                        AsyncChannel ac = new AsyncChannel();
-                        ac.connected(null, this, msg.replyTo);
-                        ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
-                                AsyncChannel.STATUS_SUCCESSFUL);
                         synchronized (mPreConnectedQueue) {
-                            mAsyncChannel = ac;
-                            for (Message m : mPreConnectedQueue) {
-                                ac.sendMessage(m);
+                            final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj;
+                            mRegistry = registry;
+                            for (RegistryAction a : mPreConnectedQueue) {
+                                try {
+                                    a.execute(registry);
+                                } catch (RemoteException e) {
+                                    Log.wtf(LOG_TAG, "Communication error with registry", e);
+                                    // Fall through
+                                }
                             }
                             mPreConnectedQueue.clear();
                         }
                     }
                     break;
                 }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
-                    if (VDBG) log("CMD_CHANNEL_DISCONNECT");
-                    if (mAsyncChannel != null) mAsyncChannel.disconnect();
-                    break;
-                }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                case EVENT_AGENT_DISCONNECTED: {
                     if (DBG) log("NetworkAgent channel lost");
                     // let the client know CS is done with us.
                     onNetworkUnwanted();
                     synchronized (mPreConnectedQueue) {
-                        mAsyncChannel = null;
+                        mRegistry = null;
                     }
                     break;
                 }
@@ -494,15 +509,7 @@
                 }
 
                 case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
-                    ArrayList<Integer> thresholds =
-                            ((Bundle) msg.obj).getIntegerArrayList("thresholds");
-                    // TODO: Change signal strength thresholds API to use an ArrayList<Integer>
-                    // rather than convert to int[].
-                    int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0];
-                    for (int i = 0; i < intThresholds.length; i++) {
-                        intThresholds[i] = thresholds.get(i);
-                    }
-                    onSignalStrengthThresholdsUpdated(intThresholds);
+                    onSignalStrengthThresholdsUpdated((int[]) msg.obj);
                     break;
                 }
                 case CMD_PREVENT_AUTOMATIC_RECONNECT: {
@@ -541,7 +548,7 @@
             }
             final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
                     .getSystemService(Context.CONNECTIVITY_SERVICE);
-            mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
+            mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
                     new NetworkInfo(mInitialConfiguration.info),
                     mInitialConfiguration.properties, mInitialConfiguration.capabilities,
                     mInitialConfiguration.score, mInitialConfiguration.config, providerId);
@@ -550,6 +557,95 @@
         return mNetwork;
     }
 
+    private static class NetworkAgentBinder extends INetworkAgent.Stub {
+        private final Handler mHandler;
+
+        private NetworkAgentBinder(Handler handler) {
+            mHandler = handler;
+        }
+
+        @Override
+        public void onRegistered(@NonNull INetworkAgentRegistry registry) {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry));
+        }
+
+        @Override
+        public void onDisconnected() {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED));
+        }
+
+        @Override
+        public void onBandwidthUpdateRequested() {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE));
+        }
+
+        @Override
+        public void onValidationStatusChanged(
+                int validationStatus, @Nullable String captivePortalUrl) {
+            // TODO: consider using a parcelable as argument when the interface is structured
+            Bundle redirectUrlBundle = new Bundle();
+            redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl);
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS,
+                    validationStatus, 0, redirectUrlBundle));
+        }
+
+        @Override
+        public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED,
+                    acceptUnvalidated ? 1 : 0, 0));
+        }
+
+        @Override
+        public void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
+                @NonNull NattKeepalivePacketData packetData) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE,
+                    slot, intervalDurationMs, packetData));
+        }
+
+        @Override
+        public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
+                @NonNull TcpKeepalivePacketData packetData) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE,
+                    slot, intervalDurationMs, packetData));
+        }
+
+        @Override
+        public void onStopSocketKeepalive(int slot) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0));
+        }
+
+        @Override
+        public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
+            mHandler.sendMessage(mHandler.obtainMessage(
+                    CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds));
+        }
+
+        @Override
+        public void onPreventAutomaticReconnect() {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT));
+        }
+
+        @Override
+        public void onAddNattKeepalivePacketFilter(int slot,
+                @NonNull NattKeepalivePacketData packetData) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
+                    slot, 0, packetData));
+        }
+
+        @Override
+        public void onAddTcpKeepalivePacketFilter(int slot,
+                @NonNull TcpKeepalivePacketData packetData) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
+                    slot, 0, packetData));
+        }
+
+        @Override
+        public void onRemoveKeepalivePacketFilter(int slot) {
+            mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
+                    slot, 0));
+        }
+    }
+
     /**
      * Register this network agent with a testing harness.
      *
@@ -559,13 +655,13 @@
      *
      * @hide
      */
-    public Messenger registerForTest(final Network network) {
+    public INetworkAgent registerForTest(final Network network) {
         log("Registering NetworkAgent for test");
         synchronized (mRegisterLock) {
             mNetwork = network;
             mInitialConfiguration = null;
         }
-        return new Messenger(mHandler);
+        return new NetworkAgentBinder(mHandler);
     }
 
     /**
@@ -589,29 +685,17 @@
         return mNetwork;
     }
 
-    private void queueOrSendMessage(int what, Object obj) {
-        queueOrSendMessage(what, 0, 0, obj);
-    }
-
-    private void queueOrSendMessage(int what, int arg1, int arg2) {
-        queueOrSendMessage(what, arg1, arg2, null);
-    }
-
-    private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
-        Message msg = Message.obtain();
-        msg.what = what;
-        msg.arg1 = arg1;
-        msg.arg2 = arg2;
-        msg.obj = obj;
-        queueOrSendMessage(msg);
-    }
-
-    private void queueOrSendMessage(Message msg) {
+    private void queueOrSendMessage(@NonNull RegistryAction action) {
         synchronized (mPreConnectedQueue) {
-            if (mAsyncChannel != null) {
-                mAsyncChannel.sendMessage(msg);
+            if (mRegistry != null) {
+                try {
+                    action.execute(mRegistry);
+                } catch (RemoteException e) {
+                    Log.wtf(LOG_TAG, "Error executing registry action", e);
+                    // Fall through: the channel is asynchronous and does not report errors back
+                }
             } else {
-                mPreConnectedQueue.add(msg);
+                mPreConnectedQueue.add(action);
             }
         }
     }
@@ -622,7 +706,8 @@
      */
     public final void sendLinkProperties(@NonNull LinkProperties linkProperties) {
         Objects.requireNonNull(linkProperties);
-        queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
+        final LinkProperties lp = new LinkProperties(linkProperties);
+        queueOrSendMessage(reg -> reg.sendLinkProperties(lp));
     }
 
     /**
@@ -647,9 +732,7 @@
     public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) {
         final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
                 ? new ArrayList<>(underlyingNetworks) : null;
-        final Bundle bundle = new Bundle();
-        bundle.putParcelableArrayList(UNDERLYING_NETWORKS_KEY, underlyingArray);
-        queueOrSendMessage(EVENT_UNDERLYING_NETWORKS_CHANGED, bundle);
+        queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray));
     }
 
     /**
@@ -659,7 +742,7 @@
     public void markConnected() {
         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */,
                 mNetworkInfo.getExtraInfo());
-        queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
+        queueOrSendNetworkInfo(mNetworkInfo);
     }
 
     /**
@@ -672,7 +755,7 @@
         // When unregistering an agent nobody should use the extrainfo (or reason) any more.
         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */,
                 null /* extraInfo */);
-        queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
+        queueOrSendNetworkInfo(mNetworkInfo);
     }
 
     /**
@@ -689,7 +772,7 @@
     @Deprecated
     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
         mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
-        queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
+        queueOrSendNetworkInfo(mNetworkInfo);
     }
 
     /**
@@ -711,7 +794,7 @@
     @Deprecated
     public void setLegacyExtraInfo(@Nullable final String extraInfo) {
         mNetworkInfo.setExtraInfo(extraInfo);
-        queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo);
+        queueOrSendNetworkInfo(mNetworkInfo);
     }
 
     /**
@@ -720,7 +803,11 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final void sendNetworkInfo(NetworkInfo networkInfo) {
-        queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
+        queueOrSendNetworkInfo(new NetworkInfo(networkInfo));
+    }
+
+    private void queueOrSendNetworkInfo(NetworkInfo networkInfo) {
+        queueOrSendMessage(reg -> reg.sendNetworkInfo(networkInfo));
     }
 
     /**
@@ -731,8 +818,8 @@
         Objects.requireNonNull(networkCapabilities);
         mBandwidthUpdatePending.set(false);
         mLastBwRefreshTime = System.currentTimeMillis();
-        queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED,
-                new NetworkCapabilities(networkCapabilities));
+        final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+        queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
     }
 
     /**
@@ -744,7 +831,7 @@
         if (score < 0) {
             throw new IllegalArgumentException("Score must be >= 0");
         }
-        queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0);
+        queueOrSendMessage(reg -> reg.sendScore(score));
     }
 
     /**
@@ -784,9 +871,8 @@
      * @hide should move to NetworkAgentConfig.
      */
     public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
-        queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED,
-                explicitlySelected ? 1 : 0,
-                acceptUnvalidated ? 1 : 0);
+        queueOrSendMessage(reg -> reg.sendExplicitlySelected(
+                explicitlySelected, acceptUnvalidated));
     }
 
     /**
@@ -909,7 +995,7 @@
      */
     public final void sendSocketKeepaliveEvent(int slot,
             @SocketKeepalive.KeepaliveEvent int event) {
-        queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event);
+        queueOrSendMessage(reg -> reg.sendSocketKeepaliveEvent(slot, event));
     }
     /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */
     public void onSocketKeepaliveEvent(int slot, int reason) {
diff --git a/core/java/android/net/TcpKeepalivePacketData.aidl b/core/java/android/net/TcpKeepalivePacketData.aidl
new file mode 100644
index 0000000..fdc7af9
--- /dev/null
+++ b/core/java/android/net/TcpKeepalivePacketData.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 perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+@JavaOnlyStableParcelable parcelable TcpKeepalivePacketData;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8ab734d..27dc6e0 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2576,6 +2576,13 @@
     public static native long getIonMappedSizeKb();
 
     /**
+     * Return memory size in kilobytes used by GPU.
+     *
+     * @hide
+     */
+    public static native long getGpuTotalUsageKb();
+
+    /**
      * Return whether virtually-mapped kernel stacks are enabled (CONFIG_VMAP_STACK).
      * Note: caller needs config_gz read sepolicy permission
      *
diff --git a/core/java/android/os/TransactionTooLargeException.java b/core/java/android/os/TransactionTooLargeException.java
index 10abf26..4d5b2a1 100644
--- a/core/java/android/os/TransactionTooLargeException.java
+++ b/core/java/android/os/TransactionTooLargeException.java
@@ -23,9 +23,11 @@
  * During a remote procedure call, the arguments and the return value of the call
  * are transferred as {@link Parcel} objects stored in the Binder transaction buffer.
  * If the arguments or the return value are too large to fit in the transaction buffer,
- * then the call will fail and {@link TransactionTooLargeException} will be thrown.
+ * then the call will fail.  {@link TransactionTooLargeException} is thrown as a
+ * heuristic when a transaction is large, and it fails, since these are the transactions
+ * which are most likely to overfill the transaction buffer.
  * </p><p>
- * The Binder transaction buffer has a limited fixed size, currently 1Mb, which
+ * The Binder transaction buffer has a limited fixed size, currently 1MB, which
  * is shared by all transactions in progress for the process.  Consequently this
  * exception can be thrown when there are many transactions in progress even when
  * most of the individual transactions are of moderate size.
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 58268e2..0fe8894 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -68,6 +68,8 @@
  */
 @SystemApi
 public class DynamicSystemClient {
+    private static final String TAG = "DynamicSystemClient";
+
     /** @hide */
     @IntDef(prefix = { "STATUS_" }, value = {
             STATUS_UNKNOWN,
@@ -92,8 +94,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface StatusChangedCause {}
 
-    private static final String TAG = "DynSystemClient";
-
     /** Listener for installation status updates. */
     public interface OnStatusChangedListener {
         /**
@@ -240,7 +240,7 @@
 
     private class DynSystemServiceConnection implements ServiceConnection {
         public void onServiceConnected(ComponentName className, IBinder service) {
-            Slog.v(TAG, "DynSystemService connected");
+            Slog.v(TAG, "onServiceConnected: " + className);
 
             mService = new Messenger(service);
 
@@ -262,7 +262,7 @@
         }
 
         public void onServiceDisconnected(ComponentName className) {
-            Slog.v(TAG, "DynSystemService disconnected");
+            Slog.v(TAG, "onServiceDisconnected: " + className);
             mService = null;
         }
     }
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 7f01cad..e8e4785 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -269,4 +269,16 @@
             throw new RuntimeException(e.toString());
         }
     }
+
+    /**
+     * Returns the suggested scratch partition size for overlayFS.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+    public long suggestScratchSize() {
+        try {
+            return mService.suggestScratchSize();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
 }
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index df0a69b..a5a40ad 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -125,4 +125,9 @@
      *                      valid VBMeta block to retrieve the AVB key from.
      */
     boolean getAvbPublicKey(out AvbPublicKey dst);
+
+    /**
+     * Returns the suggested scratch partition size for overlayFS.
+     */
+    long suggestScratchSize();
 }
diff --git a/core/java/android/os/image/OWNERS b/core/java/android/os/image/OWNERS
index 389b55b..08a51ff 100644
--- a/core/java/android/os/image/OWNERS
+++ b/core/java/android/os/image/OWNERS
@@ -1 +1,3 @@
+include /packages/DynamicSystemInstallationService/OWNERS
+
 andrewhsieh@google.com
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index f67af85..2329037 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
+import android.security.keystore.AndroidKeyStoreProvider;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -36,15 +37,15 @@
  * compromised. Implementing confirmation prompts with these guarantees requires dedicated
  * hardware-support and may not always be available.
  *
- * <p>Confirmation prompts are typically used with an external entitity - the <i>Relying Party</i> -
+ * <p>Confirmation prompts are typically used with an external entity - the <i>Relying Party</i> -
  * in the following way. The setup steps are as follows:
  * <ul>
  * <li> Before first use, the application generates a key-pair with the
  * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired
- * CONFIRMATION tag} set. Device attestation,
- * e.g. {@link java.security.KeyStore#getCertificateChain getCertificateChain()}, is used to
- * generate a certificate chain that includes the public key (<code>Kpub</code> in the following)
- * of the newly generated key.
+ * CONFIRMATION tag} set. AndroidKeyStore key attestation, e.g.,
+ * {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}
+ * is used to generate a certificate chain that includes the public key (<code>Kpub</code> in the
+ * following) of the newly generated key.
  * <li> The application sends <code>Kpub</code> and the certificate chain resulting from device
  * attestation to the <i>Relying Party</i>.
  * <li> The <i>Relying Party</i> validates the certificate chain which involves checking the root
@@ -78,9 +79,10 @@
  * previously created nonce. If all checks passes, the transaction is executed.
  * </ul>
  *
- * <p>A common way of implementing the "<code>promptText</code> is what is expected" check in the
- * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it
- * along the nonce in the <code>extraData</code> blob.
+ * <p>Note: It is vital to check the <code>promptText</code> because this is the only part that
+ * the user has approved. To avoid writing parsers for all of the possible locales, it is
+ * recommended that the <i>Relying Party</i> uses the same string generator as used on the device
+ * and performs a simple string comparison.
  */
 public class ConfirmationPrompt {
     private static final String TAG = "ConfirmationPrompt";
@@ -92,6 +94,14 @@
     private Context mContext;
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
+    private AndroidProtectedConfirmation mProtectedConfirmation;
+
+    private AndroidProtectedConfirmation getService() {
+        if (mProtectedConfirmation == null) {
+            mProtectedConfirmation = new AndroidProtectedConfirmation();
+        }
+        return mProtectedConfirmation;
+    }
 
     private void doCallback(int responseCode, byte[] dataThatWasConfirmed,
             ConfirmationCallback callback) {
@@ -119,6 +129,32 @@
         }
     }
 
+    private void doCallback2(int responseCode, byte[] dataThatWasConfirmed,
+            ConfirmationCallback callback) {
+        switch (responseCode) {
+            case AndroidProtectedConfirmation.ERROR_OK:
+                callback.onConfirmed(dataThatWasConfirmed);
+                break;
+
+            case AndroidProtectedConfirmation.ERROR_CANCELED:
+                callback.onDismissed();
+                break;
+
+            case AndroidProtectedConfirmation.ERROR_ABORTED:
+                callback.onCanceled();
+                break;
+
+            case AndroidProtectedConfirmation.ERROR_SYSTEM_ERROR:
+                callback.onError(new Exception("System error returned by ConfirmationUI."));
+                break;
+
+            default:
+                callback.onError(new Exception("Unexpected responseCode=" + responseCode
+                        + " from onConfirmtionPromptCompleted() callback."));
+                break;
+        }
+    }
+
     private final android.os.IBinder mCallbackBinder =
             new android.security.IConfirmationPromptCallback.Stub() {
                 @Override
@@ -144,6 +180,29 @@
                 }
             };
 
+    private final android.security.apc.IConfirmationCallback mConfirmationCallback =
+            new android.security.apc.IConfirmationCallback.Stub() {
+                @Override
+                public void onCompleted(int result, byte[] dataThatWasConfirmed)
+                        throws android.os.RemoteException {
+                    if (mCallback != null) {
+                        ConfirmationCallback callback = mCallback;
+                        Executor executor = mExecutor;
+                        mCallback = null;
+                        mExecutor = null;
+                        if (executor == null) {
+                            doCallback2(result, dataThatWasConfirmed, callback);
+                        } else {
+                            executor.execute(new Runnable() {
+                                @Override public void run() {
+                                    doCallback2(result, dataThatWasConfirmed, callback);
+                                }
+                            });
+                        }
+                    }
+                }
+            };
+
     /**
      * A builder that collects arguments, to be shown on the system-provided confirmation prompt.
      */
@@ -211,6 +270,9 @@
     private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1;
 
     private int getUiOptionsAsFlags() {
+        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+            return getUiOptionsAsFlags2();
+        }
         int uiOptionsAsFlags = 0;
         ContentResolver contentResolver = mContext.getContentResolver();
         int inversionEnabled = Settings.Secure.getInt(contentResolver,
@@ -226,6 +288,22 @@
         return uiOptionsAsFlags;
     }
 
+    private int getUiOptionsAsFlags2() {
+        int uiOptionsAsFlags = 0;
+        ContentResolver contentResolver = mContext.getContentResolver();
+        int inversionEnabled = Settings.Secure.getInt(contentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
+        if (inversionEnabled == 1) {
+            uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_INVERTED;
+        }
+        float fontScale = Settings.System.getFloat(contentResolver,
+                Settings.System.FONT_SCALE, (float) 1.0);
+        if (fontScale > 1.0) {
+            uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED;
+        }
+        return uiOptionsAsFlags;
+    }
+
     private static boolean isAccessibilityServiceRunning(Context context) {
         boolean serviceRunning = false;
         try {
@@ -270,29 +348,53 @@
         mCallback = callback;
         mExecutor = executor;
 
-        int uiOptionsAsFlags = getUiOptionsAsFlags();
         String locale = Locale.getDefault().toLanguageTag();
-        int responseCode = mKeyStore.presentConfirmationPrompt(
-                mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
-        switch (responseCode) {
-            case KeyStore.CONFIRMATIONUI_OK:
-                return;
+        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+            int uiOptionsAsFlags = getUiOptionsAsFlags2();
+            int responseCode = getService().presentConfirmationPrompt(
+                    mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
+                    uiOptionsAsFlags);
+            switch (responseCode) {
+                case AndroidProtectedConfirmation.ERROR_OK:
+                    return;
 
-            case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
-                throw new ConfirmationAlreadyPresentingException();
+                case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
+                    throw new ConfirmationAlreadyPresentingException();
 
-            case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
-                throw new ConfirmationNotAvailableException();
+                case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
+                    throw new ConfirmationNotAvailableException();
 
-            case KeyStore.CONFIRMATIONUI_UIERROR:
-                throw new IllegalArgumentException();
+                default:
+                    // Unexpected error code.
+                    Log.w(TAG,
+                            "Unexpected responseCode=" + responseCode
+                                    + " from presentConfirmationPrompt() call.");
+                    throw new IllegalArgumentException();
+            }
+        } else {
+            int uiOptionsAsFlags = getUiOptionsAsFlags();
+            int responseCode = mKeyStore.presentConfirmationPrompt(
+                    mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
+            switch (responseCode) {
+                case KeyStore.CONFIRMATIONUI_OK:
+                    return;
 
-            default:
-                // Unexpected error code.
-                Log.w(TAG,
-                        "Unexpected responseCode=" + responseCode
-                        + " from presentConfirmationPrompt() call.");
-                throw new IllegalArgumentException();
+                case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
+                    throw new ConfirmationAlreadyPresentingException();
+
+                case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
+                    throw new ConfirmationNotAvailableException();
+
+                case KeyStore.CONFIRMATIONUI_UIERROR:
+                    throw new IllegalArgumentException();
+
+                default:
+                    // Unexpected error code.
+                    Log.w(TAG,
+                            "Unexpected responseCode=" + responseCode
+                                    + " from presentConfirmationPrompt() call.");
+                    throw new IllegalArgumentException();
+            }
         }
     }
 
@@ -306,17 +408,33 @@
      * @throws IllegalStateException if no prompt is currently being presented.
      */
     public void cancelPrompt() {
-        int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
-        if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
-            return;
-        } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
-            throw new IllegalStateException();
+        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+            int responseCode =
+                    getService().cancelConfirmationPrompt(mConfirmationCallback);
+            if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
+                return;
+            } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
+                throw new IllegalStateException();
+            } else {
+                // Unexpected error code.
+                Log.w(TAG,
+                        "Unexpected responseCode=" + responseCode
+                                + " from cancelConfirmationPrompt() call.");
+                throw new IllegalStateException();
+            }
         } else {
-            // Unexpected error code.
-            Log.w(TAG,
-                    "Unexpected responseCode=" + responseCode
-                    + " from cancelConfirmationPrompt() call.");
-            throw new IllegalStateException();
+            int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
+            if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
+                return;
+            } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
+                throw new IllegalStateException();
+            } else {
+                // Unexpected error code.
+                Log.w(TAG,
+                        "Unexpected responseCode=" + responseCode
+                                + " from cancelConfirmationPrompt() call.");
+                throw new IllegalStateException();
+            }
         }
     }
 
@@ -330,6 +448,9 @@
         if (isAccessibilityServiceRunning(context)) {
             return false;
         }
+        if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+            return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
+        }
         return KeyStore.getInstance().isConfirmationPromptSupported();
     }
 }
diff --git a/core/java/android/service/timezone/OWNERS b/core/java/android/service/timezone/OWNERS
new file mode 100644
index 0000000..28aff18
--- /dev/null
+++ b/core/java/android/service/timezone/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+nfuller@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 7ad16ff..ece069f 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -248,6 +248,13 @@
             + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
             + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
             + "|[1-9][0-9]|[0-9]))";
+
+    /**
+     * Kept for backward compatibility reasons. It does not match IPv6 addresses.
+     *
+     * @deprecated Please use {@link android.net.InetAddresses#isNumericAddress(String)} instead.
+     */
+    @Deprecated
     public static final Pattern IP_ADDRESS = Pattern.compile(IP_ADDRESS_STRING);
 
     /**
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index bae6ee8..e66b17a 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -33,6 +33,9 @@
 per-file InputWindowHandle.java  = file:/services/core/java/com/android/server/input/OWNERS
 per-file InputWindowHandle.java  = file:/services/core/java/com/android/server/wm/OWNERS
 
+# Notifications
+per-file Notification*.java = file:/services/core/java/com/android/server/notification/OWNERS
+
 # Surface
 per-file Surface.java = file:/graphics/java/android/graphics/OWNERS
 per-file Surface.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 382b49e..c5a956a 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -2,3 +2,4 @@
 per-file *Resolver* = file:/packages/SystemUI/OWNERS
 per-file *Chooser* = file:/packages/SystemUI/OWNERS
 per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
+per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index f7fad2c..2dd51b4 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -143,6 +143,10 @@
      */
     public void removeUid(int uid) {
         mLastTimes.delete(uid);
+
+        if (mBpfTimesAvailable) {
+            mBpfReader.removeUidsInRange(uid, uid);
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index c416814..e644274 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -190,7 +190,6 @@
 
         try {
             wlStats = mSuspendControlService.getWakeLockStats();
-            Slog.i(TAG, "Number of wakelock obtained from SystemSuspend: " + wlStats.length);
             updateWakelockStats(wlStats, staleStats);
         } catch (RemoteException e) {
             Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 5a859aa..28fc8ed 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -844,6 +844,17 @@
     return ionPss;
 }
 
+static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) {
+    jlong sizeKb = -1;
+    uint64_t size;
+
+    if (meminfo::ReadGpuTotalUsageKb(&size)) {
+        sizeKb = size;
+    }
+
+    return sizeKb;
+}
+
 static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz)
 {
     static enum {
@@ -912,6 +923,8 @@
             (void*)android_os_Debug_getIonPoolsSizeKb },
     { "getIonMappedSizeKb", "()J",
             (void*)android_os_Debug_getIonMappedSizeKb },
+    { "getGpuTotalUsageKb", "()J",
+            (void*)android_os_Debug_getGpuTotalUsageKb },
     { "isVmapStack", "()Z",
             (void*)android_os_Debug_isVmapStack },
 };
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 1389753..00e3d60 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -853,7 +853,7 @@
     <string name="lockscreen_transport_prev_description" msgid="2879469521751181478">"הרצועה הקודמת"</string>
     <string name="lockscreen_transport_next_description" msgid="2931509904881099919">"הרצועה הבאה"</string>
     <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"השהה"</string>
-    <string name="lockscreen_transport_play_description" msgid="106868788691652733">"הפעל"</string>
+    <string name="lockscreen_transport_play_description" msgid="106868788691652733">"הפעלה"</string>
     <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"הפסק"</string>
     <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"הרץ אחורה"</string>
     <string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"הרץ קדימה"</string>
@@ -1842,7 +1842,7 @@
     <string name="battery_saver_description" msgid="6794188153647295212">"‏כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n• מפעילה עיצוב כהה\n• מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google"</string>
     <string name="data_saver_description" msgid="4995164271550590517">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה נעשה שימוש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string>
-    <string name="data_saver_enable_button" msgid="4399405762586419726">"הפעל"</string>
+    <string name="data_saver_enable_button" msgid="4399405762586419726">"הפעלה"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273">
       <item quantity="two">‏למשך %d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="many">‏למשך %1$d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1952,7 +1952,7 @@
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ביטול ההשהיה של האפליקציה"</string>
     <string name="work_mode_off_title" msgid="5503291976647976560">"להפעיל את פרופיל העבודה?"</string>
     <string name="work_mode_off_message" msgid="8417484421098563803">"אפליקציות העבודה, התראות, נתונים ותכונות נוספות של פרופיל העבודה יופעלו"</string>
-    <string name="work_mode_turn_on" msgid="3662561662475962285">"הפעל"</string>
+    <string name="work_mode_turn_on" msgid="3662561662475962285">"הפעלה"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"‏האפליקציה הזו עוצבה לגרסה ישנה יותר של Android וייתכן שלא תפעל כראוי. ניתן לבדוק אם יש עדכונים או ליצור קשר עם המפתח."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ef599a1..c206b12 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1838,8 +1838,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n• włącza tryb ciemny,\n• wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
-    <string name="battery_saver_description" msgid="6794188153647295212">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n• włącza tryb ciemny,\n• wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n• włącza ciemny motyw,\n• wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+    <string name="battery_saver_description" msgid="6794188153647295212">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n• włącza ciemny motyw,\n• wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index d84b019..8742a67 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1306,8 +1306,8 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"Pajisja e lidhur po karikohet. Trokit për opsione të tjera."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"U zbulua aksesor i audios analoge"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Pajisja e bashkuar nuk është e pajtueshme me këtë telefon. Trokit për të mësuar më shumë."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"Korrigjuesi i USB-së është i lidhur"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"Trokit për të çaktivizuar korrigjimin e USB-së"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"Korrigjimi përmes USB-së është i lidhur"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"Trokit për të çaktivizuar korrigjimin përmes USB-së"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Përzgjidhe për të çaktivizuar korrigjimin e gabimeve të USB-së"</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Korrigjimi përmes Wi-Fi është lidhur"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trokit për të çaktivizuar korrigjimin përmes Wi-Fi"</string>
@@ -1920,7 +1920,7 @@
     <string name="app_category_maps" msgid="6395725487922533156">"Harta dhe navigim"</string>
     <string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string>
     <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Hapësira ruajtëse e pajisjes"</string>
-    <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Korrigjimi i USB-së"</string>
+    <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Korrigjimi përmes USB-së"</string>
     <string name="time_picker_hour_label" msgid="4208590187662336864">"orë"</string>
     <string name="time_picker_minute_label" msgid="8307452311269824553">"minutë"</string>
     <string name="time_picker_header_text" msgid="9073802285051516688">"Vendos orën"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index c39e1aa..0c5f964 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -267,7 +267,7 @@
     <string name="global_action_lockdown" msgid="2475471405907902963">"பூட்டு"</string>
     <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
     <string name="notification_hidden_text" msgid="2835519769868187223">"புதிய அறிவிப்பு"</string>
-    <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"விர்ச்சுவல் கீபோர்ட்"</string>
+    <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"விர்ச்சுவல் கீபோர்டு"</string>
     <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"கைமுறை விசைப்பலகை"</string>
     <string name="notification_channel_security" msgid="8516754650348238057">"பாதுகாப்பு"</string>
     <string name="notification_channel_car_mode" msgid="2123919247040988436">"கார் பயன்முறை"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 92dd924..4c6be82 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -310,7 +310,7 @@
     <string name="permgrouplab_camera" msgid="9090413408963547706">"กล้องถ่ายรูป"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"ถ่ายภาพและบันทึกวิดีโอ"</string>
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"ประวัติการโทร"</string>
-    <string name="permgroupdesc_calllog" msgid="2026996642917801803">"อ่านและเขียนประวัติการโทรของโทรศัพท์"</string>
+    <string name="permgroupdesc_calllog" msgid="2026996642917801803">"อ่านและเขียนบันทึกการโทรของโทรศัพท์"</string>
     <string name="permgrouplab_phone" msgid="570318944091926620">"โทรศัพท์"</string>
     <string name="permgroupdesc_phone" msgid="270048070781478204">"โทรและจัดการการโทร"</string>
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"เซ็นเซอร์ร่างกาย"</string>
@@ -403,12 +403,12 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"อนุญาตให้แอปแก้ไขข้อมูลเกี่ยวกับรายชื่อติดต่อที่จัดเก็บไว้ในแท็บเล็ต สิทธิ์นี้ทำให้แอปลบข้อมูลรายชื่อติดต่อได้"</string>
     <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"อนุญาตให้แอปแก้ไขข้อมูลเกี่ยวกับรายชื่อติดต่อที่จัดเก็บไว้ในอุปกรณ์ Android TV สิทธิ์นี้ทำให้แอปลบข้อมูลรายชื่อติดต่อได้"</string>
     <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"อนุญาตให้แอปแก้ไขข้อมูลเกี่ยวกับรายชื่อติดต่อที่จัดเก็บไว้ในโทรศัพท์ สิทธิ์นี้ทำให้แอปลบข้อมูลรายชื่อติดต่อได้"</string>
-    <string name="permlab_readCallLog" msgid="1739990210293505948">"อ่านประวัติการโทร"</string>
+    <string name="permlab_readCallLog" msgid="1739990210293505948">"อ่านบันทึกการโทร"</string>
     <string name="permdesc_readCallLog" msgid="8964770895425873433">"แอปนี้สามารถอ่านประวัติการโทรของคุณได้"</string>
-    <string name="permlab_writeCallLog" msgid="670292975137658895">"เขียนประวัติการโทร"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"อนุญาตให้แอปแก้ไขประวัติการโทรจากแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"อนุญาตให้แอปแก้ไขประวัติการโทรจากอุปกรณ์ Android TV รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและสายโทรออก แอปที่เป็นอันตรายอาจใช้สิทธิ์นี้เพื่อลบหรือแก้ไขประวัติการโทรได้"</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"อนุญาตให้แอปแก้ไขประวัติการโทรจากโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
+    <string name="permlab_writeCallLog" msgid="670292975137658895">"เขียนบันทึกการโทร"</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"อนุญาตให้แอปแก้ไขบันทึกการโทรจากแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขบันทึกการโทรของคุณ"</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"อนุญาตให้แอปแก้ไขบันทึกการโทรจากอุปกรณ์ Android TV รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและสายโทรออก แอปที่เป็นอันตรายอาจใช้สิทธิ์นี้เพื่อลบหรือแก้ไขบันทึกการโทรได้"</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"อนุญาตให้แอปแก้ไขบันทึกการโทรจากโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขบันทึกการโทรของคุณ"</string>
     <string name="permlab_bodySensors" msgid="3411035315357380862">"เข้าถึงเซ็นเซอร์ร่างกาย (เช่น ตัววัดอัตราการเต้นของหัวใจ)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"อนุญาตให้แอปเข้าถึงข้อมูลจากเซ็นเซอร์ที่ตรวจสอบสภาพทางกายภาพ เช่น อัตราการเต้นของหัวใจ"</string>
     <string name="permlab_readCalendar" msgid="6408654259475396200">"อ่านกิจกรรมในปฏิทินและรายละเอียด"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index cdc132e..0480053 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -818,7 +818,7 @@
     <string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"‏PUK اور نیا PIN کوڈ ٹائپ کریں"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="2825313071899938305">"‏PUK کوڈ"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="5505434724229581207">"‏نیا PIN کوڈ"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="4032288032993261520"><font size="17">"پاسورڈ ٹائپ کرنے کیلئے تھپتھپائیں"</font></string>
+    <string name="keyguard_password_entry_touch_hint" msgid="4032288032993261520"><font size="17">"پاس ورڈ ٹائپ کرنے کیلئے تھپتھپائیں"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="2751130557661643482">"غیر مقفل کرنے کیلئے پاس ورڈ ٹائپ کریں"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"‏غیر مقفل کرنے کیلئے PIN ٹائپ کریں"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"‏غلط PIN کوڈ۔"</string>
diff --git a/core/tests/coretests/src/android/app/assist/OWNERS b/core/tests/coretests/src/android/app/assist/OWNERS
new file mode 100644
index 0000000..43ad108
--- /dev/null
+++ b/core/tests/coretests/src/android/app/assist/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/assist/OWNERS
diff --git a/core/tests/coretests/src/android/service/notification/OWNERS b/core/tests/coretests/src/android/service/notification/OWNERS
new file mode 100644
index 0000000..1502b60
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/OWNERS
@@ -0,0 +1,2 @@
+include platform/frameworks/base:/services/core/java/com/android/server/notification/OWNERS
+
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index a3a3e7c..5031ff9 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -2,3 +2,10 @@
 per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com
 per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com
 per-file VelocityTest.java = michaelwr@google.com, svv@google.com
+
+# WindowManager
+per-file *Display* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Focus* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 057c012..a185da1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -343,6 +343,8 @@
         <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
+        <!-- Needed for test only -->
+        <permission name="android.permission.NETWORK_AIRPLANE_MODE"/>
         <permission name="android.permission.OBSERVE_APP_USAGE"/>
         <permission name="android.permission.NETWORK_SCAN"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
@@ -438,6 +440,9 @@
         <permission name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
         <!-- Permissions required for CTS test - CtsHdmiCecHostTestCases -->
         <permission name="android.permission.HDMI_CEC"/>
+        <!-- Permission needed for CTS test - WifiManagerTest -->
+        <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
+        <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
@@ -447,6 +452,8 @@
     <privapp-permissions package="com.android.traceur">
         <!-- Permissions required to receive BUGREPORT_STARTED intent -->
         <permission name="android.permission.DUMP"/>
+        <!-- Permissions required to start/stop tracing -->
+        <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
         <!-- Permissions required for quick settings tile -->
         <permission name="android.permission.STATUS_BAR"/>
     </privapp-permissions>
diff --git a/data/keyboards/Vendor_0957_Product_0001.idc b/data/keyboards/Vendor_0957_Product_0001.idc
new file mode 100644
index 0000000..e1f4346
--- /dev/null
+++ b/data/keyboards/Vendor_0957_Product_0001.idc
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Input Device Configuration file for Google Reference RCU Remote.
+#
+#
+
+# Basic Parameters
+keyboard.layout = Vendor_0957_Product_0001
+keyboard.characterMap = Vendor_0957_Product_0001
+audio.mic = 1
\ No newline at end of file
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
new file mode 100644
index 0000000..e9f4f28
--- /dev/null
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -0,0 +1,72 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Key Layout file for Google Reference RCU Remote.
+#
+
+key 116   POWER         WAKE
+key 217   ASSIST        WAKE
+
+key 103   DPAD_UP
+key 108   DPAD_DOWN
+key 105   DPAD_LEFT
+key 106   DPAD_RIGHT
+key 353   DPAD_CENTER
+
+key 158   BACK
+key 172   HOME          WAKE
+
+key 113   VOLUME_MUTE
+key 114   VOLUME_DOWN
+key 115   VOLUME_UP
+
+key 2     1
+key 3     2
+key 4     3
+key 5     4
+key 6     5
+key 7     6
+key 8     7
+key 9     8
+key 10    9
+key 11    0
+
+# custom keys
+key usage 0x000c01BB    TV_INPUT
+key usage 0x000c022A    BOOKMARK
+key usage 0x000c0096    SETTINGS
+key usage 0x000c0097    NOTIFICATION
+key usage 0x000c008D    GUIDE
+key usage 0x000c0089    TV
+key usage 0x000c009C    CHANNEL_UP
+key usage 0x000c009D    CHANNEL_DOWN
+key usage 0x000c00CD    MEDIA_PLAY_PAUSE
+key usage 0x000c00B4    MEDIA_SKIP_BACKWARD
+key usage 0x000c00B3    MEDIA_SKIP_FORWARD
+key usage 0x000c0226    MEDIA_STOP
+
+key usage 0x000c0077    BUTTON_3     WAKE #YouTube
+key usage 0x000c0078    BUTTON_4     WAKE #Netflix
+key usage 0x000c0079    BUTTON_6     WAKE #Disney+
+key usage 0x000c007A    BUTTON_7     WAKE #HBOmax
+
+key usage 0x000c01BD    INFO
+key usage 0x000c0061    CAPTIONS
+key usage 0x000c0185    TV_TELETEXT
+
+key usage 0x000c0069    PROG_RED
+key usage 0x000c006A    PROG_GREEN
+key usage 0x000c006B    PROG_BLUE
+key usage 0x000c006C    PROG_YELLOW
\ No newline at end of file
diff --git a/graphics/OWNERS b/graphics/OWNERS
index a6d1bc3..5851cbb 100644
--- a/graphics/OWNERS
+++ b/graphics/OWNERS
@@ -1 +1 @@
-include /core/java/android/graphics/OWNERS
+include /graphics/java/android/graphics/OWNERS
\ No newline at end of file
diff --git a/keystore/java/android/security/AndroidProtectedConfirmation.java b/keystore/java/android/security/AndroidProtectedConfirmation.java
new file mode 100644
index 0000000..dfe485a
--- /dev/null
+++ b/keystore/java/android/security/AndroidProtectedConfirmation.java
@@ -0,0 +1,118 @@
+/*
+ * 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.security;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.apc.IConfirmationCallback;
+import android.security.apc.IProtectedConfirmation;
+import android.security.apc.ResponseCode;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class AndroidProtectedConfirmation {
+    private static final String TAG = "AndroidProtectedConfirmation";
+
+    public static final int ERROR_OK = ResponseCode.OK;
+    public static final int ERROR_CANCELED = ResponseCode.CANCELLED;
+    public static final int ERROR_ABORTED = ResponseCode.ABORTED;
+    public static final int ERROR_OPERATION_PENDING = ResponseCode.OPERATION_PENDING;
+    public static final int ERROR_IGNORED = ResponseCode.IGNORED;
+    public static final int ERROR_SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+    public static final int ERROR_UNIMPLEMENTED = ResponseCode.UNIMPLEMENTED;
+
+    public static final int FLAG_UI_OPTION_INVERTED =
+            IProtectedConfirmation.FLAG_UI_OPTION_INVERTED;
+    public static final int FLAG_UI_OPTION_MAGNIFIED =
+            IProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED;
+
+    private IProtectedConfirmation mProtectedConfirmation;
+
+    public AndroidProtectedConfirmation() {
+        mProtectedConfirmation = null;
+    }
+
+    private synchronized IProtectedConfirmation getService() {
+        if (mProtectedConfirmation == null) {
+            mProtectedConfirmation = IProtectedConfirmation.Stub.asInterface(ServiceManager
+                    .getService("android.security.apc"));
+        }
+        return mProtectedConfirmation;
+    }
+
+    /**
+     * Requests keystore call into the confirmationui HAL to display a prompt.
+     *
+     * @param listener the binder to use for callbacks.
+     * @param promptText the prompt to display.
+     * @param extraData extra data / nonce from application.
+     * @param locale the locale as a BCP 47 language tag.
+     * @param uiOptionsAsFlags the UI options to use, as flags.
+     * @return one of the {@code CONFIRMATIONUI_*} constants, for
+     * example {@code KeyStore.CONFIRMATIONUI_OK}.
+     */
+    public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText,
+                                         byte[] extraData, String locale, int uiOptionsAsFlags) {
+        try {
+            getService().presentPrompt(listener, promptText, extraData, locale,
+                                                     uiOptionsAsFlags);
+            return ERROR_OK;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return ERROR_SYSTEM_ERROR;
+        } catch (ServiceSpecificException e) {
+            return e.errorCode;
+        }
+    }
+
+    /**
+     * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
+     *
+     * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
+     * @return one of the {@code CONFIRMATIONUI_*} constants, for
+     * example {@code KeyStore.CONFIRMATIONUI_OK}.
+     */
+    public int cancelConfirmationPrompt(IConfirmationCallback listener) {
+        try {
+            getService().cancelPrompt(listener);
+            return ERROR_OK;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return ERROR_SYSTEM_ERROR;
+        } catch (ServiceSpecificException e) {
+            return e.errorCode;
+        }
+    }
+
+    /**
+     * Requests keystore to check if the confirmationui HAL is available.
+     *
+     * @return whether the confirmationUI HAL is available.
+     */
+    public boolean isConfirmationPromptSupported() {
+        try {
+            return getService().isSupported();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+}
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index f87a3d2..9924542 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -120,6 +120,7 @@
                 return new KeyPermanentlyInvalidatedException();
             case ResponseCode.LOCKED:
             case ResponseCode.UNINITIALIZED:
+            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
                 // TODO b/173111727 remove response codes LOCKED and UNINITIALIZED
                 return new UserNotAuthenticatedException();
             default:
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 433c622..30a14c8 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -2450,6 +2450,71 @@
          */
         public static final String COLUMN_GLOBAL_CONTENT_ID = "global_content_id";
 
+        /**
+         * The remote control key preset number that is assigned to this channel.
+         *
+         * <p> This can be used for one-touch-tuning, tuning to the channel with
+         * pressing the preset button.
+         *
+         * <p> Type: INTEGER (remote control key preset number)
+         */
+        public static final String COLUMN_REMOTE_CONTROL_KEY_PRESET_NUMBER =
+                "remote_control_key_preset_number";
+
+        /**
+         * The flag indicating whether this TV channel is scrambled or not.
+         *
+         * <p>Use the same coding for scrambled in the underlying broadcast standard
+         * if {@code free_ca_mode} in SDT is defined there (e.g. ETSI EN 300 468).
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_SCRAMBLED = "scrambled";
+
+        /**
+         * The typical video resolution.
+         *
+         * <p>This is primarily used to filter out channels based on video resolution
+         * by applications. The value is from SDT if defined there. (e.g. ETSI EN 300 468)
+         * The value should match one of the followings: {@link #VIDEO_RESOLUTION_SD},
+         * {@link #VIDEO_RESOLUTION_HD}, {@link #VIDEO_RESOLUTION_UHD}.
+         *
+         * <p>Type: TEXT
+         *
+         */
+        public static final String COLUMN_VIDEO_RESOLUTION = "video_resolution";
+
+        /**
+         * The channel list ID of this TV channel.
+         *
+         * <p>It is used to identify the channel list constructed from broadcast SI based on the
+         * underlying broadcast standard or country/operator profile, if applicable. Otherwise,
+         * leave empty.
+         *
+         * <p>The ID can be defined by individual TV input services. For example, one may assign a
+         * service operator name for the service operator channel list constructed from broadcast
+         * SI or one may assign the {@code profile_name} of the operator_info() APDU defined in CI
+         * Plus 1.3 for the dedicated CICAM operator profile channel list constructed
+         * from CICAM NIT.
+         *
+         * <p>Type: TEXT
+         */
+        public static final String COLUMN_CHANNEL_LIST_ID = "channel_list_id";
+
+        /**
+         * The comma-separated genre string of this TV channel.
+         *
+         * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
+         * Otherwise, leave empty. Use
+         * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
+         * Use {@link Genres#decode Genres.decode()} to get the broadcast genre strings from the
+         * text stored in the column.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_BROADCAST_GENRE
+         */
+        public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
+
         private Channels() {}
 
         /**
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 8bf688d..b743a95 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -60,6 +60,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -210,6 +211,7 @@
     @Nullable
     private FrontendInfo mFrontendInfo;
     private Integer mFrontendHandle;
+    private Boolean mIsSharedFrontend = false;
     private int mFrontendType = FrontendSettings.TYPE_UNDEFINED;
     private int mUserId;
     private Lnb mLnb;
@@ -228,8 +230,8 @@
     private Executor mOnResourceLostListenerExecutor;
 
     private Integer mDemuxHandle;
-    private Map<Integer, Descrambler> mDescramblers = new HashMap<>();
-    private List<Filter> mFilters = new ArrayList<>();
+    private Map<Integer, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
+    private List<WeakReference<Filter>> mFilters = new ArrayList<WeakReference<Filter>>();
 
     private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
             new TunerResourceManager.ResourcesReclaimListener() {
@@ -240,6 +242,7 @@
                                 .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
                                     FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
                     }
+                    releaseAll();
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
                 }
             };
@@ -336,8 +339,11 @@
      */
     public void shareFrontendFromTuner(@NonNull Tuner tuner) {
         mTunerResourceManager.shareFrontend(mClientId, tuner.mClientId);
-        mFrontendHandle = tuner.mFrontendHandle;
-        mFrontend = nativeOpenFrontendByHandle(mFrontendHandle);
+        synchronized (mIsSharedFrontend) {
+            mFrontendHandle = tuner.mFrontendHandle;
+            mFrontend = tuner.mFrontend;
+            mIsSharedFrontend = true;
+        }
     }
 
     /**
@@ -362,33 +368,53 @@
      */
     @Override
     public void close() {
+        releaseAll();
+        TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner");
+    }
+
+    private void releaseAll() {
         if (mFrontendHandle != null) {
-            int res = nativeCloseFrontend(mFrontendHandle);
-            if (res != Tuner.RESULT_SUCCESS) {
-                TunerUtils.throwExceptionForResult(res, "failed to close frontend");
+            synchronized (mIsSharedFrontend) {
+                if (!mIsSharedFrontend) {
+                    int res = nativeCloseFrontend(mFrontendHandle);
+                    if (res != Tuner.RESULT_SUCCESS) {
+                        TunerUtils.throwExceptionForResult(res, "failed to close frontend");
+                    }
+                }
+                mIsSharedFrontend = false;
             }
             mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId);
             FrameworkStatsLog
                     .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
-                        FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
+                    FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
             mFrontendHandle = null;
             mFrontend = null;
         }
         if (mLnb != null) {
             mLnb.close();
         }
-        if (!mDescramblers.isEmpty()) {
-            for (Map.Entry<Integer, Descrambler> d : mDescramblers.entrySet()) {
-                d.getValue().close();
-                mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId);
+        synchronized (mDescramblers) {
+            if (!mDescramblers.isEmpty()) {
+                for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
+                    Descrambler descrambler = d.getValue().get();
+                    if (descrambler != null) {
+                        descrambler.close();
+                    }
+                    mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId);
+                }
+                mDescramblers.clear();
             }
-            mDescramblers.clear();
         }
-        if (!mFilters.isEmpty()) {
-            for (Filter f : mFilters) {
-                f.close();
+        synchronized (mFilters) {
+            if (!mFilters.isEmpty()) {
+                for (WeakReference<Filter> weakFilter : mFilters) {
+                    Filter filter = weakFilter.get();
+                    if (filter != null) {
+                        filter.close();
+                    }
+                }
+                mFilters.clear();
             }
-            mFilters.clear();
         }
         if (mDemuxHandle != null) {
             int res = nativeCloseDemux(mDemuxHandle);
@@ -396,9 +422,9 @@
                 TunerUtils.throwExceptionForResult(res, "failed to close demux");
             }
             mTunerResourceManager.releaseDemux(mDemuxHandle, mClientId);
-            mFrontendHandle = null;
+            mDemuxHandle = null;
         }
-        TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner");
+
     }
 
     /**
@@ -610,10 +636,14 @@
     @Result
     public int scan(@NonNull FrontendSettings settings, @ScanType int scanType,
             @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
-        if (mScanCallback != null || mScanCallbackExecutor != null) {
+        /**
+         * Scan can be called again for blink scan if scanCallback and executor are same as before.
+         */
+        if (((mScanCallback != null) && (mScanCallback != scanCallback))
+                || ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) {
             throw new IllegalStateException(
-                    "Scan already in progress.  stopScan must be called before a new scan can be "
-                            + "started.");
+                    "Different Scan session already in progress.  stopScan must be called "
+                        + "before a new scan session can be " + "started.");
         }
         mFrontendType = settings.getType();
         if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
@@ -944,7 +974,10 @@
             if (mHandler == null) {
                 mHandler = createEventHandler();
             }
-            mFilters.add(filter);
+            synchronized (mFilters) {
+                WeakReference<Filter> weakFilter = new WeakReference<Filter>(filter);
+                mFilters.add(weakFilter);
+            }
         }
         return filter;
     }
@@ -1112,7 +1145,10 @@
         int handle = descramblerHandle[0];
         Descrambler descrambler = nativeOpenDescramblerByHandle(handle);
         if (descrambler != null) {
-            mDescramblers.put(handle, descrambler);
+            synchronized (mDescramblers) {
+                WeakReference weakDescrambler = new WeakReference<Descrambler>(descrambler);
+                mDescramblers.put(handle, weakDescrambler);
+            }
         } else {
             mTunerResourceManager.releaseDescrambler(handle, mClientId);
         }
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 515d610..5daf8b0 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -171,6 +171,12 @@
 
 void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
     android::sp<android::MediaEvent> event = (android::MediaEvent *)arg;
+    if (event->mLinearBlockObj != NULL) {
+        JNIEnv *env = android::AndroidRuntime::getJNIEnv();
+        env->DeleteWeakGlobalRef(event->mLinearBlockObj);
+        event->mLinearBlockObj = NULL;
+    }
+
     event->mAvHandleRefCnt--;
     event->finalize();
 }
@@ -182,6 +188,12 @@
     mLnb = env->NewWeakGlobalRef(lnbObj);
 }
 
+LnbCallback::~LnbCallback() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->DeleteWeakGlobalRef(mLnb);
+    mLnb = NULL;
+}
+
 Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) {
     ALOGD("LnbCallback::onEvent, type=%d", lnbEventType);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -291,8 +303,9 @@
 C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) {
     CHECK(isGlobal());
     CHECK_EQ(C2Param::INFO, kind());
-    DummyInfo info{value};
-    memcpy(this + 1, static_cast<C2Param *>(&info) + 1, kParamSize - sizeof(C2Param));
+    mInfo = StubInfo(value);
+    memcpy(static_cast<C2Param *>(this) + 1, static_cast<C2Param *>(&mInfo) + 1,
+            kParamSize - sizeof(C2Param));
 }
 
 /////////////// MediaEvent ///////////////////////
@@ -304,6 +317,7 @@
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     mMediaEventObj = env->NewWeakGlobalRef(obj);
     mAvHandle = native_handle_clone(avHandle.getNativeHandle());
+    mLinearBlockObj = NULL;
 }
 
 MediaEvent::~MediaEvent() {
@@ -337,33 +351,44 @@
     }
     mIonHandle = new C2HandleIon(dup(mAvHandle->data[0]), mDataLength);
     std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(mIonHandle);
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
-    context->mBlock = block;
-    std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, mDataLength);
-    context->mBuffer = pC2Buffer;
-    mC2Buffer = pC2Buffer;
-    if (mAvHandle->numInts > 0) {
-        // use first int in the native_handle as the index
-        int index = mAvHandle->data[mAvHandle->numFds];
-        std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
-        std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
-        pC2Buffer->setInfo(info);
+    if (block != nullptr) {
+        // CreateLinearBlock delete mIonHandle after it create block successfully.
+        // ToDo: coordinate who is response to delete mIonHandle
+        mIonHandle = NULL;
+        JNIEnv *env = AndroidRuntime::getJNIEnv();
+        std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
+        context->mBlock = block;
+        std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, mDataLength);
+        context->mBuffer = pC2Buffer;
+        mC2Buffer = pC2Buffer;
+        if (mAvHandle->numInts > 0) {
+            // use first int in the native_handle as the index
+            int index = mAvHandle->data[mAvHandle->numFds];
+            std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
+            std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
+            pC2Buffer->setInfo(info);
+        }
+        pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
+        jobject linearBlock =
+                env->NewObject(
+                        env->FindClass("android/media/MediaCodec$LinearBlock"),
+                        gFields.linearBlockInitID);
+        env->CallVoidMethod(
+                linearBlock,
+                gFields.linearBlockSetInternalStateID,
+                (jlong)context.release(),
+                true);
+        mLinearBlockObj = env->NewWeakGlobalRef(linearBlock);
+        mAvHandleRefCnt++;
+        return linearBlock;
+    } else {
+        native_handle_close(const_cast<native_handle_t*>(
+                    reinterpret_cast<const native_handle_t*>(mIonHandle)));
+        native_handle_delete(const_cast<native_handle_t*>(
+                    reinterpret_cast<const native_handle_t*>(mIonHandle)));
+        mIonHandle = NULL;
+        return NULL;
     }
-    pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
-    jobject linearBlock =
-            env->NewObject(
-                    env->FindClass("android/media/MediaCodec$LinearBlock"),
-                    gFields.linearBlockInitID);
-    env->CallVoidMethod(
-            linearBlock,
-            gFields.linearBlockSetInternalStateID,
-            (jlong)context.release(),
-            true);
-    mLinearBlockObj = env->NewWeakGlobalRef(linearBlock);
-    mAvHandleRefCnt++;
-    return mLinearBlockObj;
 }
 
 uint64_t MediaEvent::getAudioHandle() {
@@ -447,7 +472,7 @@
         if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
             sp<MediaEvent> mediaEventSp =
                            new MediaEvent(mIFilter, mediaEvent.avMemory,
-                               mediaEvent.avDataId, dataLength, obj);
+                               mediaEvent.avDataId, dataLength + offset, obj);
             mediaEventSp->mAvHandleRefCnt++;
             env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
             mediaEventSp->incStrong(obj);
@@ -2048,7 +2073,7 @@
                     env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
     FrontendInnerFec innerFec =
             static_cast<FrontendInnerFec>(
-                    env->GetLongField(settings, env->GetFieldID(clazz, "mFec", "J")));
+                    env->GetLongField(settings, env->GetFieldID(clazz, "mInnerFec", "J")));
     uint32_t symbolRate =
             static_cast<uint32_t>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
@@ -2057,7 +2082,7 @@
                     env->GetIntField(settings, env->GetFieldID(clazz, "mOuterFec", "I")));
     FrontendDvbcAnnex annex =
             static_cast<FrontendDvbcAnnex>(
-                    env->GetByteField(settings, env->GetFieldID(clazz, "mAnnex", "B")));
+                    env->GetIntField(settings, env->GetFieldID(clazz, "mAnnex", "I")));
     FrontendDvbcSpectralInversion spectralInversion =
             static_cast<FrontendDvbcSpectralInversion>(
                     env->GetIntField(
@@ -3497,6 +3522,10 @@
     } else {
         ALOGE("dvrMq.beginWrite failed");
     }
+
+    if (ret > 0) {
+        dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+    }
     return (jlong) ret;
 }
 
@@ -3524,7 +3553,7 @@
 
     if (dvrSp->mDvrMQ->write(reinterpret_cast<unsigned char*>(src) + offset, size)) {
         env->ReleaseByteArrayElements(buffer, src, 0);
-        dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+        dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
     } else {
         ALOGD("Failed to write FMQ");
         env->ReleaseByteArrayElements(buffer, src, 0);
@@ -3585,6 +3614,9 @@
     } else {
         ALOGE("dvrMq.beginRead failed");
     }
+    if (ret > 0) {
+        dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    }
 
     return (jlong) ret;
 }
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 83e9db7..c4deeaf 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -73,6 +73,7 @@
 
 struct LnbCallback : public ILnbCallback {
     LnbCallback(jweak tunerObj, LnbId id);
+    ~LnbCallback();
     virtual Return<void> onEvent(LnbEventType lnbEventType);
     virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
     jweak mLnb;
@@ -250,8 +251,9 @@
 public:
     C2DataIdInfo(uint32_t index, uint64_t value);
 private:
-    typedef C2GlobalParam<C2Info, C2Int64Value, 0> DummyInfo;
-    static const size_t kParamSize = sizeof(DummyInfo);
+    typedef C2GlobalParam<C2Info, C2Int64Value, 0> StubInfo;
+    StubInfo mInfo;
+    static const size_t kParamSize = sizeof(StubInfo);
 };
 
 }  // namespace android
diff --git a/native/graphics/OWNERS b/native/graphics/OWNERS
index a6d1bc3..d81ea2c 100644
--- a/native/graphics/OWNERS
+++ b/native/graphics/OWNERS
@@ -1 +1 @@
-include /core/java/android/graphics/OWNERS
+include /graphics/java/android/graphics/OWNERS
diff --git a/packages/DynamicSystemInstallationService/OWNERS b/packages/DynamicSystemInstallationService/OWNERS
new file mode 100644
index 0000000..c1b7ec4
--- /dev/null
+++ b/packages/DynamicSystemInstallationService/OWNERS
@@ -0,0 +1,3 @@
+howardsoc@google.com
+pchsueh@google.com
+yochiang@google.com
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index ac27580..7f19662 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -74,7 +74,7 @@
 public class DynamicSystemInstallationService extends Service
         implements InstallationAsyncTask.ProgressListener {
 
-    private static final String TAG = "DynSystemInstallationService";
+    private static final String TAG = "DynamicSystemInstallationService";
 
     // TODO (b/131866826): This is currently for test only. Will move this to System API.
     static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
@@ -211,10 +211,10 @@
 
     @Override
     public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
-        mCurrentPartitionName = progress.mPartitionName;
-        mCurrentPartitionSize = progress.mPartitionSize;
-        mCurrentPartitionInstalledSize = progress.mInstalledSize;
-        mNumInstalledPartitions = progress.mNumInstalledPartitions;
+        mCurrentPartitionName = progress.partitionName;
+        mCurrentPartitionSize = progress.partitionSize;
+        mCurrentPartitionInstalledSize = progress.installedSize;
+        mNumInstalledPartitions = progress.numInstalledPartitions;
 
         postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
     }
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 4d31ce9..4ef5e2b 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -20,6 +20,7 @@
 import android.gsi.AvbPublicKey;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.MemoryFile;
 import android.os.ParcelFileDescriptor;
 import android.os.image.DynamicSystemManager;
@@ -51,7 +52,8 @@
     private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;
 
     private static final List<String> UNSUPPORTED_PARTITIONS =
-            Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
+            Arrays.asList(
+                    "vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other", "scratch");
 
     private class UnsupportedUrlException extends Exception {
         private UnsupportedUrlException(String message) {
@@ -102,20 +104,16 @@
     static final int RESULT_ERROR_UNSUPPORTED_FORMAT = 5;
     static final int RESULT_ERROR_EXCEPTION = 6;
 
-    class Progress {
-        String mPartitionName;
-        long mPartitionSize;
-        long mInstalledSize;
+    static class Progress {
+        public final String partitionName;
+        public final long partitionSize;
+        public final int numInstalledPartitions;
+        public long installedSize;
 
-        int mNumInstalledPartitions;
-
-        Progress(String partitionName, long partitionSize, long installedSize,
-                int numInstalled) {
-            mPartitionName = partitionName;
-            mPartitionSize = partitionSize;
-            mInstalledSize = installedSize;
-
-            mNumInstalledPartitions = numInstalled;
+        Progress(String partitionName, long partitionSize, int numInstalledPartitions) {
+            this.partitionName = partitionName;
+            this.partitionSize = partitionSize;
+            this.numInstalledPartitions = numInstalledPartitions;
         }
     }
 
@@ -141,6 +139,8 @@
     private boolean mIsZip;
     private boolean mIsCompleted;
 
+    private int mNumInstalledPartitions;
+
     private InputStream mStream;
     private ZipFile mZipFile;
 
@@ -198,6 +198,22 @@
                 return null;
             }
 
+            if (Build.IS_DEBUGGABLE) {
+                // If host is debuggable, then install a scratch partition so that we can do
+                // adb remount in the guest system.
+                try {
+                    installScratch();
+                } catch (IOException e) {
+                    // Failing to install overlayFS scratch shouldn't be fatal.
+                    // Just ignore the error and skip installing the scratch partition.
+                    Log.w(TAG, e.toString(), e);
+                }
+                if (isCancelled()) {
+                    mDynSystem.remove();
+                    return null;
+                }
+            }
+
             mDynSystem.finishInstallation();
         } catch (Exception e) {
             Log.e(TAG, e.toString(), e);
@@ -304,30 +320,70 @@
         }
     }
 
-    private void installUserdata() throws Exception {
-        Thread thread = new Thread(() -> {
-            mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
-        });
+    private void installScratch() throws IOException, InterruptedException {
+        final long scratchSize = mDynSystem.suggestScratchSize();
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                mInstallationSession =
+                        mDynSystem.createPartition("scratch", scratchSize, /* readOnly= */ false);
+            }
+        };
 
-        Log.d(TAG, "Creating partition: userdata");
+        Log.d(TAG, "Creating partition: scratch, size = " + scratchSize);
         thread.start();
 
-        long installedSize = 0;
-        Progress progress = new Progress("userdata", mUserdataSize, installedSize, 0);
+        Progress progress = new Progress("scratch", scratchSize, mNumInstalledPartitions++);
 
         while (thread.isAlive()) {
             if (isCancelled()) {
                 return;
             }
 
-            installedSize = mDynSystem.getInstallationProgress().bytes_processed;
+            final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
 
-            if (installedSize > progress.mInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
-                progress.mInstalledSize = installedSize;
+            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
+                progress.installedSize = installedSize;
                 publishProgress(progress);
             }
 
-            Thread.sleep(10);
+            Thread.sleep(100);
+        }
+
+        if (mInstallationSession == null) {
+            throw new IOException(
+                    "Failed to start installation with requested size: " + scratchSize);
+        }
+        // Reset installation session and verify that installation completes successfully.
+        mInstallationSession = null;
+        if (!mDynSystem.closePartition()) {
+            throw new IOException("Failed to complete partition installation: scratch");
+        }
+    }
+
+    private void installUserdata() throws IOException, InterruptedException {
+        Thread thread = new Thread(() -> {
+            mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
+        });
+
+        Log.d(TAG, "Creating partition: userdata, size = " + mUserdataSize);
+        thread.start();
+
+        Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++);
+
+        while (thread.isAlive()) {
+            if (isCancelled()) {
+                return;
+            }
+
+            final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
+
+            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
+                progress.installedSize = installedSize;
+                publishProgress(progress);
+            }
+
+            Thread.sleep(100);
         }
 
         if (mInstallationSession == null) {
@@ -357,7 +413,7 @@
     private void installStreamingGzUpdate()
             throws IOException, InterruptedException, ImageValidationException {
         Log.d(TAG, "To install a streaming GZ update");
-        installImage("system", mSystemSize, new GZIPInputStream(mStream), 1);
+        installImage("system", mSystemSize, new GZIPInputStream(mStream));
     }
 
     private void installStreamingZipUpdate()
@@ -367,12 +423,8 @@
         ZipInputStream zis = new ZipInputStream(mStream);
         ZipEntry zipEntry = null;
 
-        int numInstalledPartitions = 1;
-
         while ((zipEntry = zis.getNextEntry()) != null) {
-            if (installImageFromAnEntry(zipEntry, zis, numInstalledPartitions)) {
-                numInstalledPartitions++;
-            }
+            installImageFromAnEntry(zipEntry, zis);
 
             if (isCancelled()) {
                 break;
@@ -385,14 +437,10 @@
         Log.d(TAG, "To install a local ZIP update");
 
         Enumeration<? extends ZipEntry> entries = mZipFile.entries();
-        int numInstalledPartitions = 1;
 
         while (entries.hasMoreElements()) {
             ZipEntry entry = entries.nextElement();
-            if (installImageFromAnEntry(
-                    entry, mZipFile.getInputStream(entry), numInstalledPartitions)) {
-                numInstalledPartitions++;
-            }
+            installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
 
             if (isCancelled()) {
                 break;
@@ -400,8 +448,7 @@
         }
     }
 
-    private boolean installImageFromAnEntry(
-            ZipEntry entry, InputStream is, int numInstalledPartitions)
+    private boolean installImageFromAnEntry(ZipEntry entry, InputStream is)
             throws IOException, InterruptedException, ImageValidationException {
         String name = entry.getName();
 
@@ -420,13 +467,12 @@
 
         long uncompressedSize = entry.getSize();
 
-        installImage(partitionName, uncompressedSize, is, numInstalledPartitions);
+        installImage(partitionName, uncompressedSize, is);
 
         return true;
     }
 
-    private void installImage(
-            String partitionName, long uncompressedSize, InputStream is, int numInstalledPartitions)
+    private void installImage(String partitionName, long uncompressedSize, InputStream is)
             throws IOException, InterruptedException, ImageValidationException {
 
         SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
@@ -458,7 +504,7 @@
                 return;
             }
 
-            Thread.sleep(10);
+            Thread.sleep(100);
         }
 
         if (mInstallationSession == null) {
@@ -473,10 +519,9 @@
 
         mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);
 
-        long installedSize = 0;
-        Progress progress = new Progress(
-                partitionName, partitionSize, installedSize, numInstalledPartitions);
+        Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
 
+        long installedSize = 0;
         byte[] bytes = new byte[READ_BUFFER_SIZE];
         int numBytesRead;
 
@@ -493,8 +538,8 @@
 
             installedSize += numBytesRead;
 
-            if (installedSize > progress.mInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
-                progress.mInstalledSize = installedSize;
+            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
+                progress.installedSize = installedSize;
                 publishProgress(progress);
             }
         }
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
index be778e9..94829b5 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -17,6 +17,7 @@
 package com.android.packageinstaller;
 
 import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
 import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid;
 
@@ -87,6 +88,8 @@
 
     @Override
     public void onCreate(Bundle icicle) {
+        getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
         // Never restore any state, esp. never create any fragments. The data in the fragment might
         // be stale, if e.g. the app was uninstalled while the activity was destroyed.
         super.onCreate(null);
diff --git a/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml b/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml
index 81d0dd9..cb56912 100644
--- a/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="help_feedback_label" msgid="7106780063063027882">"Yordam va fikr-mulohaza"</string>
+    <string name="help_feedback_label" msgid="7106780063063027882">"Yordam/fikr-mulohaza"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index b040958..c45255c 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -409,7 +409,7 @@
     <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"El fitxer ja està encriptat"</string>
     <string name="title_convert_fbe" msgid="5780013350366495149">"S\'està convertint en l\'encriptació basada en fitxers"</string>
     <string name="convert_to_fbe_warning" msgid="34294381569282109">"Converteix la partició de dades en una encriptació basada en fitxers.\n Advertiment: s\'esborraran totes les teves dades.\n Aquesta funció és alfa i és possible que no funcioni correctament.\n Per continuar, prem Esborra i converteix…"</string>
-    <string name="button_convert_fbe" msgid="1159861795137727671">"Esborra i converteix…"</string>
+    <string name="button_convert_fbe" msgid="1159861795137727671">"Neteja i converteix…"</string>
     <string name="picture_color_mode" msgid="1013807330552931903">"Mode de color de la imatge"</string>
     <string name="picture_color_mode_desc" msgid="151780973768136200">"Utilitza sRGB"</string>
     <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desactivat"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 3d28f1d..0854e8d 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -487,8 +487,8 @@
     <string name="status_unavailable" msgid="5279036186589861608">"Ei käytettävissä"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-osoite satunnaistetaan"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
-      <item quantity="other">%1$d laitetta liitetty</item>
-      <item quantity="one">%1$d laite liitetty</item>
+      <item quantity="other">%1$d laitetta yhdistettynä</item>
+      <item quantity="one">%1$d laite yhdistettynä</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Enemmän aikaa"</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Vähemmän aikaa"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fff881c..a65fc19 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -212,9 +212,9 @@
     <string name="adb_wireless_settings" msgid="2295017847215680229">"ניפוי באגים אלחוטי"</string>
     <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"כדי להציג את המכשירים הזמינים ולהשתמש בהם, יש להפעיל ניפוי באגים אלחוטי"</string>
     <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"‏התאמת מכשיר באמצעות קוד QR"</string>
-    <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"‏התאמת מכשירים חדשים באמצעות סורק של קודי QR"</string>
+    <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"‏התאמת מכשירים חדשים באמצעות סורק קודי QR"</string>
     <string name="adb_pair_method_code_title" msgid="1122590300445142904">"התאמת מכשיר באמצעות קוד התאמה"</string>
-    <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"התאמת מכשירים חדשים באמצעות קוד בן שש ספרות"</string>
+    <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"התאמת מכשירים חדשים באמצעות קוד בן 6 ספרות"</string>
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"מכשירים מותאמים"</string>
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"מחובר עכשיו"</string>
     <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"פרטי מכשיר"</string>
@@ -226,12 +226,12 @@
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"‏קוד התאמה של Wi-Fi"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"ההתאמה נכשלה"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"יש לוודא שהמכשיר מחובר לאותה רשת."</string>
-    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"‏יש לסרוק קוד QR כדי להתאים מכשיר באמצעות Wi‑Fi"</string>
+    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"‏כדי להתאים מכשיר דרך Wi‑Fi, יש לסרוק קוד QR"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"המכשיר בתהליך התאמה…"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"‏התאמת המכשיר נכשלה. קוד ה-QR היה שגוי או שהמכשיר לא מחובר לאותה רשת."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"‏יציאה וכתובת IP"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"‏סריקת קוד QR"</string>
-    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"‏יש לסרוק קוד QR כדי להתאים מכשיר באמצעות Wi‑Fi"</string>
+    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"‏כדי להתאים מכשיר דרך Wi‑Fi, יש לסרוק קוד QR"</string>
     <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"‏יש להתחבר לרשת Wi-Fi"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"‏adb, ניפוי באגים, פיתוח"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"קיצור של דוח באגים"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 3c281c8..11506a4 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -145,7 +145,7 @@
     <string name="data_usage_ota" msgid="7984667793701597001">"സിസ്‌റ്റം അപ്‌ഡേറ്റുകൾ"</string>
     <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB ടെതറിംഗ്"</string>
     <string name="tether_settings_title_wifi" msgid="4803402057533895526">"പോർട്ടബിൾ ഹോട്ട്സ്‌പോട്ട്"</string>
-    <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ബ്ലൂടൂത്ത് ടെതറിംഗ്"</string>
+    <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth ടെതറിംഗ്"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"ടെതറിംഗ്"</string>
     <string name="tether_settings_title_all" msgid="8910259483383010470">"ടെതറിംഗും പോർട്ടബിൾ ഹോട്ട്സ്‌പോട്ടും"</string>
     <string name="managed_user_title" msgid="449081789742645723">"എല്ലാ ഔദ്യോഗിക ആപ്‌സും"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 002c7fc..9ebab4d 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -203,9 +203,9 @@
     <string name="vpn_settings_not_available" msgid="2894137119965668920">"Cilësimet e VPN-së nuk ofrohen për këtë përdorues"</string>
     <string name="tethering_settings_not_available" msgid="266821736434699780">"Cilësimet e ndarjes nuk ofrohen për këtë përdorues"</string>
     <string name="apn_settings_not_available" msgid="1147111671403342300">"Cilësimet e \"Emrit të pikës së qasjes\" nuk mund të përdoren për këtë përdorues"</string>
-    <string name="enable_adb" msgid="8072776357237289039">"Korrigjimi i USB-së"</string>
+    <string name="enable_adb" msgid="8072776357237289039">"Korrigjimi përmes USB-së"</string>
     <string name="enable_adb_summary" msgid="3711526030096574316">"Korrigjo gabimet e modalitetit kur UBS-ja është e lidhur"</string>
-    <string name="clear_adb_keys" msgid="3010148733140369917">"Anulo autorizimet e korrigjimeve të gabimeve të USB-së"</string>
+    <string name="clear_adb_keys" msgid="3010148733140369917">"Anulo autorizimet e korrigjimeve përmes USB-së"</string>
     <string name="enable_adb_wireless" msgid="6973226350963971018">"Korrigjimi përmes Wi-Fi"</string>
     <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modaliteti i korrigjimit kur Wi‑Fi është i lidhur"</string>
     <string name="adb_wireless_error" msgid="721958772149779856">"Gabim"</string>
@@ -225,7 +225,7 @@
     <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Çifto me pajisjen"</string>
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Kodi i çiftimit të Wi‑Fi"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Çiftimi ishte i pasuksesshëm"</string>
-    <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sigurohu që pajisja të jetë e lidhur me të njëjtin rrjet"</string>
+    <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sigurohu që pajisja të jetë e lidhur me të njëjtin rrjet."</string>
     <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Çifto pajisjen përmes Wi‑Fi duke skanuar një kod QR"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Po çifton pajisjen…"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Çiftimi i pajisjes dështoi. Ose kodi QR nuk ishte i saktë, ose pajisja nuk është e lidhur me të njëjtin rrjet."</string>
@@ -299,11 +299,11 @@
     <string name="debug_view_attributes" msgid="3539609843984208216">"Aktivizo shikimin e inspektimit të atributeve"</string>
     <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Mbaji të dhënat celulare gjithmonë aktive edhe kur Wi‑Fi është aktiv (për ndërrim të shpejtë të rrjetit)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Përdor përshpejtimin e harduerit për ndarjen e lidhjes (internet) nëse është i disponueshëm"</string>
-    <string name="adb_warning_title" msgid="7708653449506485728">"Të lejohet korrigjimi i USB-së?"</string>
-    <string name="adb_warning_message" msgid="8145270656419669221">"Korrigjuesi i USB-së është vetëm për qëllime zhvillimore. Përdore për të kopjuar të dhëna mes kompjuterit dhe pajisjes tënde, për të instaluar aplikacione në pajisjen tënde pa asnjë njoftim si dhe për të lexuar të dhënat e ditarit."</string>
+    <string name="adb_warning_title" msgid="7708653449506485728">"Të lejohet korrigjimi përmes USB-së?"</string>
+    <string name="adb_warning_message" msgid="8145270656419669221">"Korrigjuesi përmes USB-së është vetëm për qëllime zhvillimore. Përdore për të kopjuar të dhëna mes kompjuterit dhe pajisjes tënde, për të instaluar aplikacione në pajisjen tënde pa asnjë njoftim si dhe për të lexuar të dhënat e evidencave."</string>
     <string name="adbwifi_warning_title" msgid="727104571653031865">"Të lejohet korrigjimi përmes Wi-Fi?"</string>
     <string name="adbwifi_warning_message" msgid="8005936574322702388">"Korrigjimin përmes Wi-Fi është vetëm për qëllime zhvillimore. Përdore për të kopjuar të dhëna mes kompjuterit dhe pajisjes sate, për të instaluar aplikacione në pajisjen tënde pa asnjë njoftim si dhe për të lexuar të dhënat e regjistrit."</string>
-    <string name="adb_keys_warning_message" msgid="2968555274488101220">"Të bllokohet qasja për korrigjim të USB-së nga të gjithë kompjuterët që ke autorizuar më parë?"</string>
+    <string name="adb_keys_warning_message" msgid="2968555274488101220">"Të bllokohet qasja për korrigjim përmes USB-së nga të gjithë kompjuterët që ke autorizuar më parë?"</string>
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"Të lejohen cilësimet e zhvillimit?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"Këto cilësime janë të projektuara vetëm për përdorim në programim. Ato mund të shkaktojnë që pajisja dhe aplikacionet në të, të mos punojnë ose të veprojnë në mënyrë të gabuar."</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Verifiko apl. përmes USB-së"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index e944c64..5a3b872 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -210,7 +210,7 @@
     <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Hali ya utatuzi wakati Wi-Fi imeunganishwa"</string>
     <string name="adb_wireless_error" msgid="721958772149779856">"Hitilafu"</string>
     <string name="adb_wireless_settings" msgid="2295017847215680229">"Utatuzi usiotumia waya"</string>
-    <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ili kungalia na kutumia vifaa vinavyopatikana, washa utatuzi usiotumia waya"</string>
+    <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ili kuangalia na kutumia vifaa vinavyopatikana, washa utatuzi usiotumia waya"</string>
     <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Oanisha kifaa ukitumia msimbo wa QR"</string>
     <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Oanisha vifaa vipya ukitumia kichanganuzi cha Msimbo wa QR"</string>
     <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Oanisha kifaa ukitumia msimbo wa kuoanisha"</string>
@@ -487,8 +487,8 @@
     <string name="status_unavailable" msgid="5279036186589861608">"Hamna"</string>
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"Imechagua anwani ya MAC kwa nasibu"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
-      <item quantity="other">Imeunganisha vifaa %1$d</item>
-      <item quantity="one">Imeunganisha kifaa %1$d</item>
+      <item quantity="other">Vifaa %1$d vimeunganishwa</item>
+      <item quantity="one">Kifaa %1$d kimeunganishwa</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Muda zaidi."</string>
     <string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Muda kidogo."</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 7468d04..4ba1c7a 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -284,7 +284,7 @@
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
     <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์นี้อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายที่มีการเปิดใช้การสุ่ม MAC"</string>
-    <string name="wifi_metered_label" msgid="8737187690304098638">"มีการวัดปริมาณอินเทอร์เน็ต"</string>
+    <string name="wifi_metered_label" msgid="8737187690304098638">"แบบจำกัดปริมาณอินเทอร์เน็ต"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
     <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"เลือกขนาด Logger ต่อบัฟเฟอร์ไฟล์บันทึก"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index de90c9a..b14049a 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -31,7 +31,7 @@
     <string name="wifi_disabled_password_failure" msgid="6892387079613226738">"توثیق کا مسئلہ"</string>
     <string name="wifi_cant_connect" msgid="5718417542623056783">"منسلک نہیں ہو سکتا ہے"</string>
     <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\' سے منسلک نہیں ہو سکتا ہے"</string>
-    <string name="wifi_check_password_try_again" msgid="8817789642851605628">"پاسورڈ چیک کر کے دوبارہ کوشش کریں"</string>
+    <string name="wifi_check_password_try_again" msgid="8817789642851605628">"پاس ورڈ چیک کر کے دوبارہ کوشش کریں"</string>
     <string name="wifi_not_in_range" msgid="1541760821805777772">"رینج میں نہیں ہے"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"خودکار طور پر منسلک نہیں ہو گا"</string>
     <string name="wifi_no_internet" msgid="1774198889176926299">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 2325efd..1347cdd 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -423,12 +423,12 @@
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
     <string name="power_discharging_duration" msgid="1076561255466053220">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Joriy holatda taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
-    <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Joriy holatda taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+    <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Quvvati tugashiga taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
+    <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Quvvati tugahsiga taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) -->
     <skip />
-    <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Joriy holatda taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha davom etadi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Joriy holatda taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha davom etadi"</string>
+    <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Shunday ishlatishda taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha yetadi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+    <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Quvvati tugashiga taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
     <string name="power_discharge_by" msgid="4113180890060388350">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha yetadi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_discharge_by_only" msgid="92545648425937000">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> gacha yetadi"</string>
     <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> gacha"</string>
@@ -510,7 +510,7 @@
     <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon karnayi"</string>
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
-    <string name="help_label" msgid="3528360748637781274">"Yordam va fikr-mulohaza"</string>
+    <string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string>
     <string name="storage_category" msgid="2287342585424631813">"Xotira"</string>
     <string name="shared_data_title" msgid="1017034836800864953">"Umumiy maʼlumotlar"</string>
     <string name="shared_data_summary" msgid="5516326713822885652">"Umumiy maʼlumotlarni ochish va oʻzgartirish"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
new file mode 100644
index 0000000..e7a20b3
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS
@@ -0,0 +1,8 @@
+# Default reviewers for this and subdirectories.
+andychou@google.com
+arcwang@google.com
+goldmanj@google.com
+qal@google.com
+wengsu@google.com
+
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsProvider/res/values-iw/strings.xml b/packages/SettingsProvider/res/values-iw/strings.xml
index 8d8594d..10765fe 100644
--- a/packages/SettingsProvider/res/values-iw/strings.xml
+++ b/packages/SettingsProvider/res/values-iw/strings.xml
@@ -20,6 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"אחסון הגדרות"</string>
-    <string name="wifi_softap_config_change" msgid="5688373762357941645">"ההגדרות של הנקודה לשיתוף אינטרנט השתנו"</string>
+    <string name="wifi_softap_config_change" msgid="5688373762357941645">"‏הגדרות נקודת האינטרנט (hotspot) השתנו"</string>
     <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"יש להקיש להצגת פרטים"</string>
 </resources>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0fdb282..88eef6a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -291,6 +291,9 @@
     <uses-permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS" />
 
     <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
+    <uses-permission android:name="android.permission.NETWORK_AIRPLANE_MODE" />
+
+    <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
     <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" />
 
     <!-- Permission needed to use wifi usability API's for CtsNetTestCases -->
@@ -337,6 +340,10 @@
     <!-- Permission needed for CTS test - CtsHdmiCecHostTestCases -->
     <uses-permission android:name="android.permission.HDMI_CEC" />
 
+    <!-- Permission needed for CTS test - WifiManagerTest -->
+    <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
+    <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 63b9bb3..8b73c5e 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -47,6 +47,7 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.BugreportManager;
 import android.os.BugreportManager.BugreportCallback;
 import android.os.BugreportManager.BugreportCallback.BugreportErrorCode;
@@ -186,7 +187,7 @@
     static final int SCREENSHOT_DELAY_SECONDS = 3;
 
     /** System property where dumpstate stores last triggered bugreport id */
-    private static final String PROPERTY_LAST_ID = "dumpstate.last_id";
+    static final String PROPERTY_LAST_ID = "dumpstate.last_id";
 
     private static final String BUGREPORT_SERVICE = "bugreport";
 
@@ -233,7 +234,7 @@
 
     private File mBugreportsDir;
 
-    private BugreportManager mBugreportManager;
+    @VisibleForTesting BugreportManager mBugreportManager;
 
     /**
      * id of the notification used to set service on foreground.
@@ -248,6 +249,11 @@
      */
     private boolean mTakingScreenshot;
 
+    /**
+     * The delay timeout before taking a screenshot.
+     */
+    @VisibleForTesting int mScreenshotDelaySec = SCREENSHOT_DELAY_SECONDS;
+
     @GuardedBy("sNotificationBundle")
     private static final Bundle sNotificationBundle = new Bundle();
 
@@ -282,6 +288,7 @@
                         mContext.getString(R.string.bugreport_notification_channel),
                         isTv(this) ? NotificationManager.IMPORTANCE_DEFAULT
                                 : NotificationManager.IMPORTANCE_LOW));
+        mBugreportManager = mContext.getSystemService(BugreportManager.class);
     }
 
     @Override
@@ -305,7 +312,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        return null;
+        return new LocalBinder();
     }
 
     @Override
@@ -373,8 +380,14 @@
         public void onFinished() {
             mInfo.renameBugreportFile();
             mInfo.renameScreenshots();
+            if (mInfo.bugreportFile.length() == 0) {
+                Log.e(TAG, "Bugreport file empty. File path = " + mInfo.bugreportFile);
+                onError(BUGREPORT_ERROR_RUNTIME);
+                return;
+            }
             synchronized (mLock) {
                 sendBugreportFinishedBroadcastLocked();
+                mMainThreadHandler.post(() -> mInfoDialog.onBugreportFinished(mInfo));
             }
         }
 
@@ -400,10 +413,6 @@
         @GuardedBy("mLock")
         private void sendBugreportFinishedBroadcastLocked() {
             final String bugreportFilePath = mInfo.bugreportFile.getAbsolutePath();
-            if (mInfo.bugreportFile.length() == 0) {
-                Log.e(TAG, "Bugreport file empty. File path = " + bugreportFilePath);
-                return;
-            }
             if (mInfo.type == BugreportParams.BUGREPORT_MODE_REMOTE) {
                 sendRemoteBugreportFinishedBroadcast(mContext, bugreportFilePath,
                         mInfo.bugreportFile);
@@ -609,12 +618,21 @@
 
         BugreportInfo info = new BugreportInfo(mContext, baseName, name,
                 shareTitle, shareDescription, bugreportType, mBugreportsDir);
+        synchronized (mLock) {
+            if (info.bugreportFile.exists()) {
+                Log.e(TAG, "Failed to start bugreport generation, the requested bugreport file "
+                        + info.bugreportFile + " already exists");
+                return;
+            }
+            info.createBugreportFile();
+        }
         ParcelFileDescriptor bugreportFd = info.getBugreportFd();
         if (bugreportFd == null) {
             Log.e(TAG, "Failed to start bugreport generation as "
                     + " bugreport parcel file descriptor is null.");
             return;
         }
+        info.createScreenshotFile(mBugreportsDir);
         ParcelFileDescriptor screenshotFd = null;
         if (isDefaultScreenshotRequired(bugreportType, /* hasScreenshotButton= */ !mIsTv)) {
             screenshotFd = info.getDefaultScreenshotFd();
@@ -627,8 +645,6 @@
             }
         }
 
-        mBugreportManager = (BugreportManager) mContext.getSystemService(
-                Context.BUGREPORT_SERVICE);
         final Executor executor = ActivityThread.currentActivityThread().getExecutor();
 
         Log.i(TAG, "bugreport type = " + bugreportType
@@ -888,12 +904,12 @@
         collapseNotificationBar();
         final String msg = mContext.getResources()
                 .getQuantityString(com.android.internal.R.plurals.bugreport_countdown,
-                        SCREENSHOT_DELAY_SECONDS, SCREENSHOT_DELAY_SECONDS);
+                        mScreenshotDelaySec, mScreenshotDelaySec);
         Log.i(TAG, msg);
         // Show a toast just once, otherwise it might be captured in the screenshot.
         Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
 
-        takeScreenshot(id, SCREENSHOT_DELAY_SECONDS);
+        takeScreenshot(id, mScreenshotDelaySec);
     }
 
     /**
@@ -1248,6 +1264,7 @@
                 .setContentText(content)
                 .setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT))
+                .setOnlyAlertOnce(false)
                 .setDeleteIntent(newCancelIntent(mContext, info));
 
         if (!TextUtils.isEmpty(info.getName())) {
@@ -1287,6 +1304,7 @@
                 .setLocalOnly(true)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color))
+                .setOnlyAlertOnce(true)
                 .extend(new Notification.TvExtender());
     }
 
@@ -1621,6 +1639,16 @@
     }
 
     /**
+     * A local binder with interface to return an instance of BugreportProgressService for the
+     * purpose of testing.
+     */
+    final class LocalBinder extends Binder {
+        @VisibleForTesting BugreportProgressService getService() {
+            return BugreportProgressService.this;
+        }
+    }
+
+    /**
      * Helper class encapsulating the UI elements and logic used to display a dialog where user
      * can change the details of a bugreport.
      */
@@ -1749,6 +1777,22 @@
             }
         }
 
+        /**
+         * Notifies the dialog that the bugreport has finished so it disables the {@code name}
+         * field.
+         * <p>Once the bugreport is finished dumpstate has already generated the final files, so
+         * changing the name would have no effect.
+         */
+        void onBugreportFinished(BugreportInfo info) {
+            if (mId == info.id && mInfoName != null) {
+                mInfoName.setEnabled(false);
+                mInfoName.setText(null);
+                if (!TextUtils.isEmpty(info.getName())) {
+                    mInfoName.setText(info.getName());
+                }
+            }
+        }
+
         void cancel() {
             if (mDialog != null) {
                 mDialog.cancel();
@@ -1883,12 +1927,10 @@
             this.shareDescription = shareDescription == null ? "" : shareDescription;
             this.type = type;
             this.baseName = baseName;
-            createBugreportFile(bugreportsDir);
-            createScreenshotFile(bugreportsDir);
+            this.bugreportFile = new File(bugreportsDir, getFileName(this, ".zip"));
         }
 
-        void createBugreportFile(File bugreportsDir) {
-            bugreportFile = new File(bugreportsDir, getFileName(this, ".zip"));
+        void createBugreportFile() {
             createReadWriteFile(bugreportFile);
         }
 
@@ -1993,12 +2035,21 @@
                 Log.i(TAG, "Deleting empty bugreport file: " + bugreportFile);
                 bugreportFile.delete();
             }
-            for (File file : screenshotFiles) {
-                if (file.length() == 0) {
+            deleteEmptyScreenshots();
+        }
+
+        /**
+         * Deletes empty screenshot files.
+         */
+        private void deleteEmptyScreenshots() {
+            screenshotFiles.removeIf(file -> {
+                final long length = file.length();
+                if (length == 0) {
                     Log.i(TAG, "Deleting empty screenshot file: " + file);
                     file.delete();
                 }
-            }
+                return length == 0;
+            });
         }
 
         /**
@@ -2006,7 +2057,8 @@
          * {@code initialName} if user has changed it.
          */
         void renameScreenshots() {
-            if (TextUtils.isEmpty(name)) {
+            deleteEmptyScreenshots();
+            if (TextUtils.isEmpty(name) || screenshotFiles.isEmpty()) {
                 return;
             }
             final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size());
@@ -2025,7 +2077,7 @@
                 if (newFile.length() > 0) {
                     renamedFiles.add(newFile);
                 } else if (newFile.delete()) {
-                    Log.d(TAG, "screenshot file: " + newFile + "deleted successfully.");
+                    Log.d(TAG, "screenshot file: " + newFile + " deleted successfully.");
                 }
             }
             screenshotFiles = renamedFiles;
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index b8cfa1e..9476912 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -25,19 +25,23 @@
 import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
 import static com.android.shell.BugreportPrefs.getWarningState;
 import static com.android.shell.BugreportPrefs.setWarningState;
-import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
-import static com.android.shell.BugreportProgressService.EXTRA_ID;
-import static com.android.shell.BugreportProgressService.EXTRA_NAME;
-import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
-import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
+import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_REQUESTED;
+import static com.android.shell.BugreportProgressService.PROPERTY_LAST_ID;
 import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningServiceInfo;
@@ -46,13 +50,18 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.BugreportManager;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IDumpstate;
+import android.os.IDumpstateListener;
+import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.service.notification.StatusBarNotification;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -60,10 +69,12 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
+import androidx.test.rule.ServiceTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
 
+import libcore.io.IoUtils;
 import libcore.io.Streams;
 
 import org.junit.After;
@@ -72,17 +83,19 @@
 import org.junit.Test;
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
-import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.SortedSet;
@@ -92,10 +105,10 @@
 import java.util.zip.ZipOutputStream;
 
 /**
- * Integration tests for {@link BugreportReceiver}.
+ * Integration tests for {@link BugreportProgressService}.
  * <p>
- * These tests don't mock any component and rely on external UI components (like the notification
- * bar and activity chooser), which can make them unreliable and slow.
+ * These tests rely on external UI components (like the notificatio bar and activity chooser),
+ * which can make them unreliable and slow.
  * <p>
  * The general workflow is:
  * <ul>
@@ -115,63 +128,48 @@
     // Timeout for UI operations, in milliseconds.
     private static final int TIMEOUT = (int) (5 * DateUtils.SECOND_IN_MILLIS);
 
+    // The default timeout is too short to verify the notification button state. Using a longer
+    // timeout in the tests.
+    private static final int SCREENSHOT_DELAY_SECONDS = 5;
+
     // Timeout for when waiting for a screenshot to finish.
     private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
 
-    private static final String BUGREPORTS_DIR = "bugreports";
     private static final String BUGREPORT_FILE = "test_bugreport.txt";
-    private static final String ZIP_FILE = "test_bugreport.zip";
-    private static final String ZIP_FILE2 = "test_bugreport2.zip";
     private static final String SCREENSHOT_FILE = "test_screenshot.png";
-
     private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n";
     private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n";
 
-    private static final int PID = 42;
-    private static final int PID2 = 24;
-    private static final int ID = 108;
-    private static final int ID2 = 801;
-    private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress";
-    private static final String MAX_PROPERTY = "dumpstate." + PID + ".max";
-    private static final String NAME_PROPERTY = "dumpstate." + PID + ".name";
     private static final String NAME = "BUG, Y U NO REPORT?";
-    private static final String NAME2 = "A bugreport's life";
     private static final String NEW_NAME = "Bug_Forrest_Bug";
-    private static final String NEW_NAME2 = "BugsyReportsy";
     private static final String TITLE = "Wimbugdom Champion 2015";
-    private static final String TITLE2 = "Master of the Universe";
-    private static final String DESCRIPTION = "One's description...";
-    private static final String DESCRIPTION2 = "...is another's treasure.";
-    // TODO(b/143130523): Fix (update) tests and add to presubmit
-    private static final String EXTRA_MAX = "android.intent.extra.MAX";
-    private static final String EXTRA_PID = "android.intent.extra.PID";
-    private static final String INTENT_BUGREPORT_STARTED =
-            "com.android.internal.intent.action.BUGREPORT_STARTED";
 
     private static final String NO_DESCRIPTION = null;
     private static final String NO_NAME = null;
     private static final String NO_SCREENSHOT = null;
     private static final String NO_TITLE = null;
-    private static final int NO_ID = 0;
-    private static final boolean RENAMED_SCREENSHOTS = true;
-    private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
 
     private String mDescription;
-
-    private String mPlainTextPath;
-    private String mZipPath;
-    private String mZipPath2;
-    private String mScreenshotPath;
+    private String mProgressTitle;
+    private int mBugreportId;
 
     private Context mContext;
     private UiBot mUiBot;
     private CustomActionSendMultipleListener mListener;
+    private BugreportProgressService mService;
+    private IDumpstateListener mIDumpstateListener;
+    private ParcelFileDescriptor mBugreportFd;
+    private ParcelFileDescriptor mScreenshotFd;
+
+    @Mock private IDumpstate mMockIDumpstate;
 
     @Rule public TestName mName = new TestName();
+    @Rule public ServiceTestRule mServiceRule = new ServiceTestRule();
 
     @Before
     public void setUp() throws Exception {
         Log.i(TAG, getName() + ".setup()");
+        MockitoAnnotations.initMocks(this);
         Instrumentation instrumentation = getInstrumentation();
         mContext = instrumentation.getTargetContext();
         mUiBot = new UiBot(instrumentation, TIMEOUT);
@@ -179,15 +177,8 @@
 
         cancelExistingNotifications();
 
-        mPlainTextPath = getPath(BUGREPORT_FILE);
-        mZipPath = getPath(ZIP_FILE);
-        mZipPath2 = getPath(ZIP_FILE2);
-        mScreenshotPath = getPath(SCREENSHOT_FILE);
-        createTextFile(mPlainTextPath, BUGREPORT_CONTENT);
-        createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
-        createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
-        createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT);
-
+        mBugreportId = getBugreportId();
+        mProgressTitle = getBugreportInProgress(mBugreportId);
         // Creates a multi-line description.
         StringBuilder sb = new StringBuilder();
         for (int i = 1; i <= 20; i++) {
@@ -195,6 +186,22 @@
         }
         mDescription = sb.toString();
 
+        // Mocks BugreportManager and updates tests value to the service
+        mService = ((BugreportProgressService.LocalBinder) mServiceRule.bindService(
+                new Intent(mContext, BugreportProgressService.class))).getService();
+        mService.mBugreportManager = new BugreportManager(mContext, mMockIDumpstate);
+        mService.mScreenshotDelaySec = SCREENSHOT_DELAY_SECONDS;
+        // Dup the fds which are passing to startBugreport function.
+        Mockito.doAnswer(invocation -> {
+            final boolean isScreenshotRequested = invocation.getArgument(6);
+            if (isScreenshotRequested) {
+                mScreenshotFd = ParcelFileDescriptor.dup(invocation.getArgument(3));
+            }
+            mBugreportFd = ParcelFileDescriptor.dup(invocation.getArgument(2));
+            return null;
+        }).when(mMockIDumpstate).startBugreport(anyInt(), any(), any(), any(), anyInt(), any(),
+                anyBoolean());
+
         setWarningState(mContext, STATE_HIDE);
 
         mUiBot.turnScreenOn();
@@ -203,6 +210,13 @@
     @After
     public void tearDown() throws Exception {
         Log.i(TAG, getName() + ".tearDown()");
+        if (mBugreportFd != null) {
+            IoUtils.closeQuietly(mBugreportFd);
+        }
+        if (mScreenshotFd != null) {
+            IoUtils.closeQuietly(mScreenshotFd);
+        }
+        mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
         try {
             cancelExistingNotifications();
         } finally {
@@ -219,131 +233,90 @@
      */
     @Test
     public void testProgress() throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
+        assertProgressNotification(mProgressTitle, 0f);
 
-        assertProgressNotification(NAME, 0f);
+        mIDumpstateListener.onProgress(10);
+        assertProgressNotification(mProgressTitle, 10);
 
-        SystemProperties.set(PROGRESS_PROPERTY, "108");
-        assertProgressNotification(NAME, 10.80f);
-
-        assertProgressNotification(NAME, 50.00f);
-
-        SystemProperties.set(PROGRESS_PROPERTY, "950");
-        assertProgressNotification(NAME, 95.00f);
-
-        // Make sure progress never goes back...
-        SystemProperties.set(MAX_PROPERTY, "2000");
-        assertProgressNotification(NAME, 95.00f);
-
-        SystemProperties.set(PROGRESS_PROPERTY, "1000");
-        assertProgressNotification(NAME, 95.00f);
-
-        // ...only forward...
-        SystemProperties.set(PROGRESS_PROPERTY, "1902");
-        assertProgressNotification(NAME, 95.10f);
-
-        SystemProperties.set(PROGRESS_PROPERTY, "1960");
-        assertProgressNotification(NAME, 98.00f);
+        mIDumpstateListener.onProgress(95);
+        assertProgressNotification(mProgressTitle, 95.00f);
 
         // ...but never more than the capped value.
-        SystemProperties.set(PROGRESS_PROPERTY, "2000");
-        assertProgressNotification(NAME, 99.00f);
+        mIDumpstateListener.onProgress(200);
+        assertProgressNotification(mProgressTitle, 99);
 
-        SystemProperties.set(PROGRESS_PROPERTY, "3000");
-        assertProgressNotification(NAME, 99.00f);
+        mIDumpstateListener.onProgress(300);
+        assertProgressNotification(mProgressTitle, 99);
 
-        Bundle extras =
-                sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
-                NAME, NO_TITLE, NO_DESCRIPTION, 0, RENAMED_SCREENSHOTS);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mBugreportId);
+        assertActionSendMultiple(extras);
 
         assertServiceNotRunning();
     }
 
     @Test
     public void testProgress_cancel() throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
 
-        final NumberFormat nf = NumberFormat.getPercentInstance();
-        nf.setMinimumFractionDigits(2);
-        nf.setMaximumFractionDigits(2);
+        assertProgressNotification(mProgressTitle, 00.00f);
 
-        assertProgressNotification(NAME, 00.00f);
+        cancelFromNotification(mProgressTitle);
 
-        cancelFromNotification();
-
-        waitForService(false);
+        assertServiceNotRunning();
     }
 
     @Test
     public void testProgress_takeExtraScreenshot() throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
 
         waitForScreenshotButtonEnabled(true);
         takeScreenshot();
         assertScreenshotButtonEnabled(false);
         waitForScreenshotButtonEnabled(true);
 
-        sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
-
-        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
-                NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mBugreportId);
+        assertActionSendMultiple(extras, NO_NAME, NO_TITLE, NO_DESCRIPTION, 1);
 
         assertServiceNotRunning();
     }
 
     @Test
     public void testScreenshotFinishesAfterBugreport() throws Exception {
-        resetProperties();
-
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
         takeScreenshot();
-        sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT);
-        waitShareNotification(ID);
+        sendBugreportFinished();
+        waitShareNotification(mBugreportId);
 
         // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
         sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
 
-        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
-                NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
+        Bundle extras = acceptBugreportAndGetSharedIntent(mBugreportId);
+        assertActionSendMultiple(extras, NO_NAME, NO_TITLE, NO_DESCRIPTION, 1);
 
         assertServiceNotRunning();
     }
 
     @Test
     public void testProgress_changeDetailsInvalidInput() throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME);
+        DetailsUi detailsUi = new DetailsUi(mBugreportId);
 
-        // Check initial name.
-        detailsUi.assertName(NAME);
-
-        // Change name - it should have changed system property once focus is changed.
+        // Change name
         detailsUi.focusOnName();
         detailsUi.nameField.setText(NEW_NAME);
         detailsUi.focusAwayFromName();
-        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
-
-        // Cancel the dialog to make sure property was restored.
-        detailsUi.clickCancel();
-        assertPropertyValue(NAME_PROPERTY, NAME);
+        detailsUi.clickOk();
 
         // Now try to set an invalid name.
-        detailsUi.reOpen(NAME);
+        detailsUi.reOpen(NEW_NAME);
         detailsUi.nameField.setText("/etc/passwd");
         detailsUi.clickOk();
-        assertPropertyValue(NAME_PROPERTY, "_etc_passwd");
 
         // Finally, make the real changes.
         detailsUi.reOpen("_etc_passwd");
@@ -353,27 +326,20 @@
 
         detailsUi.clickOk();
 
-        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
         assertProgressNotification(NEW_NAME, 00.00f);
 
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath,
-                mScreenshotPath, TITLE);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
-                NEW_NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(TITLE);
+        assertActionSendMultiple(extras, NEW_NAME, TITLE, mDescription, 0);
 
         assertServiceNotRunning();
     }
 
     @Test
     public void testProgress_cancelBugClosesDetailsDialog() throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME);
-        detailsUi.assertName(NAME);  // Sanity check
-
-        cancelFromNotification();
+        cancelFromNotification(mProgressTitle);
         mUiBot.collapseStatusBar();
 
         assertDetailsUiClosed();
@@ -381,40 +347,24 @@
     }
 
     @Test
-    public void testProgress_changeDetailsPlainBugreport() throws Exception {
-        changeDetailsTest(true);
-    }
-
-    @Test
-    public void testProgress_changeDetailsZippedBugreport() throws Exception {
-        changeDetailsTest(false);
-    }
-
-    private void changeDetailsTest(boolean plainText) throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+    public void testProgress_changeDetailsTest() throws Exception {
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME);
-
-        // Check initial name.
-        detailsUi.assertName(NAME);
+        DetailsUi detailsUi = new DetailsUi(mBugreportId);
 
         // Change fields.
-        detailsUi.reOpen(NAME);
+        detailsUi.reOpen(mProgressTitle);
         detailsUi.nameField.setText(NEW_NAME);
         detailsUi.titleField.setText(TITLE);
         detailsUi.descField.setText(mDescription);
 
         detailsUi.clickOk();
 
-        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
         assertProgressNotification(NEW_NAME, 00.00f);
 
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID,
-                plainText? mPlainTextPath : mZipPath, mScreenshotPath, TITLE);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
-                NEW_NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(TITLE);
+        assertActionSendMultiple(extras, NEW_NAME, TITLE, mDescription, 0);
 
         assertServiceNotRunning();
     }
@@ -430,60 +380,18 @@
     }
 
     private void changeJustDetailsTest(boolean touchDetails) throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         waitForScreenshotButtonEnabled(true);
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME, touchDetails);
+        DetailsUi detailsUi = new DetailsUi(mBugreportId, touchDetails);
 
         detailsUi.nameField.setText("");
         detailsUi.titleField.setText("");
         detailsUi.descField.setText(mDescription);
         detailsUi.clickOk();
 
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
-                NO_NAME, NO_TITLE, mDescription, 0, DIDNT_RENAME_SCREENSHOTS);
-
-        assertServiceNotRunning();
-    }
-
-    @Test
-    public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception {
-        resetProperties();
-        sendBugreportStarted(ID, PID, NAME, 1000);
-        waitForScreenshotButtonEnabled(true);
-
-        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME);
-        detailsUi.assertName(NAME);
-        detailsUi.assertTitle("");
-        detailsUi.assertDescription("");
-        assertTrue("didn't enable name on UI", detailsUi.nameField.isEnabled());
-        detailsUi.nameField.setText(NEW_NAME);
-        detailsUi.titleField.setText(TITLE);
-        detailsUi.descField.setText(DESCRIPTION);
-        detailsUi.clickOk();
-
-        sendBugreportStarted(ID2, PID2, NAME2, 1000);
-
-        sendBugreportFinished(ID, mZipPath, mScreenshotPath);
-        Bundle extras = acceptBugreportAndGetSharedIntent(TITLE);
-
-        detailsUi = new DetailsUi(mUiBot, ID2, NAME2);
-        detailsUi.assertName(NAME2);
-        detailsUi.assertTitle("");
-        detailsUi.assertDescription("");
-        assertTrue("didn't enable name on UI", detailsUi.nameField.isEnabled());
-        detailsUi.nameField.setText(NEW_NAME2);
-        detailsUi.titleField.setText(TITLE2);
-        detailsUi.descField.setText(DESCRIPTION2);
-        detailsUi.clickOk();
-
-        // Must use a different zip file otherwise it will fail because zip already contains
-        // title.txt and description.txt entries.
-        extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT, TITLE2);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2,
-                NEW_NAME2, TITLE2, DESCRIPTION2, 0, RENAMED_SCREENSHOTS);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mBugreportId);
+        assertActionSendMultiple(extras, NO_NAME, NO_TITLE, mDescription, 0);
 
         assertServiceNotRunning();
     }
@@ -507,26 +415,25 @@
     }
 
     private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
-        resetProperties();
-        sendBugreportStarted(1000);
+        sendBugreportStarted();
         if (waitScreenshot) {
             waitForScreenshotButtonEnabled(true);
         }
 
-        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME);
+        DetailsUi detailsUi = new DetailsUi(mBugreportId);
 
         // Finish the bugreport while user's still typing the name.
         detailsUi.nameField.setText(NEW_NAME);
-        sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
+        sendBugreportFinished();
 
         // Wait until the share notification is received...
-        waitShareNotification(ID);
+        waitShareNotification(mBugreportId);
         // ...then close notification bar.
         mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
 
         // Make sure UI was updated properly.
         assertFalse("didn't disable name on UI", detailsUi.nameField.isEnabled());
-        assertEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText().toString());
+        assertNotEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText());
 
         // Finish changing other fields.
         detailsUi.titleField.setText(TITLE);
@@ -534,9 +441,8 @@
         detailsUi.clickOk();
 
         // Finally, share bugreport.
-        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
-                NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS);
+        Bundle extras = acceptBugreportAndGetSharedIntent(mBugreportId);
+        assertActionSendMultiple(extras, NO_NAME, TITLE, mDescription, 0);
 
         assertServiceNotRunning();
     }
@@ -569,11 +475,14 @@
         }
 
         // Send notification and click on share.
-        sendBugreportFinished(NO_ID, mPlainTextPath, null);
-        mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, NO_ID));
+        sendBugreportStarted();
+        waitForScreenshotButtonEnabled(true);
+        sendBugreportFinished();
+        mUiBot.clickOnNotification(mContext.getString(
+                R.string.bugreport_finished_title, mBugreportId));
 
         // Handle the warning
-        mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
+        mUiBot.getObject(mContext.getString(R.string.bugreport_confirm));
         // TODO: get ok and dontShowAgain from the dialog reference above
         UiObject dontShowAgain =
                 mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat));
@@ -597,7 +506,7 @@
         // Share the bugreport.
         mUiBot.chooseActivity(UI_NAME);
         Bundle extras = mListener.getExtras();
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
+        assertActionSendMultiple(extras);
 
         // Make sure it's hidden now.
         int newState = getWarningState(mContext, STATE_UNKNOWN);
@@ -605,35 +514,37 @@
     }
 
     @Test
+    public void testBugreportFinished_withEmptyBugreportFile() throws Exception {
+        sendBugreportStarted();
+
+        IoUtils.closeQuietly(mBugreportFd);
+        mBugreportFd = null;
+        sendBugreportFinished();
+
+        assertServiceNotRunning();
+    }
+
+    @Test
     public void testShareBugreportAfterServiceDies() throws Exception {
-        sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
-        waitForService(false);
-        Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
+        sendBugreportStarted();
+        waitForScreenshotButtonEnabled(true);
+        sendBugreportFinished();
+        killService();
+        assertServiceNotRunning();
+        Bundle extras = acceptBugreportAndGetSharedIntent(mBugreportId);
+        assertActionSendMultiple(extras);
     }
 
     @Test
-    public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception {
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
-    }
+    public void testBugreportRequestTwice_oneStartBugreportInvoked() throws Exception {
+        sendBugreportStarted();
+        new BugreportRequestedReceiver().onReceive(mContext,
+                new Intent(INTENT_BUGREPORT_REQUESTED));
+        getInstrumentation().waitForIdleSync();
 
-    @Test
-    public void testBugreportFinished_zippedBugreportAndScreenshot() throws Exception {
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
-    }
-
-    @Test
-    public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception {
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
-    }
-
-    @Test
-    public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception {
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
+        verify(mMockIDumpstate, times(1)).startBugreport(anyInt(), any(), any(), any(),
+                anyInt(), any(), anyBoolean());
+        sendBugreportFinished();
     }
 
     private void cancelExistingNotifications() {
@@ -664,10 +575,10 @@
         assertEquals("old notifications were not cancelled", 0, nm.getActiveNotifications().length);
     }
 
-    private void cancelFromNotification() {
-        openProgressNotification(NAME);
-        UiObject cancelButton = mUiBot.getVisibleObject(mContext.getString(
-                com.android.internal.R.string.cancel).toUpperCase());
+    private void cancelFromNotification(String name) {
+        openProgressNotification(name);
+        UiObject cancelButton = mUiBot.getObject(mContext.getString(
+                com.android.internal.R.string.cancel));
         mUiBot.click(cancelButton, "cancel_button");
     }
 
@@ -676,67 +587,60 @@
         // TODO: need a way to get the ProgresBar from the "android:id/progress" UIObject...
     }
 
-    private UiObject openProgressNotification(String bugreportName) {
-        Log.v(TAG, "Looking for progress notification for '" + bugreportName + "'");
-        return mUiBot.getNotification(bugreportName);
-    }
-
-    void resetProperties() {
-        // TODO: call method to remove property instead
-        SystemProperties.set(PROGRESS_PROPERTY, "Reset");
-        SystemProperties.set(MAX_PROPERTY, "Reset");
-        SystemProperties.set(NAME_PROPERTY, "Reset");
+    private void openProgressNotification(String title) {
+        Log.v(TAG, "Looking for progress notification for '" + title + "'");
+        UiObject2 notification = mUiBot.getNotification2(title);
+        if (notification != null) {
+            mUiBot.expandNotification(notification);
+        }
     }
 
     /**
-     * Sends a "bugreport started" intent with the default values.
+     * Sends a "bugreport requested" intent with the default values.
      */
-    private void sendBugreportStarted(int max) throws Exception {
-        sendBugreportStarted(ID, PID, NAME, max);
-    }
+    private void sendBugreportStarted() throws Exception {
+        Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED);
+        // Ideally, we should invoke BugreportRequestedReceiver by sending
+        // INTENT_BUGREPORT_REQUESTED. But the intent has been protected broadcast by the system
+        // starting from S.
+        new BugreportRequestedReceiver().onReceive(mContext, intent);
 
-    private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception {
-        Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
-        intent.setPackage("com.android.shell");
-        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        intent.putExtra(EXTRA_ID, id);
-        intent.putExtra(EXTRA_PID, pid);
-        intent.putExtra(EXTRA_NAME, name);
-        intent.putExtra(EXTRA_MAX, max);
-        mContext.sendBroadcast(intent);
+        ArgumentCaptor<IDumpstateListener> listenerCap = ArgumentCaptor.forClass(
+                IDumpstateListener.class);
+        verify(mMockIDumpstate, timeout(TIMEOUT)).startBugreport(anyInt(), any(), any(), any(),
+                anyInt(), listenerCap.capture(), anyBoolean());
+        mIDumpstateListener = listenerCap.getValue();
+        assertNotNull("Dumpstate listener should not be null", mIDumpstateListener);
+        mIDumpstateListener.onProgress(0);
     }
 
     /**
-     * Sends a "bugreport finished" intent and waits for the result.
+     * Sends a "bugreport finished" event and waits for the result.
      *
+     * @param id The bugreport id for finished notification string title substitution.
      * @return extras sent in the shared intent.
      */
-    private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath,
-            String screenshotPath) {
-        return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath);
-    }
-
-    /**
-     * Sends a "bugreport finished" intent and waits for the result.
-     *
-     * @return extras sent in the shared intent.
-     */
-    private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
-            String screenshotPath) {
-        sendBugreportFinished(id, bugreportPath, screenshotPath);
+    private Bundle sendBugreportFinishedAndGetSharedIntent(int id) throws Exception {
+        sendBugreportFinished();
         return acceptBugreportAndGetSharedIntent(id);
     }
 
-    // TODO: document / merge these 3 sendBugreportFinishedAndGetSharedIntent methods
-    private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
-            String screenshotPath, String notificationTitle) {
-        sendBugreportFinished(id, bugreportPath, screenshotPath);
+    /**
+     * Sends a "bugreport finished" event and waits for the result.
+     *
+     * @param notificationTitle The title of finished notification.
+     * @return extras sent in the shared intent.
+     */
+    private Bundle sendBugreportFinishedAndGetSharedIntent(String notificationTitle)
+            throws Exception {
+        sendBugreportFinished();
         return acceptBugreportAndGetSharedIntent(notificationTitle);
     }
 
     /**
      * Accepts the notification to share the finished bugreport and waits for the result.
      *
+     * @param id The bugreport id for finished notification string title substitution.
      * @return extras sent in the shared intent.
      */
     private Bundle acceptBugreportAndGetSharedIntent(int id) {
@@ -744,7 +648,12 @@
         return acceptBugreportAndGetSharedIntent(notificationTitle);
     }
 
-    // TODO: document and/or merge these 2 acceptBugreportAndGetSharedIntent methods
+    /**
+     * Accepts the notification to share the finished bugreport and waits for the result.
+     *
+     * @param notificationTitle The title of finished notification.
+     * @return extras sent in the shared intent.
+     */
     private Bundle acceptBugreportAndGetSharedIntent(String notificationTitle) {
         mUiBot.clickOnNotification(notificationTitle);
         mUiBot.chooseActivity(UI_NAME);
@@ -759,53 +668,38 @@
     }
 
     /**
-     * Sends a "bugreport finished" intent.
+     * Callbacks to service to finish the bugreport.
      */
-    private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) {
-        Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
-        intent.setPackage("com.android.shell");
-        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        if (id != NO_ID) {
-            intent.putExtra(EXTRA_ID, id);
+    private void sendBugreportFinished() throws Exception {
+        if (mBugreportFd != null) {
+            writeZipFile(mBugreportFd, BUGREPORT_FILE, BUGREPORT_CONTENT);
         }
-        if (bugreportPath != null) {
-            intent.putExtra(EXTRA_BUGREPORT, bugreportPath);
+        if (mScreenshotFd != null) {
+            writeScreenshotFile(mScreenshotFd, SCREENSHOT_CONTENT);
         }
-        if (screenshotPath != null) {
-            intent.putExtra(EXTRA_SCREENSHOT, screenshotPath);
-        }
-
-        mContext.sendBroadcast(intent);
+        mIDumpstateListener.onFinished();
+        getInstrumentation().waitForIdleSync();
     }
 
     /**
      * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
      */
-    private void assertActionSendMultiple(Bundle extras, String bugreportContent,
-            String screenshotContent) throws IOException {
-        assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE,
-                NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS);
+    private void assertActionSendMultiple(Bundle extras) throws IOException {
+        assertActionSendMultiple(extras, NO_NAME, NO_TITLE, NO_DESCRIPTION, 0);
     }
 
     /**
      * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
      *
      * @param extras extras received in the intent
-     * @param bugreportContent expected content in the bugreport file
-     * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any
-     * @param id emulated dumpstate id
-     * @param pid emulated dumpstate pid
-     * @param name expected subject
      * @param name bugreport name as provided by the user (or received by dumpstate)
      * @param title bugreport name as provided by the user
      * @param description bugreport description as provided by the user
      * @param numberScreenshots expected number of screenshots taken by Shell.
-     * @param renamedScreenshots whether the screenshots are expected to be renamed
      */
-    private void assertActionSendMultiple(Bundle extras, String bugreportContent,
-            String screenshotContent, int id, int pid, String subject,
-            String name, String title, String description,
-            int numberScreenshots, boolean renamedScreenshots) throws IOException {
+    private void assertActionSendMultiple(Bundle extras, String name, String title,
+            String description, int numberScreenshots)
+            throws IOException {
         String body = extras.getString(Intent.EXTRA_TEXT);
         assertContainsRegex("missing build info",
                 SystemProperties.get("ro.build.description"), body);
@@ -815,11 +709,21 @@
             assertContainsRegex("missing description", description, body);
         }
 
-        assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT));
+        final String extrasSubject = extras.getString(Intent.EXTRA_SUBJECT);
+        if (title != null) {
+            assertEquals("wrong subject", title, extrasSubject);
+        } else {
+            if (name != null) {
+                assertEquals("wrong subject", getBugreportName(name), extrasSubject);
+            } else {
+                assertTrue("wrong subject", extrasSubject.startsWith(
+                        getBugreportPrefixName()));
+            }
+        }
 
         List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
         int expectedNumberScreenshots = numberScreenshots;
-        if (screenshotContent != null) {
+        if (getScreenshotContent() != null) {
             expectedNumberScreenshots ++; // Add screenshot received by dumpstate
         }
         int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file
@@ -858,7 +762,7 @@
             }
         }
         // Check external screenshot
-        if (screenshotContent != null) {
+        if (getScreenshotContent() != null) {
             assertNotNull("did not get .png attachment for external screenshot",
                     externalScreenshotUri);
             assertContent(externalScreenshotUri, SCREENSHOT_CONTENT);
@@ -866,17 +770,18 @@
             assertNull("should not have .png attachment for external screenshot",
                     externalScreenshotUri);
         }
-        // Check internal screenshots.
-        SortedSet<String> expectedNames = new TreeSet<>();
-        for (int i = 1 ; i <= numberScreenshots; i++) {
-            String prefix = renamedScreenshots  ? name : Integer.toString(pid);
-            String expectedName = "screenshot-" + prefix + "-" + i + ".png";
-            expectedNames.add(expectedName);
+        // Check internal screenshots' file names.
+        if (name != null) {
+            SortedSet<String> expectedNames = new TreeSet<>();
+            for (int i = 1; i <= numberScreenshots; i++) {
+                String expectedName = "screenshot-" + name + "-" + i + ".png";
+                expectedNames.add(expectedName);
+            }
+            // Ideally we should use MoreAsserts, but the error message in case of failure is not
+            // really useful.
+            assertEquals("wrong names for internal screenshots",
+                    expectedNames, internalScreenshotNames);
         }
-        // Ideally we should use MoreAsserts, but the error message in case of failure is not
-        // really useful.
-        assertEquals("wrong names for internal screenshots",
-                expectedNames, internalScreenshotNames);
     }
 
     private void assertContent(Uri uri, String expectedContent) throws IOException {
@@ -909,28 +814,9 @@
         fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
     }
 
-    private void assertPropertyValue(String key, String expectedValue) {
-        // Since the property is set in a different thread by BugreportProgressService, we need to
-        // poll it a couple times...
-
-        for (int i = 1; i <= 5; i++) {
-            String actualValue = SystemProperties.get(key);
-            if (expectedValue.equals(actualValue)) {
-                return;
-            }
-            Log.d(TAG, "Value of property " + key + " (" + actualValue
-                    + ") does not match expected value (" + expectedValue
-                    + ") on attempt " + i + ". Sleeping before next attempt...");
-            sleep(1000);
-        }
-        // Final try...
-        String actualValue = SystemProperties.get(key);
-        assertEquals("Wrong value for property '" + key + "'", expectedValue, actualValue);
-    }
-
     private void assertServiceNotRunning() {
-        String service = BugreportProgressService.class.getName();
-        assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
+        mServiceRule.unbindService();
+        waitForService(false);
     }
 
     private boolean isServiceRunning(String name) {
@@ -962,7 +848,7 @@
 
     private void killService() {
         String service = BugreportProgressService.class.getName();
-
+        mServiceRule.unbindService();
         if (!isServiceRunning(service)) return;
 
         Log.w(TAG, "Service '" + service + "' is still running, killing it");
@@ -980,18 +866,19 @@
         }
     }
 
-    private void createTextFile(String path, String content) throws IOException {
-        Log.v(TAG, "createFile(" + path + ")");
+    private void writeScreenshotFile(ParcelFileDescriptor fd, String content) throws IOException {
+        Log.v(TAG, "writeScreenshotFile(" + fd + ")");
         try (Writer writer = new BufferedWriter(new OutputStreamWriter(
-                new FileOutputStream(path)))) {
+                new FileOutputStream(fd.getFileDescriptor())))) {
             writer.write(content);
         }
     }
 
-    private void createZipFile(String path, String entryName, String content) throws IOException {
-        Log.v(TAG, "createZipFile(" + path + ", " + entryName + ")");
+    private void writeZipFile(ParcelFileDescriptor fd, String entryName, String content)
+            throws IOException {
+        Log.v(TAG, "writeZipFile(" + fd + ", " + entryName + ")");
         try (ZipOutputStream zos = new ZipOutputStream(
-                new BufferedOutputStream(new FileOutputStream(path)))) {
+                new BufferedOutputStream(new FileOutputStream(fd.getFileDescriptor())))) {
             ZipEntry entry = new ZipEntry(entryName);
             zos.putNextEntry(entry);
             byte[] data = content.getBytes();
@@ -1000,25 +887,13 @@
         }
     }
 
-    private String getPath(String file) {
-        final File rootDir = mContext.getFilesDir();
-        final File dir = new File(rootDir, BUGREPORTS_DIR);
-        if (!dir.exists()) {
-            Log.i(TAG, "Creating directory " + dir);
-            assertTrue("Could not create directory " + dir, dir.mkdir());
-        }
-        String path = new File(dir, file).getAbsolutePath();
-        Log.v(TAG, "Path for '" + file + "': " + path);
-        return path;
-    }
-
     /**
      * Gets the notification button used to take a screenshot.
      */
     private UiObject getScreenshotButton() {
-        openProgressNotification(NAME);
-        return mUiBot.getVisibleObject(
-                mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
+        openProgressNotification(mProgressTitle);
+        return mUiBot.getObject(
+                mContext.getString(R.string.bugreport_screenshot_action));
     }
 
     /**
@@ -1072,12 +947,36 @@
         Log.d(TAG, "woke up");
     }
 
+    private int getBugreportId() {
+        return SystemProperties.getInt(PROPERTY_LAST_ID, 1);
+    }
+
+    private String getBugreportInProgress(int bugreportId) {
+        return mContext.getString(R.string.bugreport_in_progress_title, bugreportId);
+    }
+
+    private String getBugreportPrefixName() {
+        String buildId = SystemProperties.get("ro.build.id", "UNKNOWN_BUILD");
+        String deviceName = SystemProperties.get("ro.product.name", "UNKNOWN_DEVICE");
+        return String.format("bugreport-%s-%s", deviceName, buildId);
+    }
+
+    private String getBugreportName(String name) {
+        return String.format("%s-%s.zip", getBugreportPrefixName(), name);
+    }
+
+    private String getScreenshotContent() {
+        if (mScreenshotFd == null) {
+            return NO_SCREENSHOT;
+        }
+        return SCREENSHOT_CONTENT;
+    }
+
     /**
      * Helper class containing the UiObjects present in the bugreport info dialog.
      */
     private final class DetailsUi {
 
-        final UiObject detailsButton;
         final UiObject nameField;
         final UiObject titleField;
         final UiObject descField;
@@ -1088,10 +987,9 @@
          * Gets the UI objects by opening the progress notification and clicking on DETAILS.
          *
          * @param id bugreport id
-         * @param id bugreport name
          */
-        DetailsUi(UiBot uiBot, int id, String name) throws UiObjectNotFoundException {
-            this(uiBot, id, name, true);
+        DetailsUi(int id) throws UiObjectNotFoundException {
+            this(id, true);
         }
 
         /**
@@ -1099,13 +997,12 @@
          * the notification itself.
          *
          * @param id bugreport id
-         * @param id bugreport name
          */
-        DetailsUi(UiBot uiBot, int id, String name, boolean clickDetails)
-                throws UiObjectNotFoundException {
-            final UiObject notification = openProgressNotification(name);
-            detailsButton = mUiBot.getVisibleObject(mContext.getString(
-                    R.string.bugreport_info_action).toUpperCase());
+        DetailsUi(int id, boolean clickDetails) throws UiObjectNotFoundException {
+            openProgressNotification(mProgressTitle);
+            final UiObject notification = mUiBot.getObject(mProgressTitle);
+            final UiObject detailsButton = mUiBot.getObject(mContext.getString(
+                    R.string.bugreport_info_action));
 
             if (clickDetails) {
                 mUiBot.click(detailsButton, "details_button");
@@ -1123,24 +1020,6 @@
             cancelButton = mUiBot.getObjectById("android:id/button2");
         }
 
-        private void assertField(String name, UiObject field, String expected)
-                throws UiObjectNotFoundException {
-            String actual = field.getText().toString();
-            assertEquals("Wrong value on field '" + name + "'", expected, actual);
-        }
-
-        void assertName(String expected) throws UiObjectNotFoundException {
-            assertField("name", nameField, expected);
-        }
-
-        void assertTitle(String expected) throws UiObjectNotFoundException {
-            assertField("title", titleField, expected);
-        }
-
-        void assertDescription(String expected) throws UiObjectNotFoundException {
-            assertField("description", descField, expected);
-        }
-
         /**
          * Set focus on the name field so it can be validated once focus is lost.
          */
@@ -1159,6 +1038,8 @@
 
         void reOpen(String name) {
             openProgressNotification(name);
+            final UiObject detailsButton = mUiBot.getObject(mContext.getString(
+                    R.string.bugreport_info_action));
             mUiBot.click(detailsButton, "details_button");
         }
 
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index e839765..53b124f 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -18,17 +18,23 @@
 
 import android.app.Instrumentation;
 import android.app.StatusBarManager;
+import android.os.SystemClock;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
+import android.text.format.DateUtils;
 import android.util.Log;
 
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import java.util.List;
+
 /**
  * A helper class for UI-related testing tasks.
  */
@@ -36,6 +42,9 @@
 
     private static final String TAG = "UiBot";
     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+    private static final String ANDROID_PACKAGE = "android";
+
+    private static final long SHORT_UI_TIMEOUT_MS = (3 * DateUtils.SECOND_IN_MILLIS);
 
     private final Instrumentation mInstrumentation;
     private final UiDevice mDevice;
@@ -48,9 +57,9 @@
     }
 
     /**
-     * Opens the system notification and gets a given notification.
+     * Opens the system notification and gets a UiObject with the text.
      *
-     * @param text Notificaton's text as displayed by the UI.
+     * @param text Notification's text as displayed by the UI.
      * @return notification object.
      */
     public UiObject getNotification(String text) {
@@ -62,6 +71,43 @@
         return getObject(text);
     }
 
+    /**
+     * Opens the system notification and gets a notification containing the text.
+     *
+     * @param text Notification's text as displayed by the UI.
+     * @return notification object.
+     */
+    public UiObject2 getNotification2(String text) {
+        boolean opened = mDevice.openNotification();
+        Log.v(TAG, "openNotification(): " + opened);
+        final UiObject2 notificationScroller = mDevice.wait(Until.findObject(
+                By.res(SYSTEMUI_PACKAGE, "notification_stack_scroller")), mTimeout);
+        assertNotNull("could not get notification stack scroller", notificationScroller);
+        final List<UiObject2> notificationList = notificationScroller.getChildren();
+        for (UiObject2 notification: notificationList) {
+            final UiObject2 notificationText = notification.findObject(By.textContains(text));
+            if (notificationText != null) {
+                return notification;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Expands the notification.
+     *
+     * @param notification The notification object returned by {@link #getNotification2(String)}.
+     */
+    public void expandNotification(UiObject2 notification) {
+        final UiObject2 expandBtn =  notification.findObject(
+                By.res(ANDROID_PACKAGE, "expand_button"));
+        if (expandBtn.getContentDescription().equals("Collapse")) {
+            return;
+        }
+        expandBtn.click();
+        mDevice.waitForIdle();
+    }
+
     public void collapseStatusBar() throws Exception {
         // TODO: mDevice should provide such method..
         StatusBarManager sbm =
@@ -162,6 +208,12 @@
      */
     public void chooseActivity(String name) {
         // It uses an intent chooser now, so just getting the activity by text is enough...
+        final String share = mInstrumentation.getContext().getString(
+                com.android.internal.R.string.share);
+        boolean gotIt = mDevice.wait(Until.hasObject(By.text(share)), mTimeout);
+        assertTrue("could not get share activity (" + share + ")", gotIt);
+        swipeUp();
+        SystemClock.sleep(SHORT_UI_TIMEOUT_MS);
         UiObject activity = getObject(name);
         click(activity, name);
     }
@@ -173,6 +225,11 @@
     public void turnScreenOn() throws Exception {
         mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
         mDevice.executeShellCommand("wm dismiss-keyguard");
+        mDevice.waitForIdle();
     }
 
+    public void swipeUp() {
+        mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() * 3 / 4,
+                mDevice.getDisplayWidth() / 2, 0, 30);
+    }
 }
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 0fd5e17..7f8d160 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -25,7 +25,7 @@
     <string name="keyguard_password_enter_puk_code" msgid="3813154965969758868">"‏SIM PUK اور نیا PIN کوڈ ٹائپ کریں"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="3529260761374385243">"‏SIM PUK کوڈ"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="2304037870481240781">"‏نیا SIM PIN کوڈ"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="6180028658339706333"><font size="17">"پاسورڈ ٹائپ کرنے کیلئے ٹچ کریں"</font></string>
+    <string name="keyguard_password_entry_touch_hint" msgid="6180028658339706333"><font size="17">"پاس ورڈ ٹائپ کرنے کیلئے ٹچ کریں"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="7393393239623946777">"غیر مقفل کرنے کیلئے پاس ورڈ ٹائپ کریں"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="3692259677395250509">"‏غیر مقفل کرنے کیلئے PIN ٹائپ کریں"</string>
     <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"‏اپنا PIN درج کریں"</string>
@@ -72,7 +72,7 @@
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"‏\"<xliff:g id="CARRIER">%1$s</xliff:g>\" کیلئے SIM PIN درج کریں۔"</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"‏<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> موبائل سروس کے بغیر آلہ کا استعمال کرنے کیلئے eSIM غیر فعال کریں۔"</string>
     <string name="kg_pin_instructions" msgid="822353548385014361">"‏‫PIN درج کریں"</string>
-    <string name="kg_password_instructions" msgid="324455062831719903">"پاسورڈ درج کریں"</string>
+    <string name="kg_password_instructions" msgid="324455062831719903">"پاس ورڈ درج کریں"</string>
     <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"‏SIM اب غیر فعال ہوگیا ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string>
     <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"‏SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string>
     <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"‏پسندیدہ PIN کوڈ درج کریں"</string>
@@ -83,7 +83,7 @@
     <string name="kg_invalid_puk" msgid="1774337070084931186">"‏صحیح PUK کوڈ دوبارہ درج کریں۔ بار بار کی کوششیں SIM کو مستقل طور پر غیر فعال کر دیں گی۔"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"پیٹرن کی بہت ساری کوششیں"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"‏آپ نے اپنا PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"آپ نے اپنا پاسورڈ <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"آپ نے اپنا پاس ورڈ <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"‏غلط SIM PIN کوڈ، اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے اپنے کیریئر سے رابطہ کرنا ہوگا۔"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
@@ -103,13 +103,13 @@
     <string name="airplane_mode" msgid="2528005343938497866">"ہوائی جہاز وضع"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"آلہ دوبارہ چالو ہونے کے بعد پیٹرن درکار ہوتا ہے"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"‏آلہ دوبارہ چالو ہونے کے بعد PIN درکار ہوتا ہے"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"آلہ دوبارہ چالو ہونے کے بعد پاسورڈ درکار ہوتا ہے"</string>
+    <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"آلہ دوبارہ چالو ہونے کے بعد پاس ورڈ درکار ہوتا ہے"</string>
     <string name="kg_prompt_reason_timeout_pattern" msgid="9170360502528959889">"اضافی سیکیورٹی کیلئے پیٹرن درکار ہے"</string>
     <string name="kg_prompt_reason_timeout_pin" msgid="5945186097160029201">"‏اضافی سیکیورٹی کیلئے PIN درکار ہے"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"اضافی سیکیورٹی کیلئے پاسورڈ درکار ہے"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="2258263949430384278">"اضافی سیکیورٹی کیلئے پاس ورڈ درکار ہے"</string>
     <string name="kg_prompt_reason_switch_profiles_pattern" msgid="1922016914701991230">"جب آپ پروفائل سوئچ کرتے ہیں تو پیٹرن درکار ہوتا ہے"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="6490434826361055400">"‏جب آپ پروفائل سوئچ کرتے ہیں تو PIN درکار ہوتا ہے"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="1680374696393804441">"جب آپ پروفائل سوئچ کرتے ہیں تو پاسورڈ درکار ہوتا ہے"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1680374696393804441">"جب آپ پروفائل سوئچ کرتے ہیں تو پاس ورڈ درکار ہوتا ہے"</string>
     <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"آلہ منتظم کی جانب سے مقفل ہے"</string>
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"آلہ کو دستی طور پر مقفل کیا گیا تھا"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="1337428979661197957">
@@ -121,8 +121,8 @@
       <item quantity="one">‏آلہ <xliff:g id="NUMBER_0">%d</xliff:g> گھنٹہ سے غیر مقفل نہیں کیا گیا۔ PIN کی توثیق کریں۔</item>
     </plurals>
     <plurals name="kg_prompt_reason_time_password" formatted="false" msgid="5343961527665116914">
-      <item quantity="other">آلہ <xliff:g id="NUMBER_1">%d</xliff:g> گھنٹوں سے غیر مقفل نہیں کیا گيا۔ پاسورڈ کی توثیق کریں۔</item>
-      <item quantity="one">آلہ <xliff:g id="NUMBER_0">%d</xliff:g> گھنٹہ سے غیر مقفل نہیں کیا گیا۔ پاسورڈ کی توثیق کریں۔</item>
+      <item quantity="other">آلہ <xliff:g id="NUMBER_1">%d</xliff:g> گھنٹوں سے غیر مقفل نہیں کیا گيا۔ پاس ورڈ کی توثیق کریں۔</item>
+      <item quantity="one">آلہ <xliff:g id="NUMBER_0">%d</xliff:g> گھنٹہ سے غیر مقفل نہیں کیا گیا۔ پاس ورڈ کی توثیق کریں۔</item>
     </plurals>
     <string name="kg_fingerprint_not_recognized" msgid="5982606907039479545">"تسلیم شدہ نہیں ہے"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"تسلیم شدہ نہیں ہے"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 87233dc..88bb88c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -35,7 +35,7 @@
     <string name="battery_low_why" msgid="2056750982959359863">"הגדרות"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"להפעיל את תכונת החיסכון בסוללה?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"מידע על מצב החיסכון בסוללה"</string>
-    <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"הפעל"</string>
+    <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"הפעלה"</string>
     <string name="battery_saver_start_action" msgid="4553256017945469937">"הפעלת תכונת החיסכון בסוללה"</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"הגדרות"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
@@ -298,8 +298,8 @@
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="4747870681508334200">"הפנס הופעל."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"היפוך צבעים כבוי."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"היפוך צבעים מופעל."</string>
-    <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"נקודה לשיתוף אינטרנט בנייד כבויה."</string>
-    <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"נקודה לשיתוף אינטרנט בנייד מופעלת."</string>
+    <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"‏נקודת האינטרנט (hotspot) כבויה."</string>
+    <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"‏נקודת האינטרנט (hotspot) מופעלת."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"העברת המסך הופסקה."</string>
     <string name="accessibility_quick_settings_work_mode_off" msgid="562749867895549696">"מצב עבודה כבוי."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"מצב עבודה מופעל."</string>
@@ -397,7 +397,7 @@
     <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"מחובר, הסוללה ב-<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="quick_settings_connecting" msgid="2381969772953268809">"מתחבר..."</string>
     <string name="quick_settings_tethering_label" msgid="5257299852322475780">"שיתוף אינטרנט בין ניידים"</string>
-    <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"נקודה לשיתוף אינטרנט"</string>
+    <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"‏נקודת אינטרנט (hotspot)"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"ההפעלה מתבצעת…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"חוסך הנתונים פועל"</string>
     <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
@@ -666,7 +666,7 @@
     <string name="alarm_template" msgid="2234991538018805736">"בשעה <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"ב-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"הגדרות מהירות, <xliff:g id="TITLE">%s</xliff:g>."</string>
-    <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"נקודה לשיתוף אינטרנט"</string>
+    <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"‏נקודת אינטרנט (hotspot)"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"פרופיל עבודה"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"מהנה בשביל חלק מהאנשים, אבל לא בשביל כולם"</string>
     <string name="tuner_warning" msgid="1861736288458481650">"‏System UI Tuner מספק לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, להתקלקל או להיעלם בגרסאות עתידיות. המשך בזהירות."</string>
@@ -683,7 +683,7 @@
     <string name="experimental" msgid="3549865454812314826">"ניסיוני"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"‏האם להפעיל את ה-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
-    <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"הפעל"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"הפעלה"</string>
     <string name="show_silently" msgid="5629369640872236299">"הצגת התראות בלי להשמיע צליל"</string>
     <string name="block" msgid="188483833983476566">"חסימת כל ההתראות"</string>
     <string name="do_not_silence" msgid="4982217934250511227">"לא להשתיק"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index caab00f..30ecf7a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -63,7 +63,7 @@
     <string name="usb_debugging_allow" msgid="1722643858015321328">"अनुमती द्या"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB डीबग करण्‍यास अनुमती नाही"</string>
     <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"सध्‍या या डीव्हाइसमध्‍ये साइन इन केलेला वापरकर्ता USB डीबग करणे सुरू करू शकत नाही. हे वैशिष्‍ट्य वापरण्‍यासाठी, प्राथमिक वापरकर्त्‍यावर स्विच करा."</string>
-    <string name="wifi_debugging_title" msgid="7300007687492186076">"या नेटवर्कवर वायरलेस डीबगिंग करण्याला अनुमती द्यायची का?"</string>
+    <string name="wifi_debugging_title" msgid="7300007687492186076">"या नेटवर्कवर वायरलेस डीबगिंग करण्यासाठी अनुमती द्यायची का?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्कचे नाव (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nवाय-फाय ॲड्रेस (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"या नेटवर्कवर नेहमी अनुमती द्या"</string>
     <string name="wifi_debugging_allow" msgid="4573224609684957886">"अनुमती द्या"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 9aae6ce..d304098 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -422,7 +422,7 @@
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do wschodu słońca"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Włącz o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Tryb ciemny"</string>
+    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Ciemny motyw"</string>
     <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Oszczędzanie baterii"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Włącz o zachodzie"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do wschodu słońca"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 912b25e..5b186fa 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -57,15 +57,15 @@
     <string name="label_view" msgid="6815442985276363364">"Pamje"</string>
     <string name="always_use_device" msgid="210535878779644679">"Hap gjithmonë <xliff:g id="APPLICATION">%1$s</xliff:g> kur lidhet <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
     <string name="always_use_accessory" msgid="1977225429341838444">"Hap gjithmonë <xliff:g id="APPLICATION">%1$s</xliff:g> kur lidhet <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
-    <string name="usb_debugging_title" msgid="8274884945238642726">"Të lejohet korrigjimi i USB-së?"</string>
+    <string name="usb_debugging_title" msgid="8274884945238642726">"Të lejohet korrigjimi përmes USB-së?"</string>
     <string name="usb_debugging_message" msgid="5794616114463921773">"Gjurma e gishtit të tastit \"RSA\" së kompjuterit është:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="4003121804294739548">"Lejo gjithmonë nga ky kompjuter"</string>
     <string name="usb_debugging_allow" msgid="1722643858015321328">"Lejo"</string>
-    <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Korrigjimi i USB-së nuk lejohet"</string>
-    <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin e USB-së. Për ta përdorur këtë funksion, kalo te përdoruesi parësor."</string>
+    <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Korrigjimi përmes USB-së nuk lejohet"</string>
+    <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin përmes USB-së. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Do ta lejosh korrigjimin përmes Wi-Fi në këtë rrjet?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Emri i rrjetit (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
-    <string name="wifi_debugging_always" msgid="2968383799517975155">"Shfaq gjithmonë në këtë rrjet"</string>
+    <string name="wifi_debugging_always" msgid="2968383799517975155">"Lejo gjithmonë në këtë rrjet"</string>
     <string name="wifi_debugging_allow" msgid="4573224609684957886">"Lejo"</string>
     <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Korrigjimi përmes Wi-Fi nuk lejohet"</string>
     <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin përmes Wi-Fi. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 51124aa..06eeb0d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -26,7 +26,7 @@
     <string name="status_bar_latest_events_title" msgid="202755896454005436">"Eslatmalar"</string>
     <string name="battery_low_title" msgid="6891106956328275225">"Batareya tez orada tugaydi"</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi"</string>
-    <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> (joriy holatda taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi)"</string>
+    <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"Batareya qivvati – <xliff:g id="PERCENTAGE">%1$s</xliff:g>, tugashiga taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
     <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> (taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi)"</string>
     <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi. Quvvat tejash rejimi yoniq."</string>
     <string name="invalid_charger" msgid="4370074072117767416">"USB orqali quvvatlash imkonsiz. Qurilmangiz bilan kelgan quvvatlash moslamasidan foydalaning."</string>
@@ -700,13 +700,13 @@
     <string name="inline_block_button" msgid="479892866568378793">"Bloklash"</string>
     <string name="inline_keep_button" msgid="299631874103662170">"Ha"</string>
     <string name="inline_minimize_button" msgid="1474436209299333445">"Kichraytirish"</string>
-    <string name="inline_silent_button_silent" msgid="525243786649275816">"Tovushsiz"</string>
+    <string name="inline_silent_button_silent" msgid="525243786649275816">"Sokin"</string>
     <string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"Ovozsiz qolsin"</string>
     <string name="inline_silent_button_alert" msgid="5705343216858250354">"Ogohlantirish"</string>
     <string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"Signal berishda davom etilsin"</string>
     <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Bildirishnoma kelmasin"</string>
     <string name="inline_keep_showing_app" msgid="4393429060390649757">"Bu ilovadan keladigan bildirishnomalar chiqaversinmi?"</string>
-    <string name="notification_silence_title" msgid="8608090968400832335">"Tovushsiz"</string>
+    <string name="notification_silence_title" msgid="8608090968400832335">"Sokin"</string>
     <string name="notification_alert_title" msgid="3656229781017543655">"Standart"</string>
     <string name="notification_bubble_title" msgid="8330481035191903164">"Pufaklar"</string>
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"Tovush yoki tebranishsiz"</string>
@@ -718,8 +718,8 @@
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Sozlamalar"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
-    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Avvalgi bulutchalar topilmadi"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bu yerda oxirgi va yopilgan bulutcha shaklidagi bildirishnomalar chiqadi"</string>
+    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hech qanday bulutcha topilmadi"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Eng oxirgi va yopilgan bulutchali chatlar shu yerda chiqadi"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Ishonchli bildirishnoma"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index 449ed8c..57e6568 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -16,6 +16,7 @@
 
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.slice.SliceManager;
@@ -29,6 +30,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.text.BidiFormatter;
+import android.util.EventLog;
 import android.util.Log;
 import android.widget.CheckBox;
 import android.widget.TextView;
@@ -50,10 +52,12 @@
 
         mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI);
         mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG);
-        mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG);
 
         try {
             PackageManager pm = getPackageManager();
+            mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(),
+                    PackageManager.GET_META_DATA).applicationInfo.packageName;
+            verifyCallingPkg();
             CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo(
                     mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
                     PackageItemInfo.SAFE_LABEL_FLAG_TRIM
@@ -97,4 +101,27 @@
     public void onDismiss(DialogInterface dialog) {
         finish();
     }
+
+    private void verifyCallingPkg() {
+        final String providerPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG);
+        if (providerPkg == null || mProviderPkg.equals(providerPkg)) return;
+        final String callingPkg = getCallingPkg();
+        EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg));
+    }
+
+    @Nullable
+    private String getCallingPkg() {
+        final Uri referrer = getReferrer();
+        if (referrer == null) return null;
+        return referrer.getHost();
+    }
+
+    private int getUid(@Nullable final String pkg) {
+        if (pkg == null) return -1;
+        try {
+            return getPackageManager().getApplicationInfo(pkg, 0).uid;
+        } catch (NameNotFoundException e) {
+        }
+        return -1;
+    }
 }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index a704c58..66bbf66 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -372,7 +372,10 @@
 
             checkArgument(getCallingUserId() == userId,
                     "Must be called by either same user or system");
-            mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+            int callingUid = Binder.getCallingUid();
+            if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) {
+                throw new SecurityException(pkg + " doesn't belong to uid " + callingUid);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index fe116d9..0403247 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -83,6 +83,7 @@
 import android.net.ConnectivityDiagnosticsManager.DataStallReport;
 import android.net.ConnectivityManager;
 import android.net.DataStallReportParcelable;
+import android.net.DnsResolverServiceManager;
 import android.net.ICaptivePortal;
 import android.net.IConnectivityDiagnosticsCallback;
 import android.net.IConnectivityManager;
@@ -94,7 +95,6 @@
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
-import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.ISocketKeepaliveCallback;
 import android.net.InetAddresses;
@@ -174,6 +174,7 @@
 import android.util.SparseIntArray;
 import android.util.Xml;
 
+import com.android.connectivity.aidl.INetworkAgent;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -335,7 +336,7 @@
     @VisibleForTesting
     protected INetd mNetd;
     private INetworkStatsService mStatsService;
-    private INetworkPolicyManager mPolicyManager;
+    private NetworkPolicyManager mPolicyManager;
     private NetworkPolicyManagerInternal mPolicyManagerInternal;
 
     /**
@@ -571,9 +572,8 @@
         return sMagicDecoderRing.get(what, Integer.toString(what));
     }
 
-    private static IDnsResolver getDnsResolver() {
-        return IDnsResolver.Stub
-                .asInterface(ServiceManager.getService("dnsresolver"));
+    private static IDnsResolver getDnsResolver(Context context) {
+        return IDnsResolver.Stub.asInterface(DnsResolverServiceManager.getService(context));
     }
 
     /** Handler thread used for all of the handlers below. */
@@ -945,15 +945,15 @@
     }
 
     public ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService, INetworkPolicyManager policyManager) {
-        this(context, netManager, statsService, policyManager, getDnsResolver(),
-                new IpConnectivityLog(), NetdService.getInstance(), new Dependencies());
+            INetworkStatsService statsService) {
+        this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(),
+                NetdService.getInstance(), new Dependencies());
     }
 
     @VisibleForTesting
     protected ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService, INetworkPolicyManager policyManager,
-            IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
+            INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger,
+            INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
         mDeps = Objects.requireNonNull(deps, "missing Dependencies");
@@ -991,7 +991,7 @@
 
         mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
-        mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager");
+        mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
         mPolicyManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
@@ -1007,12 +1007,7 @@
         // To ensure uid rules are synchronized with Network Policy, register for
         // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
         // reading existing policy from disk.
-        try {
-            mPolicyManager.registerListener(mPolicyListener);
-        } catch (RemoteException e) {
-            // ouch, no rules updates means some processes may never get network
-            loge("unable to register INetworkPolicyListener" + e);
-        }
+        mPolicyManager.registerListener(mPolicyListener);
 
         final PowerManager powerManager = (PowerManager) context.getSystemService(
                 Context.POWER_SERVICE);
@@ -2007,7 +2002,7 @@
     void handleRestrictBackgroundChanged(boolean restrictBackground) {
         if (mRestrictBackground == restrictBackground) return;
 
-        for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
             final boolean curMetered = nai.networkCapabilities.isMetered();
             maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
                     restrictBackground);
@@ -2715,7 +2710,7 @@
      */
     private NetworkAgentInfo[] networksSortedById() {
         NetworkAgentInfo[] networks = new NetworkAgentInfo[0];
-        networks = mNetworkAgentInfos.values().toArray(networks);
+        networks = mNetworkAgentInfos.toArray(networks);
         Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.getNetId()));
         return networks;
     }
@@ -2761,11 +2756,6 @@
                     handleAsyncChannelHalfConnect(msg);
                     break;
                 }
-                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
-                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
-                    if (nai != null) nai.asyncChannel.disconnect();
-                    break;
-                }
                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
                     handleAsyncChannelDisconnected(msg);
                     break;
@@ -2775,8 +2765,9 @@
         }
 
         private void maybeHandleNetworkAgentMessage(Message msg) {
-            NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
-            if (nai == null) {
+            final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj;
+            final NetworkAgentInfo nai = arg.first;
+            if (!mNetworkAgentInfos.contains(nai)) {
                 if (VDBG) {
                     log(String.format("%s from unknown NetworkAgent", eventName(msg.what)));
                 }
@@ -2785,7 +2776,7 @@
 
             switch (msg.what) {
                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
-                    NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
+                    NetworkCapabilities networkCapabilities = (NetworkCapabilities) arg.second;
                     if (networkCapabilities.hasConnectivityManagedCapability()) {
                         Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
                     }
@@ -2802,13 +2793,13 @@
                     break;
                 }
                 case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
-                    LinkProperties newLp = (LinkProperties) msg.obj;
+                    LinkProperties newLp = (LinkProperties) arg.second;
                     processLinkPropertiesFromAgent(nai, newLp);
                     handleUpdateLinkProperties(nai, newLp);
                     break;
                 }
                 case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
-                    NetworkInfo info = (NetworkInfo) msg.obj;
+                    NetworkInfo info = (NetworkInfo) arg.second;
                     updateNetworkInfo(nai, info);
                     break;
                 }
@@ -2833,7 +2824,7 @@
                     break;
                 }
                 case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
-                    mKeepaliveTracker.handleEventSocketKeepalive(nai, msg);
+                    mKeepaliveTracker.handleEventSocketKeepalive(nai, msg.arg1, msg.arg2);
                     break;
                 }
                 case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
@@ -2844,7 +2835,7 @@
                     }
                     final ArrayList<Network> underlying;
                     try {
-                        underlying = ((Bundle) msg.obj).getParcelableArrayList(
+                        underlying = ((Bundle) arg.second).getParcelableArrayList(
                                 NetworkAgent.UNDERLYING_NETWORKS_KEY);
                     } catch (NullPointerException | ClassCastException e) {
                         break;
@@ -2923,8 +2914,7 @@
                         if (nai.lastCaptivePortalDetected &&
                             Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
                             if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
-                            nai.asyncChannel.sendMessage(
-                                    NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
+                            nai.onPreventAutomaticReconnect();
                             teardownUnneededNetwork(nai);
                             break;
                         }
@@ -3016,13 +3006,10 @@
             }
             updateInetCondition(nai);
             // Let the NetworkAgent know the state of its network
-            Bundle redirectUrlBundle = new Bundle();
-            redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
             // TODO: Evaluate to update partial connectivity to status to NetworkAgent.
-            nai.asyncChannel.sendMessage(
-                    NetworkAgent.CMD_REPORT_NETWORK_STATUS,
-                    (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
-                    0, redirectUrlBundle);
+            nai.onValidationStatusChanged(
+                    valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK,
+                    redirectUrl);
 
             // If NetworkMonitor detects partial connectivity before
             // EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification
@@ -3056,6 +3043,14 @@
                     }
                     break;
                 }
+                case NetworkAgentInfo.EVENT_AGENT_REGISTERED: {
+                    handleNetworkAgentRegistered(msg);
+                    break;
+                }
+                case NetworkAgentInfo.EVENT_AGENT_DISCONNECTED: {
+                    handleNetworkAgentDisconnected(msg);
+                    break;
+                }
             }
             return true;
         }
@@ -3232,7 +3227,7 @@
     private void handlePrivateDnsSettingsChanged() {
         final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
 
-        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (NetworkAgentInfo nai : mNetworkAgentInfos) {
             handlePerNetworkPrivateDnsConfig(nai, cfg);
             if (networkRequiresPrivateDnsValidation(nai)) {
                 handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
@@ -3330,7 +3325,6 @@
 
     private void handleAsyncChannelHalfConnect(Message msg) {
         ensureRunningOnConnectivityServiceThread();
-        final AsyncChannel ac = (AsyncChannel) msg.obj;
         if (mNetworkProviderInfos.containsKey(msg.replyTo)) {
             if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                 if (VDBG) log("NetworkFactory connected");
@@ -3342,39 +3336,45 @@
                 loge("Error connecting NetworkFactory");
                 mNetworkProviderInfos.remove(msg.obj);
             }
-        } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
-            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                if (VDBG) log("NetworkAgent connected");
-                // A network agent has requested a connection.  Establish the connection.
-                mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
-                        sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
-            } else {
-                loge("Error connecting NetworkAgent");
-                NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
-                if (nai != null) {
-                    final boolean wasDefault = isDefaultNetwork(nai);
-                    synchronized (mNetworkForNetId) {
-                        mNetworkForNetId.remove(nai.network.getNetId());
-                    }
-                    mNetIdManager.releaseNetId(nai.network.getNetId());
-                    // Just in case.
-                    mLegacyTypeTracker.remove(nai, wasDefault);
+        }
+    }
+
+    private void handleNetworkAgentRegistered(Message msg) {
+        final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
+        if (!mNetworkAgentInfos.contains(nai)) {
+            return;
+        }
+
+        if (msg.arg1 == NetworkAgentInfo.ARG_AGENT_SUCCESS) {
+            if (VDBG) log("NetworkAgent registered");
+        } else {
+            loge("Error connecting NetworkAgent");
+            mNetworkAgentInfos.remove(nai);
+            if (nai != null) {
+                final boolean wasDefault = isDefaultNetwork(nai);
+                synchronized (mNetworkForNetId) {
+                    mNetworkForNetId.remove(nai.network.getNetId());
                 }
+                mNetIdManager.releaseNetId(nai.network.getNetId());
+                // Just in case.
+                mLegacyTypeTracker.remove(nai, wasDefault);
             }
         }
     }
 
-    // This is a no-op if it's called with a message designating a network that has
+    private void handleNetworkAgentDisconnected(Message msg) {
+        NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
+        if (mNetworkAgentInfos.contains(nai)) {
+            disconnectAndDestroyNetwork(nai);
+        }
+    }
+
+    // This is a no-op if it's called with a message designating a provider that has
     // already been destroyed, because its reference will not be found in the relevant
     // maps.
     private void handleAsyncChannelDisconnected(Message msg) {
-        NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
-        if (nai != null) {
-            disconnectAndDestroyNetwork(nai);
-        } else {
-            NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo);
-            if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name);
-        }
+        NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo);
+        if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name);
     }
 
     // Destroys a network, remove references to it from the internal state managed by
@@ -3418,7 +3418,7 @@
             wakeupModifyInterface(iface, nai.networkCapabilities, false);
         }
         nai.networkMonitor().notifyNetworkDisconnected();
-        mNetworkAgentInfos.remove(nai.messenger);
+        mNetworkAgentInfos.remove(nai);
         nai.clatd.update();
         synchronized (mNetworkForNetId) {
             // Remove the NetworkAgent, but don't mark the netId as
@@ -3526,7 +3526,7 @@
         mNetworkRequests.put(nri.request, nri);
         mNetworkRequestInfoLogs.log("REGISTER " + nri);
         if (nri.request.isListen()) {
-            for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
+            for (NetworkAgentInfo network : mNetworkAgentInfos) {
                 if (nri.request.networkCapabilities.hasSignalStrength() &&
                         network.satisfiesImmutableCapabilitiesOf(nri.request)) {
                     updateSignalStrengthThresholds(network, "REGISTER", nri.request);
@@ -3591,8 +3591,8 @@
     private boolean isNetworkPotentialSatisfier(
             @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) {
         // listen requests won't keep up a network satisfying it. If this is not a multilayer
-        // request, we can return immediately. For multilayer requests, we have to check to see if
-        // any of the multilayer requests may have a potential satisfier.
+        // request, return immediately. For multilayer requests, check to see if any of the
+        // multilayer requests may have a potential satisfier.
         if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
             return false;
         }
@@ -3742,7 +3742,7 @@
         } else {
             // listens don't have a singular affectedNetwork.  Check all networks to see
             // if this listen request applies and remove it.
-            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
                 nai.removeRequest(nri.request.requestId);
                 if (nri.request.networkCapabilities.hasSignalStrength() &&
                         nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
@@ -3815,13 +3815,12 @@
         }
 
         if (always) {
-            nai.asyncChannel.sendMessage(
-                    NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept));
+            nai.onSaveAcceptUnvalidated(accept);
         }
 
         if (!accept) {
             // Tell the NetworkAgent to not automatically reconnect to the network.
-            nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
+            nai.onPreventAutomaticReconnect();
             // Teardown the network.
             teardownUnneededNetwork(nai);
         }
@@ -3852,13 +3851,12 @@
 
         // TODO: Use the current design or save the user choice into IpMemoryStore.
         if (always) {
-            nai.asyncChannel.sendMessage(
-                    NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept));
+            nai.onSaveAcceptUnvalidated(accept);
         }
 
         if (!accept) {
             // Tell the NetworkAgent to not automatically reconnect to the network.
-            nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
+            nai.onPreventAutomaticReconnect();
             // Tear down the network.
             teardownUnneededNetwork(nai);
         } else {
@@ -3996,7 +3994,7 @@
 
     private void rematchForAvoidBadWifiUpdate() {
         rematchAllNetworksAndRequests();
-        for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
+        for (NetworkAgentInfo nai: mNetworkAgentInfos) {
             if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                 sendUpdatedScoreToFactories(nai);
             }
@@ -4139,7 +4137,7 @@
         // to a network that provides no or limited connectivity is not useful, because the user
         // cannot use that network except through the notification shown by this method, and the
         // notification is only shown if the network is explicitly selected by the user.
-        nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
+        nai.onPreventAutomaticReconnect();
 
         // TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when
         // NetworkMonitor detects the network is partial connectivity. Need to change the design to
@@ -4789,7 +4787,7 @@
                 return new VpnInfo[0];
             }
             List<VpnInfo> infoList = new ArrayList<>();
-            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
                 VpnInfo info = createVpnInfo(nai);
                 if (info != null) {
                     infoList.add(info);
@@ -4890,7 +4888,7 @@
      */
     private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) {
         ensureRunningOnConnectivityServiceThread();
-        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (NetworkAgentInfo nai : mNetworkAgentInfos) {
             if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) {
                 updateCapabilitiesForNetwork(nai);
             }
@@ -5591,7 +5589,7 @@
         mAppOpsManager.checkPackage(callerUid, callerPackageName);
     }
 
-    private ArrayList<Integer> getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
+    private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
         final SortedSet<Integer> thresholds = new TreeSet<>();
         synchronized (nai) {
             for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -5603,14 +5601,13 @@
                 }
             }
         }
-        return new ArrayList<>(thresholds);
+        // TODO: use NetworkStackUtils.convertToIntArray after moving it
+        return ArrayUtils.convertToIntArray(new ArrayList<>(thresholds));
     }
 
     private void updateSignalStrengthThresholds(
             NetworkAgentInfo nai, String reason, NetworkRequest request) {
-        ArrayList<Integer> thresholdsArray = getSignalStrengthThresholds(nai);
-        Bundle thresholds = new Bundle();
-        thresholds.putIntegerArrayList("thresholds", thresholdsArray);
+        final int[] thresholdsArray = getSignalStrengthThresholds(nai);
 
         if (VDBG || (DBG && !"CONNECT".equals(reason))) {
             String detail;
@@ -5620,12 +5617,10 @@
                 detail = reason;
             }
             log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s",
-                    detail, Arrays.toString(thresholdsArray.toArray()), nai.toShortString()));
+                    detail, Arrays.toString(thresholdsArray), nai.toShortString()));
         }
 
-        nai.asyncChannel.sendMessage(
-                android.net.NetworkAgent.CMD_SET_SIGNAL_STRENGTH_THRESHOLDS,
-                0, 0, thresholds);
+        nai.onSignalStrengthThresholdsUpdated(thresholdsArray);
     }
 
     private void ensureValidNetworkSpecifier(NetworkCapabilities nc) {
@@ -5735,7 +5730,7 @@
             nai = mNetworkForNetId.get(network.getNetId());
         }
         if (nai != null) {
-            nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
+            nai.onBandwidthUpdateRequested();
             synchronized (mBandwidthRequests) {
                 final int uid = mDeps.getCallingUid();
                 Integer uidReqs = mBandwidthRequests.get(uid);
@@ -5978,7 +5973,7 @@
     // NetworkAgentInfo keyed off its connecting messenger
     // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
     // NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
-    private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos = new HashMap<>();
+    private final ArraySet<NetworkAgentInfo> mNetworkAgentInfos = new ArraySet<>();
 
     @GuardedBy("mBlockedAppUids")
     private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
@@ -6026,17 +6021,17 @@
     /**
      * Register a new agent. {@see #registerNetworkAgent} below.
      */
-    public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+    public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig) {
-        return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
+        return registerNetworkAgent(na, networkInfo, linkProperties, networkCapabilities,
                 currentScore, networkAgentConfig, NetworkProvider.ID_NONE);
     }
 
     /**
      * Register a new agent with ConnectivityService to handle a network.
      *
-     * @param messenger a messenger for ConnectivityService to contact the agent asynchronously.
+     * @param na a reference for ConnectivityService to contact the agent asynchronously.
      * @param networkInfo the initial info associated with this network. It can be updated later :
      *         see {@link #updateNetworkInfo}.
      * @param linkProperties the initial link properties of this network. They can be updated
@@ -6049,7 +6044,7 @@
      * @param providerId the ID of the provider owning this NetworkAgent.
      * @return the network created for this agent.
      */
-    public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+    public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
         if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
@@ -6061,14 +6056,14 @@
         final int uid = mDeps.getCallingUid();
         final long token = Binder.clearCallingIdentity();
         try {
-            return registerNetworkAgentInternal(messenger, networkInfo, linkProperties,
+            return registerNetworkAgentInternal(na, networkInfo, linkProperties,
                     networkCapabilities, currentScore, networkAgentConfig, providerId, uid);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
-    private Network registerNetworkAgentInternal(Messenger messenger, NetworkInfo networkInfo,
+    private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) {
         if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
@@ -6084,7 +6079,7 @@
         // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
         // satisfies mDefaultRequest.
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
-        final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
+        final NetworkAgentInfo nai = new NetworkAgentInfo(na,
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
                 currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
                 this, mNetd, mDnsResolver, mNMS, providerId, uid);
@@ -6102,7 +6097,7 @@
                 nai.network, name, new NetworkMonitorCallbacks(nai));
         // NetworkAgentInfo registration will finish when the NetworkMonitor is created.
         // If the network disconnects or sends any other event before that, messages are deferred by
-        // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
+        // NetworkAgent until nai.connect(), which will be called when finalizing the
         // registration.
         return nai.network;
     }
@@ -6110,7 +6105,7 @@
     private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
         nai.onNetworkMonitorCreated(networkMonitor);
         if (VDBG) log("Got NetworkAgent Messenger");
-        mNetworkAgentInfos.put(nai.messenger, nai);
+        mNetworkAgentInfos.add(nai);
         synchronized (mNetworkForNetId) {
             mNetworkForNetId.put(nai.network.getNetId(), nai);
         }
@@ -6120,7 +6115,7 @@
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
-        nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
+        nai.notifyRegistered();
         NetworkInfo networkInfo = nai.networkInfo;
         updateNetworkInfo(nai, networkInfo);
         updateUids(nai, null, nai.networkCapabilities);
@@ -6933,7 +6928,7 @@
                 break;
             }
         }
-        nai.asyncChannel.disconnect();
+        nai.disconnect();
     }
 
     private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
@@ -7123,7 +7118,7 @@
 
         // Gather the list of all relevant agents and sort them by score.
         final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
-        for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
             if (!nai.everConnected) continue;
             nais.add(nai);
         }
@@ -7158,7 +7153,7 @@
 
     private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
             final long now) {
-        final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos.values();
+        final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos;
 
         // Since most of the time there are only 0 or 1 background networks, it would probably
         // be more efficient to just use an ArrayList here. TODO : measure performance
@@ -7251,7 +7246,7 @@
         updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
 
         // Tear down all unneeded networks.
-        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (NetworkAgentInfo nai : mNetworkAgentInfos) {
             if (unneeded(nai, UnneededFor.TEARDOWN)) {
                 if (nai.getLingerExpiry() > 0) {
                     // This network has active linger timers and no requests, but is not
@@ -7488,7 +7483,7 @@
             // This has to happen after matching the requests, because callbacks are just requests.
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
         } else if (state == NetworkInfo.State.DISCONNECTED) {
-            networkAgent.asyncChannel.disconnect();
+            networkAgent.disconnect();
             if (networkAgent.isVPN()) {
                 updateUids(networkAgent, networkAgent.networkCapabilities, null);
             }
@@ -7576,7 +7571,7 @@
      * @param newRules The new rules to apply.
      */
     private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
-        for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
             final boolean metered = nai.networkCapabilities.isMetered();
             final boolean oldBlocked, newBlocked;
             // TODO: Consider that doze mode or turn on/off battery saver would deliver lots of uid
@@ -7682,7 +7677,7 @@
         ensureRunningOnConnectivityServiceThread();
         ArrayList<Network> defaultNetworks = new ArrayList<>();
         NetworkAgentInfo defaultNetwork = getDefaultNetwork();
-        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+        for (NetworkAgentInfo nai : mNetworkAgentInfos) {
             if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) {
                 defaultNetworks.add(nai.network);
             }
@@ -8233,6 +8228,13 @@
         final IBinder iCb = cb.asBinder();
         final NetworkRequestInfo nri = cbInfo.mRequestInfo;
 
+        // Connectivity Diagnostics are meant to be used with a single network request. It would be
+        // confusing for these networks to change when an NRI is satisfied in another layer.
+        if (nri.isMultilayerRequest()) {
+            throw new IllegalArgumentException("Connectivity Diagnostics do not support multilayer "
+                + "network requests.");
+        }
+
         // This means that the client registered the same callback multiple times. Do
         // not override the previous entry, and exit silently.
         if (mConnectivityDiagnosticsCallbacks.containsKey(iCb)) {
@@ -8259,7 +8261,8 @@
         synchronized (mNetworkForNetId) {
             for (int i = 0; i < mNetworkForNetId.size(); i++) {
                 final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
-                if (nai.satisfies(nri.request)) {
+                // Connectivity Diagnostics rejects multilayer requests at registration hence get(0)
+                if (nai.satisfies(nri.mRequests.get(0))) {
                     matchingNetworks.add(nai);
                 }
             }
@@ -8387,7 +8390,8 @@
                 mConnectivityDiagnosticsCallbacks.entrySet()) {
             final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue();
             final NetworkRequestInfo nri = cbInfo.mRequestInfo;
-            if (nai.satisfies(nri.request)) {
+            // Connectivity Diagnostics rejects multilayer requests at registration hence get(0).
+            if (nai.satisfies(nri.mRequests.get(0))) {
                 if (checkConnectivityDiagnosticsPermissions(
                         nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
                     results.add(entry.getValue().mCb);
@@ -8416,7 +8420,7 @@
             return false;
         }
 
-        for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) {
+        for (NetworkAgentInfo virtual : mNetworkAgentInfos) {
             if (virtual.supportsUnderlyingNetworks()
                     && virtual.networkCapabilities.getOwnerUid() == callbackUid
                     && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index 2bc8925..f701688 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -20,7 +20,6 @@
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
 
 import android.content.Context;
-import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.os.INetworkManagementService;
 import android.os.ServiceManager;
@@ -38,7 +37,7 @@
         super(context);
         // TODO: Define formal APIs to get the needed services.
         mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
-                getNetworkStatsService(), getNetworkPolicyManager());
+                getNetworkStatsService());
     }
 
     @Override
@@ -57,10 +56,4 @@
         return INetworkStatsService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
     }
-
-    private INetworkPolicyManager getNetworkPolicyManager() {
-        return INetworkPolicyManager.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
-    }
-
 }
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 500e768..f2b63a6 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -236,4 +236,9 @@
             throw new RuntimeException(e.toString());
         }
     }
+
+    @Override
+    public long suggestScratchSize() throws RemoteException {
+        return getGsiService().suggestScratchSize();
+    }
 }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 85523f7..bf53f28 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -14,6 +14,9 @@
 # Sensor Privacy
 per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
 
+# ServiceWatcher
+per-file ServiceWatcher.java = sooniln@google.com
+
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
 per-file *AppOp* = file:/core/java/android/permission/OWNERS
 per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
@@ -23,6 +26,7 @@
 per-file *Storage* = file:/core/java/android/os/storage/OWNERS
 per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS
 per-file ConnectivityService.java = file:/services/core/java/com/android/server/net/OWNERS
+per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS
 per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
 per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWNERS
 per-file MmsServiceBroker.java = file:/telephony/OWNERS
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index dd497a6..c8d457d 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3298,6 +3298,9 @@
             try {
                 mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
                         encodeBytes(secret));
+            } catch (ServiceSpecificException sse) {
+                Slog.d(TAG, "Expected if the user has not unlocked the device.", sse);
+                return;
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
                 return;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e4cdfe9..7e67f97 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10459,12 +10459,10 @@
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
-        if (uid == Process.INVALID_UID) {
-            return Process.INVALID_UID;
-        }
+        // If the uid is Process.INVALID_UID, the below 'if' check will be always true
         if (UserHandle.getAppId(uid) != UserHandle.getAppId(callingUid)) {
             // Requires the DUMP permission if the target package doesn't belong
-            // to the caller.
+            // to the caller or it doesn't exist.
             enforceCallingPermission(android.Manifest.permission.DUMP, function);
         }
         return uid;
@@ -13744,6 +13742,10 @@
                 // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
                 kernelUsed += ionHeap;
             }
+            final long gpuUsage = Debug.getGpuTotalUsageKb();
+            if (gpuUsage >= 0) {
+                pw.print("      GPU: "); pw.println(stringifyKBSize(gpuUsage));
+            }
             final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
                     - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
                     - kernelUsed - memInfo.getZramTotalSizeKb();
@@ -14552,6 +14554,12 @@
             // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
             kernelUsed += ionHeap;
         }
+        final long gpuUsage = Debug.getGpuTotalUsageKb();
+        if (gpuUsage >= 0) {
+            memInfoBuilder.append("       GPU: ");
+            memInfoBuilder.append(stringifyKBSize(gpuUsage));
+            memInfoBuilder.append("\n");
+        }
         memInfoBuilder.append("  Used RAM: ");
         memInfoBuilder.append(stringifyKBSize(
                                   totalPss - cachedPss + kernelUsed));
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index ef1b574..b4d74e0 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -16,16 +16,22 @@
 
 package com.android.server.biometrics;
 
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.security.KeyStore;
+import android.util.EventLog;
 import android.util.Slog;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A class to keep track of the authentication state for a given client.
@@ -148,7 +154,54 @@
                     + ", requireConfirmation: " + mRequireConfirmation
                     + ", user: " + getTargetUserId());
 
+            // Ensure authentication only succeeds if the client activity is on top or is keyguard.
+            boolean isBackgroundAuth = false;
+            if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) {
+                try {
+                    final List<ActivityManager.RunningTaskInfo> tasks =
+                            ActivityTaskManager.getService().getTasks(1);
+                    if (tasks == null || tasks.isEmpty()) {
+                        Slog.e(TAG, "No running tasks reported");
+                        isBackgroundAuth = true;
+                    } else {
+                        final ComponentName topActivity = tasks.get(0).topActivity;
+                        if (topActivity == null) {
+                            Slog.e(TAG, "Unable to get top activity");
+                            isBackgroundAuth = true;
+                        } else {
+                            final String topPackage = topActivity.getPackageName();
+                            if (!topPackage.contentEquals(getOwnerString())) {
+                                Slog.e(TAG, "Background authentication detected, top: " + topPackage
+                                        + ", client: " + this);
+                                isBackgroundAuth = true;
+                            }
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to get running tasks", e);
+                    isBackgroundAuth = true;
+                }
+            }
+
+            // Fail authentication if we can't confirm the client activity is on top.
+            if (isBackgroundAuth) {
+                Slog.e(TAG, "Failing possible background authentication");
+                authenticated = false;
+
+                // SafetyNet logging for exploitation attempts of b/159249069.
+                final ApplicationInfo appInfo = getContext().getApplicationInfo();
+                EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
+                        "Attempted background authentication");
+            }
+
             if (authenticated) {
+                // SafetyNet logging for b/159249069 if constraint is violated.
+                if (isBackgroundAuth) {
+                    final ApplicationInfo appInfo = getContext().getApplicationInfo();
+                    EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1,
+                            "Successful background authentication!");
+                }
+
                 mAlreadyDone = true;
 
                 if (listener != null) {
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 96cbfde..34d9ccc 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -18,10 +18,7 @@
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.NattSocketKeepalive.NATT_PORT;
-import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER;
-import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER;
 import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
-import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
 import static android.net.SocketKeepalive.BINDER_DIED;
 import static android.net.SocketKeepalive.DATA_RECEIVED;
 import static android.net.SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES;
@@ -330,10 +327,9 @@
                 Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.toShortString());
                 switch (mType) {
                     case TYPE_NATT:
-                        mNai.asyncChannel.sendMessage(
-                                CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket);
-                        mNai.asyncChannel
-                                .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
+                        final NattKeepalivePacketData nattData = (NattKeepalivePacketData) mPacket;
+                        mNai.onAddNattKeepalivePacketFilter(slot, nattData);
+                        mNai.onStartNattSocketKeepalive(slot, mInterval, nattData);
                         break;
                     case TYPE_TCP:
                         try {
@@ -342,11 +338,10 @@
                             handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET);
                             return;
                         }
-                        mNai.asyncChannel.sendMessage(
-                                CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket);
+                        final TcpKeepalivePacketData tcpData = (TcpKeepalivePacketData) mPacket;
+                        mNai.onAddTcpKeepalivePacketFilter(slot, tcpData);
                         // TODO: check result from apf and notify of failure as needed.
-                        mNai.asyncChannel
-                                .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
+                        mNai.onStartTcpSocketKeepalive(slot, mInterval, tcpData);
                         break;
                     default:
                         Log.wtf(TAG, "Starting keepalive with unknown type: " + mType);
@@ -394,9 +389,8 @@
                             mTcpController.stopSocketMonitor(mSlot);
                             // fall through
                         case TYPE_NATT:
-                            mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
-                            mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
-                                    mSlot);
+                            mNai.onStopSocketKeepalive(mSlot);
+                            mNai.onRemoveKeepalivePacketFilter(mSlot);
                             break;
                         default:
                             Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
@@ -548,17 +542,13 @@
     }
 
     /** Handle keepalive events from lower layer. */
-    public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai,
-            @NonNull Message message) {
-        int slot = message.arg1;
-        int reason = message.arg2;
-
+    public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
         KeepaliveInfo ki = null;
         try {
             ki = mKeepalives.get(nai).get(slot);
         } catch(NullPointerException e) {}
         if (ki == null) {
-            Log.e(TAG, "Event " + message.what + "," + slot + "," + reason
+            Log.e(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
                     + " for unknown keepalive " + slot + " on " + nai.toShortString());
             return;
         }
@@ -601,7 +591,7 @@
             ki.mStartedState = KeepaliveInfo.NOT_STARTED;
             cleanupStoppedKeepalive(nai, slot);
         } else {
-            Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason
+            Log.wtf(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
                     + " for keepalive in wrong state: " + ki.toString());
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 52b9f5c..841c970 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -27,25 +27,35 @@
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.LinkProperties;
+import android.net.NattKeepalivePacketData;
 import android.net.Network;
+import android.net.NetworkAgent;
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkMonitorManager;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
+import android.net.TcpKeepalivePacketData;
+import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.INetworkManagementService;
-import android.os.Messenger;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
-import com.android.internal.util.AsyncChannel;
+import com.android.connectivity.aidl.INetworkAgent;
+import com.android.connectivity.aidl.INetworkAgentRegistry;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.ConnectivityService;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -221,6 +231,31 @@
      */
     public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001;
 
+    /**
+     * Inform ConnectivityService that the agent is half-connected.
+     * arg1 = ARG_AGENT_SUCCESS or ARG_AGENT_FAILURE
+     * obj = NetworkAgentInfo
+     * @hide
+     */
+    public static final int EVENT_AGENT_REGISTERED = 1002;
+
+    /**
+     * Inform ConnectivityService that the agent was disconnected.
+     * obj = NetworkAgentInfo
+     * @hide
+     */
+    public static final int EVENT_AGENT_DISCONNECTED = 1003;
+
+    /**
+     * Argument for EVENT_AGENT_HALF_CONNECTED indicating failure.
+     */
+    public static final int ARG_AGENT_FAILURE = 0;
+
+    /**
+     * Argument for EVENT_AGENT_HALF_CONNECTED indicating success.
+     */
+    public static final int ARG_AGENT_SUCCESS = 1;
+
     // All linger timers for this network, sorted by expiry time. A linger timer is added whenever
     // a request is moved to a network with a better score, regardless of whether the network is or
     // was lingering or not.
@@ -262,8 +297,9 @@
     // report is generated. Once non-null, it will never be null again.
     @Nullable private ConnectivityReport mConnectivityReport;
 
-    public final Messenger messenger;
-    public final AsyncChannel asyncChannel;
+    public final INetworkAgent networkAgent;
+    // Only accessed from ConnectivityService handler thread
+    private final AgentDeathMonitor mDeathMonitor = new AgentDeathMonitor();
 
     public final int factorySerialNumber;
 
@@ -279,13 +315,12 @@
     private final Context mContext;
     private final Handler mHandler;
 
-    public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
+    public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
             int creatorUid) {
-        this.messenger = messenger;
-        asyncChannel = ac;
+        networkAgent = na;
         network = net;
         networkInfo = info;
         linkProperties = lp;
@@ -300,6 +335,249 @@
         this.creatorUid = creatorUid;
     }
 
+    private class AgentDeathMonitor implements IBinder.DeathRecipient {
+        @Override
+        public void binderDied() {
+            notifyDisconnected();
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that it was registered, and should be unregistered if it dies.
+     *
+     * Must be called from the ConnectivityService handler thread. A NetworkAgent can only be
+     * registered once.
+     */
+    public void notifyRegistered() {
+        try {
+            networkAgent.asBinder().linkToDeath(mDeathMonitor, 0);
+            networkAgent.onRegistered(new NetworkAgentMessageHandler(mHandler));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error registering NetworkAgent", e);
+            maybeUnlinkDeathMonitor();
+            mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_FAILURE, 0, this)
+                    .sendToTarget();
+            return;
+        }
+
+        mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_SUCCESS, 0, this).sendToTarget();
+    }
+
+    /**
+     * Disconnect the NetworkAgent. Must be called from the ConnectivityService handler thread.
+     */
+    public void disconnect() {
+        try {
+            networkAgent.onDisconnected();
+        } catch (RemoteException e) {
+            Log.i(TAG, "Error disconnecting NetworkAgent", e);
+            // Fall through: it's fine if the remote has died
+        }
+
+        notifyDisconnected();
+        maybeUnlinkDeathMonitor();
+    }
+
+    private void maybeUnlinkDeathMonitor() {
+        try {
+            networkAgent.asBinder().unlinkToDeath(mDeathMonitor, 0);
+        } catch (NoSuchElementException e) {
+            // Was not linked: ignore
+        }
+    }
+
+    private void notifyDisconnected() {
+        // Note this may be called multiple times if ConnectivityService disconnects while the
+        // NetworkAgent also dies. ConnectivityService ignores disconnects of already disconnected
+        // agents.
+        mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED, this).sendToTarget();
+    }
+
+    /**
+     * Notify the NetworkAgent that bandwidth update was requested.
+     */
+    public void onBandwidthUpdateRequested() {
+        try {
+            networkAgent.onBandwidthUpdateRequested();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending bandwidth update request event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that validation status has changed.
+     */
+    public void onValidationStatusChanged(int validationStatus, @Nullable String captivePortalUrl) {
+        try {
+            networkAgent.onValidationStatusChanged(validationStatus, captivePortalUrl);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending validation status change event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that the acceptUnvalidated setting should be saved.
+     */
+    public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) {
+        try {
+            networkAgent.onSaveAcceptUnvalidated(acceptUnvalidated);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending accept unvalidated event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that NATT socket keepalive should be started.
+     */
+    public void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
+            @NonNull NattKeepalivePacketData packetData) {
+        try {
+            networkAgent.onStartNattSocketKeepalive(slot, intervalDurationMs, packetData);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending NATT socket keepalive start event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that TCP socket keepalive should be started.
+     */
+    public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
+            @NonNull TcpKeepalivePacketData packetData) {
+        try {
+            networkAgent.onStartTcpSocketKeepalive(slot, intervalDurationMs, packetData);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending TCP socket keepalive start event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that socket keepalive should be stopped.
+     */
+    public void onStopSocketKeepalive(int slot) {
+        try {
+            networkAgent.onStopSocketKeepalive(slot);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending TCP socket keepalive stop event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that signal strength thresholds should be updated.
+     */
+    public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
+        try {
+            networkAgent.onSignalStrengthThresholdsUpdated(thresholds);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending signal strength thresholds event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that automatic reconnect should be prevented.
+     */
+    public void onPreventAutomaticReconnect() {
+        try {
+            networkAgent.onPreventAutomaticReconnect();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending prevent automatic reconnect event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that a NATT keepalive packet filter should be added.
+     */
+    public void onAddNattKeepalivePacketFilter(int slot,
+            @NonNull NattKeepalivePacketData packetData) {
+        try {
+            networkAgent.onAddNattKeepalivePacketFilter(slot, packetData);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending add NATT keepalive packet filter event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that a TCP keepalive packet filter should be added.
+     */
+    public void onAddTcpKeepalivePacketFilter(int slot,
+            @NonNull TcpKeepalivePacketData packetData) {
+        try {
+            networkAgent.onAddTcpKeepalivePacketFilter(slot, packetData);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending add TCP keepalive packet filter event", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that a keepalive packet filter should be removed.
+     */
+    public void onRemoveKeepalivePacketFilter(int slot) {
+        try {
+            networkAgent.onRemoveKeepalivePacketFilter(slot);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending remove keepalive packet filter event", e);
+        }
+    }
+
+    // TODO: consider moving out of NetworkAgentInfo into its own class
+    private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
+        private final Handler mHandler;
+
+        private NetworkAgentMessageHandler(Handler handler) {
+            mHandler = handler;
+        }
+
+        @Override
+        public void sendNetworkCapabilities(NetworkCapabilities nc) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED,
+                    new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget();
+        }
+
+        @Override
+        public void sendLinkProperties(LinkProperties lp) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED,
+                    new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget();
+        }
+
+        @Override
+        public void sendNetworkInfo(NetworkInfo info) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,
+                    new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
+        }
+
+        @Override
+        public void sendScore(int score) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED, score, 0,
+                    new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+        }
+
+        @Override
+        public void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED,
+                    explicitlySelected ? 1 : 0, acceptPartial ? 1 : 0,
+                    new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+        }
+
+        @Override
+        public void sendSocketKeepaliveEvent(int slot, int reason) {
+            mHandler.obtainMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE,
+                    slot, reason, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+        }
+
+        @Override
+        public void sendUnderlyingNetworks(@Nullable List<Network> networks) {
+            final Bundle args = new Bundle();
+            if (networks instanceof ArrayList<?>) {
+                args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
+                        (ArrayList<Network>) networks);
+            } else {
+                args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
+                        networks == null ? null : new ArrayList<>(networks));
+            }
+            mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED,
+                    new Pair<>(NetworkAgentInfo.this, args)).sendToTarget();
+        }
+    }
+
     /**
      * Inform NetworkAgentInfo that a new NetworkMonitor was created.
      */
diff --git a/services/core/java/com/android/server/location/timezone/OWNERS b/services/core/java/com/android/server/location/timezone/OWNERS
new file mode 100644
index 0000000..28aff18
--- /dev/null
+++ b/services/core/java/com/android/server/location/timezone/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+nfuller@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c121d24..a7b9622 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -331,6 +331,7 @@
 import com.android.internal.os.Zygote;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
@@ -12455,12 +12456,17 @@
                 mPermissionManager.addAllPermissionGroups(pkg, chatty);
             }
 
+            // If a permission has had its defining app changed, or it has had its protection
+            // upgraded, we need to revoke apps that hold it
+            final List<String> permissionsWithChangedDefinition;
             // Don't allow ephemeral applications to define new permissions.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
+                permissionsWithChangedDefinition = null;
                 Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
                         + " ignored: instant apps cannot define new permissions.");
             } else {
-                mPermissionManager.addAllPermissions(pkg, chatty);
+                permissionsWithChangedDefinition =
+                        mPermissionManager.addAllPermissions(pkg, chatty);
             }
 
             int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
@@ -12489,7 +12495,10 @@
                 }
             }
 
-            if (oldPkg != null) {
+            boolean hasOldPkg = oldPkg != null;
+            boolean hasPermissionDefinitionChanges =
+                    !CollectionUtils.isEmpty(permissionsWithChangedDefinition);
+            if (hasOldPkg || hasPermissionDefinitionChanges) {
                 // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
                 // revoke callbacks from this method might need to kill apps which need the
                 // mPackages lock on a different thread. This would dead lock.
@@ -12500,9 +12509,16 @@
                 // won't be granted yet, hence new packages are no problem.
                 final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
 
-                AsyncTask.execute(() ->
+                AsyncTask.execute(() -> {
+                    if (hasOldPkg) {
                         mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
-                                allPackageNames));
+                                allPackageNames);
+                    }
+                    if (hasPermissionDefinitionChanges) {
+                        mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                                permissionsWithChangedDefinition, allPackageNames);
+                    }
+                });
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f5d7d9e..9aa47a6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3724,7 +3724,7 @@
     UserData putUserInfo(UserInfo userInfo) {
         final UserData userData = new UserData();
         userData.info = userInfo;
-        synchronized (mUsers) {
+        synchronized (mUsersLock) {
             mUsers.put(userInfo.id, userData);
         }
         return userData;
@@ -3732,7 +3732,7 @@
 
     @VisibleForTesting
     void removeUserInfo(@UserIdInt int userId) {
-        synchronized (mUsers) {
+        synchronized (mUsersLock) {
             mUsers.remove(userId);
         }
     }
@@ -4052,7 +4052,7 @@
         userFile.delete();
         updateUserIds();
         if (RELEASE_DELETED_USER_ID) {
-            synchronized (mUsers) {
+            synchronized (mUsersLock) {
                 mRemovingUserIds.delete(userId);
             }
         }
@@ -5183,6 +5183,9 @@
                                 debugMsg + " for another profile "
                                         + targetUserId + " from " + callingUserId);
                     }
+                    Slog.w(LOG_TAG, debugMsg + " for another profile "
+                            + targetUserId + " from " + callingUserId);
+                    return false;
                 }
 
                 UserInfo targetUserInfo = getUserInfoLU(targetUserId);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index cfa0449..5e04171 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -83,6 +83,8 @@
 
     final @PermissionType int type;
 
+    private boolean mPermissionDefinitionChanged;
+
     String sourcePackageName;
 
     int protectionLevel;
@@ -126,6 +128,11 @@
     public String getSourcePackageName() {
         return sourcePackageName;
     }
+
+    public boolean isPermissionDefinitionChanged() {
+        return mPermissionDefinitionChanged;
+    }
+
     public int getType() {
         return type;
     }
@@ -140,6 +147,10 @@
         this.perm = perm;
     }
 
+    public void setPermissionDefinitionChanged(boolean shouldOverride) {
+        mPermissionDefinitionChanged = shouldOverride;
+    }
+
     public int[] computeGids(int userId) {
         if (perUser) {
             final int[] userGids = new int[gids.length];
@@ -322,6 +333,7 @@
         final PackageSettingBase pkgSetting =
                 (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName());
         // Allow system apps to redefine non-system permissions
+        boolean ownerChanged = false;
         if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) {
             final boolean currentOwnerIsSystem;
             if (bp.perm == null) {
@@ -347,6 +359,7 @@
                     String msg = "New decl " + pkg + " of permission  "
                             + p.getName() + " is system; overriding " + bp.sourcePackageName;
                     PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    ownerChanged = true;
                     bp = null;
                 }
             }
@@ -354,6 +367,7 @@
         if (bp == null) {
             bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL);
         }
+        boolean wasNonRuntime = !bp.isRuntime();
         StringBuilder r = null;
         if (bp.perm == null) {
             if (bp.sourcePackageName == null
@@ -397,6 +411,11 @@
                 && Objects.equals(bp.perm.getName(), p.getName())) {
             bp.protectionLevel = p.getProtectionLevel();
         }
+        if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) {
+            // If this is a runtime permission and the owner has changed, or this was a normal
+            // permission, then permission state should be cleaned up
+            bp.mPermissionDefinitionChanged = true;
+        }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
             Log.d(TAG, "  Permissions: " + r);
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 66d8b59..3ffca02 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2344,8 +2344,74 @@
         }
     }
 
-    private void addAllPermissions(AndroidPackage pkg, boolean chatty) {
+    /**
+     * If permissions are upgraded to runtime, or their owner changes to the system, then any
+     * granted permissions must be revoked.
+     *
+     * @param permissionsToRevoke A list of permission names to revoke
+     * @param allPackageNames All package names
+     * @param permissionCallback Callback for permission changed
+     */
+    private void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+            @NonNull List<String> permissionsToRevoke,
+            @NonNull ArrayList<String> allPackageNames,
+            @NonNull PermissionCallback permissionCallback) {
+
+        final int[] userIds = mUserManagerInt.getUserIds();
+        final int numPermissions = permissionsToRevoke.size();
+        final int numUserIds = userIds.length;
+        final int numPackages = allPackageNames.size();
+        final int callingUid = Binder.getCallingUid();
+
+        for (int permNum = 0; permNum < numPermissions; permNum++) {
+            String permName = permissionsToRevoke.get(permNum);
+            BasePermission bp = mSettings.getPermission(permName);
+            if (bp == null || !bp.isRuntime()) {
+                continue;
+            }
+            for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
+                final int userId = userIds[userIdNum];
+                for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+                    final String packageName = allPackageNames.get(packageNum);
+                    final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
+                    if (uid < Process.FIRST_APPLICATION_UID) {
+                        // do not revoke from system apps
+                        continue;
+                    }
+                    final int permissionState = checkPermissionImpl(permName, packageName,
+                            userId);
+                    final int flags = getPermissionFlags(permName, packageName, userId);
+                    final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
+                            | FLAG_PERMISSION_POLICY_FIXED
+                            | FLAG_PERMISSION_GRANTED_BY_DEFAULT
+                            | FLAG_PERMISSION_GRANTED_BY_ROLE;
+                    if (permissionState == PackageManager.PERMISSION_GRANTED
+                            && (flags & flagMask) == 0) {
+                        EventLog.writeEvent(0x534e4554, "154505240", uid,
+                                "Revoking permission " + permName + " from package "
+                                        + packageName + " due to definition change");
+                        EventLog.writeEvent(0x534e4554, "168319670", uid,
+                                "Revoking permission " + permName + " from package "
+                                        + packageName + " due to definition change");
+                        Slog.e(TAG, "Revoking permission " + permName + " from package "
+                                + packageName + " due to definition change");
+                        try {
+                            revokeRuntimePermissionInternal(permName, packageName,
+                                    false, callingUid, userId, null, permissionCallback);
+                        } catch (Exception e) {
+                            Slog.e(TAG, "Could not revoke " + permName + " from "
+                                    + packageName, e);
+                        }
+                    }
+                }
+            }
+            bp.setPermissionDefinitionChanged(false);
+        }
+    }
+
+    private List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) {
         final int N = ArrayUtils.size(pkg.getPermissions());
+        ArrayList<String> definitionChangedPermissions = new ArrayList<>();
         for (int i=0; i<N; i++) {
             ParsedPermission p = pkg.getPermissions().get(i);
 
@@ -2367,21 +2433,26 @@
                     }
                 }
 
+                final BasePermission bp;
                 if (p.isTree()) {
-                    final BasePermission bp = BasePermission.createOrUpdate(
+                    bp = BasePermission.createOrUpdate(
                             mPackageManagerInt,
                             mSettings.getPermissionTreeLocked(p.getName()), p, pkg,
                             mSettings.getAllPermissionTreesLocked(), chatty);
                     mSettings.putPermissionTreeLocked(p.getName(), bp);
                 } else {
-                    final BasePermission bp = BasePermission.createOrUpdate(
+                    bp = BasePermission.createOrUpdate(
                             mPackageManagerInt,
                             mSettings.getPermissionLocked(p.getName()),
                             p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
                     mSettings.putPermissionLocked(p.getName(), bp);
                 }
+                if (bp.isPermissionDefinitionChanged()) {
+                    definitionChangedPermissions.add(p.getName());
+                }
             }
         }
+        return definitionChangedPermissions;
     }
 
     private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
@@ -4672,9 +4743,18 @@
             PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
                     oldPackage, allPackageNames, mDefaultPermissionCallback);
         }
+
         @Override
-        public void addAllPermissions(AndroidPackage pkg, boolean chatty) {
-            PermissionManagerService.this.addAllPermissions(pkg, chatty);
+        public void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                @NonNull List<String> permissionsToRevoke,
+                @NonNull ArrayList<String> allPackageNames) {
+            PermissionManagerService.this.revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                    permissionsToRevoke, allPackageNames, mDefaultPermissionCallback);
+        }
+
+        @Override
+        public List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) {
+            return PermissionManagerService.this.addAllPermissions(pkg, chatty);
         }
         @Override
         public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 37f4059..393e852 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -254,12 +254,26 @@
             @NonNull ArrayList<String> allPackageNames);
 
     /**
+     * Some permissions might have been owned by a non-system package, and the system then defined
+     * said permission. Some other permissions may one have been install permissions, but are now
+     * runtime or higher. These permissions should be revoked.
+     *
+     * @param permissionsToRevoke A list of permission names to revoke
+     * @param allPackageNames All packages
+     */
+    public abstract void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+            @NonNull List<String> permissionsToRevoke,
+            @NonNull ArrayList<String> allPackageNames);
+
+    /**
      * Add all permissions in the given package.
      * <p>
      * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
      * the permission settings.
+     *
+     * @return A list of BasePermissions that were updated, and need to be revoked from packages
      */
-    public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
+    public abstract List<String> addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
     public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty);
     public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
 
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index ca382c4..81878e7 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -1292,7 +1292,7 @@
     private SparseIntArray getExtensionVersions() {
         // This list must be updated whenever the current API level is increased, or should be
         // replaced when we have another way of determining the relevant SDK versions.
-        final int[] relevantSdkVersions = { Build.VERSION_CODES.R };
+        final int[] relevantSdkVersions = { Build.VERSION_CODES.R, Build.VERSION_CODES.S };
 
         SparseIntArray result = new SparseIntArray(relevantSdkVersions.length);
         for (int i = 0; i < relevantSdkVersions.length; i++) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index bedcf9c..6cd0258 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -97,6 +97,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -1176,7 +1177,8 @@
             final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
                     userId, "createSession");
             final long identity = Binder.clearCallingIdentity();
-            StringBuilder sessionId = new StringBuilder();
+            // Generate a unique session id with a random UUID.
+            String uniqueSessionId = UUID.randomUUID().toString();
             try {
                 synchronized (mLock) {
                     if (userId != mCurrentUserId && !isRecordingSession) {
@@ -1205,20 +1207,17 @@
                         return;
                     }
 
-                    // Create a unique session id with pid, uid and resolved user id
-                    sessionId.append(callingUid).append(callingPid).append(resolvedUserId);
-
                     // Create a new session token and a session state.
                     IBinder sessionToken = new Binder();
                     SessionState sessionState = new SessionState(sessionToken, info.getId(),
                             info.getComponent(), isRecordingSession, client, seq, callingUid,
-                            callingPid, resolvedUserId, sessionId.toString());
+                            callingPid, resolvedUserId, uniqueSessionId);
 
                     // Add them to the global session state map of the current user.
                     userState.sessionStateMap.put(sessionToken, sessionState);
 
                     // Map the session id to the sessionStateMap in the user state
-                    mSessionIdToSessionStateMap.put(sessionId.toString(), sessionState);
+                    mSessionIdToSessionStateMap.put(uniqueSessionId, sessionState);
 
                     // Also, add them to the session state map of the current service.
                     serviceState.sessionTokens.add(sessionToken);
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 2b0fe8a..2fc17fe 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -68,6 +68,11 @@
     private Set<Integer> mUsingFrontendIds = new HashSet<>();
 
     /**
+     * List of the client ids that share frontend with the current client.
+     */
+    private Set<Integer> mShareFeClientIds = new HashSet<>();
+
+    /**
      * List of the Lnb ids that are used by the current client.
      */
     private Set<Integer> mUsingLnbIds = new HashSet<>();
@@ -113,11 +118,7 @@
     }
 
     public int getPriority() {
-        return mPriority;
-    }
-
-    public int getNiceValue() {
-        return mNiceValue;
+        return mPriority - mNiceValue;
     }
 
     public void setGroupId(int groupId) {
@@ -141,17 +142,38 @@
         mUsingFrontendIds.add(frontendId);
     }
 
+    /**
+     * Update the set of client that share frontend with the current client.
+     *
+     * @param clientId the client to share the fe with the current client.
+     */
+    public void shareFrontend(int clientId) {
+        mShareFeClientIds.add(clientId);
+    }
+
+    /**
+     * Remove the given client id from the share frontend client id set.
+     *
+     * @param clientId the client to stop sharing the fe with the current client.
+     */
+    public void stopSharingFrontend(int clientId) {
+        mShareFeClientIds.remove(clientId);
+    }
+
     public Set<Integer> getInUseFrontendIds() {
         return mUsingFrontendIds;
     }
 
+    public Set<Integer> getShareFeClientIds() {
+        return mShareFeClientIds;
+    }
+
     /**
      * Called when the client released a frontend.
-     *
-     * @param frontendId being released.
      */
-    public void releaseFrontend(int frontendId) {
-        mUsingFrontendIds.remove(frontendId);
+    public void releaseFrontend() {
+        mUsingFrontendIds.clear();
+        mShareFeClientIds.clear();
     }
 
     /**
@@ -201,6 +223,7 @@
      */
     public void reclaimAllResources() {
         mUsingFrontendIds.clear();
+        mShareFeClientIds.clear();
         mUsingLnbIds.clear();
         mUsingCasSystemId = INVALID_RESOURCE_ID;
     }
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 7cb59dc..fb2347e8 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -210,19 +210,36 @@
             }
             synchronized (mLock) {
                 if (!checkClientExists(request.getClientId())) {
-                    throw new RemoteException("Request frontend from unregistered client:"
+                    throw new RemoteException("Request frontend from unregistered client: "
                             + request.getClientId());
                 }
+                // If the request client is holding or sharing a frontend, throw an exception.
+                if (!getClientProfile(request.getClientId()).getInUseFrontendIds().isEmpty()) {
+                    throw new RemoteException("Release frontend before requesting another one. "
+                            + "Client id: " + request.getClientId());
+                }
                 return requestFrontendInternal(request, frontendHandle);
             }
         }
 
         @Override
-        public void shareFrontend(int selfClientId, int targetClientId) {
+        public void shareFrontend(int selfClientId, int targetClientId) throws RemoteException {
             enforceTunerAccessPermission("shareFrontend");
             enforceTrmAccessPermission("shareFrontend");
-            if (DEBUG) {
-                Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId);
+            synchronized (mLock) {
+                if (!checkClientExists(selfClientId)) {
+                    throw new RemoteException("Share frontend request from an unregistered client:"
+                            + selfClientId);
+                }
+                if (!checkClientExists(targetClientId)) {
+                    throw new RemoteException("Request to share frontend with an unregistered "
+                            + "client:" + targetClientId);
+                }
+                if (getClientProfile(targetClientId).getInUseFrontendIds().isEmpty()) {
+                    throw new RemoteException("Request to share frontend with a client that has no "
+                            + "frontend resources. Target client id:" + targetClientId);
+                }
+                shareFrontendInternal(selfClientId, targetClientId);
             }
         }
 
@@ -315,7 +332,7 @@
                     throw new RemoteException(
                             "Client is not the current owner of the releasing fe.");
                 }
-                releaseFrontendInternal(fe);
+                releaseFrontendInternal(fe, clientId);
             }
         }
 
@@ -649,6 +666,17 @@
     }
 
     @VisibleForTesting
+    protected void shareFrontendInternal(int selfClientId, int targetClientId) {
+        if (DEBUG) {
+            Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId);
+        }
+        for (int feId : getClientProfile(targetClientId).getInUseFrontendIds()) {
+            getClientProfile(selfClientId).useFrontend(feId);
+        }
+        getClientProfile(targetClientId).shareFrontend(selfClientId);
+    }
+
+    @VisibleForTesting
     protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle) {
         if (DEBUG) {
             Slog.d(TAG, "requestLnb(request=" + request + ")");
@@ -777,11 +805,17 @@
     }
 
     @VisibleForTesting
-    protected void releaseFrontendInternal(FrontendResource fe) {
+    protected void releaseFrontendInternal(FrontendResource fe, int clientId) {
         if (DEBUG) {
-            Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ")");
+            Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ", clientId=" + clientId + " )");
         }
-        updateFrontendClientMappingOnRelease(fe);
+        if (clientId == fe.getOwnerClientId()) {
+            ClientProfile ownerClient = getClientProfile(fe.getOwnerClientId());
+            for (int shareOwnerId : ownerClient.getShareFeClientIds()) {
+                clearFrontendAndClientMapping(getClientProfile(shareOwnerId));
+            }
+        }
+        clearFrontendAndClientMapping(getClientProfile(clientId));
     }
 
     @VisibleForTesting
@@ -882,8 +916,21 @@
             Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingClientId, e);
             return false;
         }
+
+        // Reclaim all the resources of the share owners of the frontend that is used by the current
+        // resource reclaimed client.
         ClientProfile profile = getClientProfile(reclaimingClientId);
-        reclaimingResourcesFromClient(profile);
+        Set<Integer> shareFeClientIds = profile.getShareFeClientIds();
+        for (int clientId : shareFeClientIds) {
+            try {
+                mListeners.get(clientId).getListener().onReclaimResources();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to reclaim resources on client " + clientId, e);
+                return false;
+            }
+            clearAllResourcesAndClientMapping(getClientProfile(clientId));
+        }
+        clearAllResourcesAndClientMapping(profile);
         return true;
     }
 
@@ -929,16 +976,6 @@
         }
     }
 
-    private void updateFrontendClientMappingOnRelease(@NonNull FrontendResource releasingFrontend) {
-        ClientProfile ownerProfile = getClientProfile(releasingFrontend.getOwnerClientId());
-        releasingFrontend.removeOwner();
-        ownerProfile.releaseFrontend(releasingFrontend.getId());
-        for (int exclusiveGroupMember : releasingFrontend.getExclusiveGroupMemberFeIds()) {
-            getFrontendResource(exclusiveGroupMember).removeOwner();
-            ownerProfile.releaseFrontend(exclusiveGroupMember);
-        }
-    }
-
     private void updateLnbClientMappingOnNewGrant(int grantingId, int ownerClientId) {
         LnbResource grantingLnb = getLnbResource(grantingId);
         ClientProfile ownerProfile = getClientProfile(ownerClientId);
@@ -967,10 +1004,10 @@
     }
 
     /**
-     * Get the owner client's priority from the resource id.
+     * Get the owner client's priority.
      *
      * @param clientId the owner client id.
-     * @return the priority of the owner client of the resource.
+     * @return the priority of the owner client.
      */
     private int getOwnerClientPriority(int clientId) {
         return getClientProfile(clientId).getPriority();
@@ -1011,7 +1048,11 @@
             return;
         }
         if (fe.isInUse()) {
-            releaseFrontendInternal(fe);
+            ClientProfile ownerClient = getClientProfile(fe.getOwnerClientId());
+            for (int shareOwnerId : ownerClient.getShareFeClientIds()) {
+                clearFrontendAndClientMapping(getClientProfile(shareOwnerId));
+            }
+            clearFrontendAndClientMapping(ownerClient);
         }
         for (int excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
             getFrontendResource(excGroupmemberFeId)
@@ -1093,21 +1134,37 @@
     }
 
     private void removeClientProfile(int clientId) {
-        reclaimingResourcesFromClient(getClientProfile(clientId));
+        for (int shareOwnerId : getClientProfile(clientId).getShareFeClientIds()) {
+            clearFrontendAndClientMapping(getClientProfile(shareOwnerId));
+        }
+        clearAllResourcesAndClientMapping(getClientProfile(clientId));
         mClientProfiles.remove(clientId);
         mListeners.remove(clientId);
     }
 
-    private void reclaimingResourcesFromClient(ClientProfile profile) {
+    private void clearFrontendAndClientMapping(ClientProfile profile) {
         for (Integer feId : profile.getInUseFrontendIds()) {
-            getFrontendResource(feId).removeOwner();
+            FrontendResource fe = getFrontendResource(feId);
+            if (fe.getOwnerClientId() == profile.getId()) {
+                fe.removeOwner();
+                continue;
+            }
+            getClientProfile(fe.getOwnerClientId()).stopSharingFrontend(profile.getId());
         }
+        profile.releaseFrontend();
+    }
+
+    private void clearAllResourcesAndClientMapping(ClientProfile profile) {
+        // Clear Lnb
         for (Integer lnbId : profile.getInUseLnbIds()) {
             getLnbResource(lnbId).removeOwner();
         }
+        // Clear Cas
         if (profile.getInUseCasSystemId() != ClientProfile.INVALID_RESOURCE_ID) {
             getCasResource(profile.getInUseCasSystemId()).removeOwner(profile.getId());
         }
+        // Clear Frontend
+        clearFrontendAndClientMapping(profile);
         profile.reclaimAllResources();
     }
 
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 0034286..f076ca9 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -46,6 +46,8 @@
 #include <utils/misc.h>
 #include <utils/Log.h>
 
+#include <android-base/strings.h>
+
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::hardware::Void;
@@ -200,67 +202,13 @@
         return 0;
     }
 
-    char* mergedreasonpos = mergedreason;
-    int i = 0;
-    for (auto wakeupReason : wakeupReasons) {
-        auto reasonline = const_cast<char*>(wakeupReason.c_str());
-        char* pos = reasonline;
-        char* endPos;
-        int len;
-        // First field is the index or 'Abort'.
-        int irq = (int)strtol(pos, &endPos, 10);
-        if (pos != endPos) {
-            // Write the irq number to the merged reason string.
-            len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%d" : ":%d", irq);
-        } else {
-            // The first field is not an irq, it may be the word Abort.
-            const size_t abortPrefixLen = strlen("Abort:");
-            if (strncmp(pos, "Abort:", abortPrefixLen) != 0) {
-                // Ooops.
-                ALOGE("Bad reason line: %s", reasonline);
-                continue;
-            }
+    std::string mergedReasonStr = ::android::base::Join(wakeupReasons, ":");
+    strncpy(mergedreason, mergedReasonStr.c_str(), remainreasonlen);
+    mergedreason[remainreasonlen - 1] = '\0';
 
-            // Write 'Abort' to the merged reason string.
-            len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "Abort" : ":Abort");
-            endPos = pos + abortPrefixLen;
-        }
-        pos = endPos;
+    ALOGV("Got %d reasons", (int)wakeupReasons.size());
 
-        if (len >= 0 && len < remainreasonlen) {
-            mergedreasonpos += len;
-            remainreasonlen -= len;
-        }
-
-        // Skip whitespace; rest of the buffer is the reason string.
-        while (*pos == ' ') {
-            pos++;
-        }
-
-        // Chop newline at end.
-        char* endpos = pos;
-        while (*endpos != 0) {
-            if (*endpos == '\n') {
-                *endpos = 0;
-                break;
-            }
-            endpos++;
-        }
-
-        len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos);
-        if (len >= 0 && len < remainreasonlen) {
-            mergedreasonpos += len;
-            remainreasonlen -= len;
-        }
-        i++;
-    }
-
-    ALOGV("Got %d reasons", i);
-    if (i > 0) {
-        *mergedreasonpos = 0;
-    }
-
-    return mergedreasonpos - mergedreason;
+    return strlen(mergedreason);
 }
 
 // The caller must be holding gPowerHalMutex.
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index f3940e6..d07e70c 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -476,6 +476,9 @@
         if (!mkdirOrLog(path::join(backing, ".index"), 0777)) {
             return kInvalidStorageId;
         }
+        if (!mkdirOrLog(path::join(backing, ".incomplete"), 0777)) {
+            return kInvalidStorageId;
+        }
         auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
         if (!status.isOk()) {
             LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS
new file mode 100644
index 0000000..28aff18
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/internal/location/timezone/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+nfuller@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
new file mode 100644
index 0000000..28aff18
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+nfuller@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 2372dd2..1055069 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -74,7 +74,7 @@
             mReclaimed = true;
         }
 
-        public boolean isRelaimed() {
+        public boolean isReclaimed() {
             return mReclaimed;
         }
     }
@@ -379,13 +379,13 @@
                 new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isFalse();
-        assertThat(listener.isRelaimed()).isFalse();
+        assertThat(listener.isReclaimed()).isFalse();
 
         request =
                 new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
         assertThat(mTunerResourceManagerService
                 .requestFrontendInternal(request, frontendHandle)).isFalse();
-        assertThat(listener.isRelaimed()).isFalse();
+        assertThat(listener.isReclaimed()).isFalse();
     }
 
     @Test
@@ -444,7 +444,7 @@
                 .getOwnerClientId()).isEqualTo(clientId1[0]);
         assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
                 .getOwnerClientId()).isEqualTo(clientId1[0]);
-        assertThat(listener.isRelaimed()).isTrue();
+        assertThat(listener.isReclaimed()).isTrue();
     }
 
     @Test
@@ -478,7 +478,7 @@
 
         // Release frontend
         mTunerResourceManagerService.releaseFrontendInternal(mTunerResourceManagerService
-                .getFrontendResource(frontendId));
+                .getFrontendResource(frontendId), clientId[0]);
         assertThat(mTunerResourceManagerService
                 .getFrontendResource(frontendId).isInUse()).isFalse();
         assertThat(mTunerResourceManagerService
@@ -540,7 +540,7 @@
         assertThat(mTunerResourceManagerService.getCasResource(1)
                 .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId1[0])));
         assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
-        assertThat(listener.isRelaimed()).isTrue();
+        assertThat(listener.isReclaimed()).isTrue();
     }
 
     @Test
@@ -625,7 +625,7 @@
                 .isInUse()).isTrue();
         assertThat(mTunerResourceManagerService.getLnbResource(lnbIds[0])
                 .getOwnerClientId()).isEqualTo(clientId1[0]);
-        assertThat(listener.isRelaimed()).isTrue();
+        assertThat(listener.isReclaimed()).isTrue();
         assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
                 .getInUseLnbIds().size()).isEqualTo(0);
     }
@@ -753,4 +753,293 @@
                 backgroundRecordProfile)).isEqualTo(
                         (backgroundPlaybackPriority > backgroundRecordPriority));
     }
+
+    @Test
+    public void shareFrontendTest_FrontendWithExclusiveGroupReadyToShare() {
+        /**** Register Clients and Set Priority ****/
+
+        // Int array to save the returned client ids
+        int[] ownerClientId0 = new int[1];
+        int[] ownerClientId1 = new int[1];
+        int[] shareClientId0 = new int[1];
+        int[] shareClientId1 = new int[1];
+
+        // Predefined client profiles
+        ResourceClientProfile[] ownerProfiles = new ResourceClientProfile[2];
+        ResourceClientProfile[] shareProfiles = new ResourceClientProfile[2];
+        ownerProfiles[0] = new ResourceClientProfile(
+                "0" /*sessionId*/,
+                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE);
+        ownerProfiles[1] = new ResourceClientProfile(
+                "1" /*sessionId*/,
+                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE);
+        shareProfiles[0] = new ResourceClientProfile(
+                "2" /*sessionId*/,
+                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
+        shareProfiles[1] = new ResourceClientProfile(
+                "3" /*sessionId*/,
+                TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
+
+        // Predefined client reclaim listeners
+        TestResourcesReclaimListener ownerListener0 = new TestResourcesReclaimListener();
+        TestResourcesReclaimListener shareListener0 = new TestResourcesReclaimListener();
+        TestResourcesReclaimListener ownerListener1 = new TestResourcesReclaimListener();
+        TestResourcesReclaimListener shareListener1 = new TestResourcesReclaimListener();
+        // Register clients and validate the returned client ids
+        mTunerResourceManagerService
+                .registerClientProfileInternal(ownerProfiles[0], ownerListener0, ownerClientId0);
+        mTunerResourceManagerService
+                .registerClientProfileInternal(shareProfiles[0], shareListener0, shareClientId0);
+        mTunerResourceManagerService
+                .registerClientProfileInternal(ownerProfiles[1], ownerListener1, ownerClientId1);
+        mTunerResourceManagerService
+                .registerClientProfileInternal(shareProfiles[1], shareListener1, shareClientId1);
+        assertThat(ownerClientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+        assertThat(shareClientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+        assertThat(ownerClientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+        assertThat(shareClientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                ownerClientId0[0],
+                100/*priority*/,
+                0/*niceValue*/);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                shareClientId0[0],
+                200/*priority*/,
+                0/*niceValue*/);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                ownerClientId1[0],
+                300/*priority*/,
+                0/*niceValue*/);
+        mTunerResourceManagerService.updateClientPriorityInternal(
+                shareClientId1[0],
+                400/*priority*/,
+                0/*niceValue*/);
+
+        /**** Init Frontend Resources ****/
+
+        // Predefined frontend info
+        TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
+        infos[0] = new TunerFrontendInfo(
+                0 /*id*/,
+                FrontendSettings.TYPE_DVBT,
+                1 /*exclusiveGroupId*/);
+        infos[1] = new TunerFrontendInfo(
+                1 /*id*/,
+                FrontendSettings.TYPE_DVBS,
+                1 /*exclusiveGroupId*/);
+
+        /**** Init Lnb Resources ****/
+        int[] lnbIds = {1};
+        mTunerResourceManagerService.setLnbInfoListInternal(lnbIds);
+
+        // Update frontend list in TRM
+        mTunerResourceManagerService.setFrontendInfoListInternal(infos);
+
+        /**** Request Frontend ****/
+
+        // Predefined frontend request and array to save returned frontend handle
+        int[] frontendHandle = new int[1];
+        TunerFrontendRequest request = new TunerFrontendRequest(
+                ownerClientId0[0] /*clientId*/,
+                FrontendSettings.TYPE_DVBT);
+
+        // Request call and validate granted resource and internal mapping
+        assertThat(mTunerResourceManagerService
+                .requestFrontendInternal(request, frontendHandle))
+                .isTrue();
+        assertThat(mTunerResourceManagerService
+                .getResourceIdFromHandle(frontendHandle[0]))
+                .isEqualTo(infos[0].getId());
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId0[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+
+        /**** Share Frontend ****/
+
+        // Share frontend call and validate the internal mapping
+        mTunerResourceManagerService.shareFrontendInternal(
+                shareClientId0[0]/*selfClientId*/,
+                ownerClientId0[0]/*targetClientId*/);
+        mTunerResourceManagerService.shareFrontendInternal(
+                shareClientId1[0]/*selfClientId*/,
+                ownerClientId0[0]/*targetClientId*/);
+        // Verify fe in use status
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
+                .isInUse()).isTrue();
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
+                .isInUse()).isTrue();
+        // Verify fe owner status
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
+                .getOwnerClientId()).isEqualTo(ownerClientId0[0]);
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
+                .getOwnerClientId()).isEqualTo(ownerClientId0[0]);
+        // Verify share fe client status in the primary owner client
+        assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
+                .getShareFeClientIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        shareClientId0[0],
+                        shareClientId1[0])));
+        // Verify in use frontend list in all the primary owner and share owner clients
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId0[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId0[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId1[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+
+        /**** Remove Frontend Share Owner ****/
+
+        // Unregister the second share fe client
+        mTunerResourceManagerService.unregisterClientProfileInternal(shareClientId1[0]);
+
+        // Validate the internal mapping
+        assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
+                .getShareFeClientIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        shareClientId0[0])));
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId0[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId0[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+
+        /**** Request Shared Frontend with Higher Priority Client ****/
+
+        // Predefined second frontend request
+        request = new TunerFrontendRequest(
+                ownerClientId1[0] /*clientId*/,
+                FrontendSettings.TYPE_DVBT);
+
+        // Second request call
+        assertThat(mTunerResourceManagerService
+                .requestFrontendInternal(request, frontendHandle))
+                .isTrue();
+
+        // Validate granted resource and internal mapping
+        assertThat(mTunerResourceManagerService
+                .getResourceIdFromHandle(frontendHandle[0]))
+                .isEqualTo(infos[0].getId());
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
+                .getOwnerClientId()).isEqualTo(ownerClientId1[0]);
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
+                .getOwnerClientId()).isEqualTo(ownerClientId1[0]);
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId1[0])
+                .getInUseFrontendIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        infos[0].getId(),
+                        infos[1].getId())));
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId0[0])
+                .getInUseFrontendIds()
+                .isEmpty())
+                .isTrue();
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId0[0])
+                .getInUseFrontendIds()
+                .isEmpty())
+                .isTrue();
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId0[0])
+                .getShareFeClientIds()
+                .isEmpty())
+                .isTrue();
+        assertThat(ownerListener0.isReclaimed()).isTrue();
+        assertThat(shareListener0.isReclaimed()).isTrue();
+
+        /**** Release Frontend Resource From Primary Owner ****/
+
+        // Reshare the frontend
+        mTunerResourceManagerService.shareFrontendInternal(
+                shareClientId0[0]/*selfClientId*/,
+                ownerClientId1[0]/*targetClientId*/);
+
+        // Release the frontend resource from the primary owner
+        mTunerResourceManagerService.releaseFrontendInternal(mTunerResourceManagerService
+                .getFrontendResource(infos[0].getId()), ownerClientId1[0]);
+
+        // Validate the internal mapping
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
+                .isInUse()).isFalse();
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
+                .isInUse()).isFalse();
+        // Verify client status
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId1[0])
+                .getInUseFrontendIds()
+                .isEmpty())
+                .isTrue();
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId0[0])
+                .getInUseFrontendIds()
+                .isEmpty())
+                .isTrue();
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(ownerClientId1[0])
+                .getShareFeClientIds()
+                .isEmpty())
+                .isTrue();
+
+        /**** Unregister Primary Owner when the Share owner owns an Lnb ****/
+
+        // Predefined Lnb request and handle array
+        TunerLnbRequest requestLnb = new TunerLnbRequest(shareClientId0[0]);
+        int[] lnbHandle = new int[1];
+
+        // Request for an Lnb
+        assertThat(mTunerResourceManagerService
+                .requestLnbInternal(requestLnb, lnbHandle))
+                .isTrue();
+
+        // Request and share the frontend resource again
+        assertThat(mTunerResourceManagerService
+                .requestFrontendInternal(request, frontendHandle))
+                .isTrue();
+        mTunerResourceManagerService.shareFrontendInternal(
+                shareClientId0[0]/*selfClientId*/,
+                ownerClientId1[0]/*targetClientId*/);
+
+        // Unregister the primary owner of the shared frontend
+        mTunerResourceManagerService.unregisterClientProfileInternal(ownerClientId1[0]);
+
+        // Validate the internal mapping
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
+                .isInUse()).isFalse();
+        assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
+                .isInUse()).isFalse();
+        // Verify client status
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId0[0])
+                .getInUseFrontendIds()
+                .isEmpty())
+                .isTrue();
+        assertThat(mTunerResourceManagerService
+                .getClientProfile(shareClientId0[0])
+                .getInUseLnbIds())
+                .isEqualTo(new HashSet<Integer>(Arrays.asList(
+                        lnbIds[0])));
+    }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 5024ae2..835ecaa 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -361,7 +361,13 @@
      */
     public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000;
 
-    /* NEXT CAPABILITY: 0x8000 */
+    /**
+     * Flag indicating whether this {@link PhoneAccount} is capable of supporting the call composer
+     * functionality for enriched calls.
+     */
+    public static final int CAPABILITY_CALL_COMPOSER = 0x8000;
+
+    /* NEXT CAPABILITY: 0x10000 */
 
     /**
      * URI scheme for telephone number URIs.
@@ -1088,6 +1094,9 @@
         if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) {
             sb.append("AdhocConf");
         }
+        if (hasCapabilities(CAPABILITY_CALL_COMPOSER)) {
+            sb.append("CallComposer ");
+        }
         return sb.toString();
     }
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index da2d4d8..3f8b683 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -266,10 +266,69 @@
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a string call
      * subject which will be associated with an outgoing call.  Should only be specified if the
-     * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
+     * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}
+     * or {@link PhoneAccount#CAPABILITY_CALL_COMPOSER}.
      */
     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
 
+    // Values for EXTRA_PRIORITY
+    /**
+     * Indicates the call composer call priority is normal.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_NORMAL = 0;
+
+    /**
+     * Indicates the call composer call priority is urgent.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_URGENT = 1;
+
+    /**
+     * Extra for the call composer call priority, either {@link #PRIORITY_NORMAL} or
+     * {@link #PRIORITY_URGENT}.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
+
+    /**
+     * Extra for the call composer call location, an {@link android.location.Location} parcelable
+     * class to represent the geolocation as a latitude and longitude pair.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
+
+    /**
+     * A boolean extra set on incoming calls to indicate that the call has a picture specified.
+     * Given that image download could take a (short) time, the EXTRA is set immediately upon
+     * adding the call to the Dialer app, this allows the Dialer app to reserve space for an image
+     * if one is expected. The EXTRA may be unset if the image download ends up failing for some
+     * reason.
+     */
+    public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
+
+    /**
+     * A URI representing the picture that was downloaded when a call is received.
+     * This is a content URI within the call log provider which can be used to open a file
+     * descriptor. This could be set a short time after a call is added to the Dialer app if the
+     * download is delayed for some reason. The Dialer app will receive a callback via
+     * {@link Call.Callback#onDetailsChanged} when this value has changed.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
+
+    // TODO(hallliu), This UUID is obtained from TelephonyManager#uploadCallComposerPicture.
+    /**
+     * A ParcelUuid used as a token to represent a picture that was uploaded prior to the call
+     * being placed.
+     */
+    public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
+
     /**
      * The extra used by a {@link ConnectionService} to provide the handle of the caller that
      * has initiated a new incoming call.
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4e9e6a8..74b2aad 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4056,6 +4056,17 @@
             "default_preferred_apn_name_string";
 
     /**
+     * Indicates if the carrier supports call composer.
+     */
+    public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
+
+    /**
+     * Indicates the carrier server url that serves the call composer picture.
+     */
+    public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING =
+            "call_composer_picture_server_url_string";
+
+    /**
      * For Android 11, provide a temporary solution for OEMs to use the lower of the two MTU values
      * for IPv4 and IPv6 if both are sent.
      * TODO: remove in later release
@@ -4613,6 +4624,8 @@
         sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
         sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
+        sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
+        sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
         sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
         sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
     }
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
new file mode 100644
index 0000000..46bc4ab
--- /dev/null
+++ b/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable ApnThrottleStatus;
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.java b/telephony/java/android/telephony/data/ApnThrottleStatus.java
new file mode 100644
index 0000000..51461d1
--- /dev/null
+++ b/telephony/java/android/telephony/data/ApnThrottleStatus.java
@@ -0,0 +1,383 @@
+/*
+ * 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.data;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.Annotation;
+
+import java.util.Objects;
+
+/**
+ * Status information regarding the throttle status of an APN type.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ApnThrottleStatus implements Parcelable {
+    /**
+     * The APN type is not throttled.
+     */
+    public static final int THROTTLE_TYPE_NONE = 1;
+
+    /**
+     * The APN type is throttled until {@link android.os.SystemClock#elapsedRealtime()}
+     * has reached {@link ApnThrottleStatus#getThrottleExpiryTimeMillis}
+     */
+    public static final int THROTTLE_TYPE_ELAPSED_TIME = 2;
+
+    /** {@hide} */
+    @IntDef(flag = true, prefix = {"THROTTLE_TYPE_"}, value = {
+            ApnThrottleStatus.THROTTLE_TYPE_NONE,
+            ApnThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME,
+    })
+    public @interface ThrottleType {
+    }
+
+    /**
+     * The framework will not retry the APN type.
+     */
+    public static final int RETRY_TYPE_NONE = 1;
+
+    /**
+     * The next time the framework retries, it will attempt to establish a new connection.
+     */
+    public static final int RETRY_TYPE_NEW_CONNECTION = 2;
+
+    /**
+     * The next time the framework retires, it will retry to handover.
+     */
+    public static final int RETRY_TYPE_HANDOVER = 3;
+
+    /** {@hide} */
+    @IntDef(flag = true, prefix = {"RETRY_TYPE_"}, value = {
+            ApnThrottleStatus.RETRY_TYPE_NONE,
+            ApnThrottleStatus.RETRY_TYPE_NEW_CONNECTION,
+            ApnThrottleStatus.RETRY_TYPE_HANDOVER,
+    })
+    public @interface RetryType {
+    }
+
+    private final int mSlotIndex;
+    private final @AccessNetworkConstants.TransportType int mTransportType;
+    private final @Annotation.ApnType int mApnType;
+    private final long mThrottleExpiryTimeMillis;
+    private final @RetryType int mRetryType;
+    private final @ThrottleType int mThrottleType;
+
+    /**
+     * The slot index that the status applies to.
+     *
+     * @return the slot index
+     */
+    public int getSlotIndex() {
+        return mSlotIndex;
+    }
+
+    /**
+     * The type of transport that the status applies to.
+     *
+     * @return the transport type
+     */
+    @AccessNetworkConstants.TransportType
+    public int getTransportType() {
+        return mTransportType;
+    }
+
+    /**
+     * The APN type that the status applies to.
+     *
+     * @return the apn type
+     */
+    @Annotation.ApnType
+    public int getApnType() {
+        return mApnType;
+    }
+
+    /**
+     * The type of throttle applied to the APN type.
+     *
+     * @return the throttle type
+     */
+    @ThrottleType
+    public int getThrottleType() {
+        return mThrottleType;
+    }
+
+    /**
+     * Indicates the type of request that the framework will make the next time it retries
+     * to call {@link IDataService#setupDataCall}.
+     *
+     * @return the retry type
+     */
+    @RetryType
+    public int getRetryType() {
+        return mRetryType;
+    }
+
+    /**
+     * Gets the time at which the throttle expires.  The value is based off of
+     * {@link SystemClock#elapsedRealtime}.
+     *
+     * This value only applies when the throttle type is set to
+     * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
+     *
+     * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
+     *
+     * @return the time at which the throttle expires
+     */
+    @ElapsedRealtimeLong
+    public long getThrottleExpiryTimeMillis() {
+        return mThrottleExpiryTimeMillis;
+    }
+
+    private ApnThrottleStatus(int slotIndex,
+            @AccessNetworkConstants.TransportType int transportType,
+            @Annotation.ApnType int apnTypes,
+            @ThrottleType int throttleType,
+            long throttleExpiryTimeMillis,
+            @RetryType int retryType) {
+        mSlotIndex = slotIndex;
+        mTransportType = transportType;
+        mApnType = apnTypes;
+        mThrottleType = throttleType;
+        mThrottleExpiryTimeMillis = throttleExpiryTimeMillis;
+        mRetryType = retryType;
+    }
+
+    private ApnThrottleStatus(@NonNull Parcel source) {
+        mSlotIndex = source.readInt();
+        mTransportType = source.readInt();
+        mApnType = source.readInt();
+        mThrottleExpiryTimeMillis = source.readLong();
+        mRetryType = source.readInt();
+        mThrottleType = source.readInt();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mSlotIndex);
+        dest.writeInt(mTransportType);
+        dest.writeInt(mApnType);
+        dest.writeLong(mThrottleExpiryTimeMillis);
+        dest.writeInt(mRetryType);
+        dest.writeInt(mThrottleType);
+    }
+
+    public static final @NonNull Parcelable.Creator<ApnThrottleStatus> CREATOR =
+            new Parcelable.Creator<ApnThrottleStatus>() {
+                @Override
+                public ApnThrottleStatus createFromParcel(@NonNull Parcel source) {
+                    return new ApnThrottleStatus(source);
+                }
+
+                @Override
+                public ApnThrottleStatus[] newArray(int size) {
+                    return new ApnThrottleStatus[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSlotIndex, mApnType, mRetryType, mThrottleType,
+                mThrottleExpiryTimeMillis, mTransportType);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        } else if (obj instanceof ApnThrottleStatus) {
+            ApnThrottleStatus other = (ApnThrottleStatus) obj;
+            return this.mSlotIndex == other.mSlotIndex
+                    && this.mApnType == other.mApnType
+                    && this.mRetryType == other.mRetryType
+                    && this.mThrottleType == other.mThrottleType
+                    && this.mThrottleExpiryTimeMillis == other.mThrottleExpiryTimeMillis
+                    && this.mTransportType == other.mTransportType;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ApnThrottleStatus{"
+                + "mSlotIndex=" + mSlotIndex
+                + ", mTransportType=" + mTransportType
+                + ", mApnType=" + ApnSetting.getApnTypeString(mApnType)
+                + ", mThrottleExpiryTimeMillis=" + mThrottleExpiryTimeMillis
+                + ", mRetryType=" + mRetryType
+                + ", mThrottleType=" + mThrottleType
+                + '}';
+    }
+
+    /**
+     * Provides a convenient way to set the fields of an {@link ApnThrottleStatus} when creating a
+     * new instance.
+     *
+     * <p>The example below shows how you might create a new {@code ApnThrottleStatus}:
+     *
+     * <pre><code>
+     *
+     * DataCallResponseApnThrottleStatus = new ApnThrottleStatus.Builder()
+     *     .setSlotIndex(1)
+     *     .setApnType({@link ApnSetting#TYPE_EMERGENCY})
+     *     .setNoThrottle()
+     *     .setRetryType({@link ApnThrottleStatus#RETRY_TYPE_NEW_CONNECTION})
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        private int mSlotIndex;
+        private @AccessNetworkConstants.TransportType int mTransportType;
+        private @Annotation.ApnType int mApnType;
+        private long mThrottleExpiryTimeMillis;
+        private @RetryType int mRetryType;
+        private @ThrottleType int mThrottleType;
+        public static final long NO_THROTTLE_EXPIRY_TIME =
+                DataCallResponse.RETRY_DURATION_UNDEFINED;
+
+        /**
+         * Default constructor for the Builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Set the slot index.
+         *
+         * @param slotIndex the slot index.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setSlotIndex(int slotIndex) {
+            this.mSlotIndex = slotIndex;
+            return this;
+        }
+
+        /**
+         * Set the transport type.
+         *
+         * @param transportType the transport type.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setTransportType(@AccessNetworkConstants.TransportType
+                int transportType) {
+            this.mTransportType = transportType;
+            return this;
+        }
+
+        /**
+         * Set the APN type.
+         *
+         * @param apnType  the APN type.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setApnType(@Annotation.ApnType int apnType) {
+            this.mApnType = apnType;
+            return this;
+        }
+
+        /**
+         * Sets the time at which the throttle will expire.  The value is based off of
+         * {@link SystemClock#elapsedRealtime}.
+         *
+         * When setting this value, the throttle type is set to
+         * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
+         *
+         * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
+         *
+         * @param throttleExpiryTimeMillis The elapsed time at which the throttle expires.
+         *                                 Throws {@link IllegalArgumentException} for values less
+         *                                 than 0.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setThrottleExpiryTimeMillis(
+                @ElapsedRealtimeLong long throttleExpiryTimeMillis) {
+            if (throttleExpiryTimeMillis >= 0) {
+                this.mThrottleExpiryTimeMillis = throttleExpiryTimeMillis;
+                this.mThrottleType = THROTTLE_TYPE_ELAPSED_TIME;
+            } else {
+                throw new IllegalArgumentException("throttleExpiryTimeMillis must be greater than "
+                        + "or equal to 0");
+            }
+            return this;
+        }
+
+        /**
+         * Sets the status of the APN type as not being throttled.
+         *
+         * When setting this value, the throttle type is set to
+         * {@link ApnThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to
+         * {@link Builder#NO_THROTTLE_EXPIRY_TIME}.
+         *
+         * @return The same instance of the builder.
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @NonNull
+        public Builder setNoThrottle() {
+            mThrottleType = THROTTLE_TYPE_NONE;
+            mThrottleExpiryTimeMillis = NO_THROTTLE_EXPIRY_TIME;
+            return this;
+        }
+
+        /**
+         * Set the type of request that the framework will make the next time it retries
+         * to call {@link IDataService#setupDataCall}.
+         *
+         * @param retryType the type of request
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setRetryType(@RetryType int retryType) {
+            this.mRetryType = retryType;
+            return this;
+        }
+
+        /**
+         * Build the {@link ApnThrottleStatus}
+         *
+         * @return the {@link ApnThrottleStatus} object
+         */
+        @NonNull
+        public ApnThrottleStatus build() {
+            return new ApnThrottleStatus(
+                    mSlotIndex,
+                    mTransportType,
+                    mApnType,
+                    mThrottleType,
+                    mThrottleExpiryTimeMillis,
+                    mRetryType);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index f0088b9..8348502 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -109,10 +109,10 @@
     public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3;
 
     /**
-     * Indicates that data retry interval is not specified. Platform can determine when to
+     * Indicates that data retry duration is not specified. Platform can determine when to
      * perform data setup appropriately.
      */
-    public static final int RETRY_INTERVAL_UNDEFINED = -1;
+    public static final int RETRY_DURATION_UNDEFINED = -1;
 
     /**
      * Indicates that the pdu session id is not set.
@@ -254,19 +254,26 @@
     /**
      * @return The suggested data retry time in milliseconds.
      *
-     * @deprecated Use {@link #getRetryIntervalMillis()} instead.
+     * @deprecated Use {@link #getRetryDurationMillis()} instead.
      */
     @Deprecated
     public int getSuggestedRetryTime() {
+
+        // To match the pre-deprecated getSuggestedRetryTime() behavior.
+        if (mSuggestedRetryTime == RETRY_DURATION_UNDEFINED) {
+            return 0;
+        } else if (mSuggestedRetryTime > Integer.MAX_VALUE) {
+            return Integer.MAX_VALUE;
+        }
         return (int) mSuggestedRetryTime;
     }
 
     /**
-     * @return The network suggested data retry interval in milliseconds. {@code Long.MAX_VALUE}
-     * indicates data retry should not occur. {@link #RETRY_INTERVAL_UNDEFINED} indicates network
-     * did not suggest any retry interval.
+     * @return The network suggested data retry duration in milliseconds. {@code Long.MAX_VALUE}
+     * indicates data retry should not occur. {@link #RETRY_DURATION_UNDEFINED} indicates network
+     * did not suggest any retry duration.
      */
-    public long getRetryIntervalMillis() {
+    public long getRetryDurationMillis() {
         return mSuggestedRetryTime;
     }
 
@@ -537,7 +544,7 @@
     public static final class Builder {
         private @DataFailureCause int mCause;
 
-        private long mSuggestedRetryTime = RETRY_INTERVAL_UNDEFINED;
+        private long mSuggestedRetryTime = RETRY_DURATION_UNDEFINED;
 
         private int mId;
 
@@ -592,7 +599,7 @@
          * @param suggestedRetryTime The suggested data retry time in milliseconds.
          * @return The same instance of the builder.
          *
-         * @deprecated Use {@link #setRetryIntervalMillis(long)} instead.
+         * @deprecated Use {@link #setRetryDurationMillis(long)} instead.
          */
         @Deprecated
         public @NonNull Builder setSuggestedRetryTime(int suggestedRetryTime) {
@@ -601,13 +608,13 @@
         }
 
         /**
-         * Set the network suggested data retry interval.
+         * Set the network suggested data retry duration.
          *
-         * @param retryIntervalMillis The suggested data retry interval in milliseconds.
+         * @param retryDurationMillis The suggested data retry duration in milliseconds.
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setRetryIntervalMillis(long retryIntervalMillis) {
-            mSuggestedRetryTime = retryIntervalMillis;
+        public @NonNull Builder setRetryDurationMillis(long retryDurationMillis) {
+            mSuggestedRetryTime = retryDurationMillis;
             return this;
         }
 
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 7768597..2ec9651 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -107,6 +107,9 @@
     private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED            = 11;
     private static final int DATA_SERVICE_REQUEST_START_HANDOVER                       = 12;
     private static final int DATA_SERVICE_REQUEST_CANCEL_HANDOVER                      = 13;
+    private static final int DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED             = 14;
+    private static final int DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED           = 15;
+    private static final int DATA_SERVICE_INDICATION_APN_UNTHROTTLED                   = 16;
 
     private final HandlerThread mHandlerThread;
 
@@ -129,6 +132,8 @@
 
         private final List<IDataServiceCallback> mDataCallListChangedCallbacks = new ArrayList<>();
 
+        private final List<IDataServiceCallback> mApnUnthrottledCallbacks = new ArrayList<>();
+
         /**
          * Constructor
          * @param slotIndex SIM slot index the data service provider associated with.
@@ -326,6 +331,19 @@
             }
         }
 
+        private void registerForApnUnthrottled(IDataServiceCallback callback) {
+            synchronized (mApnUnthrottledCallbacks) {
+                mApnUnthrottledCallbacks.add(callback);
+            }
+        }
+
+        private void unregisterForApnUnthrottled(IDataServiceCallback callback) {
+            synchronized (mApnUnthrottledCallbacks) {
+                mApnUnthrottledCallbacks.remove(callback);
+            }
+        }
+
+
         /**
          * Notify the system that current data call list changed. Data service must invoke this
          * method whenever there is any data call status changed.
@@ -343,6 +361,21 @@
         }
 
         /**
+         * Notify the system that a given APN was unthrottled.
+         *
+         * @param apn Access Point Name defined by the carrier.
+         */
+        public final void notifyApnUnthrottled(@NonNull String apn) {
+            synchronized (mApnUnthrottledCallbacks) {
+                for (IDataServiceCallback callback : mApnUnthrottledCallbacks) {
+                    mHandler.obtainMessage(DATA_SERVICE_INDICATION_APN_UNTHROTTLED,
+                            mSlotIndex, 0, new ApnUnthrottledIndication(apn,
+                                    callback)).sendToTarget();
+                }
+            }
+        }
+
+        /**
          * Called when the instance of data service is destroyed (e.g. got unbind or binder died)
          * or when the data service provider is removed. The extended class should implement this
          * method to perform cleanup works.
@@ -429,6 +462,16 @@
         }
     }
 
+    private static final class ApnUnthrottledIndication {
+        public final String apn;
+        public final IDataServiceCallback callback;
+        ApnUnthrottledIndication(String apn,
+                IDataServiceCallback callback) {
+            this.apn = apn;
+            this.callback = callback;
+        }
+    }
+
     private class DataServiceHandler extends Handler {
 
         DataServiceHandler(Looper looper) {
@@ -544,6 +587,26 @@
                             (cReq.callback != null)
                                     ? new DataServiceCallback(cReq.callback) : null);
                     break;
+                case DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED:
+                    if (serviceProvider == null) break;
+                    serviceProvider.registerForApnUnthrottled((IDataServiceCallback) message.obj);
+                    break;
+                case DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED:
+                    if (serviceProvider == null) break;
+                    callback = (IDataServiceCallback) message.obj;
+                    serviceProvider.unregisterForApnUnthrottled(callback);
+                    break;
+                case DATA_SERVICE_INDICATION_APN_UNTHROTTLED:
+                    if (serviceProvider == null) break;
+                    ApnUnthrottledIndication apnUnthrottledIndication =
+                            (ApnUnthrottledIndication) message.obj;
+                    try {
+                        apnUnthrottledIndication.callback
+                                .onApnUnthrottled(apnUnthrottledIndication.apn);
+                    } catch (RemoteException e) {
+                        loge("Failed to call onApnUnthrottled. " + e);
+                    }
+                    break;
             }
         }
     }
@@ -695,6 +758,26 @@
             mHandler.obtainMessage(DATA_SERVICE_REQUEST_CANCEL_HANDOVER,
                     slotIndex, 0, req).sendToTarget();
         }
+
+        @Override
+        public void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback) {
+            if (callback == null) {
+                loge("registerForUnthrottleApn: callback is null");
+                return;
+            }
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED, slotIndex,
+                    0, callback).sendToTarget();
+        }
+
+        @Override
+        public void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback) {
+            if (callback == null) {
+                loge("uregisterForUnthrottleApn: callback is null");
+                return;
+            }
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED,
+                    slotIndex, 0, callback).sendToTarget();
+        }
     }
 
     private void log(String s) {
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index eef0e01..52bf15f 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -233,7 +233,7 @@
      */
     @NonNull
     public static String resultCodeToString(@DataServiceCallback.ResultCode int resultCode) {
-        switch(resultCode) {
+        switch (resultCode) {
             case RESULT_SUCCESS:
                 return "RESULT_SUCCESS";
             case RESULT_ERROR_UNSUPPORTED:
@@ -248,4 +248,22 @@
                 return "Missing case for result code=" + resultCode;
         }
     }
+
+    /**
+     * Indicates that the specified APN is no longer throttled.
+     *
+     * @param apn Access Point Name defined by the carrier.
+     */
+    public void onApnUnthrottled(@NonNull String apn) {
+        if (mCallback != null) {
+            try {
+                if (DBG) Rlog.d(TAG, "onApnUnthrottled");
+                mCallback.onApnUnthrottled(apn);
+            } catch (RemoteException e) {
+                Rlog.e(TAG, "onApnUnthrottled: remote exception", e);
+            }
+        } else {
+            Rlog.e(TAG, "onApnUnthrottled: callback is null!");
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 33226fe..3f1f033 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -40,4 +40,6 @@
     void unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback);
     void startHandover(int slotId, int cid, IDataServiceCallback callback);
     void cancelHandover(int slotId, int cid, IDataServiceCallback callback);
+    void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback);
+    void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback);
 }
diff --git a/telephony/java/android/telephony/data/IDataServiceCallback.aidl b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
index d296e7b..9cc2fea 100644
--- a/telephony/java/android/telephony/data/IDataServiceCallback.aidl
+++ b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
@@ -32,4 +32,5 @@
     void onDataCallListChanged(in List<DataCallResponse> dataCallList);
     void onHandoverStarted(int result);
     void onHandoverCancelled(int result);
+    void onApnUnthrottled(in String apn);
 }
diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
index 3bf09bc..2904082 100644
--- a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
@@ -17,6 +17,7 @@
 package android.telephony.data;
 
 import android.telephony.data.IQualifiedNetworksServiceCallback;
+import android.telephony.data.ApnThrottleStatus;
 
 /**
  * {@hide}
@@ -25,4 +26,5 @@
 {
     oneway void createNetworkAvailabilityProvider(int slotId, IQualifiedNetworksServiceCallback callback);
     oneway void removeNetworkAvailabilityProvider(int slotId);
+    oneway void reportApnThrottleStatusChanged(int slotId, in List<ApnThrottleStatus> statuses);
 }
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 05971c4..4af63b4 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -28,6 +28,7 @@
 import android.os.RemoteException;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.Annotation.ApnType;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -65,6 +66,7 @@
     private static final int QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER               = 2;
     private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS          = 3;
     private static final int QNS_UPDATE_QUALIFIED_NETWORKS                          = 4;
+    private static final int QNS_APN_THROTTLE_STATUS_CHANGED                        = 5;
 
     private final HandlerThread mHandlerThread;
 
@@ -160,6 +162,17 @@
         }
 
         /**
+         * The framework calls this method when the throttle status of an APN changes.
+         *
+         * This method is meant to be overridden.
+         *
+         * @param statuses the statuses that have changed
+         */
+        public void reportApnThrottleStatusChanged(@NonNull List<ApnThrottleStatus> statuses) {
+            Log.d(TAG, "reportApnThrottleStatusChanged: statuses size=" + statuses.size());
+        }
+
+        /**
          * Called when the qualified networks provider is removed. The extended class should
          * implement this method to perform cleanup works.
          */
@@ -197,6 +210,12 @@
                                 + slotIndex);
                     }
                     break;
+                case QNS_APN_THROTTLE_STATUS_CHANGED:
+                    if (provider != null) {
+                        List<ApnThrottleStatus> statuses = (List<ApnThrottleStatus>) message.obj;
+                        provider.reportApnThrottleStatusChanged(statuses);
+                    }
+                    break;
 
                 case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER:
                     if (provider != null) {
@@ -286,6 +305,13 @@
             mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0)
                     .sendToTarget();
         }
+
+        @Override
+        public void reportApnThrottleStatusChanged(int slotIndex,
+                List<ApnThrottleStatus> statuses) {
+            mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses)
+                    .sendToTarget();
+        }
     }
 
     private void log(String s) {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 1b51936..aaa68d6 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -207,6 +208,42 @@
             "android.telephony.ims.extra.RETRY_CALL_FAIL_NETWORKTYPE";
 
     /**
+     * Extra for the call composer call priority, either {@link ImsCallProfile#PRIORITY_NORMAL} or
+     * {@link ImsCallProfile#PRIORITY_URGENT}. It can be set via
+     * {@link #setCallExtraInt(String, int)}.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY";
+
+    // TODO(hallliu) remove the reference to the maximum length and update it later.
+    /**
+     * Extra for the call composer call subject, a string of maximum length 60 characters.
+     * It can be set via {@link #setCallExtra(String, String)}.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT";
+
+    /**
+     * Extra for the call composer call location, an {@Link android.location.Location} parcelable
+     * class to represent the geolocation as a latitude and longitude pair. It can be set via
+     * {@link #setCallExtraParcelable(String, Parcelable)}.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION";
+
+    /**
+     * Extra for the call composer picture URL, a String that indicates the URL on the carrier’s
+     * server infrastructure to get the picture. It can be set via
+     * {@link #setCallExtra(String, String)}.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
+
+    /**
      * Values for EXTRA_OIR / EXTRA_CNAP
      */
     /**
@@ -244,6 +281,21 @@
      */
     public static final int DIALSTRING_USSD = 2;
 
+    // Values for EXTRA_PRIORITY
+    /**
+     * Indicates the call composer call priority is normal.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_NORMAL = 0;
+
+    /**
+     * Indicates the call composer call priority is urgent.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_URGENT = 1;
+
     /**
      * Call is not restricted on peer side and High Definition media is supported
      */
@@ -588,6 +640,19 @@
         return mCallExtras.getInt(name, defaultValue);
     }
 
+    /**
+     * Get the call extras (Parcelable), given the extra name.
+     * @param name call extra name
+     * @return the corresponding call extra Parcelable or null if not applicable
+     */
+    @Nullable
+    public <T extends Parcelable> T getCallExtraParcelable(@Nullable String name) {
+        if (mCallExtras != null) {
+            return mCallExtras.getParcelable(name);
+        }
+        return null;
+    }
+
     public void setCallExtra(String name, String value) {
         if (mCallExtras != null) {
             mCallExtras.putString(name, value);
@@ -607,6 +672,17 @@
     }
 
     /**
+     * Set the call extra value (Parcelable), given the call extra name.
+     * @param name call extra name
+     * @param parcelable call extra value
+     */
+    public void setCallExtraParcelable(@NonNull String name, @NonNull Parcelable parcelable) {
+        if (mCallExtras != null) {
+            mCallExtras.putParcelable(name, parcelable);
+        }
+    }
+
+    /**
      * Set the call restrict cause, which provides the reason why a call has been restricted from
      * using High Definition media.
      */
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index a3efb79..0aff997 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -101,10 +101,29 @@
      */
     public static class Listener {
         /**
-         * Called when a request is sent out to initiate a new session
-         * and 1xx response is received from the network.
+         * Called when the session is initiating.
          *
-         * @param session the session object that carries out the IMS session
+         * see: {@link ImsCallSessionListener#callSessionInitiating(ImsCallProfile)}
+         */
+        public void callSessionInitiating(ImsCallSession session,
+                ImsCallProfile profile) {
+            // no-op
+        }
+
+        /**
+         * Called when the session failed before initiating was called.
+         *
+         * see: {@link ImsCallSessionListener#callSessionInitiatingFailed(ImsReasonInfo)}
+         */
+        public void callSessionInitiatingFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            // no-op
+        }
+
+        /**
+         * Called when the session is progressing.
+         *
+         * see: {@link ImsCallSessionListener#callSessionProgressing(ImsStreamMediaProfile)}
          */
         public void callSessionProgressing(ImsCallSession session,
                 ImsStreamMediaProfile profile) {
@@ -1179,6 +1198,13 @@
          * Notifies the result of the basic session operation (setup / terminate).
          */
         @Override
+        public void callSessionInitiating(ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionInitiating(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
         public void callSessionProgressing(ImsStreamMediaProfile profile) {
             if (mListener != null) {
                 mListener.callSessionProgressing(ImsCallSession.this, profile);
@@ -1193,6 +1219,13 @@
         }
 
         @Override
+        public void callSessionInitiatingFailed(ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        @Override
         public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) {
             if (mListener != null) {
                 mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 86bb5d9..db99acf 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -53,8 +53,45 @@
     }
 
     /**
-     * A request has been sent out to initiate a new IMS call session and a 1xx response has been
-     * received from the network.
+     * Called when the network first begins to establish the call session and is now connecting
+     * to the remote party. This must be called once after {@link ImsCallSessionImplBase#start} and
+     * before any other method on this listener.  After this is called,
+     * {@link #callSessionProgressing(ImsStreamMediaProfile)} must be called to communicate any
+     * further updates.
+     * <p/>
+     * Once this is called, {@link #callSessionTerminated} must be called
+     * to end the call session.  In the event that the session failed before the remote party
+     * was contacted, {@link #callSessionInitiatingFailed} must be called.
+     *
+     * @param profile the associated {@link ImsCallProfile}.
+     */
+    public void callSessionInitiating(@NonNull ImsCallProfile profile) {
+        try {
+            mListener.callSessionInitiating(profile);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * The IMS call session establishment has failed while initiating.
+     *
+     * @param reasonInfo {@link ImsReasonInfo} detailing the reason of the IMS call session
+     * establishment failure.
+     */
+    public void callSessionInitiatingFailed(@NonNull ImsReasonInfo reasonInfo) {
+        try {
+            mListener.callSessionInitiatingFailed(reasonInfo);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Called after the network has contacted the remote party and the call state should move to
+     * ALERTING.
+     *
+     * @param profile the associated {@link ImsCallProfile}.
      */
     public void callSessionProgressing(ImsStreamMediaProfile profile) {
         try {
@@ -65,7 +102,8 @@
     }
 
     /**
-     * The IMS call session has been initiated.
+     * Called once the outgoing IMS call session has been begun between the local and remote party.
+     * The call state should move to ACTIVE.
      *
      * @param profile the associated {@link ImsCallProfile}.
      */
@@ -82,7 +120,12 @@
      *
      * @param reasonInfo {@link ImsReasonInfo} detailing the reason of the IMS call session
      * establishment failure.
+     * @deprecated {@link #callSessionInitiated(ImsCallProfile)} is called immediately after
+     * the session is first started which meant that there was no time in which a call to this
+     * method was technically valid.  This method is replaced starting Android S in favor of
+     * {@link #callSessionInitiatingFailed(ImsReasonInfo)}.
      */
+    @Deprecated
     public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) {
         try {
             mListener.callSessionInitiatedFailed(reasonInfo);
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index ed895b7..ed03752 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -37,6 +37,8 @@
     /**
      * Notifies the result of the basic session operation (setup / terminate).
      */
+    void callSessionInitiating(in ImsCallProfile profile);
+    void callSessionInitiatingFailed(in ImsReasonInfo reasonInfo);
     void callSessionProgressing(in ImsStreamMediaProfile profile);
     void callSessionInitiated(in ImsCallProfile profile);
     void callSessionInitiatedFailed(in ImsReasonInfo reasonInfo);
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index e570fb6..0b2c6d9 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -231,8 +231,9 @@
      * The capabilities that are used in MmTelFeature are defined as
      * {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE},
      * {@link MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
-     * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, and
-     * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}.
+     * {@link MmTelCapabilities#CAPABILITY_TYPE_UT},
+     * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}, and
+     * {@link MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER}.
      *
      * The capabilities of this MmTelFeature will be set by the framework.
      */
@@ -275,7 +276,8 @@
                         CAPABILITY_TYPE_VOICE,
                         CAPABILITY_TYPE_VIDEO,
                         CAPABILITY_TYPE_UT,
-                        CAPABILITY_TYPE_SMS
+                        CAPABILITY_TYPE_SMS,
+                        CAPABILITY_TYPE_CALL_COMPOSER
                 })
         @Retention(RetentionPolicy.SOURCE)
         public @interface MmTelCapability {}
@@ -301,6 +303,11 @@
         public static final int CAPABILITY_TYPE_SMS = 1 << 3;
 
         /**
+         * This MmTelFeature supports Call Composer (section 2.4 of RC.20)
+         */
+        public static final int CAPABILITY_TYPE_CALL_COMPOSER = 1 << 4;
+
+        /**
          * @hide
          */
         @Override
@@ -343,6 +350,8 @@
             builder.append(isCapable(CAPABILITY_TYPE_UT));
             builder.append(" SMS: ");
             builder.append(isCapable(CAPABILITY_TYPE_SMS));
+            builder.append(" CALL_COMPOSER: ");
+            builder.append(isCapable(CAPABILITY_TYPE_CALL_COMPOSER));
             builder.append("]");
             return builder.toString();
         }
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 76fc4f7..6fbde50 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -113,6 +113,7 @@
     public static final int EVENT_NR_TIMER_WATCHDOG = BASE + 53;
     public static final int EVENT_CARRIER_CONFIG_CHANGED = BASE + 54;
     public static final int EVENT_SIM_STATE_UPDATED = BASE + 55;
+    public static final int EVENT_APN_UNTHROTTLED = BASE + 56;
 
     /***** Constants *****/
 
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 70f6386..8e18751 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -25,7 +25,6 @@
 import android.net.ConnectivityManager
 import android.net.IDnsResolver
 import android.net.INetd
-import android.net.INetworkPolicyManager
 import android.net.INetworkStatsService
 import android.net.LinkProperties
 import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
@@ -88,8 +87,6 @@
     @Mock
     private lateinit var statsService: INetworkStatsService
     @Mock
-    private lateinit var policyManager: INetworkPolicyManager
-    @Mock
     private lateinit var log: IpConnectivityLog
     @Mock
     private lateinit var netd: INetd
@@ -171,7 +168,7 @@
     }
 
     private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
-            context, netManager, statsService, policyManager, dnsResolver, log, netd, deps)
+            context, netManager, statsService, dnsResolver, log, netd, deps)
 
     private fun makeDependencies(): ConnectivityService.Dependencies {
         val deps = spy(ConnectivityService.Dependencies())
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a613e5e..efd852b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -166,7 +166,6 @@
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
-import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.InetAddresses;
 import android.net.InterfaceConfigurationParcel;
@@ -183,6 +182,7 @@
 import android.net.NetworkFactory;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
@@ -365,7 +365,6 @@
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
     @Mock IBatteryStats mBatteryStatsService;
-    @Mock INetworkPolicyManager mNpm;
     @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
     @Mock NetworkStackClient mNetworkStack;
@@ -380,6 +379,7 @@
     @Mock TelephonyManager mTelephonyManager;
     @Mock MockableSystemProperties mSystemProperties;
     @Mock EthernetManager mEthernetManager;
+    @Mock NetworkPolicyManager mNetworkPolicyManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -477,6 +477,7 @@
             if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
             if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
             if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
+            if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
             return super.getSystemService(name);
         }
 
@@ -1326,7 +1327,6 @@
         mService = new ConnectivityService(mServiceContext,
                 mNetworkManagementService,
                 mStatsService,
-                mNpm,
                 mMockDnsResolver,
                 mock(IpConnectivityLog.class),
                 mMockNetd,
@@ -1336,7 +1336,7 @@
 
         final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
                 ArgumentCaptor.forClass(INetworkPolicyListener.class);
-        verify(mNpm).registerListener(policyListenerCaptor.capture());
+        verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
         mPolicyListener = policyListenerCaptor.getValue();
 
         // Create local CM before sending system ready so that we can answer
@@ -7810,8 +7810,7 @@
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
         final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(
-                        null, null, null, null, null, new NetworkCapabilities(), 0,
+                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
 
         mServiceContext.setPermission(
@@ -7826,8 +7825,7 @@
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
         final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(
-                        null, null, null, null, null, new NetworkCapabilities(), 0,
+                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -7842,8 +7840,7 @@
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
         final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(
-                        null, null, null, null, null, new NetworkCapabilities(), 0,
+                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -7859,8 +7856,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
         final Network network = new Network(NET_ID);
         final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(
-                        null, null, network, null, null, new NetworkCapabilities(), 0,
+                new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
@@ -7894,8 +7890,7 @@
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setAdministratorUids(new int[] {Process.myUid()});
         final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(
-                        null, null, null, null, null, nc, 0, mServiceContext, null, null,
+                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
                         mService, null, null, null, 0, INVALID_UID);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
@@ -7914,8 +7909,7 @@
         nc.setOwnerUid(Process.myUid());
         nc.setAdministratorUids(new int[] {Process.myUid()});
         final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(
-                        null, null, null, null, null, nc, 0, mServiceContext, null, null,
+                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
                         mService, null, null, null, 0, INVALID_UID);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index aafa18a..96c56e3 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -353,7 +353,7 @@
         NetworkCapabilities caps = new NetworkCapabilities();
         caps.addCapability(0);
         caps.addTransportType(transport);
-        NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
+        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null,
                 caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
                 NetworkProvider.ID_NONE, Binder.getCallingUid());
         nai.everValidated = true;
diff --git a/wifi/MOVED.txt b/wifi/MOVED.txt
new file mode 100644
index 0000000..6ffb23c
--- /dev/null
+++ b/wifi/MOVED.txt
@@ -0,0 +1,8 @@
+Source code and tests for Wifi module APIs have moved to
+packages/modules/Wifi/framework.
+
+- frameworks/base/wifi/java -> packages/modules/Wifi/framework/java
+- frameworks/base/wifi/tests -> packages/modules/Wifi/framework/tests
+
+What remains in frameworks/base/wifi are Wifi APIs that
+are not part of the Wifi module.
diff --git a/wifi/TEST_MAPPING b/wifi/TEST_MAPPING
new file mode 100644
index 0000000..94e4f4d
--- /dev/null
+++ b/wifi/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksWifiNonUpdatableApiTests"
+    }
+  ]
+}