Merge "Change Task to have generic WindowContainer children (73/n)"
diff --git a/Android.bp b/Android.bp
index 8926372..c1f6860 100644
--- a/Android.bp
+++ b/Android.bp
@@ -266,11 +266,19 @@
 }
 
 filegroup {
+    name: "framework-updatable-sources",
+    srcs: [
+        ":framework-sdkext-sources",
+        ":updatable-media-srcs",
+    ]
+}
+
+filegroup {
     name: "framework-all-sources",
     srcs: [
         ":framework-mime-sources",
         ":framework-non-updatable-sources",
-        ":updatable-media-srcs",
+        ":framework-updatable-sources",
     ],
 }
 
@@ -576,6 +584,12 @@
     ],
 }
 
+java_library {
+    name: "framework-annotations-lib",
+    srcs: [ ":framework-annotations" ],
+    sdk_version: "current",
+}
+
 filegroup {
     name: "framework-networkstack-shared-srcs",
     srcs: [
@@ -1019,15 +1033,15 @@
 stubs_defaults {
     name: "framework-doc-stubs-default",
     srcs: [
-        ":framework-non-updatable-sources",
         ":framework-mime-sources",
+        ":framework-non-updatable-sources",
+        ":framework-updatable-sources",
         "core/java/**/*.logtags",
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":core-current-stubs-source",
         ":core_public_api_files",
-        ":updatable-media-srcs",
         "test-mock/src/**/*.java",
         "test-runner/src/**/*.java",
     ],
@@ -1085,12 +1099,12 @@
     name: "metalava-api-stubs-default",
     srcs: [
         ":framework-non-updatable-sources",
+        ":framework-updatable-sources",
         "core/java/**/*.logtags",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":core-current-stubs-source",
         ":core_public_api_files",
-        ":updatable-media-srcs",
         ":ike-api-srcs",
     ],
     libs: ["framework-internal-utils"],
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 2cd7aa0..4ebafce8 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -21,4 +21,7 @@
     "framework",
     "services.core",
   ],
+  static_libs: [
+    "icing-java-proto-lite",
+  ]
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
index e611033..5ac922c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
@@ -20,9 +20,11 @@
 import android.annotation.Nullable;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
 import android.util.SparseArray;
 
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -42,18 +44,19 @@
 public class FakeIcing {
     private final AtomicInteger mNextDocId = new AtomicInteger();
     private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>();
-    /** Array of Documents (pair of uri and content) where index into the array is the docId. */
-    private final SparseArray<Pair<String, String>> mDocStore = new SparseArray<>();
+    /** Array of Documents where index into the array is the docId. */
+    private final SparseArray<DocumentProto> mDocStore = new SparseArray<>();
     /** Map of term to posting-list (the set of DocIds containing that term). */
     private final Map<String, Set<Integer>> mIndex = new ArrayMap<>();
 
     /**
      * Inserts a document into the index.
      *
-     * @param uri The globally unique identifier of the document.
-     * @param doc The contents of the document.
+     * @param document The document to insert.
      */
-    public void put(@NonNull String uri, @NonNull String doc) {
+    public void put(@NonNull DocumentProto document) {
+        String uri = document.getUri();
+
         // Update mDocIdMap
         Integer docId = mUriToDocIdMap.get(uri);
         if (docId != null) {
@@ -66,18 +69,10 @@
         mUriToDocIdMap.put(uri, docId);
 
         // Update mDocStore
-        mDocStore.put(docId, Pair.create(uri, doc));
+        mDocStore.put(docId, document);
 
         // Update mIndex
-        String[] words = normalizeString(doc).split("\\s+");
-        for (String word : words) {
-            Set<Integer> postingList = mIndex.get(word);
-            if (postingList == null) {
-                postingList = new ArraySet<>();
-                mIndex.put(word, postingList);
-            }
-            postingList.add(docId);
-        }
+        indexDocument(docId, document);
     }
 
     /**
@@ -87,39 +82,35 @@
      * @return The body of the document, or {@code null} if no such document exists.
      */
     @Nullable
-    public String get(@NonNull String uri) {
+    public DocumentProto get(@NonNull String uri) {
         Integer docId = mUriToDocIdMap.get(uri);
         if (docId == null) {
             return null;
         }
-        Pair<String, String> record = mDocStore.get(docId);
-        if (record == null) {
-            return null;
-        }
-        return record.second;
+        return mDocStore.get(docId);
     }
 
     /**
      * Returns documents containing the given term.
      *
      * @param term A single exact term to look up in the index.
-     * @return The URIs of the matching documents, or an empty {@code List} if no documents match.
+     * @return The matching documents, or an empty {@code List} if no documents match.
      */
     @NonNull
-    public List<String> query(@NonNull String term) {
+    public List<DocumentProto> query(@NonNull String term) {
         String normTerm = normalizeString(term);
         Set<Integer> docIds = mIndex.get(normTerm);
         if (docIds == null || docIds.isEmpty()) {
             return Collections.emptyList();
         }
-        List<String> uris = new ArrayList<>(docIds.size());
+        List<DocumentProto> matches = new ArrayList<>(docIds.size());
         for (int docId : docIds) {
-            Pair<String, String> record = mDocStore.get(docId);
-            if (record != null) {
-                uris.add(record.first);
+            DocumentProto document = mDocStore.get(docId);
+            if (document != null) {
+                matches.add(document);
             }
         }
-        return uris;
+        return matches;
     }
 
     /**
@@ -137,6 +128,39 @@
         }
     }
 
+    private void indexDocument(int docId, DocumentProto document) {
+        for (PropertyProto property : document.getPropertiesList()) {
+            for (String stringValue : property.getStringValuesList()) {
+                String[] words = normalizeString(stringValue).split("\\s+");
+                for (String word : words) {
+                    indexTerm(docId, word);
+                }
+            }
+            for (Long longValue : property.getInt64ValuesList()) {
+                indexTerm(docId, longValue.toString());
+            }
+            for (Double doubleValue : property.getDoubleValuesList()) {
+                indexTerm(docId, doubleValue.toString());
+            }
+            for (Boolean booleanValue : property.getBooleanValuesList()) {
+                indexTerm(docId, booleanValue.toString());
+            }
+            // Intentionally skipping bytes values
+            for (DocumentProto documentValue : property.getDocumentValuesList()) {
+                indexDocument(docId, documentValue);
+            }
+        }
+    }
+
+    private void indexTerm(int docId, String term) {
+        Set<Integer> postingList = mIndex.get(term);
+        if (postingList == null) {
+            postingList = new ArraySet<>();
+            mIndex.put(term, postingList);
+        }
+        postingList.add(docId);
+    }
+
     /** Strips out punctuation and converts to lowercase. */
     private static String normalizeString(String input) {
         return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault());
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
new file mode 100644
index 0000000..b8dcb90
--- /dev/null
+++ b/apex/sdkext/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 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.
+
+apex {
+    name: "com.android.sdkext",
+    manifest: "manifest.json",
+    java_libs: [ "framework-sdkext" ],
+    key: "com.android.sdkext.key",
+    certificate: ":com.android.sdkext.certificate",
+}
+
+apex_key {
+    name: "com.android.sdkext.key",
+    public_key: "com.android.sdkext.avbpubkey",
+    private_key: "com.android.sdkext.pem",
+}
+
+android_app_certificate {
+    name: "com.android.sdkext.certificate",
+    certificate: "com.android.sdkext",
+}
diff --git a/apex/sdkext/OWNERS b/apex/sdkext/OWNERS
new file mode 100644
index 0000000..feb2742
--- /dev/null
+++ b/apex/sdkext/OWNERS
@@ -0,0 +1 @@
+hansson@google.com
diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkext/com.android.sdkext.avbpubkey
new file mode 100644
index 0000000..8f47741
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.avbpubkey
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkext/com.android.sdkext.pem
new file mode 100644
index 0000000..8164601
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAr72pTSavrziDP54AtQZlRclDxJf9HXRZwFRbYx9hWZ4z7ZtO
+pNBDPvPJCiAOVUsILgCQhBUolz2dyLob25Fd0PVp0n9ibIPEQYjTfHjOK40qb57N
+LhEp2ceGiAfsywPSi0TH1PQ6JgbCe/RM4TefI/sj3gYJPka3ksMvylhMIgUVLgME
+kYizhzwHqlLMspB858SioREZdGwcdZrMMIajGFU69Q9ZRDBzhPvxyKhYoObcOtk1
+uVaiE/fNoi3wKGJz2l2vhUuNrQW7MWlVMag+Qes4YACUTk9LZrOVFEJFjWc8xGUi
+ABtfKGs5JgNr/sWnhvifLn8lJuf0/BJmjD+L5QwXYs2cS7gcZJtTM12J94r0Twgw
+wF2lNmIxAE9sYqj5Rh3dIlTPE5vMUECmQEGjIBB/hzT65VxVqSjU/IlS506JTg3p
+IOQtZ15cUzTBpda4jrvqcq6RNVvgBCu2bV5D8Z4z9FUlPyvD+Zq/6lcoJfLtznAs
+G2463hyPAHTGBIcZ5p5bTuGxoAb6ivyqo4b9Qi4yYA6je9HJmuy8T3Mn5JROoeu9
+BH1K54r/mpT4TQPwuKUvRRtBAV2OPHjo+zp0Gd4Y6rxDYxEIdfEae7pQr/QExSPB
+q/QCr9RhixR1mO373LHuja+MxdAxIxugb2HTS61PQo+PbYrhJMcVuxTwJOECAwEA
+AQKCAgAH7ToRrMkH0ji5SdsmTx+KQkW4PFLCXVke/68PjX7KmAQnl3W4oVwnHr/W
+oROEbVn1GTlre7jU+YaAY0SWZrwgjLE1OWGrG1ZizlUbrCdAd6GOX09J4KROml1L
+DXB0x7tbZMLOrCVjSbLD/ITrM6MN8Gnxvbv0/yOQjxU8vzbP4gLOjHxMRCo001RV
+Ll7lPvcjTQ84zJilU6sE8vJ6zdfVZSK/ou2X0cekG+kP7+fvefo8/UcbEPlGhUrV
+IdVPPQGUu90K2hmN0FBdLi8Vik0klAN68Qu/bHwuKbNzsnmIoztucFFUR+fG3u84
+87aPS0L/J3+mjT2Tv6qhJANUGBmrK/h7MkelpKXlRTCITJLX9xP7hfSbJ4f6aLVq
+ZYPPciGxSBbUDgAwvPtOlMDzccg7YsYyiBBO28wh8MN97rePmc0z6nGmjeXhcbCC
+QktG50VYFCyqp5muKgqQmRfRjHFHLWs8GEqgxMeEL3U3HjYfCYr+6E8Sr5OnOBeH
+3buCi1+zgnNYCvbamgY/OJmW7f9h5O31hxmTplc2E1ZuxUGQZthabt1rN3bmNkyf
+KUmPwnIYkDkWBSV5lzyQExfS3/EVvj0EnHhx8faamimNrGo8xCcfnLT3c0WEFVmo
+yIyVRX3EpXJFM2JkeJ21/IEZXTzHSoNxk12CBG8i8lLSflWSMQKCAQEA2ZqVnOuV
+SZfLCUYUUh8Hvhc5zONstfq7ma1Zsttsdaj9t68nLRiBDvLOGnMjDkYZzoSd4fyl
+oy+YqWGBqcqa5kg1NOCH0I46p9d8RcWAfDnB4sqbLgWh70qsvni6igRijmsMDvkA
+U9HeEdPaLCjQ4UXw7GQvN5rRxuRt+OSqV3tV/Pk9JYyYjz7faC8dmbKDrWHHuOvm
+/9y6Xy+L5IgftykNlUeddSCIoMOAadM7BiRjsrHnOYBQ8xBcn0OYafpIswItrgVi
+IrsPJaBFidx8QYK4MVibyka6U0cm28OocDSPtSk/4jrnCEEhLjFUnWwuMXuBGlrd
+W7wP/muoJqb1VwKCAQEAzsAT90kkOCvAcrfGRE3KkUjwWAsQyP8u2+27JIQPqrpW
+GfWAzJXFt80TSp0Zf/Lrq3/SQ9n4AaL4K9dcMoreedoQN9C9JI7zPtZAWNrJVUcV
+dq2gZjBQ78+oK7uQgvFNWxga5D+Nh+Y+9Tp537fc5HIh0Y13PgsxxPk2OnZJTvLX
+HM5H7Aua9ssmqChsrKihuUsDSPozfBz+H7FNHEdKMqVLqJJSK6m0uMxuLovdVfka
+5S7iBMjEGZc46Iz3ckE0pdOiQLooNqfEQqFe5Uou/KZxxKI1NW25rEEBTVyQWt+2
+BNUCfKP7noZ45u5sUY3eJrgI7BrPEDbNS81WYaLchwKCAQA8Q4mHyd6wYO+EA/qA
+u8NDK9+AFMP4qhXme5HJ7Obetwx9IG7zGEQ1xZy6yoQ84cEn5qZq/bNJvFbFIhHs
+2gWIHRtPJ5e1dI5eCVmLYSUyQjSmAIJ1fm3YfY/VuE3BB3HcC11tkBw9GnQr78YO
+UMd4fAw7C4vgFGpgcMbcFUfvrmKkCsqaaZOeqETq75F9DWlWTSwo1HxHA/RBhENz
+6RcPfLkcTJcY5wevrjUUGcHQ86cAyDBHRngkuLVODkRZpU0Y9lN8TFVfVPre6sIX
+ag6nffJRCD8tB+V2RtBGMKunV4ctHt1oY/Oz34W260aJynoIjjG1ANEpJK4xQdNx
+0O9FAoIBAQCz2AGGKemHswdEwveEkuaSWpA3Bekj7lYkmTchHH9EU7JyAkx3qhDD
+QXB2hxGXawf1tsqAmypQwiJ+gGeCz6mW9UkGRF1DX9XX4yc2I5rew2a4RXAxc/Xz
+pP70i8O5I43Wn7FEusOyY2aAis1Y/eb4EQ+56QTAw5wXa3DwidRbCIJ2XDnT6oRy
+CWUnAYMG7ek/9TB2Wq5OWCn2B5S79IdmZsLZb+5qbMT3u1xcwO1Xy8jJc27IGpv6
+ZsDqCTV1/aJ+XQnWpBg28tiV3Sle6pjUzTRJh5AhWcEZRbKMSOiJI/CBY4k2Qq6t
+xuuEdgFjL7T+mTepqehUglcyiPuLEtAhAoIBAQDDQ5pTFOlunfYzm+CIvvImAgy7
+vrEabJYABATytAbXRMMbrKoEdU2ApEDyEW7PgysDnYLAZ+icObnJlBTYvNdlWFly
+XiviGVfpjFWDT9U/gUwFQu2lfEjoiivoGS92USHUy4UMVHiiznnm20VLLkgd3xna
+HUNSDdHIEgzOTmDsKJwMfA9zGckx23JJimPR5ekv6vr6QllYtECs4lTC1gVQAp2f
+5daxHRbkmO6gw1RgQADLkAnYz3aI1jNuHm5VyAZGt/d3JCtZ3Wwwejll8uJ4J09G
+oEtqyY9RVeHK50bLO4lyAXFiE+J6qqXjsGC20cpxeZYW5llMY/dhA6WV4YXV
+-----END RSA PRIVATE KEY-----
diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkext/com.android.sdkext.pk8
new file mode 100644
index 0000000..ccc0bf4
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pk8
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkext/com.android.sdkext.x509.pem
new file mode 100644
index 0000000..45d2ade
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGIzCCBAugAwIBAgIUXuDL7QvzQh7S6rihWz2KRvCFVT0wDQYJKoZIhvcNAQEL
+BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5zZGtleHQxIjAgBgkqhkiG9w0BCQEW
+E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjAyMTQyNDM0WhgPNDc1NzEwMjgx
+NDI0MzRaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuc2RrZXh0MSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxFvZZ6ES1oqAu1K74/ZxnC3SOhHnLISLBgJEe7DqtdpuNFAwvdVO
+RL/HULhDbjYlOhpU2x3SavDIZZ2lRfiS9Q+M25WftxTRHVjBcpgwbV77TVxPKlAa
+tVN2lUVOY+s4QAVMNIXjC4kCKK/pCQtacH715EtdV47fWdg/Nx4iP/Aord8k3KGI
+9iI2ZOUjaugTRxu5lKRNDrv0bw5rEzyYmDyMud+kR/iS3/5oog57wPE0ffAkZXWE
+p3L2Cejre3ekCizsvVh6EmH6ForKLtL6f0z5Zir1f4R9+YcENspTlJR3pDhg7y3I
+uTQT/iDCtV0l+g2PjGZPEeAQHND3+kDQR7Sno/WC1Nhws6vcu1MdrC+kIh1ewx4y
+8moy/yqb5M98PJDzTSi/AOTB/OiqLXo/T8rjLBmirs9y3fTT6gJ6qXxOWgt8dle9
+7TBfa84Xi8uVY61c+A+YI0nLal7QDPsP3RPv5sJSQ9x9YnweVfD9Q0EOi52sSNu+
+QuN/kcUrMgPgha20VhfH/CkkPDyIp6aZyHHM69MIl+cYEm8vPa5uy3dosuRomT0f
+I4HOBjULDIuj+rIi+Rg3qHvmpuejwZXI/FBNWIhLEUG3ytgksjMaBoYAYflGdrcj
+BQexuF3EO+j4uo7JGjNcaT7wRoCH9gt29VHckDg2qz6VWXrlpmME4UkCAwEAAaNT
+MFEwHQYDVR0OBBYEFISN2nmUHllgPZMZ62U7mU3ZxzlXMB8GA1UdIwQYMBaAFISN
+2nmUHllgPZMZ62U7mU3ZxzlXMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggIBAFHIwyBNIVyHXUsDUdcjxfojXQsF/BCL9ehE3pgdkvDfQanaIREWn0nc
+oCFDFkYMRqaXOGC5TKq4OCjXOLsdfODt8HQ3F9J1B0ghQ5tfOdw7xDugNAszqP/Q
+h7kpvqLTycjrqOeZ5KjxEEYtP/KlUmALgOKcTcSH+XhWyxhjF4j24T9F2yJRr3/A
+r1NGU/djH953bHKC8OpJ2teUpDLA4TxVp/EhslH2eVigF80c/w74QPLEWkD9zv/4
+YeRg/R5N83zHs99NtlWMIeHfK6fUbzMyaSZtvm+jK20tkByQb/OQRed+drk25MtL
+68IRvxqri367qRScdpTZbu0ByLO4X8gFdubRUWr+tcO4pZX+DJRVriExbOkU2xhS
+Vtslq23V/hwTuUNm1CXjR70mPS13BTmHrIQDqLoIw/WTQlGh+vxnlAFRIHM3KB2c
+OdzUBu+NcB4aZEd0KKtct600A0DKPr1MQPb5jDq9wEtPSQYwMF0nRFNnXltbrXMd
+4hhwnhKr74fVMUmb+7eQP56XE/Nk4D+npMO54vv1pav+DI2/nxCND9BOLBweY38p
+Tvd2RjesMok0zXuVXiCIu4GEpwo7WkSnv25xrb0Ey2M8QWnGNnCcX7Kv6ip3RdWy
+HiN0G8RJrs/yNEVSDRx8ZhtwTpXVPQxbARbmhNF4/fnolElkmrMP
+-----END CERTIFICATE-----
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkext/framework/Android.bp
new file mode 100644
index 0000000..b17f0f8
--- /dev/null
+++ b/apex/sdkext/framework/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 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.
+
+filegroup {
+    name: "framework-sdkext-sources",
+    srcs: [
+        "java/**/*.java",
+    ],
+    path: "java",
+}
+
+java_library {
+    name: "framework-sdkext",
+    srcs: [ ":framework-sdkext-sources" ],
+    sdk_version: "system_current",
+    libs: [ "framework-annotations-lib" ],
+    permitted_packages: [ "android.os.ext" ],
+    installable: true,
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
new file mode 100644
index 0000000..c039a82
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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.os.ext;
+
+import android.annotation.IntDef;
+import android.os.Build.VERSION_CODES;
+import android.os.SystemProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public class SdkExtensions {
+
+    private static final int R_EXTENSION_INT;
+    static {
+        R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0);
+    }
+
+    /** Values suitable as parameters for {@link #getExtensionVersion(int)}. */
+    @IntDef(value = { VERSION_CODES.R })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SdkVersion {}
+
+    /**
+     * Return the version of the extension to the given SDK.
+     *
+     * @param sdk the SDK version to get the extension version of.
+     * @see SdkVersion
+     * @throws IllegalArgumentException if sdk is not an sdk version with extensions
+     */
+    public static int getExtensionVersion(@SdkVersion int sdk) {
+        if (sdk < VERSION_CODES.R) {
+            throw new IllegalArgumentException();
+        }
+        return R_EXTENSION_INT;
+    }
+
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkext/framework/java/android/os/ext/package.html
new file mode 100644
index 0000000..34c1697
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Provides APIs to interface with the SDK extensions.
+</BODY>
+</HTML>
diff --git a/apex/sdkext/framework/tests/Android.bp b/apex/sdkext/framework/tests/Android.bp
new file mode 100644
index 0000000..3d5dbb3
--- /dev/null
+++ b/apex/sdkext/framework/tests/Android.bp
@@ -0,0 +1,10 @@
+android_test {
+    name: "framework-sdkext-tests",
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    static_libs: [ "framework-sdkext" ],
+    platform_apis: true,
+}
diff --git a/apex/sdkext/framework/tests/AndroidManifest.xml b/apex/sdkext/framework/tests/AndroidManifest.xml
new file mode 100644
index 0000000..831f132
--- /dev/null
+++ b/apex/sdkext/framework/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.sdkext.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+            android:targetPackage="com.android.sdkext.tests" />
+
+</manifest>
diff --git a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
new file mode 100644
index 0000000..6885110
--- /dev/null
+++ b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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.os.ext;
+
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class SdkExtensionsTest extends TestCase {
+
+    @SmallTest
+    public void testBadArgument() throws Exception {
+        try {
+            SdkExtensions.getExtensionVersion(Build.VERSION_CODES.Q);
+            fail("expected IllegalArgumentException");
+        } catch (IllegalArgumentException expected) { }
+
+        try {
+            SdkExtensions.getExtensionVersion(999999);
+            fail("expected IllegalArgumentException");
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    @SmallTest
+    public void testDefault() throws Exception {
+        int r = SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R);
+        assertTrue(r >= 0);
+    }
+
+}
diff --git a/apex/sdkext/manifest.json b/apex/sdkext/manifest.json
new file mode 100644
index 0000000..048f5c4
--- /dev/null
+++ b/apex/sdkext/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.sdkext",
+  "version": 1
+}
diff --git a/api/current.txt b/api/current.txt
index b66f830..b1eac59 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28928,6 +28928,7 @@
     method @Nullable public String getInterfaceName();
     method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
     method public int getMtu();
+    method @Nullable public android.net.IpPrefix getNat64Prefix();
     method @Nullable public String getPrivateDnsServerName();
     method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
     method public boolean isPrivateDnsActive();
@@ -28938,6 +28939,7 @@
     method public void setInterfaceName(@Nullable String);
     method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
     method public void setMtu(int);
+    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 5a695a5..5ff6778 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -213,6 +213,8 @@
     field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
+    field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
+    field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
     field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
@@ -4441,7 +4443,6 @@
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
-    method @Nullable public android.net.IpPrefix getNat64Prefix();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
     method @Nullable public String getTcpBufferSizes();
     method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -4455,7 +4456,6 @@
     method public boolean removeDnsServer(@NonNull java.net.InetAddress);
     method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean removeRoute(@NonNull android.net.RouteInfo);
-    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
     method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
     method public void setPrivateDnsServerName(@Nullable String);
     method public void setTcpBufferSizes(@Nullable String);
@@ -5425,7 +5425,7 @@
   }
 
   public class WifiManager {
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -5458,12 +5458,12 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
     method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
-    method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
+    method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
@@ -5477,7 +5477,7 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
     field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
     field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
     field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
@@ -8022,6 +8022,10 @@
     field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
   }
 
+  public final class ConnectionRequest implements android.os.Parcelable {
+    method @Nullable public String getTelecomCallId();
+  }
+
   public abstract class ConnectionService extends android.app.Service {
     method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
   }
@@ -8229,6 +8233,7 @@
     method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
     method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
     method public int getAllPhoneAccountsCount();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
     method public int getCallState();
     method public android.telecom.PhoneAccountHandle getConnectionManager();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
diff --git a/api/test-current.txt b/api/test-current.txt
index 9445322..9ac789e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1466,7 +1466,6 @@
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
-    method @Nullable public android.net.IpPrefix getNat64Prefix();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
     method @Nullable public String getTcpBufferSizes();
     method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -1480,7 +1479,6 @@
     method public boolean removeDnsServer(@NonNull java.net.InetAddress);
     method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean removeRoute(@NonNull android.net.RouteInfo);
-    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
     method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
     method public void setPrivateDnsServerName(@Nullable String);
     method public void setTcpBufferSizes(@Nullable String);
@@ -2974,6 +2972,23 @@
     field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
   }
 
+  public final class ConnectionRequest implements android.os.Parcelable {
+    method @Nullable public String getTelecomCallId();
+  }
+
+  public static final class ConnectionRequest.Builder {
+    ctor public ConnectionRequest.Builder();
+    method @NonNull public android.telecom.ConnectionRequest build();
+    method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setTelecomCallId(@NonNull String);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setVideoState(int);
+  }
+
   public static class PhoneAccount.Builder {
     method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
   }
@@ -2987,6 +3002,7 @@
   }
 
   public class TelecomManager {
+    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
     method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
@@ -4274,6 +4290,7 @@
     field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
     field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+    field public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
     field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
   }
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 49cc3c4..2f22b49 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6362,7 +6362,8 @@
     optional bool is_preinstalled = 3;
 
     // True if the package is privileged.
-    optional bool is_priv_app = 4;
+    // Starting from Android 11, this boolean is not set and will always be false.
+    optional bool is_priv_app = 4 [deprecated = true];
 }
 
 /**
diff --git a/core/TEST_MAPPING b/core/TEST_MAPPING
new file mode 100644
index 0000000..fd571c9
--- /dev/null
+++ b/core/TEST_MAPPING
@@ -0,0 +1,24 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.view.inputmethod"
+        },
+        {
+          "include-filter": "com.android.internal.inputmethod"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ],
+      "file_patterns": [
+        "core/java/com/android/internal/inputmethod/.*",
+        "core/java/android/view/inputmethod/.*",
+        "core/tests/coretests/src/android/view/inputmethod/.*",
+        "core/tests/coretests/src/com/android/internal/inputmethod/.*"
+      ]
+    }
+  ]
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0706e75..8e18341 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -762,10 +762,7 @@
      * Returns the NAT64 prefix in use on this link, if any.
      *
      * @return the NAT64 prefix or {@code null}.
-     * @hide
      */
-    @SystemApi
-    @TestApi
     public @Nullable IpPrefix getNat64Prefix() {
         return mNat64Prefix;
     }
@@ -777,10 +774,7 @@
      * 128-bit IPv6 address) are supported or {@code null} for no prefix.
      *
      * @param prefix the NAT64 prefix.
-     * @hide
      */
-    @SystemApi
-    @TestApi
     public void setNat64Prefix(@Nullable IpPrefix prefix) {
         if (prefix != null && prefix.getPrefixLength() != 96) {
             throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ec39199..15ff69e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -505,6 +505,19 @@
     public static final native void restoreCallingWorkSource(long token);
 
     /**
+     * Mark as being built with VINTF-level stability promise. This API should
+     * only ever be invoked by the build system. It means that the interface
+     * represented by this binder is guaranteed to be kept stable for several
+     * years, and the build system also keeps snapshots of these APIs and
+     * invokes the AIDL compiler to make sure that these snapshots are
+     * backwards compatible. Instead of using this API, use an @VintfStability
+     * interface.
+     *
+     * @hide
+     */
+    public final native void markVintfStability();
+
+    /**
      * Flush any Binder commands pending in the current thread to the kernel
      * driver.  This can be
      * useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 4d9ebc2..5b715c0 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -32,7 +32,7 @@
 
 /**
  * Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
- * to fire an event after files are accessed or changed by by any process on
+ * to fire an event after files are accessed or changed by any process on
  * the device (including this one).  FileObserver is an abstract class;
  * subclasses must implement the event handler {@link #onEvent(int, String)}.
  *
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ce91c50..74340f0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -46,6 +46,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.view.WindowManager.LayoutParams;
@@ -486,13 +487,13 @@
      *
      * <p>This user restriction is different from {@link #DISALLOW_SHARE_LOCATION},
      * as the device owner or profile owner can still enable or disable location mode via
-     * {@link DevicePolicyManager#setSecureSetting} when this restriction is on.
+     * {@link DevicePolicyManager#setLocationEnabled} when this restriction is on.
      *
      * <p>The default value is <code>false</code>.
      *
      * <p>Key for user restrictions.
      * <p>Type: Boolean
-     * @see android.location.LocationManager#isProviderEnabled(String)
+     * @see LocationManager#isLocationEnabled()
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 7e09740..236e5ae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,6 +41,7 @@
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
     public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+    public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
 
     private static final Map<String, String> DEFAULT_FLAGS;
 
@@ -48,6 +49,7 @@
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
+        DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "false");
         DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6458737..1855a26 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -161,6 +161,8 @@
     private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
                                                                  int[] allowedConfigs);
     private static native int[] nativeGetAllowedDisplayConfigs(IBinder displayToken);
+    private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
+            int defaultModeId, float minRefreshRate, float maxRefreshRate);
     private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
     private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
             IBinder displayToken);
@@ -1492,6 +1494,19 @@
     /**
      * @hide
      */
+    public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
+            int defaultModeId, float minRefreshRate, float maxRefreshRate) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+
+        return nativeSetDesiredDisplayConfigSpecs(displayToken, defaultModeId, minRefreshRate,
+            maxRefreshRate);
+    }
+
+    /**
+     * @hide
+     */
     public static int[] getDisplayColorModes(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 75a5804..f1e299d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1870,6 +1870,7 @@
             mCount = computeCurrentCountLocked();
             mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
             mUnpluggedReportedCount = mCurrentReportedCount = 0;
+            mTrackingReportedValues = false;
         }
 
         public void setUpdateVersion(int version) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 51f8fcc..148b0a2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,6 +110,7 @@
                 "android_view_InputEventReceiver.cpp",
                 "android_view_InputEventSender.cpp",
                 "android_view_InputQueue.cpp",
+                "android_view_FrameMetricsObserver.cpp",
                 "android_view_KeyCharacterMap.cpp",
                 "android_view_KeyEvent.cpp",
                 "android_view_MotionEvent.cpp",
@@ -424,9 +425,9 @@
         android: {
             srcs: [ // sources that depend on android only libraries
                 "android/graphics/apex/android_canvas.cpp",
+                "android/graphics/apex/renderthread.cpp",
                 "android/graphics/apex/jni_runtime.cpp",
 
-                "android_view_FrameMetricsObserver.cpp",
                 "android_view_TextureLayer.cpp",
                 "android_view_ThreadedRenderer.cpp",
                 "android/graphics/BitmapRegionDecoder.cpp",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2dec4b3..984f93c 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -12,7 +12,6 @@
 #include "SkWebpEncoder.h"
 
 #include "android_os_Parcel.h"
-#include "android_util_Binder.h"
 #include "android_nio_utils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include <hwui/Paint.h>
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 6ffa72a..f18632d 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -25,18 +25,13 @@
 #include "SkBitmapRegionDecoder.h"
 #include "SkCodec.h"
 #include "SkData.h"
-#include "SkUtils.h"
-#include "SkPixelRef.h"
 #include "SkStream.h"
 
-#include "android_nio_utils.h"
-#include "android_util_Binder.h"
 #include "core_jni_helpers.h"
 
 #include <HardwareBitmapUploader.h>
 #include <nativehelper/JNIHelp.h>
 #include <androidfw/Asset.h>
-#include <binder/Parcel.h>
 #include <jni.h>
 #include <sys/stat.h>
 
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 7a9fea7..4de6c86 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -7,6 +7,7 @@
 #include "Utils.h"
 
 #include <nativehelper/JNIHelp.h>
+#include <log/log.h>
 #include <memory>
 
 static jmethodID    gInputStream_readMethodID;
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 9603a10..4ce56ba 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -22,8 +22,6 @@
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include "SkTypeface.h"
-#include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager.h>
 #include <hwui/Typeface.h>
 #include <minikin/FontFamily.h>
 #include <minikin/SystemFonts.h>
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 462d052..17c194d 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -18,6 +18,8 @@
 #include "SkUtils.h"
 #include "SkData.h"
 
+#include <log/log.h>
+
 using namespace android;
 
 AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset)
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index ac291ea..8925517 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -19,8 +19,6 @@
 
 #include "SkStream.h"
 
-#include "android_util_Binder.h"
-
 #include <jni.h>
 #include <androidfw/Asset.h>
 
diff --git a/core/jni/android/graphics/apex/include/android/graphics/renderthread.h b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
new file mode 100644
index 0000000..0a790af
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#ifndef ANDROID_GRAPHICS_RENDERTHREAD_H
+#define ANDROID_GRAPHICS_RENDERTHREAD_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Dumps a textual representation of the graphics stats for this process.
+ * @param fd The file descriptor that the available graphics stats will be appended to.  The
+ *           function requires a valid fd, but does not persist or assume ownership of the fd
+ *           outside the scope of this function.
+ */
+void ARenderThread_dumpGraphicsMemory(int fd);
+
+__END_DECLS
+
+#endif // ANDROID_GRAPHICS_RENDERTHREAD_H
diff --git a/core/jni/android/graphics/apex/renderthread.cpp b/core/jni/android/graphics/apex/renderthread.cpp
new file mode 100644
index 0000000..5d26afe
--- /dev/null
+++ b/core/jni/android/graphics/apex/renderthread.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "android/graphics/renderthread.h"
+
+#include <renderthread/RenderProxy.h>
+
+using namespace android;
+
+void ARenderThread_dumpGraphicsMemory(int fd) {
+    uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+}
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index ca8b8de..5aa684d 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -17,13 +17,11 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
-#include <minikin/Layout.h>
-#include <renderthread/RenderProxy.h>
-
 #include "core_jni_helpers.h"
 #include <unistd.h>
 
 #include <bionic/malloc.h>
+#include <android/graphics/renderthread.h>
 
 namespace android {
 
@@ -35,7 +33,7 @@
 static void
 android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+    ARenderThread_dumpGraphicsMemory(fd);
 }
 
 static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index cb7f0dd..f2a51ad 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -396,9 +396,8 @@
 }
 
 static sp<ANativeWindow> getSurfaceTextureNativeWindow(JNIEnv* env, jobject thiz) {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
-    sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
+    sp<Surface> surfaceTextureClient(producer != NULL ? new Surface(producer) : NULL);
     return surfaceTextureClient;
 }
 
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 2232393..0992beb 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -30,12 +30,13 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-#include <binder/Parcel.h>
 #include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
 #include <binder/ProcessState.h>
+#include <binder/Stability.h>
 #include <cutils/atomic.h>
 #include <log/log.h>
 #include <utils/KeyedVector.h>
@@ -459,6 +460,9 @@
         sp<JavaBBinder> b = mBinder.promote();
         if (b == NULL) {
             b = new JavaBBinder(env, obj);
+            if (mVintf) {
+                ::android::internal::Stability::markVintf(b.get());
+            }
             mBinder = b;
             ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
                  b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
@@ -473,9 +477,18 @@
         return mBinder.promote();
     }
 
+    void markVintf() {
+        mVintf = true;
+    }
+
 private:
     Mutex           mLock;
     wp<JavaBBinder> mBinder;
+
+    // in the future, we might condense this into int32_t stability, or if there
+    // is too much binder state here, we can think about making JavaBBinder an
+    // sp here (avoid recreating it)
+    bool            mVintf = false;
 };
 
 // ----------------------------------------------------------------------------
@@ -965,6 +978,12 @@
     IPCThreadState::self()->restoreCallingWorkSource(token);
 }
 
+static void android_os_Binder_markVintfStability(JNIEnv* env, jobject clazz) {
+    JavaBBinderHolder* jbh =
+        (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+    jbh->markVintf();
+}
+
 static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
 {
     IPCThreadState::self()->flushCommands();
@@ -1041,6 +1060,7 @@
     // @CriticalNative
     { "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
     { "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
+    { "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
     { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
     { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
     { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9f20388..bd202c1 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -810,6 +810,16 @@
     return allowedConfigsArray;
 }
 
+static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz,
+        jobject tokenObj, jint displayModeId, jfloat minRefreshRate, jfloat maxRefreshRate) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == nullptr) return JNI_FALSE;
+
+    size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+        token, displayModeId, minRefreshRate, maxRefreshRate);
+    return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
 static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return -1;
@@ -1366,6 +1376,8 @@
             (void*)nativeSetAllowedDisplayConfigs },
     {"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
             (void*)nativeGetAllowedDisplayConfigs },
+    {"nativeSetDesiredDisplayConfigSpecs", "(Landroid/os/IBinder;IFF)Z",
+            (void*)nativeSetDesiredDisplayConfigSpecs },
     {"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
             (void*)nativeGetDisplayColorModes},
     {"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index 6475151..5491a33 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include "jni.h"
-#include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
 #include "core_jni_helpers.h"
@@ -27,12 +26,8 @@
 #include <gui/surfacetexture/surface_texture_platform.h>
 #include <gui/surfacetexture/SurfaceTexture.h>
 #include <hwui/Paint.h>
-
 #include <SkMatrix.h>
-
 #include <DeferredLayerUpdater.h>
-#include <Rect.h>
-#include <RenderNode.h>
 
 namespace android {
 
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index d181436..ab97fdd 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -693,6 +693,12 @@
     // CATEGORY: SETTINGS
     // OS: R
     ACTION_CONTROLLER_UPDATE_STATE = 1728;
+
+    // Custom tag to evaluate the consuming time from onAttach to
+    // DashboardFragment.updatePreferenceStates.
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACTION_DASHBOARD_VISIBLE_TIME = 1729;
 }
 
 /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 936099f..b83294c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1673,13 +1673,13 @@
     <permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
         android:protectionLevel="signature" />
 
-    <!-- #SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can be increased
-         when the device is stationary in order to save power.
+    <!-- @SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can
+         be increased when the device is stationary in order to save power.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- #SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+    <!-- @SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
         android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6741fea..76d9561 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2363,9 +2363,11 @@
          1 (0b001) - enforce (only install system packages if they are whitelisted)
          2 (0b010) - log (log when a non-whitelisted package is run)
          4 (0b100) - treat any package not mentioned in the whitelist file as implicitly whitelisted
+         8 (0b1000) - ignore OTAs (don't install system packages during OTAs)
         Note: This list must be kept current with PACKAGE_WHITELIST_MODE_PROP in
         frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
-    <integer name="config_userTypePackageWhitelistMode">5</integer> <!-- 0b101 -->
+    <integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 0b1101 -->
+    <!-- TODO(b/143200798): Change to value 5, i.e. 0b0101, when b/143200798 is resolved. -->
 
     <!-- Whether UI for multi user should be shown -->
     <bool name="config_enableMultiUserUI">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2d31f49..7310daf 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5336,5 +5336,5 @@
     <string name="accessibility_system_action_screenshot_label">Screenshot</string>
 
     <!-- Accessibility description of caption view -->
-    <string name="accessibility_freeform_caption"><xliff:g id="app_name">%1$s</xliff:g> app in Pop-up window.</string>
+    <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
 </resources>
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index 6f44d45..f4fb7f4 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -17,10 +17,13 @@
 package android.media;
 
 import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2Info;
+import android.os.Bundle;
 
 /**
  * @hide
  */
 oneway interface IMediaRoute2ProviderClient {
     void updateProviderInfo(in MediaRoute2ProviderInfo info);
+    void notifyRouteSelected(String packageName, String routeId, in Bundle controlHints, int seq);
 }
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 386d2dc..1b6183e 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -18,14 +18,19 @@
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.Objects;
+
 /**
  * @hide
  */
@@ -44,7 +49,7 @@
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
+    public IBinder onBind(@NonNull Intent intent) {
         //TODO: Allow binding from media router service only?
         if (SERVICE_INTERFACE.equals(intent.getAction())) {
             if (mStub == null) {
@@ -57,11 +62,17 @@
 
     /**
      * Called when selectRoute is called on a route of the provider.
+     * Once the route is ready to be used , call {@link #notifyRouteSelected(SelectToken, Bundle)}
+     * to notify that.
      *
      * @param packageName the package name of the application that selected the route
      * @param routeId the id of the route being selected
+     * @param token token that contains select info
+     *
+     * @see #notifyRouteSelected
      */
-    public abstract void onSelectRoute(String packageName, String routeId);
+    public abstract void onSelectRoute(@NonNull String packageName, @NonNull String routeId,
+            @NonNull SelectToken token);
 
     /**
      * Called when unselectRoute is called on a route of the provider.
@@ -69,7 +80,7 @@
      * @param packageName the package name of the application that has selected the route.
      * @param routeId the id of the route being unselected
      */
-    public abstract void onUnselectRoute(String packageName, String routeId);
+    public abstract void onUnselectRoute(@NonNull String packageName, @NonNull String routeId);
 
     /**
      * Called when sendControlRequest is called on a route of the provider
@@ -78,21 +89,21 @@
      * @param request the media control request intent
      */
     //TODO: Discuss what to use for request (e.g., Intent? Request class?)
-    public abstract void onControlRequest(String routeId, Intent request);
+    public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);
 
     /**
      * Called when requestSetVolume is called on a route of the provider
      * @param routeId the id of the route
      * @param volume the target volume
      */
-    public abstract void onSetVolume(String routeId, int volume);
+    public abstract void onSetVolume(@NonNull String routeId, int volume);
 
     /**
      * Called when requestUpdateVolume is called on a route of the provider
      * @param routeId id of the route
      * @param delta the delta to add to the current volume
      */
-    public abstract void onUpdateVolume(String routeId, int delta);
+    public abstract void onUpdateVolume(@NonNull String routeId, int delta);
 
     /**
      * Updates provider info and publishes routes
@@ -102,6 +113,29 @@
         publishState();
     }
 
+    /**
+     * Notifies the client of that the selected route is ready for use. If the selected route can be
+     * controlled, pass a {@link Bundle} that contains how to control it.
+     *
+     * @param token token passed in {@link #onSelectRoute}
+     * @param controlHints a {@link Bundle} that contains how to control the given route.
+     * Pass {@code null} if the route is not available.
+     */
+    public final void notifyRouteSelected(@NonNull SelectToken token,
+            @Nullable Bundle controlHints) {
+        Objects.requireNonNull(token, "token must not be null");
+
+        if (mClient == null) {
+            return;
+        }
+        try {
+            mClient.notifyRouteSelected(token.mPackageName, token.mRouteId,
+                    controlHints, token.mSeq);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to notify route selected");
+        }
+    }
+
     void setClient(IMediaRoute2ProviderClient client) {
         mClient = client;
         publishState();
@@ -118,6 +152,23 @@
         }
     }
 
+    /**
+     * Route selection information.
+     *
+     * @see #notifyRouteSelected
+     */
+    public final class SelectToken {
+        final String mPackageName;
+        final String mRouteId;
+        final int mSeq;
+
+        SelectToken(String packageName, String routeId, int seq) {
+            mPackageName = packageName;
+            mRouteId = routeId;
+            mSeq = seq;
+        }
+    }
+
     final class ProviderStub extends IMediaRoute2Provider.Stub {
         ProviderStub() { }
 
@@ -129,10 +180,10 @@
 
         @Override
         public void requestSelectRoute(String packageName, String id, int seq) {
-            // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
-            // use the sequence number here properly.
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
-                    MediaRoute2ProviderService.this, packageName, id));
+                    MediaRoute2ProviderService.this, packageName, id,
+                    new SelectToken(packageName, id, seq)));
+
         }
 
         @Override
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9cb7869..7b15d95 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -1318,6 +1318,7 @@
         sStatic.rebindAsUser(userId);
     }
 
+    //TODO: remove this and Client1Record in MediaRouter2ServiceImpl.
     /**
      * Sets the control categories of the application.
      * Routes that support at least one of the given control categories only exists and are handled
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 94ac77a..35cb066 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -57,7 +57,8 @@
     @IntDef(value = {
             SELECT_REASON_UNKNOWN,
             SELECT_REASON_USER_SELECTED,
-            SELECT_REASON_FALLBACK})
+            SELECT_REASON_FALLBACK,
+            SELECT_REASON_SYSTEM_SELECTED})
     public @interface SelectReason {}
 
     /**
@@ -80,6 +81,13 @@
      */
     public static final int SELECT_REASON_FALLBACK = 2;
 
+    /**
+     * This is passed from {@link com.android.server.media.MediaRouterService} when the route
+     * is selected in response to a request from other apps (e.g. System UI).
+     * @hide
+     */
+    public static final int SELECT_REASON_SYSTEM_SELECTED = 3;
+
     private static final String TAG = "MR2";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final Object sLock = new Object();
@@ -485,6 +493,9 @@
             }
             mSelectingRoute = null;
         }
+        if (reason == SELECT_REASON_SYSTEM_SELECTED) {
+            reason = SELECT_REASON_USER_SELECTED;
+        }
         mSelectedRoute = route;
         notifyRouteSelected(route, reason, controlHints);
     }
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 378baf4..b65039d3 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 
-#include <media/IDataSource.h>
+#include <android/IDataSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp
index b7cbd97..4fd5153 100644
--- a/media/jni/android_media_Streams.cpp
+++ b/media/jni/android_media_Streams.cpp
@@ -28,67 +28,6 @@
 
 namespace android {
 
-AssetStream::AssetStream(SkStream* stream)
-    : mStream(stream), mPosition(0) {
-}
-
-AssetStream::~AssetStream() {
-}
-
-piex::Error AssetStream::GetData(
-        const size_t offset, const size_t length, std::uint8_t* data) {
-    // Seek first.
-    if (mPosition != offset) {
-        if (!mStream->seek(offset)) {
-            return piex::Error::kFail;
-        }
-    }
-
-    // Read bytes.
-    size_t size = mStream->read((void*)data, length);
-    mPosition = offset + size;
-
-    return size == length ? piex::Error::kOk : piex::Error::kFail;
-}
-
-BufferedStream::BufferedStream(SkStream* stream)
-    : mStream(stream) {
-}
-
-BufferedStream::~BufferedStream() {
-}
-
-piex::Error BufferedStream::GetData(
-        const size_t offset, const size_t length, std::uint8_t* data) {
-    // Seek first.
-    if (offset + length > mStreamBuffer.bytesWritten()) {
-        size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
-        if (sizeToRead <= kMinSizeToRead) {
-            sizeToRead = kMinSizeToRead;
-        }
-
-        void* tempBuffer = malloc(sizeToRead);
-        if (tempBuffer == NULL) {
-          return piex::Error::kFail;
-        }
-
-        size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
-        if (bytesRead != sizeToRead) {
-            free(tempBuffer);
-            return piex::Error::kFail;
-        }
-        mStreamBuffer.write(tempBuffer, bytesRead);
-        free(tempBuffer);
-    }
-
-    // Read bytes.
-    if (mStreamBuffer.read((void*)data, offset, length)) {
-        return piex::Error::kOk;
-    } else {
-        return piex::Error::kFail;
-    }
-}
-
 FileStream::FileStream(const int fd)
     : mPosition(0) {
     mFile = fdopen(fd, "r");
diff --git a/media/jni/android_media_Streams.h b/media/jni/android_media_Streams.h
index d174f9a..800591c 100644
--- a/media/jni/android_media_Streams.h
+++ b/media/jni/android_media_Streams.h
@@ -25,53 +25,9 @@
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/StrongPointer.h>
-#include <SkStream.h>
-
 
 namespace android {
 
-class AssetStream : public piex::StreamInterface {
-private:
-    SkStream *mStream;
-    size_t mPosition;
-
-public:
-    explicit AssetStream(SkStream* stream);
-    ~AssetStream();
-
-    // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
-    // provided by the caller, guaranteed to be at least "length" bytes long.
-    // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
-    // 'offset' bytes from the start of the stream.
-    // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
-    // change the contents of 'data'.
-    piex::Error GetData(
-            const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
-class BufferedStream : public piex::StreamInterface {
-private:
-    SkStream *mStream;
-    // Growable memory stream
-    SkDynamicMemoryWStream mStreamBuffer;
-
-    // Minimum size to read on filling the buffer.
-    const size_t kMinSizeToRead = 8192;
-
-public:
-    explicit BufferedStream(SkStream* stream);
-    ~BufferedStream();
-
-    // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
-    // provided by the caller, guaranteed to be at least "length" bytes long.
-    // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
-    // 'offset' bytes from the start of the stream.
-    // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
-    // change the contents of 'data'.
-    piex::Error GetData(
-            const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
 class FileStream : public piex::StreamInterface {
 private:
     FILE *mFile;
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index f4f8d0b..6650f96 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -20,6 +20,7 @@
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
 import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
 import android.os.IBinder;
 
 import java.util.HashMap;
@@ -95,7 +96,7 @@
     }
 
     @Override
-    public void onSelectRoute(String packageName, String routeId) {
+    public void onSelectRoute(String packageName, String routeId, SelectToken token) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null) {
             return;
@@ -104,6 +105,7 @@
                 .setClientPackageName(packageName)
                 .build());
         publishRoutes();
+        notifyRouteSelected(token, Bundle.EMPTY);
     }
 
     @Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index d0f7c78..c70ad8d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -23,23 +23,19 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.content.Intent;
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2;
 import android.media.MediaRouter2Manager;
+import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 
-import org.junit.Assert;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -95,9 +91,14 @@
     private Executor mExecutor;
     private String mPackageName;
 
+    private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
+    private final List<MediaRouter2.Callback> mRouterCallbacks = new ArrayList<>();
+    private Map<String, MediaRoute2Info> mRoutes;
+
     private static final List<String> CATEGORIES_ALL = new ArrayList();
     private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
     private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
+
     static {
         CATEGORIES_ALL.add(CATEGORY_SAMPLE);
         CATEGORIES_ALL.add(CATEGORY_SPECIAL);
@@ -108,6 +109,7 @@
         CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
     }
 
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
@@ -116,6 +118,16 @@
         //TODO: If we need to support thread pool executors, change this to thread pool executor.
         mExecutor = Executors.newSingleThreadExecutor();
         mPackageName = mContext.getPackageName();
+
+        // ensure media router 2 client
+        addRouterCallback(new MediaRouter2.Callback());
+        mRoutes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+    }
+
+    @After
+    public void tearDown() {
+        // unregister callbacks
+        clearCallbacks();
     }
 
     //TODO: Move to a separate file
@@ -132,10 +144,13 @@
         assertNotEquals(routeInfo1, routeInfo3);
     }
 
+    /**
+     * Tests if routes are added correctly when a new callback is registered.
+     */
     @Test
     public void testOnRoutesAdded() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
-        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+        addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
                 assertTrue(routes.size() > 0);
@@ -145,27 +160,15 @@
                     }
                 }
             }
-        };
-        mManager.registerCallback(mExecutor, callback);
+        });
 
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
-        mManager.unregisterCallback(callback);
     }
 
     @Test
     public void testOnRoutesRemoved() throws Exception {
-        MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.registerCallback(mExecutor, mockCallback);
-
-        MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
-        mRouter2.registerCallback(mExecutor, routerCallback);
-
-        Map<String, MediaRoute2Info> routes =
-                waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
         CountDownLatch latch = new CountDownLatch(1);
-        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+        addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesRemoved(List<MediaRoute2Info> routes) {
                 assertTrue(routes.size() > 0);
@@ -175,16 +178,12 @@
                     }
                 }
             }
-        };
-        mManager.registerCallback(mExecutor, callback);
+        });
 
         //TODO: Figure out a more proper way to test.
         // (Control requests shouldn't be used in this way.)
-        mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
+        mRouter2.sendControlRequest(mRoutes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
-        mRouter2.unregisterCallback(routerCallback);
-        mManager.unregisterCallback(mockCallback);
     }
 
     /**
@@ -192,16 +191,10 @@
      */
     @Test
     public void testControlCategory() throws Exception {
-        MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.registerCallback(mExecutor, mockCallback);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
 
-        Map<String, MediaRoute2Info> routes =
-                waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
-
-        Assert.assertEquals(1, routes.size());
-        Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
-        mManager.unregisterCallback(mockCallback);
+        assertEquals(1, routes.size());
+        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
     }
 
     /**
@@ -209,37 +202,60 @@
      */
     @Test
     public void testGetRoutes() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-        mRouter2.registerCallback(mExecutor, mockCallback);
-
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
 
-        Assert.assertEquals(1, routes.size());
-        Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
-        mRouter2.unregisterCallback(mockCallback);
+        assertEquals(1, routes.size());
+        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
     }
 
+    /**
+     * Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
+     */
     @Test
-    public void testOnRouteSelected() throws Exception {
-        MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
-        MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
+    public void testRouterOnRouteSelected() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
 
-        mManager.registerCallback(mExecutor, managerCallback);
-        mRouter2.registerCallback(mExecutor, routerCallback);
+        addRouterCallback(new MediaRouter2.Callback() {
+            @Override
+            public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
+                if (route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+                    latch.countDown();
+                }
+            }
+        });
 
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
-        MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+        MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
         assertNotNull(routeToSelect);
 
         mManager.selectRoute(mPackageName, routeToSelect);
-        verify(managerCallback, timeout(TIMEOUT_MS))
-                .onRouteSelected(eq(mPackageName),
-                        argThat(route -> route != null && route.equals(routeToSelect)));
 
-        mRouter2.unregisterCallback(routerCallback);
-        mManager.unregisterCallback(managerCallback);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    /**
+     * Tests if MR2Manager.Callback.onRouteSelected is called
+     * when a route is selected by MR2Manager.
+     */
+    @Test
+    public void testManagerOnRouteSelected() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        addManagerCallback(new MediaRouter2Manager.Callback() {
+            @Override
+            public void onRouteSelected(String packageName, MediaRoute2Info route) {
+                if (TextUtils.equals(mPackageName, packageName)
+                        && route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+                    latch.countDown();
+                }
+            }
+        });
+
+        MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
+        assertNotNull(routeToSelect);
+
+        mManager.selectRoute(mPackageName, routeToSelect);
+
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     /**
@@ -247,19 +263,13 @@
      */
     @Test
     public void testSingleProviderSelect() throws Exception {
-        MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
-
-        mRouter2.registerCallback(mExecutor, routerCallback);
-
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
         awaitOnRouteChangedManager(
-                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
+                () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID1)),
                 ROUTE_ID1,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
         awaitOnRouteChangedManager(
-                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
+                () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID2)),
                 ROUTE_ID2,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
@@ -267,8 +277,6 @@
                 () -> mManager.unselectRoute(mPackageName),
                 ROUTE_ID2,
                 route -> TextUtils.equals(route.getClientPackageName(), null));
-
-        mRouter2.unregisterCallback(routerCallback);
     }
 
     @Test
@@ -292,12 +300,7 @@
 
     @Test
     public void testControlVolumeWithManager() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-
-        mRouter2.registerCallback(mExecutor, mockCallback);
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
-        MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+        MediaRoute2Info volRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
         int originalVolume = volRoute.getVolume();
         int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
 
@@ -310,24 +313,16 @@
                 () -> mManager.requestSetVolume(volRoute, originalVolume),
                 ROUTE_ID_VARIABLE_VOLUME,
                 (route -> route.getVolume() == originalVolume));
-
-        mRouter2.unregisterCallback(mockCallback);
     }
 
     @Test
     public void testVolumeHandling() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-        mRouter2.registerCallback(mExecutor, mockCallback);
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
-
-        MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
-        MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+        MediaRoute2Info fixedVolumeRoute = mRoutes.get(ROUTE_ID_FIXED_VOLUME);
+        MediaRoute2Info variableVolumeRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
 
         assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
         assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
         assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
-
-        mRouter2.unregisterCallback(mockCallback);
     }
 
     @Test
@@ -368,6 +363,7 @@
                     latch.countDown();
                 }
             }
+
             @Override
             public void onControlCategoriesChanged(String packageName) {
                 if (TextUtils.equals(mPackageName, packageName)) {
@@ -401,7 +397,7 @@
         };
         mRouter2.registerCallback(mExecutor, callback);
         try {
-            new Thread(task).start();
+            task.run();
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         } finally {
             mRouter2.unregisterCallback(callback);
@@ -422,7 +418,7 @@
         };
         mManager.registerCallback(mExecutor, callback);
         try {
-            new Thread(task).start();
+            task.run();
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         } finally {
             mManager.unregisterCallback(callback);
@@ -433,9 +429,31 @@
     static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
         Map<String, MediaRoute2Info> routeMap = new HashMap<>();
         for (MediaRoute2Info route : routes) {
-            // intentionally not route.getUniqueId() for convenience.
+            // intentionally not using route.getUniqueId() for convenience.
             routeMap.put(route.getId(), route);
         }
         return routeMap;
     }
+
+    private void addManagerCallback(MediaRouter2Manager.Callback callback) {
+        mManagerCallbacks.add(callback);
+        mManager.registerCallback(mExecutor, callback);
+    }
+
+    private void addRouterCallback(MediaRouter2.Callback callback) {
+        mRouterCallbacks.add(callback);
+        mRouter2.registerCallback(mExecutor, callback);
+    }
+
+    private void clearCallbacks() {
+        for (MediaRouter2Manager.Callback callback : mManagerCallbacks) {
+            mManager.unregisterCallback(callback);
+        }
+        mManagerCallbacks.clear();
+
+        for (MediaRouter2.Callback callback : mRouterCallbacks) {
+            mRouter2.unregisterCallback(callback);
+        }
+        mRouterCallbacks.clear();
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index 1c62879..0a1a122 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -76,6 +76,19 @@
     }
 
     /**
+     * Logs the elapsed time from onAttach to calling {@link #writeElapsedTimeMetric(int, String)}.
+     * @param action : The value of the Action Enums.
+     * @param key : The value of special key string.
+     */
+    public void writeElapsedTimeMetric(int action, String key) {
+        if (mMetricsFeature == null || mMetricsCategory == METRICS_CATEGORY_UNKNOWN) {
+            return;
+        }
+        final int elapse = (int) (SystemClock.elapsedRealtime() - mTimestamp);
+        mMetricsFeature.action(METRICS_CATEGORY_UNKNOWN, action, mMetricsCategory, key, elapse);
+    }
+
+    /**
      * Sets source metrics category for this logger. Source is the caller that opened this UI.
      */
     public void setSourceMetricsCategory(Activity activity) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7d06e6c..7b1c382 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -120,7 +120,7 @@
     private OsuProvider createOsuProvider() {
         Map<String, String> friendlyNames = new HashMap<>();
         friendlyNames.put("en", OSU_FRIENDLY_NAME);
-        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null, null);
+        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
     }
 
     @Before
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 94fbc54..81cf118 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -336,7 +336,7 @@
     private static OsuProvider buildOsuProvider(String friendlyName) {
         Map<String, String> friendlyNames = new HashMap<>();
         friendlyNames.put("en", friendlyName);
-        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null, null);
+        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
     }
 
     private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java
new file mode 100644
index 0000000..5f3d7f1
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+
+import android.text.TextUtils;
+
+/**
+ * Ensure a restored value is a string in the format the accessibility shortcut system handles
+ *
+ * @hide
+ */
+public final class AccessibilityShortcutTargetListValidator extends ListValidator {
+    public AccessibilityShortcutTargetListValidator() {
+        super(":");
+    }
+
+    @Override
+    protected boolean isEntryValid(String entry) {
+        return !TextUtils.isEmpty(entry);
+    }
+
+    @Override
+    protected boolean isItemValid(String item) {
+        if (TextUtils.isEmpty(item)) {
+            return false;
+        }
+        return (COMPONENT_NAME_VALIDATOR.validate(item) || PACKAGE_NAME_VALIDATOR.validate(item));
+    }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
index a6001d2..104fa11 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
@@ -35,7 +35,7 @@
         if (!isEntryValid(value)) {
             return false;
         }
-        String[] items = value.split(",");
+        String[] items = value.split(mListSplitRegex);
         for (String item : items) {
             if (!isItemValid(item)) {
                 return false;
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 9460d27f..090af98 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -16,6 +16,7 @@
 
 package android.provider.settings.validators;
 
+import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
@@ -71,10 +72,13 @@
         VALIDATORS.put(Secure.TOUCH_EXPLORATION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
-                Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, NULLABLE_COMPONENT_NAME_VALIDATOR);
+                Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
         // technically either ComponentName or class name, but there's proper value
         // validation at callsites, so allow any non-null string
-        VALIDATORS.put(Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, value -> value != null);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+                ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 224042c..71c7544 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -204,4 +204,7 @@
             new InclusiveIntegerRangeValidator(0, 100);
 
     static final Validator VIBRATION_INTENSITY_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
+    static final Validator ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR =
+            new AccessibilityShortcutTargetListValidator();
 }
diff --git a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index a3b0835..bb9e6f6 100644
--- a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -297,6 +297,18 @@
     }
 
     @Test
+    public void testAccessibilityShortcutTargetValidator() {
+        assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android/.AccessibilityShortcutTarget"));
+        assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android"));
+        assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android/.AccessibilityShortcutTarget:com.google.android"));
+        assertFalse(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android/.AccessibilityShortcutTarget:com.google.@android"));
+    }
+
+    @Test
     public void ensureAllBackedUpGlobalSettingsHaveValidators() {
         String offenders = getOffenders(concat(GlobalSettings.SETTINGS_TO_BACKUP,
                 Settings.Global.LEGACY_RESTORE_SETTINGS), GlobalSettingsValidators.VALIDATORS);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 2068f7c..dfd9941 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -125,6 +126,7 @@
         assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.getKey()));
     }
 
+    @Ignore("b/141538055")
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
         NotificationEntry laterEntry = new NotificationEntryBuilder()
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
new file mode 100644
index 0000000..bca01ebd
--- /dev/null
+++ b/packages/Tethering/apex/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 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.
+//
+
+apex {
+    name: "com.android.tethering.apex",
+    apps: ["Tethering"],
+    manifest: "manifest.json",
+    key: "com.android.tethering.apex.key",
+
+    androidManifest: "AndroidManifest.xml",
+}
+
+apex_key {
+    name: "com.android.tethering.apex.key",
+    public_key: "com.android.tethering.apex.avbpubkey",
+    private_key: "com.android.tethering.apex.pem",
+}
+
+android_app_certificate {
+    name: "com.android.tethering.apex.certificate",
+    certificate: "com.android.tethering.apex",
+}
diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml
new file mode 100644
index 0000000..7769b79
--- /dev/null
+++ b/packages/Tethering/apex/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.tethering.apex">
+  <!-- APEX does not have classes.dex -->
+  <application android:hasCode="false" />
+  <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version
+                    before ship. -->
+  <uses-sdk
+      android:minSdkVersion="29"
+      android:targetSdkVersion="29"
+  />
+</manifest>
diff --git a/packages/Tethering/apex/com.android.tethering.apex.avbpubkey b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
new file mode 100644
index 0000000..9c87111
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pem b/packages/Tethering/apex/com.android.tethering.apex.pem
new file mode 100644
index 0000000..a8cd12e
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwloHpMmwszNBEgUVion141BTvF/oJ5g5DlQIYBtmht4tSpc3
+6elWXd+dhMzFxf/RkxSNRsU+dhD11cPKGp9nUYQQGrHEf3xEKwAHJKRMq26TkJ3o
+1TwOO70TaRKKA4ThNiM3VFDX2vy1ijArhZDIBTGVJCUl9HOHiO+ZJG5DKCx3KXbO
+QWz3c+Lbprr1L76dwIsl5kuoAFwgG0J+9BZhHEzIG1lVpGG7RRLxc8eDIxNN/oKT
+gPYBcOxFYqOECKGBBvElf6MxdRv6xG7gooALY2/HDMYUjAJSOosfwzeymugCzMhK
+e+6CSTAaEfUzuVZvMc2qnd1ly7zpLo9x+TOdH5LEVZpSwqmu2n5bqrUnSEAJUvMz
+SSw0YbsLWJZuTiTV7lecSITgqsmwuZyDexDmUkDQChzrTixsQV6S8vsh/FanjWoi
+zBlPneX8Q7/LME3hxHyLbrabxX0zWiyj8iM9h/8Y4mpO/MjEmmavglTAP4J8zrKD
+FBsntCoch9I49IpYBuO6NfKw1h7AUpLf8gARAjFjRxiJVcSgGY/Wt4/pBzJ57T5g
+xPvqxfpPQP0OA2CT8LqqzZIR8jXs8/TquvwLkkY2kRRPXx+azd5oU2A0uonrUY31
+Bc1obfmWPuEMz9bO/i06ETHuWPd4RiUNaB8qEmjYuKJfhv72YNcRwhrAYJECAwEA
+AQKCAgAaQn3b5yCH5fn5zFQPxvpBP35A6ph8mRXEeNg03B7rRCPMe0gjw9JWlrs6
+0Uw7p4gSnmlEUaxR2ZLN0kmBdV5JZlWitbg+HXU8diGA8u4lD6jCloN6JEYsDi0M
+OmQJe6/OV83HB7FStmh1BnMq9dgA06U6IAbT07RRbUY85OUQDYoAQTw3HNkGgHV7
+PrGYROIdvO9fAYPuoIP6Cu8KXee7Iii7gUOQFWBvQdL7+M4gNCCKrevuNc8WCeaK
+IFvbqq67WGPfrhYlo6UrW2vgqPpg8h5r/GuUS0/+9wNQpjrssUKHltxxiFV0PBqZ
+qI7XkPUvPoG6GMsDT0AWeW1F5ZJqEGPN67Xek0BCD0cpUli+nHD0yWGVHtkpHU2D
+qUOZdB2COfBuXRdW1LsYNPg8YjTCPsmGhISLTwiTNcZJeTxoK1y0CcVW9d7Af2aD
+lYzCegscQlXkSZiFj9s90Vd3KdD2XKrH/ADxzsOxQJ89ka004efdQa5/MKs9aChG
+/5XrwBEfN4O92OjY7KqXUAwB7CcVzNymOjD6r07LM24zbkRpwwXlkP0wmjsHBXkh
+8p0ISmY9QRdvhBgYmFmoPWZncM0zym9LI8atBs4CijQ7JjuOQ8HgHg+Se2eppWfe
+t8r6TVkDB8JeNAMxjX9q0G7icf3JjlIrgERZfyXLmpduR9NdkQKCAQEA5rp2fSKh
+RwihHNtJhNktFJuLR9OA++vyfjqhWnB8CrLPo3//LGWW/+WBr8EwXi/76hQpeKlf
+u8SmkTtxIHlTP2Brh2koh1Qf8HKzPHGjZeDFOoVPKHPqe3nV+cv3srd1mS0Eq3BA
+ZFQq+l61f2iiTZKxDroCahNEa8VMzirW6nKb5xhyMPHXgncCUdphHbwAGatas6be
+RUFg4ChH8BwX6jYw7leRUy2K6OqEl0fckT4Laitlb/ezKtwmD4PPE95q5hH0v3SO
+wetHWafiNrOXPn2wQqBrI2y+AfbTjNmQiaIPgcFKAQ7V3n+c3XfGZ9Xfv4L8m/wo
+RZ4ika1zur021QKCAQEA16OUBPA7BnWd+RJFri2kJBG5JZElaV9chO2ZHcXUbFR9
+HIPkWN19bJbki8Ca0w8FUQuS/M7JeeFjoZ194NlczbR899GVmb0X2AUKXilMacs3
+IONxIDczx3KFtsge8ewXRAjQvgE7M3NpmmJfPLPog7spMCbUIxbc3jzjiZgB/J1s
+WytlUTUY/Zy4V1wujkoydgK2KcHcEWG2oIy7EP0RwnL1NhTksXOtBH6+MoRMAT+H
+fcBK6yfJBNBRQzJ0PdkCCLdQPN1VtwRlWjPXZ3ey4fWvZ399wSLUkM2V1jB4GcOZ
++DAgtwFKs9+HfOdV42GgFWFcjP+bkM3bcdrQFnmYzQKCAQAQnf1KpePXqddwrJpu
+5vVINquhUKpJeoTMcoyMZu2IF7i8nctS9z4Yz/63GcLSBcKu6STTe99ZNqCIdS+A
+lzxXpCoaZoh0tqpWNuyRvd12yOlrfY5l63NH0U6H3xjH1k6x6XwcnMkGcMlnnsqT
+koWd8KKv3NWvrhOPb3ZIou03lWmFC02uGLzcuJWCL6gu7AtVzfGKXspDUqIXgs8r
+i9ptE9oSUFw3EWCfxcQm4RYRn9ZSny1/EufkflZ/Z47Sb4Jjb4ehAlQFw1wwKNcx
++V07MvIu2j7dHkfQ/GXgDwtJ3lIfljwuN1NP4wD5Mlcnw0+KC3UGBvMfkHQM6eEb
+4eTBAoIBAQDWfZsqHlpX3n431XkB+9wdFJP5ThrMaVJ51mxLNRBKgO/BgV+NFSNA
+9AZ5DCf0cCh1qPGYDYhSd2LGywT+trac1j7Hse0AcxpYgQsDBkk/oic/y3wm80HJ
+zZw7Z2uAb7nkrnATzt24G8CbE+ZvVvScs3oQr06raH5hgGdD4bN4No4lUVECKbKl
+8VFbdBHK7vqqb6AKgQ4JLAygPduE1nTn2bkXBklESS98HSXK0dVYGH0JFFBw/63v
+39Y05ObC7iwbx1tEb1RnKzQ1OQO1o1aHc/35ENNhXOfa8ONtneCYn/ty50xjPCG2
+MU1vbBv+hIjbO3D3vvhaXKk+4svAz0qxAoIBAQC84FJEjKHJHx17jLeoTuDfuxwX
+6bOQrI3nHbtnFRvPrMryWRDtHLv89Zma3o68/n4vTn5+AnvgYMZifOYlTlIPxinH
+tlE+qCD8KBXUlZdrc+5GGM18lp5tF3Ro4LireH+OhiOAWawaSzDIDYdiR6Kz9NU+
+SjcHKjDObeM6iMEukoaRsufMedpUSrnbzMraAJgBZGay1NZs/o8Icl3OySYPZWEK
+MJxVBMXU9QcUp2GEioYd/eNuP9rwyjq/EIUDJbP2vESAe6+FdGbIgvyYTV/gnKaH
+GcvyMNVZbCMp/wCYNonjlu+18m2w+pVs2uuZLqORkrKYhisK83TKxh4YOWJh
+-----END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pk8 b/packages/Tethering/apex/com.android.tethering.apex.pk8
new file mode 100644
index 0000000..5663246
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pk8
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.x509.pem b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
new file mode 100644
index 0000000..a5e9401
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGMzCCBBugAwIBAgIUXVtoDaXanhs7ma8VIICambMkj5UwDQYJKoZIhvcNAQEL
+BQAwgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcuYXBleDEiMCAGCSqG
+SIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAgFw0xOTExMjgwNjU4MTRaGA80
+NzU3MTAyNDA2NTgxNFowgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcu
+YXBleDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBANwzufMBdOj9XlNwiX+bXl/94G0DklWW
+nzob0jPlubCFfRqYkjCf2eOd28Mu/O1pOBcvobnrs9OTpGzcHkz2h58L5/0UMVTS
+tBugwCE49XF5FHawqVHNZE+s5tDmnp2cufhNc5HXHY4oZKh80/WVdbcKxiLjSY2T
+PgRAfB6E6XByKD3t1cSsc3liRVKADoJOVDvmF+xnyvSV/SN38bvTQk9aVs95mj0W
+yov6gzXBnqN7iQlvkhcijZBnFWxvoNbJ5KFy1abYOrm+ueXje4BcNhVOeRMb4E9N
+eo7+9k1GEI7TYG7laNNcp7UJ1IXCJzv/wBFKRg3f1HB3unKfx2rtKerDnVsr3o7V
+KProkgRNKNhhQ6opNguiH1YMzKpWMaC988n4AQPryPdIOmVIxIC5jJrixdxgzDXT
+qeiwFiXis291uyls08B03PQFlY9oWaY9P8s+4hIUjB6rLl+XZXsLDtDFxXeJ97NB
+8XZN1gBJoBoLknFs0C4LKpmJZB/EBao9tXV9dL/5lydRo6HzQDpjW8QX06CTUM6z
+Lr3LVelhqbsuZsV42yBKl+/LfrvNjBLEPdSevt2oMrlJW7m4iSNaMtDtJ2Oy8fA5
+WSIgLWuMbkaFDza3JzwiMzxbtbJHYiy6rY7aVywo3Vqwr1+KO3cq4eLQq62zUjRY
+e6KJwvgE2YmpAgMBAAGjUzBRMB0GA1UdDgQWBBQ8h1oF5JfKFmJCN8nfimbUK+IR
+wjAfBgNVHSMEGDAWgBQ8h1oF5JfKFmJCN8nfimbUK+IRwjAPBgNVHRMBAf8EBTAD
+AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAP5hIkAxSyt9hRafMKiFlmXcL277bgoxNd
+qGZYbdcCFjfvM2r0QQcM/K7x2ZslFe7mJSzcyMifpm4YQTEo2yYbzKItXQV+eV1K
+9RNksRGFG9umsdWaSHhfQmcmxtr2nu9rGAgxy5OQFtyXmJPUPEM2cb/YeILwYhuQ
+Ux3kaj/fxGltX1JBag7HnMzCTZK++fRo5nqFVOJQgJH8ZpuzGeM9kZvP1+b55046
+PhSnlqmZoKhG4i5POPvvZvaakh/lM3x/N7lIlSaQpCGf7jmldni4L0/GenULVKzH
+iN73aBfh4GEvE0HRcOoH3L7V6kc3WMMLve0chZBHpoVYbzUJEJOUL4yrmwEehqtf
+xm4vlYg3vqtcE3UnU/UGdMb16t77Nz88LlpBY5ierIt0jZMU0M81ppRhr1uiD2Lj
+091sEA0Bxcw/6Q8QNF2eR7SG7Qwipnms+lw6Vcxve+7DdTrdEA0k3XgpdXp8Ya+2
+PAp9SLVp1UHiGq3qD9Jvm34QmlUWAIUTHZs3DSgs1y3K5eyw/cnzTvUUOljc/n2y
+VF0FFZtJ1dVLrzQ80Ik7apEXpBqkgBGV04/L3QYk4C0/sP+1yk6zjeeeAvDtUcHS
+gLtjAfacQl/kwfVQWfrF7VByLcivApC6EUdvT3cURM5DfZRQ4RcKr1D61VYPnNRH
++/NVbMObwQ==
+-----END CERTIFICATE-----
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
new file mode 100644
index 0000000..3fb62f3
--- /dev/null
+++ b/packages/Tethering/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.tethering.apex",
+  "version": 290000000
+}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 652dd40..a3a6172 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -925,6 +925,10 @@
             return IIpConnectivityMetrics.Stub.asInterface(
                     ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
         }
+
+        public IBatteryStats getBatteryStatsService() {
+            return BatteryStatsService.getService();
+        }
     }
 
     public ConnectivityService(Context context, INetworkManagementService netManager,
@@ -2144,7 +2148,7 @@
                     opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
                     options = opts.toBundle();
                 }
-                final IBatteryStats bs = BatteryStatsService.getService();
+                final IBatteryStats bs = mDeps.getBatteryStatsService();
                 try {
                     bs.noteConnectivityChanged(intent.getIntExtra(
                             ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
@@ -5628,7 +5632,8 @@
         // are accurate.
         networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
 
-        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
+        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
+                networkAgent.networkInfo.getType());
 
         // update filtering rules, need to happen after the interface update so netd knows about the
         // new interface (the interface name -> index map becomes initialized)
@@ -5707,21 +5712,26 @@
 
     }
 
-    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
-                                  NetworkCapabilities caps) {
-        CompareResult<String> interfaceDiff = new CompareResult<>(
+    private void updateInterfaces(final @Nullable LinkProperties newLp,
+            final @Nullable LinkProperties oldLp, final int netId,
+            final @Nullable NetworkCapabilities caps, final int legacyType) {
+        final CompareResult<String> interfaceDiff = new CompareResult<>(
                 oldLp != null ? oldLp.getAllInterfaceNames() : null,
                 newLp != null ? newLp.getAllInterfaceNames() : null);
-        for (String iface : interfaceDiff.added) {
-            try {
-                if (DBG) log("Adding iface " + iface + " to network " + netId);
-                mNMS.addInterfaceToNetwork(iface, netId);
-                wakeupModifyInterface(iface, caps, true);
-            } catch (Exception e) {
-                loge("Exception adding interface: " + e);
+        if (!interfaceDiff.added.isEmpty()) {
+            final IBatteryStats bs = mDeps.getBatteryStatsService();
+            for (final String iface : interfaceDiff.added) {
+                try {
+                    if (DBG) log("Adding iface " + iface + " to network " + netId);
+                    mNMS.addInterfaceToNetwork(iface, netId);
+                    wakeupModifyInterface(iface, caps, true);
+                    bs.noteNetworkInterfaceType(iface, legacyType);
+                } catch (Exception e) {
+                    loge("Exception adding interface: " + e);
+                }
             }
         }
-        for (String iface : interfaceDiff.removed) {
+        for (final String iface : interfaceDiff.removed) {
             try {
                 if (DBG) log("Removing iface " + iface + " from network " + netId);
                 wakeupModifyInterface(iface, caps, false);
@@ -6457,77 +6467,6 @@
         // do this after the default net is switched, but
         // before LegacyTypeTracker sends legacy broadcasts
         for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
-
-        // Linger any networks that are no longer needed. This should be done after sending the
-        // available callback for newNetwork.
-        for (NetworkAgentInfo nai : removedRequests) {
-            updateLingerState(nai, now);
-        }
-        // Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
-        // does not need to be done in any particular order.
-        updateLingerState(newNetwork, now);
-
-        if (isNewDefault) {
-            // Maintain the illusion: since the legacy API only
-            // understands one network at a time, we must pretend
-            // that the current default network disconnected before
-            // the new one connected.
-            if (oldDefaultNetwork != null) {
-                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
-                                          oldDefaultNetwork, true);
-            }
-            mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
-            mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
-            notifyLockdownVpn(newNetwork);
-        }
-
-        if (reassignedRequests.containsValue(newNetwork) || newNetwork.isVPN()) {
-            // Notify battery stats service about this network, both the normal
-            // interface and any stacked links.
-            // TODO: Avoid redoing this; this must only be done once when a network comes online.
-            try {
-                final IBatteryStats bs = BatteryStatsService.getService();
-                final int type = newNetwork.networkInfo.getType();
-
-                final String baseIface = newNetwork.linkProperties.getInterfaceName();
-                bs.noteNetworkInterfaceType(baseIface, type);
-                for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
-                    final String stackedIface = stacked.getInterfaceName();
-                    bs.noteNetworkInterfaceType(stackedIface, type);
-                }
-            } catch (RemoteException ignored) {
-            }
-
-            // This has to happen after the notifyNetworkCallbacks as that tickles each
-            // ConnectivityManager instance so that legacy requests correctly bind dns
-            // requests to this network.  The legacy users are listening for this broadcast
-            // and will generally do a dns request so they can ensureRouteToHost and if
-            // they do that before the callbacks happen they'll use the default network.
-            //
-            // TODO: Is there still a race here? We send the broadcast
-            // after sending the callback, but if the app can receive the
-            // broadcast before the callback, it might still break.
-            //
-            // This *does* introduce a race where if the user uses the new api
-            // (notification callbacks) and then uses the old api (getNetworkInfo(type))
-            // they may get old info.  Reverse this after the old startUsing api is removed.
-            // This is on top of the multiple intent sequencing referenced in the todo above.
-            for (int i = 0; i < newNetwork.numNetworkRequests(); i++) {
-                NetworkRequest nr = newNetwork.requestAt(i);
-                if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
-                    // legacy type tracker filters out repeat adds
-                    mLegacyTypeTracker.add(nr.legacyType, newNetwork);
-                }
-            }
-
-            // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
-            // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
-            // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
-            // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
-            if (newNetwork.isVPN()) {
-                mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
-            }
-        }
     }
 
     /**
@@ -6541,15 +6480,32 @@
         // requests. Once the code has switched to a request-major iteration style, this can
         // be optimized to only do the processing needed.
         final long now = SystemClock.elapsedRealtime();
+        final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
+
         final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
                 new NetworkAgentInfo[mNetworkAgentInfos.size()]);
         // Rematch higher scoring networks first to prevent requests first matching a lower
         // scoring network and then a higher scoring network, which could produce multiple
-        // callbacks and inadvertently unlinger networks.
+        // callbacks.
         Arrays.sort(nais);
-        for (NetworkAgentInfo nai : nais) {
+        for (final NetworkAgentInfo nai : nais) {
             rematchNetworkAndRequests(nai, now);
         }
+
+        final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+
+        for (final NetworkAgentInfo nai : nais) {
+            // Rematching may have altered the linger state of some networks, so update all linger
+            // timers. updateLingerState reads the state from the network agent and does nothing
+            // if the state has not changed : the source of truth is controlled with
+            // NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
+            // called while rematching the individual networks above.
+            updateLingerState(nai, now);
+        }
+
+        updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
+
+        // Tear down all unneeded networks.
         for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
             if (unneeded(nai, UnneededFor.TEARDOWN)) {
                 if (nai.getLingerExpiry() > 0) {
@@ -6569,6 +6525,70 @@
         }
     }
 
+    private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
+            @Nullable final NetworkAgentInfo oldDefaultNetwork,
+            @Nullable final NetworkAgentInfo newDefaultNetwork,
+            @NonNull final NetworkAgentInfo[] nais) {
+        if (oldDefaultNetwork != newDefaultNetwork) {
+            // Maintain the illusion : since the legacy API only understands one network at a time,
+            // if the default network changed, apps should see a disconnected broadcast for the
+            // old default network before they see a connected broadcast for the new one.
+            if (oldDefaultNetwork != null) {
+                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
+                        oldDefaultNetwork, true);
+            }
+            if (newDefaultNetwork != null) {
+                // The new default network can be newly null if and only if the old default
+                // network doesn't satisfy the default request any more because it lost a
+                // capability.
+                mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
+                mLegacyTypeTracker.add(newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
+                // If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
+                // to reflect the NetworkInfo of this new network. This broadcast has to be sent
+                // after the disconnect broadcasts above, but before the broadcasts sent by the
+                // legacy type tracker below.
+                // TODO : refactor this, it's too complex
+                notifyLockdownVpn(newDefaultNetwork);
+            }
+        }
+
+        // Now that all the callbacks have been sent, send the legacy network broadcasts
+        // as needed. This is necessary so that legacy requests correctly bind dns
+        // requests to this network. The legacy users are listening for this broadcast
+        // and will generally do a dns request so they can ensureRouteToHost and if
+        // they do that before the callbacks happen they'll use the default network.
+        //
+        // TODO: Is there still a race here? The legacy broadcast will be sent after sending
+        // callbacks, but if apps can receive the broadcast before the callback, they still might
+        // have an inconsistent view of networking.
+        //
+        // This *does* introduce a race where if the user uses the new api
+        // (notification callbacks) and then uses the old api (getNetworkInfo(type))
+        // they may get old info. Reverse this after the old startUsing api is removed.
+        // This is on top of the multiple intent sequencing referenced in the todo above.
+        for (NetworkAgentInfo nai : nais) {
+            addNetworkToLegacyTypeTracker(nai);
+        }
+    }
+
+    private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
+        for (int i = 0; i < nai.numNetworkRequests(); i++) {
+            NetworkRequest nr = nai.requestAt(i);
+            if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
+                // legacy type tracker filters out repeat adds
+                mLegacyTypeTracker.add(nr.legacyType, nai);
+            }
+        }
+
+        // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
+        // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
+        // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
+        // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
+        if (nai.isVPN()) {
+            mLegacyTypeTracker.add(TYPE_VPN, nai);
+        }
+    }
+
     private void updateInetCondition(NetworkAgentInfo nai) {
         // Don't bother updating until we've graduated to validated at least once.
         if (!nai.everValidated) return;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9ebe896..5f562cf 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -146,8 +146,13 @@
 
         @Override
         public void onBootPhase(int phase) {
-            if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
-                mService.systemRunning();
+            if (phase == PHASE_SYSTEM_SERVICES_READY) {
+                // the location service must be functioning after this boot phase
+                mService.onSystemReady();
+            } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+                // some providers rely on third party code, so we wait to initialize
+                // providers until third party code is allowed to run
+                mService.onSystemThirdPartyAppsCanStart();
             }
         }
     }
@@ -264,156 +269,159 @@
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationExtraPackageNames));
 
-        // most startup is deferred until systemRunning()
+        // most startup is deferred until systemReady()
     }
 
-    private void systemRunning() {
+    private void onSystemReady() {
         synchronized (mLock) {
-            initializeLocked();
+            mPackageManager = mContext.getPackageManager();
+            mAppOps = mContext.getSystemService(AppOpsManager.class);
+            mPowerManager = mContext.getSystemService(PowerManager.class);
+            mActivityManager = mContext.getSystemService(ActivityManager.class);
+            mUserManager = mContext.getSystemService(UserManager.class);
+
+            mSettingsStore = new LocationSettingsStore(mContext, mHandler);
+            mLocationFudger = new LocationFudger(mContext, mHandler);
+            mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
+
+            PowerManagerInternal localPowerManager =
+                    LocalServices.getService(PowerManagerInternal.class);
+
+            // add listeners
+            mAppOps.startWatchingMode(
+                    AppOpsManager.OP_COARSE_LOCATION,
+                    null,
+                    AppOpsManager.WATCH_FOREGROUND_CHANGES,
+                    new AppOpsManager.OnOpChangedInternalListener() {
+                        public void onOpChanged(int op, String packageName) {
+                            // onOpChanged invoked on ui thread, move to our thread to reduce
+                            // risk of
+                            // blocking ui thread
+                            mHandler.post(() -> {
+                                synchronized (mLock) {
+                                    onAppOpChangedLocked();
+                                }
+                            });
+                        }
+                    });
+            mPackageManager.addOnPermissionsChangeListener(
+                    uid -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk of
+                        // blocking
+                        // ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onPermissionsChangedLocked();
+                            }
+                        });
+                    });
+            mActivityManager.addOnUidImportanceListener(
+                    (uid, importance) -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk of
+                        // blocking
+                        // ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onUidImportanceChangedLocked(uid, importance);
+                            }
+                        });
+                    },
+                    FOREGROUND_IMPORTANCE_CUTOFF);
+
+            localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
+                    state -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk of
+                        // blocking
+                        // ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onBatterySaverModeChangedLocked(state.locationMode);
+                            }
+                        });
+                    });
+            mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
+
+            mSettingsStore.addOnLocationEnabledChangedListener(() -> {
+                synchronized (mLock) {
+                    onLocationModeChangedLocked(true);
+                }
+            });
+            mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
+                synchronized (mLock) {
+                    onProviderAllowedChangedLocked();
+                }
+            });
+            mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
+                synchronized (mLock) {
+                    onBackgroundThrottleIntervalChangedLocked();
+                }
+            });
+            mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
+                synchronized (mLock) {
+                    onBackgroundThrottleWhitelistChangedLocked();
+                }
+            });
+            mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
+                synchronized (mLock) {
+                    onIgnoreSettingsWhitelistChangedLocked();
+                }
+            });
+
+            new PackageMonitor() {
+                @Override
+                public void onPackageDisappeared(String packageName, int reason) {
+                    synchronized (mLock) {
+                        LocationManagerService.this.onPackageDisappearedLocked(packageName);
+                    }
+                }
+            }.register(mContext, mHandler.getLooper(), true);
+
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+            intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+            intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+            intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+            intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+
+            mContext.registerReceiverAsUser(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final String action = intent.getAction();
+                    if (action == null) {
+                        return;
+                    }
+                    synchronized (mLock) {
+                        switch (action) {
+                            case Intent.ACTION_USER_SWITCHED:
+                                onUserChangedLocked(
+                                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                                break;
+                            case Intent.ACTION_MANAGED_PROFILE_ADDED:
+                            case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+                                onUserProfilesChangedLocked();
+                                break;
+                            case Intent.ACTION_SCREEN_ON:
+                            case Intent.ACTION_SCREEN_OFF:
+                                onScreenStateChangedLocked();
+                                break;
+                        }
+                    }
+                }
+            }, UserHandle.ALL, intentFilter, null, mHandler);
+
+            // switching the user from null to system here performs the bulk of the initialization
+            // work. the user being changed will cause a reload of all user specific settings, which
+            // causes initialization, and propagates changes until a steady state is reached
+            mCurrentUserId = UserHandle.USER_NULL;
+            onUserChangedLocked(ActivityManager.getCurrentUser());
         }
     }
 
-    @GuardedBy("mLock")
-    private void initializeLocked() {
-        mPackageManager = mContext.getPackageManager();
-        mAppOps = mContext.getSystemService(AppOpsManager.class);
-        mPowerManager = mContext.getSystemService(PowerManager.class);
-        mActivityManager = mContext.getSystemService(ActivityManager.class);
-        mUserManager = mContext.getSystemService(UserManager.class);
-
-        mSettingsStore = new LocationSettingsStore(mContext, mHandler);
-
-        mLocationFudger = new LocationFudger(mContext, mHandler);
-        mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
-
-        PowerManagerInternal localPowerManager =
-                LocalServices.getService(PowerManagerInternal.class);
-
-        // prepare providers
-        initializeProvidersLocked();
-
-        // add listeners
-        mAppOps.startWatchingMode(
-                AppOpsManager.OP_COARSE_LOCATION,
-                null,
-                AppOpsManager.WATCH_FOREGROUND_CHANGES,
-                new AppOpsManager.OnOpChangedInternalListener() {
-                    public void onOpChanged(int op, String packageName) {
-                        // onOpChanged invoked on ui thread, move to our thread to reduce risk of
-                        // blocking ui thread
-                        mHandler.post(() -> {
-                            synchronized (mLock) {
-                                onAppOpChangedLocked();
-                            }
-                        });
-                    }
-                });
-        mPackageManager.addOnPermissionsChangeListener(
-                uid -> {
-                    // listener invoked on ui thread, move to our thread to reduce risk of blocking
-                    // ui thread
-                    mHandler.post(() -> {
-                        synchronized (mLock) {
-                            onPermissionsChangedLocked();
-                        }
-                    });
-                });
-        mActivityManager.addOnUidImportanceListener(
-                (uid, importance) -> {
-                    // listener invoked on ui thread, move to our thread to reduce risk of blocking
-                    // ui thread
-                    mHandler.post(() -> {
-                        synchronized (mLock) {
-                            onUidImportanceChangedLocked(uid, importance);
-                        }
-                    });
-                },
-                FOREGROUND_IMPORTANCE_CUTOFF);
-
-        localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
-                state -> {
-                    // listener invoked on ui thread, move to our thread to reduce risk of blocking
-                    // ui thread
-                    mHandler.post(() -> {
-                        synchronized (mLock) {
-                            onBatterySaverModeChangedLocked(state.locationMode);
-                        }
-                    });
-                });
-        mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
-
-        mSettingsStore.addOnLocationEnabledChangedListener(() -> {
-            synchronized (mLock) {
-                onLocationModeChangedLocked(true);
-            }
-        });
-        mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
-            synchronized (mLock) {
-                onProviderAllowedChangedLocked();
-            }
-        });
-        mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
-            synchronized (mLock) {
-                onBackgroundThrottleIntervalChangedLocked();
-            }
-        });
-        mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
-            synchronized (mLock) {
-                onBackgroundThrottleWhitelistChangedLocked();
-            }
-        });
-        mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
-            synchronized (mLock) {
-                onIgnoreSettingsWhitelistChangedLocked();
-            }
-        });
-
-        new PackageMonitor() {
-            @Override
-            public void onPackageDisappeared(String packageName, int reason) {
-                synchronized (mLock) {
-                    LocationManagerService.this.onPackageDisappearedLocked(packageName);
-                }
-            }
-        }.register(mContext, mHandler.getLooper(), true);
-
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final String action = intent.getAction();
-                if (action == null) {
-                    return;
-                }
-                synchronized (mLock) {
-                    switch (action) {
-                        case Intent.ACTION_USER_SWITCHED:
-                            onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                            break;
-                        case Intent.ACTION_MANAGED_PROFILE_ADDED:
-                        case Intent.ACTION_MANAGED_PROFILE_REMOVED:
-                            onUserProfilesChangedLocked();
-                            break;
-                        case Intent.ACTION_SCREEN_ON:
-                        case Intent.ACTION_SCREEN_OFF:
-                            onScreenStateChangedLocked();
-                            break;
-                    }
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, mHandler);
-
-        // switching the user from null to system here performs the bulk of the initialization work.
-        // the user being changed will cause a reload of all user specific settings, which causes
-        // provider initialization, and propagates changes until a steady state is reached
-        mCurrentUserId = UserHandle.USER_NULL;
-        onUserChangedLocked(ActivityManager.getCurrentUser());
+    private void onSystemThirdPartyAppsCanStart() {
+        synchronized (mLock) {
+            // prepare providers
+            initializeProvidersLocked();
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index a4bc3bd..9d1eb6c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -118,6 +118,7 @@
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.DataUnit;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -819,7 +820,6 @@
                     refreshFuseSettings();
                 });
         refreshIsolatedStorageSettings();
-        refreshFuseSettings();
     }
 
     /**
@@ -883,16 +883,25 @@
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
     }
 
+    /**
+     * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
+     * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
+     * whenever the user reboots.
+     */
     private void refreshFuseSettings() {
         int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
                 FUSE_ENABLED, 0);
         if (isFuseEnabled == 1) {
-            SystemProperties.set(StorageManager.PROP_FUSE, "true");
+            Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
+            SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+                    + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
         } else if (isFuseEnabled == -1) {
-            SystemProperties.set(StorageManager.PROP_FUSE, "false");
+            Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
+            SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+                    + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
         }
         // else, keep the build config.
-        // This can be overridden be direct adjustment of persist.sys.prop
+        // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
     }
 
     /**
@@ -1548,6 +1557,8 @@
     public StorageManagerService(Context context) {
         sSelf = this;
 
+        updateFusePropFromSettings();
+
         // Snapshot feature flag used for this boot
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
                 SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
@@ -1609,6 +1620,23 @@
         }
     }
 
+    /**
+     *  Checks if user changed the persistent settings_fuse flag from Settings UI
+     *  and updates PROP_FUSE (reboots if changed).
+     */
+    private void updateFusePropFromSettings() {
+        Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
+                + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
+        Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
+        if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
+            Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
+            SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
+            // Perform hard reboot to kick policy into place
+            mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
+                    + "property change to take effect");
+        }
+    }
+
     private void start() {
         connectStoraged();
         connectVold();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e119d1e..5b8ffde 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3784,7 +3784,7 @@
     }
 
     @GuardedBy("this")
-    void waitForProcKillLocked(final ProcessRecord app, final String formatString,
+    private void waitForProcKillLocked(final ProcessRecord app, final String formatString,
             final long startTime) {
         app.mAppDiedCallback = () -> {
             synchronized (ActivityManagerService.this) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 375da8a..2bb7035 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1421,7 +1421,7 @@
         if (app.pendingStart) {
             return true;
         }
-        long startTime = SystemClock.uptimeMillis();
+        long startTime = SystemClock.elapsedRealtime();
         if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
             checkSlow(startTime, "startProcess: removing from pids map");
             mService.mPidsSelfLocked.remove(app);
@@ -1856,7 +1856,7 @@
             boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
             boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
             String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
-        long startTime = SystemClock.uptimeMillis();
+        long startTime = SystemClock.elapsedRealtime();
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
@@ -1917,9 +1917,10 @@
             // An application record is attached to a previous process,
             // clean it up now.
             if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
+            checkSlow(startTime, "startProcess: bad proc running, killing");
             ProcessList.killProcessGroup(app.uid, app.pid);
-            mService.waitForProcKillLocked(app, "startProcess: bad proc running, killing: %s",
-                    startTime);
+            mService.handleAppDiedLocked(app, true, true);
+            checkSlow(startTime, "startProcess: done killing old proc");
         }
 
         if (app == null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e426c6c..4bf1de6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -269,6 +269,7 @@
     private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
     private static final int MSG_HDMI_VOLUME_CHECK = 28;
     private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
+    private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -2925,9 +2926,8 @@
             AudioSystem.muteMicrophone(muted);
             try {
                 if (muted != currentMute) {
-                    mContext.sendBroadcastAsUser(
-                        new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
-                                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+                    sendMsg(mAudioHandler, MSG_BROADCAST_MICROPHONE_MUTE,
+                                SENDMSG_NOOP, 0, 0, null, 0);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -5236,6 +5236,13 @@
                 case MSG_PLAYBACK_CONFIG_CHANGE:
                     onPlaybackConfigChange((List<AudioPlaybackConfiguration>) msg.obj);
                     break;
+
+                case MSG_BROADCAST_MICROPHONE_MUTE:
+                    mContext.sendBroadcastAsUser(
+                            new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
+                                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+                                    UserHandle.ALL);
+                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 24a5b7f..bb7f862 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -580,7 +580,7 @@
         // semantics of WakeupMessage guarantee that if cancel is called then the alarm will
         // never call its callback (handleLingerComplete), even if it has already fired.
         // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
-        // has already been dispatched, rescheduling to some time in the future it won't stop it
+        // has already been dispatched, rescheduling to some time in the future won't stop it
         // from calling its callback immediately.
         if (mLingerMessage != null) {
             mLingerMessage.cancel();
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9882f6c..7ce63c5 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -138,13 +138,17 @@
     }
 
     /**
-     * Sets the display modes the system is allowed to switch between, roughly ordered by
-     * preference.
+     * Sets the refresh ranges, and display modes that the system is allowed to switch between.
+     * Display modes are roughly ordered by preference.
      *
      * Not all display devices will automatically switch between modes, so it's important that the
      * most-desired modes are at the beginning of the allowed array.
+     *
+     * @param defaultModeId is used, if the device does not support multiple refresh
+     * rates, and to navigate other parameters.
      */
-    public void setAllowedDisplayModesLocked(int[] modes) {
+    public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+            float maxRefreshRate, int[] modes) {
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d24bd1a..6118df5 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.hardware.display.DisplayManager;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
-
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.UserHandle;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -47,11 +43,11 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.server.display.utils.AmbientFilter;
 import com.android.server.display.utils.AmbientFilterFactory;
-import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -87,11 +83,11 @@
     // A map from the display ID to the collection of votes and their priority. The latter takes
     // the form of another map from the priority to the vote itself so that each priority is
     // guaranteed to have exactly one vote, which is also easily and efficiently replaceable.
-    private final SparseArray<SparseArray<Vote>> mVotesByDisplay;
+    private SparseArray<SparseArray<Vote>> mVotesByDisplay;
     // A map from the display ID to the supported modes on that display.
-    private final SparseArray<Display.Mode[]> mSupportedModesByDisplay;
+    private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
     // A map from the display ID to the default mode of that display.
-    private final SparseArray<Display.Mode> mDefaultModeByDisplay;
+    private SparseArray<Display.Mode> mDefaultModeByDisplay;
 
     private final AppRequestObserver mAppRequestObserver;
     private final SettingsObserver mSettingsObserver;
@@ -143,17 +139,7 @@
      */
     @NonNull
     public int[] getAllowedModes(int displayId) {
-        synchronized (mLock) {
-            SparseArray<Vote> votes = getVotesLocked(displayId);
-            Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
-            Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
-            if (modes == null || defaultMode == null) {
-                Slog.e(TAG, "Asked about unknown display, returning empty allowed set! (id="
-                        + displayId + ")");
-                return new int[0];
-            }
-            return getAllowedModesLocked(votes, modes, defaultMode);
-        }
+        return getDesiredDisplayConfigSpecs(displayId).allowedConfigs;
     }
 
     @NonNull
@@ -178,76 +164,101 @@
         return votes;
     }
 
+    /**
+     * Calculates the refresh rate ranges and display modes that the system is allowed to freely
+     * switch between based on global and display-specific constraints.
+     *
+     * @param displayId The display to query for.
+     * @return The ID of the default mode the system should use, and the refresh rate range the
+     * system is allowed to switch between.
+     */
     @NonNull
-    private int[] getAllowedModesLocked(@NonNull SparseArray<Vote> votes,
-            @NonNull Display.Mode[] modes, @NonNull Display.Mode defaultMode) {
-        int lowestConsideredPriority = Vote.MIN_PRIORITY;
-        while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+    public DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(int displayId) {
+        synchronized (mLock) {
+            SparseArray<Vote> votes = getVotesLocked(displayId);
+            Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
+            Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
+            if (modes == null || defaultMode == null) {
+                Slog.e(TAG, "Asked about unknown display, returning empty desired configs!"
+                        + "(id=" + displayId + ")");
+                return new DesiredDisplayConfigSpecs(displayId, new RefreshRateRange(60, 60),
+                        new int[0]);
+            }
+
+            int[] availableModes = new int[]{defaultMode.getModeId()};
             float minRefreshRate = 0f;
             float maxRefreshRate = Float.POSITIVE_INFINITY;
-            int height = Vote.INVALID_SIZE;
-            int width = Vote.INVALID_SIZE;
+            int lowestConsideredPriority = Vote.MIN_PRIORITY;
+            while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+                int height = Vote.INVALID_SIZE;
+                int width = Vote.INVALID_SIZE;
 
-            for (int priority = Vote.MAX_PRIORITY;
-                    priority >= lowestConsideredPriority;
-                    priority--) {
-                Vote vote = votes.get(priority);
-                if (vote == null) {
-                    continue;
+                for (int priority = Vote.MAX_PRIORITY;
+                        priority >= lowestConsideredPriority; priority--) {
+                    Vote vote = votes.get(priority);
+                    if (vote == null) {
+                        continue;
+                    }
+                    // For refresh rates, just use the tightest bounds of all the votes
+                    minRefreshRate = Math.max(minRefreshRate, vote.refreshRateRange.min);
+                    maxRefreshRate = Math.min(maxRefreshRate, vote.refreshRateRange.max);
+                    // For display size, use only the first vote we come across (i.e. the highest
+                    // priority vote that includes the width / height).
+                    if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
+                            && vote.height > 0 && vote.width > 0) {
+                        width = vote.width;
+                        height = vote.height;
+                    }
                 }
-                // For refresh rates, just use the tightest bounds of all the votes
-                minRefreshRate = Math.max(minRefreshRate, vote.minRefreshRate);
-                maxRefreshRate = Math.min(maxRefreshRate, vote.maxRefreshRate);
-                // For display size, use only the first vote we come across (i.e. the highest
-                // priority vote that includes the width / height).
-                if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
-                        && vote.height > 0 && vote.width > 0) {
-                    width = vote.width;
-                    height = vote.height;
+
+                // If we don't have anything specifying the width / height of the display, just use
+                // the default width and height. We don't want these switching out from underneath
+                // us since it's a pretty disruptive behavior.
+                if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
+                    width = defaultMode.getPhysicalWidth();
+                    height = defaultMode.getPhysicalHeight();
                 }
-            }
 
-            // If we don't have anything specifying the width / height of the display, just use the
-            // default width and height. We don't want these switching out from underneath us since
-            // it's a pretty disruptive behavior.
-            if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
-                width = defaultMode.getPhysicalWidth();
-                height = defaultMode.getPhysicalHeight();
-            }
+                availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
+                if (availableModes.length > 0) {
+                    if (DEBUG) {
+                        Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+                                + " with lowest priority considered "
+                                + Vote.priorityToString(lowestConsideredPriority)
+                                + " and constraints: "
+                                + "width=" + width
+                                + ", height=" + height
+                                + ", minRefreshRate=" + minRefreshRate
+                                + ", maxRefreshRate=" + maxRefreshRate);
+                    }
+                    break;
+                }
 
-            int[] availableModes =
-                    filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
-            if (availableModes.length > 0) {
                 if (DEBUG) {
-                    Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
-                            + " with lowest priority considered "
+                    Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
                             + Vote.priorityToString(lowestConsideredPriority)
-                            + " and constraints: "
+                            + " and with the following constraints: "
                             + "width=" + width
                             + ", height=" + height
                             + ", minRefreshRate=" + minRefreshRate
                             + ", maxRefreshRate=" + maxRefreshRate);
                 }
-                return availableModes;
+
+                // If we haven't found anything with the current set of votes, drop the
+                // current lowest priority vote.
+                lowestConsideredPriority++;
             }
 
-            if (DEBUG) {
-                Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
-                        + Vote.priorityToString(lowestConsideredPriority)
-                        + " and with the following constraints: "
-                        + "width=" + width
-                        + ", height=" + height
-                        + ", minRefreshRate=" + minRefreshRate
-                        + ", maxRefreshRate=" + maxRefreshRate);
+            int defaultModeId = defaultMode.getModeId();
+            if (availableModes.length > 0) {
+                defaultModeId = availableModes[0];
             }
-            // If we haven't found anything with the current set of votes, drop the current lowest
-            // priority vote.
-            lowestConsideredPriority++;
+            // filterModes function is going to filter the modes based on the voting system. If
+            // the application requests a given mode with preferredModeId function, it will be
+            // stored as the first and only element in available modes array.
+            return new DesiredDisplayConfigSpecs(defaultModeId,
+                    new RefreshRateRange(minRefreshRate, maxRefreshRate), availableModes);
         }
-
-        // If we still haven't found anything that matches our current set of votes, just fall back
-        // to the default mode.
-        return new int[] { defaultMode.getModeId() };
     }
 
     private int[] filterModes(Display.Mode[] supportedModes,
@@ -403,6 +414,21 @@
         }
     }
 
+    @VisibleForTesting
+    void injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay) {
+        mSupportedModesByDisplay = supportedModesByDisplay;
+    }
+
+    @VisibleForTesting
+    void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) {
+        mDefaultModeByDisplay = defaultModeByDisplay;
+    }
+
+    @VisibleForTesting
+    void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
+        mVotesByDisplay = votesByDisplay;
+    }
+
     /**
      * Listens for changes to display mode coordination.
      */
@@ -452,7 +478,129 @@
         }
     }
 
-    private static final class Vote {
+    /**
+     * Information about the min and max refresh rate DM would like to set the display to.
+     */
+    public static final class RefreshRateRange {
+        /**
+         * The lowest desired refresh rate.
+         */
+        public final float min;
+        /**
+         * The highest desired refresh rate.
+         */
+        public final float max;
+
+        public RefreshRateRange(float min, float max) {
+            if (min < 0 || max < 0 || min > max) {
+                Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
+                        + min + " " + max);
+                this.min = this.max = 0;
+                return;
+            }
+            this.min = min;
+            this.max = max;
+        }
+
+        /**
+         * Checks whether the two objects have the same values.
+         */
+        @Override
+        public boolean equals(Object other) {
+            if (other == this) {
+                return true;
+            }
+
+            if (!(other instanceof RefreshRateRange)) {
+                return false;
+            }
+
+            RefreshRateRange refreshRateRange = (RefreshRateRange) other;
+            return (min == refreshRateRange.min && max == refreshRateRange.max);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(min, max);
+        }
+
+        @Override
+        public String toString() {
+            return "(" + min + " " + max + ")";
+        }
+    }
+
+    /**
+     * Information about the desired configuration to be set by the system. Includes the default
+     * configuration ID, refresh rate range, and the list of policy decisions that influenced the
+     * choice.
+     */
+    public static final class DesiredDisplayConfigSpecs {
+        /**
+         * Default configuration ID. This is what system defaults to for all other settings, or
+         * if the refresh rate range is not available.
+         */
+        public final int defaultModeId;
+        /**
+         * The refresh rate range.
+         */
+        public final RefreshRateRange refreshRateRange;
+        /**
+         * For legacy reasons, keep a list of allowed configs.
+         * TODO(b/142507213): Re-assess whether the list of allowed configs is still necessary.
+         */
+        public final int[] allowedConfigs;
+
+        public DesiredDisplayConfigSpecs(int defaultModeId,
+                @NonNull RefreshRateRange refreshRateRange,
+                @NonNull int[] allowedConfigs) {
+            this.defaultModeId = defaultModeId;
+            this.refreshRateRange = refreshRateRange;
+            this.allowedConfigs = allowedConfigs;
+        }
+
+        /**
+         * Returns a string representation of the object.
+         */
+        @Override
+        public String toString() {
+            return "DesiredDisplayConfigSpecs(defaultModeId=" + defaultModeId
+                    + ", refreshRateRange=" + refreshRateRange.toString()
+                    + ", allowedConfigs=" + Arrays.toString(allowedConfigs) + ")";
+        }
+        /**
+         * Checks whether the two objects have the same values.
+         */
+        @Override
+        public boolean equals(Object other) {
+            if (other == this) {
+                return true;
+            }
+
+            if (!(other instanceof DesiredDisplayConfigSpecs)) {
+                return false;
+            }
+
+            DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
+                    (DesiredDisplayConfigSpecs) other;
+
+            if (defaultModeId != desiredDisplayConfigSpecs.defaultModeId) {
+                return false;
+            }
+            if (!refreshRateRange.equals(desiredDisplayConfigSpecs.refreshRateRange)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(defaultModeId, refreshRateRange);
+        }
+    }
+
+    @VisibleForTesting
+    static final class Vote {
         // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
         // If the higher voters result is a range, it will fix the rate to a single choice.
         // It's used to avoid rate switch in certain conditions.
@@ -499,15 +647,10 @@
          * The requested height of the display in pixels, or INVALID_SIZE;
          */
         public final int height;
-
         /**
-         * The lowest desired refresh rate.
+         * Information about the min and max refresh rate DM would like to set the display to.
          */
-        public final float minRefreshRate;
-        /**
-         * The highest desired refresh rate.
-         */
-        public final float maxRefreshRate;
+        public final RefreshRateRange refreshRateRange;
 
         public static Vote forRefreshRates(float minRefreshRate, float maxRefreshRate) {
             return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate);
@@ -521,8 +664,8 @@
                 float minRefreshRate, float maxRefreshRate) {
             this.width = width;
             this.height = height;
-            this.minRefreshRate = minRefreshRate;
-            this.maxRefreshRate = maxRefreshRate;
+            this.refreshRateRange =
+                    new RefreshRateRange(minRefreshRate, maxRefreshRate);
         }
 
         public static String priorityToString(int priority) {
@@ -547,11 +690,9 @@
         @Override
         public String toString() {
             return "Vote{"
-                + "width=" + width
-                + ", height=" + height
-                + ", minRefreshRate=" + minRefreshRate
-                + ", maxRefreshRate=" + maxRefreshRate
-                + "}";
+                + "width=" + width + ", height=" + height
+                + ", minRefreshRate=" + refreshRateRange.min
+                + ", maxRefreshRate=" + refreshRateRange.max + "}";
         }
     }
 
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b03dc3b..1586473 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -173,6 +173,8 @@
         private int mActiveModeId;
         private boolean mActiveModeInvalid;
         private int[] mAllowedModeIds;
+        private float mMinRefreshRate;
+        private float mMaxRefreshRate;
         private boolean mAllowedModeIdsInvalid;
         private int mActivePhysIndex;
         private int[] mAllowedPhysIndexes;
@@ -623,7 +625,9 @@
         }
 
         @Override
-        public void setAllowedDisplayModesLocked(int[] modes) {
+        public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+                float maxRefreshRate, int[] modes) {
+            updateDesiredDisplayConfigSpecs(defaultModeId, minRefreshRate, maxRefreshRate);
             updateAllowedModesLocked(modes);
         }
 
@@ -653,6 +657,7 @@
             return true;
         }
 
+        // TODO(b/142507213): Remove once refresh rates are plummed through to kernel.
         public void updateAllowedModesLocked(int[] allowedModes) {
             if (Arrays.equals(allowedModes, mAllowedModeIds) && !mAllowedModeIdsInvalid) {
                 return;
@@ -662,6 +667,38 @@
             }
         }
 
+        public void updateDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+                float maxRefreshRate) {
+            if (minRefreshRate == mMinRefreshRate
+                        && maxRefreshRate == mMaxRefreshRate
+                        && defaultModeId == mDefaultModeId) {
+                return;
+            }
+            if (updateDesiredDisplayConfigSpecsInternalLocked(defaultModeId, minRefreshRate,
+                    maxRefreshRate)) {
+                updateDeviceInfoLocked();
+            }
+        }
+
+        public boolean updateDesiredDisplayConfigSpecsInternalLocked(int defaultModeId,
+                float minRefreshRate, float maxRefreshRate) {
+            if (DEBUG) {
+                Slog.w(TAG, "updateDesiredDisplayConfigSpecsInternalLocked("
+                        + "defaultModeId="
+                        + Integer.toString(defaultModeId)
+                        + ", minRefreshRate="
+                        + Float.toString(minRefreshRate)
+                        + ", maxRefreshRate="
+                        + Float.toString(minRefreshRate));
+            }
+
+            final IBinder token = getDisplayTokenLocked();
+            SurfaceControl.setDesiredDisplayConfigSpecs(token, defaultModeId, minRefreshRate,
+                    maxRefreshRate);
+            int activePhysIndex = SurfaceControl.getActiveConfig(token);
+            return updateActiveModeLocked(activePhysIndex);
+        }
+
         public boolean updateAllowedModesInternalLocked(int[] allowedModes) {
             if (DEBUG) {
                 Slog.w(TAG, "updateAllowedModesInternalLocked(allowedModes="
@@ -735,6 +772,8 @@
             pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
             pw.println("mAllowedPhysIndexes=" + Arrays.toString(mAllowedPhysIndexes));
             pw.println("mAllowedModeIds=" + Arrays.toString(mAllowedModeIds));
+            pw.println("mMinRefreshRate=" + mMinRefreshRate);
+            pw.println("mMaxRefreshRate=" + mMaxRefreshRate);
             pw.println("mAllowedModeIdsInvalid=" + mAllowedModeIdsInvalid);
             pw.println("mActivePhysIndex=" + mActivePhysIndex);
             pw.println("mActiveModeId=" + mActiveModeId);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dcef998..f4b2dc8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -352,11 +352,12 @@
 
         // Set the color mode and allowed display mode.
         if (device == mPrimaryDisplayDevice) {
-            device.setAllowedDisplayModesLocked(mAllowedDisplayModes);
+            // See ag/9588196 for correct values.
+            device.setDesiredDisplayConfigSpecs(0, 60, 60, mAllowedDisplayModes);
             device.setRequestedColorModeLocked(mRequestedColorMode);
         } else {
             // Reset to default for non primary displays
-            device.setAllowedDisplayModesLocked(new int[] {0});
+            device.setDesiredDisplayConfigSpecs(0, 60, 60, new int[] {0});
             device.setRequestedColorModeLocked(0);
         }
 
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 60cfbd0..739dd64 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -315,16 +315,9 @@
         }
 
         @Override
-        public void setAllowedDisplayModesLocked(int[] modes) {
-            final int id;
-            if (modes.length > 0) {
-                // The allowed modes should be ordered by preference, so just use the first mode
-                // here.
-                id = modes[0];
-            } else {
-                // If we don't have any allowed modes, just use the default mode.
-                id = 0;
-            }
+        public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+                float maxRefreshRate, int[] modes) {
+            final int id = defaultModeId;
             int index = -1;
             if (id == 0) {
                 // Use the default.
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a4e7ac4..83b6215 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -181,6 +181,7 @@
     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
     private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
     private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
+    private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
 
     // No challenge provided
     private static final int CHALLENGE_NONE = 0;
@@ -661,6 +662,34 @@
     }
 
     /**
+     * Clean up states associated with the given user, in case the userId is reused but LSS didn't
+     * get a chance to do cleanup previously during ACTION_USER_REMOVED.
+     *
+     * Internally, LSS stores serial number for each user and check it against the current user's
+     * serial number to determine if the userId is reused and invoke cleanup code.
+     */
+    private void cleanupDataForReusedUserIdIfNecessary(int userId) {
+        if (userId == UserHandle.USER_SYSTEM) {
+            // Short circuit as we never clean up user 0.
+            return;
+        }
+        // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse.
+        int serialNumber = mUserManager.getUserSerialNumber(userId);
+
+        int storedSerialNumber = getIntUnchecked(USER_SERIAL_NUMBER_KEY, -1, userId);
+        if (storedSerialNumber != serialNumber) {
+            // If LockSettingsStorage does not have a copy of the serial number, it could be either
+            // this is a user created before the serial number recording logic is introduced, or
+            // the user does not exist or was removed and cleaned up properly. In either case, don't
+            // invoke removeUser().
+            if (storedSerialNumber != -1) {
+                removeUser(userId, /* unknownUser */ true);
+            }
+            setIntUnchecked(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
+        }
+    }
+
+    /**
      * Check if profile got unlocked but the keystore is still locked. This happens on full disk
      * encryption devices since the profile may not yet be running when we consider unlocking it
      * during the normal flow. In this case unlock the keystore for the profile.
@@ -684,6 +713,7 @@
         mHandler.post(new Runnable() {
             @Override
             public void run() {
+                cleanupDataForReusedUserIdIfNecessary(userId);
                 ensureProfileKeystoreUnlocked(userId);
                 // Hide notification first, as tie managed profile lock takes time
                 hideEncryptionNotification(new UserHandle(userId));
@@ -729,9 +759,6 @@
             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
                 // Notify keystore that a new user was added.
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-                if (userHandle > UserHandle.USER_SYSTEM) {
-                    removeUser(userHandle, /* unknownUser= */ true);
-                }
                 final KeyStore ks = KeyStore.getInstance();
                 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
@@ -1066,6 +1093,10 @@
         setStringUnchecked(key, userId, Long.toString(value));
     }
 
+    private void setIntUnchecked(String key, int value, int userId) {
+        setStringUnchecked(key, userId, Integer.toString(value));
+    }
+
     @Override
     public void setString(String key, String value, int userId) {
         checkWritePermission(userId);
@@ -1104,6 +1135,11 @@
         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
     }
 
+    private int getIntUnchecked(String key, int defaultValue, int userId) {
+        String value = getStringUnchecked(key, null, userId);
+        return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+    }
+
     @Override
     public String getString(String key, String defaultValue, int userId) {
         checkReadPermission(key, userId);
@@ -2171,8 +2207,8 @@
     }
 
     private void removeUser(int userId, boolean unknownUser) {
+        Slog.i(TAG, "RemoveUser: " + userId);
         mSpManager.removeUser(userId);
-        mStorage.removeUser(userId);
         mStrongAuth.removeUser(userId);
         tryRemoveUserFromSpCacheLater(userId);
 
@@ -2183,6 +2219,9 @@
         if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
             removeKeystoreProfileKey(userId);
         }
+        // Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
+        // can make the assumption that no USER_SERIAL_NUMBER_KEY means user is fully removed.
+        mStorage.removeUser(userId);
     }
 
     private void removeKeystoreProfileKey(int targetUserId) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 91c9253..9a49c16 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
+import android.os.Bundle;
 
 import java.util.Objects;
 
@@ -29,7 +30,7 @@
     final ComponentName mComponentName;
     final String mUniqueId;
 
-    private Callback mCallback;
+    Callback mCallback;
     private MediaRoute2ProviderInfo mProviderInfo;
 
     MediaRoute2Provider(@NonNull ComponentName componentName) {
@@ -77,6 +78,9 @@
     }
 
     public interface Callback {
-        void onProviderStateChanged(MediaRoute2Provider provider);
+        void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
+        void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
+                @NonNull String clientPackageName, @NonNull MediaRoute2Info route,
+                @Nullable Bundle controlHints, int seq);
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 3b6580a..a5abb18 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -26,6 +26,7 @@
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
 import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
@@ -253,6 +254,20 @@
         setAndNotifyProviderInfo(info);
     }
 
+    private void onRouteSelected(Connection connection,
+            String packageName, String routeId, Bundle controlHints, int seq) {
+        if (mActiveConnection != connection) {
+            return;
+        }
+        MediaRoute2ProviderInfo providerInfo = getProviderInfo();
+        MediaRoute2Info route = (providerInfo == null) ? null : providerInfo.getRoute(routeId);
+        if (route == null) {
+            Slog.w(TAG, this + ": Unknown route " + routeId + " is selected from remove provider");
+            return;
+        }
+        mCallback.onRouteSelected(this, packageName, route, controlHints, seq);
+    }
+
     private void disconnect() {
         if (mActiveConnection != null) {
             mConnectionReady = false;
@@ -341,6 +356,11 @@
         void postProviderInfoUpdated(MediaRoute2ProviderInfo info) {
             mHandler.post(() -> onProviderInfoUpdated(Connection.this, info));
         }
+
+        void postRouteSelected(String packageName, String routeId, Bundle controlHints, int seq) {
+            mHandler.post(() -> onRouteSelected(Connection.this,
+                    packageName, routeId, controlHints, seq));
+        }
     }
 
     private static final class ProviderClient extends IMediaRoute2ProviderClient.Stub  {
@@ -361,5 +381,15 @@
                 connection.postProviderInfoUpdated(info);
             }
         }
+
+        @Override
+        public void notifyRouteSelected(String packageName, String routeId,
+                Bundle controlHints, int seq) {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postRouteSelected(packageName, routeId, controlHints, seq);
+            }
+        }
+
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2cf920d..2c478df 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -77,7 +77,7 @@
     @GuardedBy("mLock")
     private int mCurrentUserId = -1;
     @GuardedBy("mLock")
-    private int mSelectRouteRequestSequenceNumber = 0;
+    private int mSelectRouteRequestSequenceNumber = 1;
 
     MediaRouter2ServiceImpl(Context context) {
         mContext = context;
@@ -218,7 +218,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
+                requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), false, route);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -399,10 +399,12 @@
         }
     }
 
-    private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
+    private void requestSelectRoute2Locked(ClientRecord clientRecord, boolean selectedByManager,
+            MediaRoute2Info route) {
         if (clientRecord != null) {
             MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
             clientRecord.mSelectingRoute = route;
+            clientRecord.mIsManagerSelecting = selectedByManager;
 
             UserHandler handler = clientRecord.mUserRecord.mHandler;
             //TODO: Handle transfer instead of unselect and select
@@ -417,7 +419,6 @@
                 handler.sendMessage(obtainMessage(
                         UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
                         route, seq));
-
                 // Remove all previous timeout messages
                 for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
                     clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
@@ -543,7 +544,7 @@
                 Slog.w(TAG, "Ignoring route selection for unknown client.");
             }
             if (clientRecord != null && managerRecord.mTrusted) {
-                requestSelectRoute2Locked(clientRecord, route);
+                requestSelectRoute2Locked(clientRecord, true, route);
             }
         }
     }
@@ -656,7 +657,9 @@
         public final UserRecord mUserRecord;
         public final String mPackageName;
         public final List<Integer> mSelectRouteSequenceNumbers;
+
         public List<String> mControlCategories;
+        public boolean mIsManagerSelecting;
         public MediaRoute2Info mSelectingRoute;
         public MediaRoute2Info mSelectedRoute;
 
@@ -802,9 +805,8 @@
             sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
         }
 
-        // TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
-        // Make this method to be called.
-        public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
+        @Override
+        public void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
                 String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
             sendMessage(PooledLambda.obtainMessage(
                     UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
@@ -917,6 +919,8 @@
                 return;
             }
 
+            //TODO: handle a case such that controlHints is null. (How should we notify MR2?)
+
             if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
                     clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
                 Log.w(TAG, "Ignoring invalid updateSelectedRoute call. selectingRoute="
@@ -929,7 +933,9 @@
 
             notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
                     selectedRoute,
-                    MediaRouter2.SELECT_REASON_USER_SELECTED,
+                    clientRecord.mIsManagerSelecting
+                            ? MediaRouter2.SELECT_REASON_SYSTEM_SELECTED :
+                            MediaRouter2.SELECT_REASON_USER_SELECTED,
                     controlHints);
             updateClientUsage(clientRecord);
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 863991c..3c76c67 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8268,7 +8268,7 @@
             try {
                 assistant.onAllowedAdjustmentsChanged();
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
+                Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
             }
         }
 
@@ -8278,7 +8278,7 @@
             try {
                 assistant.onNotificationsSeen(keys);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
+                Slog.e(TAG, "unable to notify assistant (seen): " + info, ex);
             }
         }
 
@@ -8584,7 +8584,7 @@
                         listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
                     } catch (RemoteException ex) {
                         Slog.e(TAG, "unable to notify listener "
-                                + "(hideSilentStatusIcons): " + listener, ex);
+                                + "(hideSilentStatusIcons): " + info, ex);
                     }
                 });
             }
@@ -8877,7 +8877,7 @@
             try {
                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
             }
         }
 
@@ -8891,7 +8891,7 @@
             try {
                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
             }
         }
 
@@ -8901,7 +8901,7 @@
             try {
                 listener.onNotificationRankingUpdate(rankingUpdate);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
             }
         }
 
@@ -8910,7 +8910,7 @@
             try {
                 listener.onListenerHintsChanged(hints);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex);
             }
         }
 
@@ -8920,7 +8920,7 @@
             try {
                 listener.onInterruptionFilterChanged(interruptionFilter);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex);
             }
         }
 
@@ -8931,7 +8931,7 @@
             try {
                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex);
             }
         }
 
@@ -8942,7 +8942,7 @@
             try {
                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex);
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index faff394..05f62b2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3210,6 +3210,13 @@
                         flags |= UserInfo.FLAG_EPHEMERAL;
                     }
 
+                    // Always clear EPHEMERAL for pre-created users, otherwise the storage key
+                    // won't be persisted. The flag will be re-added (if needed) when the
+                    // pre-created user is "converted" to a normal user.
+                    if (preCreate) {
+                        flags &= ~UserInfo.FLAG_EPHEMERAL;
+                    }
+
                     userInfo = new UserInfo(userId, name, null, flags, userType);
                     userInfo.serialNumber = mNextSerialNumber++;
                     userInfo.creationTime = getCreationTime();
@@ -4428,6 +4435,7 @@
         pw.println("  Supports switchable users: " + UserManager.supportsMultipleUsers());
         pw.println("  All guests ephemeral: " + Resources.getSystem().getBoolean(
                 com.android.internal.R.bool.config_guestUserEphemeral));
+        pw.println("  Force ephemeral users: " + mForceEphemeralUsers);
         pw.println("  Is split-system user: " + UserManager.isSplitSystemUser());
         pw.println("  Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
         pw.println("  User version: " + mUserVersion);
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 6abfbdc..0a6a435 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -85,28 +85,30 @@
      * System Property whether to only install system packages on a user if they're whitelisted for
      * that user type. These are flags and can be freely combined.
      * <ul>
-     * <li> 0 (0b000) - disable whitelist (install all system packages; no logging)</li>
-     * <li> 1 (0b001) - enforce (only install system packages if they are whitelisted)</li>
-     * <li> 2 (0b010) - log (log when a non-whitelisted package is run)</li>
-     * <li> 4 (0b100) - implicitly whitelist any package not mentioned in the whitelist</li>
-     * <li>-1         - use device default (as defined in res/res/values/config.xml)</li>
+     * <li> 0 (0b0000) - disable whitelist (install all system packages; no logging)</li>
+     * <li> 1 (0b0001) - enforce (only install system packages if they are whitelisted)</li>
+     * <li> 2 (0b0010) - log (log when a non-whitelisted package is run)</li>
+     * <li> 4 (0b0100) - implicitly whitelist any package not mentioned in the whitelist</li>
+     * <li> 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)</li>
+     * <li>-1          - use device default (as defined in res/res/values/config.xml)</li>
      * </ul>
      * Note: This list must be kept current with config_userTypePackageWhitelistMode in
      * frameworks/base/core/res/res/values/config.xml
      */
     static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
     static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b010;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b0001;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b0010;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b0100;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0b1000;
     static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
 
     @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
             USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
             USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
-            USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
             USER_TYPE_PACKAGE_WHITELIST_MODE_LOG,
             USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST,
+            USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PackageWhitelistMode {}
@@ -169,11 +171,17 @@
     boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) {
         final int mode = getWhitelistMode();
         checkWhitelistedSystemPackages(mode);
-        if (!isUpgrade && !isFirstBoot) {
+        final boolean isConsideredUpgrade = isUpgrade && !isIgnoreOtaMode(mode);
+        if (!isConsideredUpgrade && !isFirstBoot) {
+            return false;
+        }
+        if (isFirstBoot && !isEnforceMode(mode)) {
+            // Note that if !isEnforceMode, we nonetheless still install packages if isUpgrade
+            // in order to undo any previous non-installing. isFirstBoot lacks this requirement.
             return false;
         }
         Slog.i(TAG, "Reviewing whitelisted packages due to "
-                + (isFirstBoot ? "[firstBoot]" : "") + (isUpgrade ? "[upgrade]" : ""));
+                + (isFirstBoot ? "[firstBoot]" : "") + (isConsideredUpgrade ? "[upgrade]" : ""));
         final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
         // Install/uninstall system packages per user.
         for (int userId : mUm.getUserIds()) {
@@ -185,7 +193,7 @@
                 final boolean install =
                         (userWhitelist == null || userWhitelist.contains(pkg.packageName))
                         && !pkg.applicationInfo.hiddenUntilInstalled;
-                if (isUpgrade && !isFirstBoot && !install) {
+                if (isConsideredUpgrade && !isFirstBoot && !install) {
                     return; // To be careful, we don’t uninstall apps during OTAs
                 }
                 final boolean changed = pmInt.setInstalled(pkg, userId, install);
@@ -245,6 +253,19 @@
     }
 
     /**
+     * Whether to ignore OTAs, and therefore not install missing system packages during OTAs.
+     * <p>Note:
+     * If in this mode, old system packages will not be installed on pre-existing users during OTAs.
+     * Any system packages that had not been installed at the time of the user's creation,
+     * due to {@link UserSystemPackageInstaller}'s previous actions, will therefore continue to
+     * remain uninstalled, even if the whitelist (or enforcement mode) now declares that they should
+     * be.
+     */
+    boolean isIgnoreOtaMode() {
+        return isIgnoreOtaMode(getWhitelistMode());
+    }
+
+    /**
      * Whether to log a warning concerning potential problems with the user-type package whitelist.
      */
     boolean isLogMode() {
@@ -264,6 +285,11 @@
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
     }
 
+    /** See {@link #isIgnoreOtaMode()}. */
+    private static boolean isIgnoreOtaMode(int whitelistMode) {
+        return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA) != 0;
+    }
+
     /** See {@link #isLogMode()}. */
     private static boolean isLogMode(int whitelistMode) {
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_LOG) != 0;
@@ -536,6 +562,7 @@
         pw.print(isEnforceMode(mode) ? " (enforced)" : "");
         pw.print(isLogMode(mode) ? " (logged)" : "");
         pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : "");
+        pw.print(isIgnoreOtaMode(mode) ? " (ignore OTAs)" : "");
         pw.println();
 
         pw.print(prefix); pw.println("Legend");
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 01f29dc..00779ec 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -67,6 +67,7 @@
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -82,6 +83,7 @@
 class RollbackManagerServiceImpl extends IRollbackManager.Stub {
 
     private static final String TAG = "RollbackManager";
+    private static final boolean LOCAL_LOGV = false;
 
     // Rollbacks expire after 14 days.
     private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
@@ -220,6 +222,9 @@
                 if (Intent.ACTION_CANCEL_ENABLE_ROLLBACK.equals(intent.getAction())) {
                     int token = intent.getIntExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token);
+                    }
                     synchronized (mLock) {
                         for (NewRollback rollback : mNewRollbacks) {
                             if (rollback.hasToken(token)) {
@@ -269,10 +274,17 @@
                 String action = intent.getAction();
                 if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                     String packageName = intent.getData().getSchemeSpecificPart();
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "broadcast=ACTION_PACKAGE_REPLACED" + " pkg=" + packageName);
+                    }
                     onPackageReplaced(packageName);
                 }
                 if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
                     String packageName = intent.getData().getSchemeSpecificPart();
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED"
+                                + " pkg=" + packageName);
+                    }
                     onPackageFullyRemoved(packageName);
                 }
             }
@@ -359,7 +371,7 @@
      */
     private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
             String callerPackageName, IntentSender statusReceiver) {
-        Slog.i(TAG, "Initiating rollback");
+        Slog.i(TAG, "commitRollback id=" + rollbackId + " caller=" + callerPackageName);
 
         Rollback rollback = getRollbackForId(rollbackId);
         if (rollback == null) {
@@ -444,6 +456,9 @@
     }
 
     void onUnlockUser(int userId) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "onUnlockUser id=" + userId);
+        }
         // In order to ensure that no package begins running while a backup or restore is taking
         // place, onUnlockUser must remain blocked until all pending backups and restores have
         // completed.
@@ -611,6 +626,9 @@
                 if (!now.isBefore(
                         rollbackTimestamp
                                 .plusMillis(mRollbackLifetimeDurationInMillis))) {
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "runExpiration id=" + rollback.info.getRollbackId());
+                    }
                     iter.remove();
                     rollback.delete(mAppDataRollbackHelper);
                 } else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
@@ -675,6 +693,10 @@
      */
     private boolean enableRollback(
             int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "enableRollback user=" + user + " token=" + token
+                    + " path=" + newPackageCodePath.getAbsolutePath());
+        }
 
         // Find the session id associated with this install.
         // TODO: It would be nice if package manager or package installer told
@@ -838,6 +860,10 @@
     }
 
     private void snapshotUserDataInternal(String packageName, int[] userIds) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "snapshotUserData pkg=" + packageName
+                    + " users=" + Arrays.toString(userIds));
+        }
         synchronized (mLock) {
             // staged installs
             for (int i = 0; i < mRollbacks.size(); i++) {
@@ -854,6 +880,10 @@
 
     private void restoreUserDataInternal(
             String packageName, int[] userIds, int appId, String seInfo) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "restoreUserData pkg=" + packageName
+                    + " users=" + Arrays.toString(userIds));
+        }
         synchronized (mLock) {
             for (int i = 0; i < mRollbacks.size(); ++i) {
                 Rollback rollback = mRollbacks.get(i);
@@ -1041,6 +1071,9 @@
 
         @Override
         public void onFinished(int sessionId, boolean success) {
+            if (LOCAL_LOGV) {
+                Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
+            }
             NewRollback newRollback;
             synchronized (mLock) {
                 newRollback = getNewRollbackForPackageSessionLocked(sessionId);
@@ -1070,6 +1103,10 @@
      */
     private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
         Rollback rollback = newRollback.rollback;
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "completeEnableRollback id="
+                    + rollback.info.getRollbackId() + " success=" + success);
+        }
         if (!success) {
             // The install session was aborted, clean up the pending install.
             rollback.delete(mAppDataRollbackHelper);
@@ -1108,6 +1145,9 @@
 
     @GuardedBy("rollback.getLock")
     private void makeRollbackAvailable(Rollback rollback) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "makeRollbackAvailable id=" + rollback.info.getRollbackId());
+        }
         rollback.makeAvailable();
 
         // TODO(zezeozue): Provide API to explicitly start observing instead
@@ -1280,6 +1320,11 @@
         final Rollback rollback;
         int parentSessionId = parentSession.getSessionId();
 
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "createNewRollback id=" + rollbackId
+                    + " user=" + userId + " installer=" + installerPackageName);
+        }
+
         if (parentSession.isStaged()) {
             rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
                     installerPackageName);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 0930975..7f5b403 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -149,6 +149,6 @@
     }
 
     private void enforceSuggestManualTimePermission() {
-        mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SET_TIME, "set time");
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index bc6ee84..6af5025 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1526,7 +1526,13 @@
         hasBeenLaunched = false;
         mStackSupervisor = supervisor;
 
-        taskAffinity = aInfo.taskAffinity;
+        // b/35954083: Limit task affinity to uid to avoid various issues associated with sharing
+        // affinity across uids.
+        final String uid = Integer.toString(info.applicationInfo.uid);
+        if (info.taskAffinity != null && !info.taskAffinity.startsWith(uid)) {
+            info.taskAffinity = uid + ":" + info.taskAffinity;
+        }
+        taskAffinity = info.taskAffinity;
         stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
         nonLocalizedLabel = aInfo.nonLocalizedLabel;
         labelRes = aInfo.labelRes;
@@ -1804,7 +1810,7 @@
                 // task snapshot starting window.
                 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
             }
-            return snapshot == null ? STARTING_WINDOW_TYPE_SPLASH_SCREEN
+            return snapshot == null ? STARTING_WINDOW_TYPE_NONE
                     : snapshotOrientationSameAsTask(snapshot) || fromRecents
                             ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
         } else {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 145cf60..a496396 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -149,7 +149,8 @@
     private final ActivityStartController mController;
 
     // Share state variable among methods when starting an activity.
-    private ActivityRecord mStartActivity;
+    @VisibleForTesting
+    ActivityRecord mStartActivity;
     private Intent mIntent;
     private int mCallingUid;
     private ActivityOptions mOptions;
@@ -173,7 +174,8 @@
     private int mPreferredDisplayId;
 
     private Task mInTask;
-    private boolean mAddingToTask;
+    @VisibleForTesting
+    boolean mAddingToTask;
     private Task mReuseTask;
 
     private ActivityInfo mNewTaskInfo;
@@ -1665,7 +1667,16 @@
      * - Comply to the specified activity launch flags
      * - Determine whether need to add a new activity on top or just brought the task to front.
      */
-    private int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+    @VisibleForTesting
+    int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+        // Should not recycle task which is from a different user, just adding the starting
+        // activity to the task.
+        if (targetTask.mUserId != mStartActivity.mUserId) {
+            mTargetStack = targetTask.getStack();
+            mAddingToTask = true;
+            return START_SUCCESS;
+        }
+
         // True if we are clearing top and resetting of a standard (default) launch mode
         // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
         final boolean clearTopAndResetStandardLaunchMode =
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5a946f2..66f01f3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1114,9 +1114,10 @@
             SignedConfigService.registerUpdateReceiver(mSystemContext);
             t.traceEnd();
 
-        } catch (RuntimeException e) {
+        } catch (Throwable e) {
             Slog.e("System", "******************************************");
-            Slog.e("System", "************ Failure starting core service", e);
+            Slog.e("System", "************ Failure starting core service");
+            throw e;
         }
 
         // Before things start rolling, be sure we have decided whether
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
index 73279cb5..adef02e 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
@@ -19,75 +19,105 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
 public class FakeIcingTest {
     @Test
     public void query() {
         FakeIcing icing = new FakeIcing();
-        icing.put("uri:cat", "The cat said meow");
-        icing.put("uri:dog", "The dog said woof");
+        icing.put(createDoc("uri:cat", "The cat said meow"));
+        icing.put(createDoc("uri:dog", "The dog said woof"));
 
-        assertThat(icing.query("meow")).containsExactly("uri:cat");
-        assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.query("fred")).isEmpty();
+        assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+        assertThat(queryGetUris(icing, "fred")).isEmpty();
     }
 
     @Test
     public void queryNorm() {
         FakeIcing icing = new FakeIcing();
-        icing.put("uri:cat", "The cat said meow");
-        icing.put("uri:dog", "The dog said woof");
+        icing.put(createDoc("uri:cat", "The cat said meow"));
+        icing.put(createDoc("uri:dog", "The dog said woof"));
 
-        assertThat(icing.query("the")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.query("The")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.query("tHe")).containsExactly("uri:cat", "uri:dog");
+        assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog");
+        assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog");
+        assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog");
     }
 
     @Test
     public void get() {
+        DocumentProto cat = createDoc("uri:cat", "The cat said meow");
         FakeIcing icing = new FakeIcing();
-        icing.put("uri:cat", "The cat said meow");
-        assertThat(icing.get("uri:cat")).isEqualTo("The cat said meow");
+        icing.put(cat);
+        assertThat(icing.get("uri:cat")).isEqualTo(cat);
     }
 
     @Test
     public void replace() {
-        FakeIcing icing = new FakeIcing();
-        icing.put("uri:cat", "The cat said meow");
-        icing.put("uri:dog", "The dog said woof");
+        DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+        DocumentProto dog = createDoc("uri:dog", "The dog said woof");
 
-        assertThat(icing.query("meow")).containsExactly("uri:cat");
-        assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.get("uri:cat")).isEqualTo("The cat said meow");
+        FakeIcing icing = new FakeIcing();
+        icing.put(cat);
+        icing.put(dog);
+
+        assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+        assertThat(icing.get("uri:cat")).isEqualTo(cat);
 
         // Replace
-        icing.put("uri:cat", "The cat said purr");
-        icing.put("uri:bird", "The cat said tweet");
+        DocumentProto cat2 = createDoc("uri:cat", "The cat said purr");
+        DocumentProto bird = createDoc("uri:bird", "The cat said tweet");
+        icing.put(cat2);
+        icing.put(bird);
 
-        assertThat(icing.query("meow")).isEmpty();
-        assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
-        assertThat(icing.get("uri:cat")).isEqualTo("The cat said purr");
+        assertThat(queryGetUris(icing, "meow")).isEmpty();
+        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
+        assertThat(icing.get("uri:cat")).isEqualTo(cat2);
     }
 
     @Test
     public void delete() {
-        FakeIcing icing = new FakeIcing();
-        icing.put("uri:cat", "The cat said meow");
-        icing.put("uri:dog", "The dog said woof");
+        DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+        DocumentProto dog = createDoc("uri:dog", "The dog said woof");
 
-        assertThat(icing.query("meow")).containsExactly("uri:cat");
-        assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog");
-        assertThat(icing.get("uri:cat")).isEqualTo("The cat said meow");
+        FakeIcing icing = new FakeIcing();
+        icing.put(cat);
+        icing.put(dog);
+
+        assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+        assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+        assertThat(icing.get("uri:cat")).isEqualTo(cat);
 
         // Delete
         icing.delete("uri:cat");
         icing.delete("uri:notreal");
 
-        assertThat(icing.query("meow")).isEmpty();
-        assertThat(icing.query("said")).containsExactly("uri:dog");
+        assertThat(queryGetUris(icing, "meow")).isEmpty();
+        assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog");
         assertThat(icing.get("uri:cat")).isNull();
     }
+
+    private static DocumentProto createDoc(String uri, String body) {
+        return DocumentProto.newBuilder()
+                .setUri(uri)
+                .addProperties(PropertyProto.newBuilder().addStringValues(body))
+                .build();
+    }
+
+    private static List<String> queryGetUris(FakeIcing icing, String term) {
+        List<String> uris = new ArrayList<>();
+        for (DocumentProto result : icing.query(term)) {
+            uris.add(result.getUri());
+        }
+        return uris;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
new file mode 100644
index 0000000..269f918
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.SparseArray;
+import android.view.Display;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayModeDirectorTest {
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    private DisplayModeDirector createDisplayModeDirectorWithDisplayFpsRange(
+            int minFps, int maxFps) {
+        DisplayModeDirector director =
+                new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+        int displayId = 0;
+        int numModes = maxFps - minFps + 1;
+        Display.Mode[] modes = new Display.Mode[numModes];
+        for (int i = minFps; i <= maxFps; i++) {
+            modes[i - minFps] = new Display.Mode(
+                    /*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
+        }
+        SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+        supportedModesByDisplay.put(displayId, modes);
+        director.injectSupportedModesByDisplay(supportedModesByDisplay);
+        SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+        defaultModesByDisplay.put(displayId, modes[0]);
+        director.injectDefaultModeByDisplay(defaultModesByDisplay);
+        return director;
+    }
+
+    private int[] intRange(int min, int max) {
+        int[] range = new int[max - min + 1];
+        for (int i = min; i <= max; i++) {
+            range[i - min] = i;
+        }
+        return range;
+    }
+
+    @Test
+    public void testDisplayModeVoting() {
+        int displayId = 0;
+
+        // With no votes present, DisplayModeDirector should allow any refresh rate.
+        assertEquals(new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/60,
+                             new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY),
+                             intRange(60, 90)),
+                createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayConfigSpecs(
+                        displayId));
+
+        int numPriorities =
+                DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
+
+        // Ensure vote priority works as expected. As we add new votes with higher priority, they
+        // should take precedence over lower priority votes.
+        {
+            int minFps = 60;
+            int maxFps = 90;
+            DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+            assertTrue(2 * numPriorities < maxFps - minFps + 1);
+            SparseArray<DisplayModeDirector.Vote> votes =
+                    new SparseArray<DisplayModeDirector.Vote>();
+            SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+                    new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+            votesByDisplay.put(displayId, votes);
+            for (int i = 0; i < numPriorities; i++) {
+                int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
+                votes.put(
+                        priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+                director.injectVotesByDisplay(votesByDisplay);
+                assertEquals(
+                        new DisplayModeDirector.DesiredDisplayConfigSpecs(
+                                /*defaultModeId=*/minFps + i,
+                                new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i),
+                                intRange(minFps + i, maxFps - i)),
+                        director.getDesiredDisplayConfigSpecs(displayId));
+            }
+        }
+
+        // Ensure lower priority votes are able to influence the final decision, even in the
+        // presence of higher priority votes.
+        {
+            assertTrue(numPriorities >= 2);
+            DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+            SparseArray<DisplayModeDirector.Vote> votes =
+                    new SparseArray<DisplayModeDirector.Vote>();
+            SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+                    new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+            votesByDisplay.put(displayId, votes);
+            votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
+                    DisplayModeDirector.Vote.forRefreshRates(65, 85));
+            votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
+                    DisplayModeDirector.Vote.forRefreshRates(70, 80));
+            director.injectVotesByDisplay(votesByDisplay);
+            assertEquals(
+                    new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/70,
+                            new DisplayModeDirector.RefreshRateRange(70, 80), intRange(70, 80)),
+                    director.getDesiredDisplayConfigSpecs(displayId));
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 601e2e9..790f2b4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -24,6 +24,7 @@
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE;
+import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_LOG;
 
@@ -394,33 +395,45 @@
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
+
+        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
+        assertFalse(mUserSystemPackageInstaller.isLogMode());
+        assertFalse(mUserSystemPackageInstaller.isEnforceMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(
                 USER_TYPE_PACKAGE_WHITELIST_MODE_LOG | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
                 | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
     }
 
     /** Sets the whitelist mode to the desired value via adb's setprop. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ae1bb8e..c712d6d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -962,4 +962,19 @@
         }
         assertThat(exceptionCaught).isTrue();
     }
+
+    @Test
+    public void testRecycleTaskFromAnotherUser() {
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        starter.mStartActivity = new ActivityBuilder(mService).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor)
+                .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
+                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
+                .setUserId(10)
+                .build();
+
+        final int result = starter.recycleTask(task, null, null);
+        assertThat(result == START_SUCCESS).isTrue();
+        assertThat(starter.mAddingToTask).isTrue();
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index b428530..221f8f1 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,6 +16,10 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -32,6 +36,7 @@
      * Builder class for {@link ConnectionRequest}
      * @hide
      */
+    @TestApi // For convenience in CTS tests
     public static final class Builder {
         private PhoneAccountHandle mAccountHandle;
         private Uri mAddress;
@@ -48,7 +53,7 @@
          * Sets the phone account handle for the resulting {@link ConnectionRequest}
          * @param accountHandle The accountHandle which should be used to place the call.
          */
-        public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+        public @NonNull Builder setAccountHandle(@NonNull PhoneAccountHandle accountHandle) {
             this.mAccountHandle = accountHandle;
             return this;
         }
@@ -58,7 +63,7 @@
          * @param address The address(e.g., phone number) to which the {@link Connection} is to
          *                connect.
          */
-        public Builder setAddress(Uri address) {
+        public @NonNull Builder setAddress(@NonNull Uri address) {
             this.mAddress = address;
             return this;
         }
@@ -67,7 +72,7 @@
          * Sets the extras bundle for the resulting {@link ConnectionRequest}
          * @param extras Application-specific extra data.
          */
-        public Builder setExtras(Bundle extras) {
+        public @NonNull Builder setExtras(@NonNull Bundle extras) {
             this.mExtras = extras;
             return this;
         }
@@ -76,7 +81,7 @@
          * Sets the video state for the resulting {@link ConnectionRequest}
          * @param videoState Determines the video state for the connection.
          */
-        public Builder setVideoState(int videoState) {
+        public @NonNull Builder setVideoState(int videoState) {
             this.mVideoState = videoState;
             return this;
         }
@@ -85,7 +90,7 @@
          * Sets the Telecom call ID for the resulting {@link ConnectionRequest}
          * @param telecomCallId The telecom call ID.
          */
-        public Builder setTelecomCallId(String telecomCallId) {
+        public @NonNull Builder setTelecomCallId(@NonNull String telecomCallId) {
             this.mTelecomCallId = telecomCallId;
             return this;
         }
@@ -97,7 +102,7 @@
          *                                 its own incoming call UI for an incoming call.  When
          *                                 {@code false}, Telecom shows the incoming call UI.
          */
-        public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+        public @NonNull Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
             this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
             return this;
         }
@@ -107,7 +112,8 @@
          * resulting {@link ConnectionRequest}
          * @param rttPipeFromInCall The data pipe to read from.
          */
-        public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+        public @NonNull Builder setRttPipeFromInCall(
+                @NonNull ParcelFileDescriptor rttPipeFromInCall) {
             this.mRttPipeFromInCall = rttPipeFromInCall;
             return this;
         }
@@ -117,12 +123,16 @@
          * resulting {@link ConnectionRequest}
          * @param rttPipeToInCall The data pipe to write to.
          */
-        public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+        public @NonNull Builder setRttPipeToInCall(@NonNull ParcelFileDescriptor rttPipeToInCall) {
             this.mRttPipeToInCall = rttPipeToInCall;
             return this;
         }
 
-        public ConnectionRequest build() {
+        /**
+         * Build the {@link ConnectionRequest}
+         * @return Result of the builder
+         */
+        public @NonNull ConnectionRequest build() {
             return new ConnectionRequest(
                     mAccountHandle,
                     mAddress,
@@ -261,7 +271,9 @@
      * @return The Telecom ID.
      * @hide
      */
-    public String getTelecomCallId() {
+    @SystemApi
+    @TestApi
+    public @Nullable String getTelecomCallId() {
         return mTelecomCallId;
     }
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4016943..39d741c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1029,12 +1029,16 @@
      * by the user.
      *
      * @param includeDisabledAccounts When {@code true}, disabled phone accounts will be included,
-     *                                when {@code false}, only
+     *                                when {@code false}, only enabled phone accounts will be
+     *                                included.
      * @return A list of {@code PhoneAccountHandle} objects.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590)
-    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
+    @SystemApi
+    @TestApi
+    @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
+    public @NonNull List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+            boolean includeDisabledAccounts) {
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getCallCapablePhoneAccounts(
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1dd1185..fc26122 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,7 +86,6 @@
 
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.IOns;
@@ -5176,13 +5175,11 @@
      * @return the current call state.
      */
     public @CallState int getCallState() {
-        try {
-            ITelecomService telecom = getTelecomService();
-            if (telecom != null) {
-                return telecom.getCallState();
+        if (mContext != null) {
+            TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+            if (telecomManager != null) {
+                return telecomManager.getCallState();
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecomService#getCallState", e);
         }
         return CALL_STATE_IDLE;
     }
@@ -5341,13 +5338,6 @@
         return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
     }
 
-    /**
-    * @hide
-    */
-    private ITelecomService getTelecomService() {
-        return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
-    }
-
     private ITelephonyRegistry getTelephonyRegistry() {
         return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
     }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 6e20621..96ddf22 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -390,7 +390,6 @@
     private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
             int uid, String callingPackage, String message) {
         boolean isPreinstalled = false;
-        boolean isPrivApp = false;
         ApplicationInfo callingPackageInfo = null;
         try {
             callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
@@ -398,9 +397,6 @@
             if (callingPackageInfo != null) {
                 if (callingPackageInfo.isSystemApp()) {
                     isPreinstalled = true;
-                    if (callingPackageInfo.isPrivilegedApp()) {
-                        isPrivApp = true;
-                    }
                 }
             }
         } catch (PackageManager.NameNotFoundException e) {
@@ -423,10 +419,10 @@
             }
             invokedMethods.add(message);
             StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
-                    isPreinstalled, isPrivApp);
+                    isPreinstalled, false);
         }
         Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
-                + ":isPreinstalled=" + isPreinstalled + ":isPrivApp=" + isPrivApp);
+                + ":isPreinstalled=" + isPreinstalled);
         // if the target SDK is pre-Q then check if the calling package would have previously
         // had access to device identifiers.
         if (callingPackageInfo != null && (
diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
new file mode 100644
index 0000000..a28d65c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+
+import java.io.PrintWriter;
+
+/**
+ * This class provides various util functions
+ */
+public final class TelephonyUtils {
+    public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
+    public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    /**
+     * Verify that caller holds {@link android.Manifest.permission#DUMP}.
+     *
+     * @return true if access should be granted.
+     */
+    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump " + tag + " from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " due to missing android.permission.DUMP permission");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /** Returns an empty string if the input is {@code null}. */
+    public static String emptyIfNull(@Nullable String str) {
+        return str == null ? "" : str;
+    }
+
+    /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */
+    public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
+        throw new RuntimeException(remoteException);
+    }
+
+    /**
+     * Returns a {@link ComponentInfo} from the {@link ResolveInfo},
+     * or throws an {@link IllegalStateException} if not available.
+     */
+    public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) {
+        if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo;
+        if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo;
+        if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo;
+        throw new IllegalStateException("Missing ComponentInfo!");
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2a09f64..c4e353b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -96,6 +96,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.startsWith;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
@@ -198,6 +199,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
 import com.android.internal.util.ArrayUtils;
@@ -305,6 +307,7 @@
     @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
+    @Mock IBatteryStats mBatteryStatsService;
     @Mock INetworkPolicyManager mNpm;
     @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
@@ -1135,6 +1138,7 @@
         doReturn(mMetricsService).when(deps).getMetricsLogger();
         doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
         doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+        doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
         doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
@@ -5640,6 +5644,36 @@
         mCm.unregisterNetworkCallback(defaultCallback);
     }
 
+    @Test
+    public final void testBatteryStatsNetworkType() throws Exception {
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName("cell0");
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(true);
+        waitForIdle();
+        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+                TYPE_MOBILE);
+        reset(mBatteryStatsService);
+
+        final LinkProperties wifiLp = new LinkProperties();
+        wifiLp.setInterfaceName("wifi0");
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+        mWiFiNetworkAgent.connect(true);
+        waitForIdle();
+        verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
+                TYPE_WIFI);
+        reset(mBatteryStatsService);
+
+        mCellNetworkAgent.disconnect();
+
+        cellLp.setInterfaceName("wifi0");
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(true);
+        waitForIdle();
+        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+                TYPE_MOBILE);
+    }
+
     /**
      * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
      */
@@ -5680,25 +5714,28 @@
         mCm.registerNetworkCallback(networkRequest, networkCallback);
 
         // Prepare ipv6 only link properties.
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         cellLp.addLinkAddress(myIpv6);
         cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
         cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         reset(mNetworkManagementService);
         reset(mMockDnsResolver);
         reset(mMockNetd);
+        reset(mBatteryStatsService);
         when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfig(myIpv4));
 
         // Connect with ipv6 link properties. Expect prefix discovery to be started.
-        mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
+        final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+        waitForIdle();
 
         verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+                TYPE_MOBILE);
 
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -5714,6 +5751,11 @@
         verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
 
+        // Make sure BatteryStats was not told about any v4- interfaces, as none should have
+        // come online yet.
+        waitForIdle();
+        verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
         reset(mMockNetd);
@@ -5760,6 +5802,11 @@
         assertEquals(1, resolvrParams.servers.length);
         assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
+        for (final LinkProperties stackedLp : stackedLpsAfterChange) {
+            verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
+                    TYPE_MOBILE);
+        }
+
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
         cellLp.addLinkAddress(myIpv4);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e08a11e..d068fc6 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -39,7 +39,6 @@
 import android.util.BackupUtils;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.TimeUtils;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -49,6 +48,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Calendar;
 import java.util.HashMap;
 
 /**
@@ -2006,6 +2006,16 @@
                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
     }
 
+    private static String logTimeOfDay(long millis) {
+        Calendar c = Calendar.getInstance();
+        if (millis >= 0) {
+            c.setTimeInMillis(millis);
+            return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
+        } else {
+            return Long.toString(millis);
+        }
+    }
+
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
@@ -2042,7 +2052,7 @@
         if (mNetworkSelectionStatus.getConnectChoice() != null) {
             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
             sbuf.append(" connect choice set time: ")
-                    .append(TimeUtils.logTimeOfDay(
+                    .append(logTimeOfDay(
                             mNetworkSelectionStatus.getConnectChoiceTimestamp()));
         }
         sbuf.append(" hasEverConnected: ")
@@ -2081,7 +2091,7 @@
         sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
         sbuf.append(" randomizedMacExpirationTimeMs: ")
                 .append(randomizedMacExpirationTimeMs == 0 ? "<none>"
-                        : TimeUtils.logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
+                        : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
         sbuf.append(" KeyMgmt:");
         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
             if (this.allowedKeyManagement.get(k)) {
@@ -2205,7 +2215,7 @@
 
         if (this.lastConnected != 0) {
             sbuf.append('\n');
-            sbuf.append("lastConnected: ").append(TimeUtils.logTimeOfDay(this.lastConnected));
+            sbuf.append("lastConnected: ").append(logTimeOfDay(this.lastConnected));
             sbuf.append(" ");
         }
         sbuf.append('\n');
@@ -2355,7 +2365,7 @@
                 ? getSsidAndSecurityTypeString()
                 : FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
         if (!shared) {
-            key += "-" + UserHandle.getUserId(creatorUid);
+            key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
         }
         return key;
     }
@@ -2426,13 +2436,13 @@
     @NonNull
     @SystemApi
     public IpConfiguration.IpAssignment getIpAssignment() {
-        return mIpConfiguration.ipAssignment;
+        return mIpConfiguration.getIpAssignment();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
-        mIpConfiguration.ipAssignment = ipAssignment;
+        mIpConfiguration.setIpAssignment(ipAssignment);
     }
 
     /**
@@ -2442,13 +2452,13 @@
     @NonNull
     @SystemApi
     public IpConfiguration.ProxySettings getProxySettings() {
-        return mIpConfiguration.proxySettings;
+        return mIpConfiguration.getProxySettings();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
-        mIpConfiguration.proxySettings = proxySettings;
+        mIpConfiguration.setProxySettings(proxySettings);
     }
 
     /**
@@ -2457,10 +2467,10 @@
      *                  WifiConfiguration, or {@code null} if no proxy is specified.
      */
     public ProxyInfo getHttpProxy() {
-        if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
+        if (mIpConfiguration.getProxySettings() == IpConfiguration.ProxySettings.NONE) {
             return null;
         }
-        return new ProxyInfo(mIpConfiguration.httpProxy);
+        return new ProxyInfo(mIpConfiguration.getHttpProxy());
     }
 
     /**
@@ -2485,12 +2495,12 @@
         if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
             proxySettingCopy = IpConfiguration.ProxySettings.PAC;
             // Construct a new PAC URL Proxy
-            httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
+            httpProxyCopy = ProxyInfo.buildPacProxy(httpProxy.getPacFileUrl(), httpProxy.getPort());
         } else {
             proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
             // Construct a new HTTP Proxy
-            httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
-                    httpProxy.getExclusionListAsString());
+            httpProxyCopy = ProxyInfo.buildDirectProxy(httpProxy.getHost(), httpProxy.getPort(),
+                    Arrays.asList(httpProxy.getExclusionList()));
         }
         if (!httpProxyCopy.isValid()) {
             throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
@@ -2505,8 +2515,8 @@
      */
     @SystemApi
     public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
-        mIpConfiguration.proxySettings = settings;
-        mIpConfiguration.httpProxy = proxy;
+        mIpConfiguration.setProxySettings(settings);
+        mIpConfiguration.setHttpProxy(proxy);
     }
 
     /** Implement the Parcelable interface {@hide} */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6557bbe..bf609d7 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -36,15 +36,12 @@
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
 import android.net.NetworkStack;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.IBinder;
@@ -57,7 +54,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.net.NetworkPinner;
 
 import dalvik.system.CloseGuard;
 
@@ -2022,28 +2018,11 @@
      */
     @Deprecated
     public boolean enableNetwork(int netId, boolean attemptConnect) {
-        final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
-        if (pin) {
-            NetworkRequest request = new NetworkRequest.Builder()
-                    .clearCapabilities()
-                    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                    .build();
-            NetworkPinner.pin(mContext, request);
-        }
-
-        boolean success;
         try {
-            success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
+            return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-
-        if (pin && !success) {
-            NetworkPinner.unpin();
-        }
-
-        return success;
     }
 
     /**
@@ -5105,9 +5084,9 @@
                                 Log.v(TAG, "OnWifiUsabilityStatsListener: "
                                         + "onWifiUsabilityStats: seqNum=" + seqNum);
                             }
-                            Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
-                                            isSameBssidAndFreq, stats)));
+                            Binder.clearCallingIdentity();
+                            executor.execute(() -> listener.onWifiUsabilityStats(
+                                    seqNum, isSameBssidAndFreq, stats));
                         }
                     },
                     listener.hashCode()
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 77f7b9e..b293077 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -59,6 +59,60 @@
 public class WifiScanner {
 
     /** @hide */
+    public static final int WIFI_BAND_INDEX_24_GHZ = 0;
+    /** @hide */
+    public static final int WIFI_BAND_INDEX_5_GHZ = 1;
+    /** @hide */
+    public static final int WIFI_BAND_INDEX_5_GHZ_DFS_ONLY = 2;
+    /** @hide */
+    public static final int WIFI_BAND_COUNT = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"WIFI_BAND_INDEX_"}, value = {
+            WIFI_BAND_INDEX_24_GHZ,
+            WIFI_BAND_INDEX_5_GHZ,
+            WIFI_BAND_INDEX_5_GHZ_DFS_ONLY})
+    public @interface WifiBandIndex {}
+
+    /** no band specified; use channel list instead */
+    public static final int WIFI_BAND_UNSPECIFIED = 0;
+    /** 2.4 GHz band */
+    public static final int WIFI_BAND_24_GHZ = 1 << WIFI_BAND_INDEX_24_GHZ;
+    /** 5 GHz band excluding DFS channels */
+    public static final int WIFI_BAND_5_GHZ = 1 << WIFI_BAND_INDEX_5_GHZ;
+    /** DFS channels from 5 GHz band only */
+    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"WIFI_BAND_"}, value = {
+            WIFI_BAND_UNSPECIFIED,
+            WIFI_BAND_24_GHZ,
+            WIFI_BAND_5_GHZ,
+            WIFI_BAND_5_GHZ_DFS_ONLY})
+    public @interface WifiBandBasic {}
+
+    /**
+     * Combination of bands
+     * Note that those are only the common band combinations,
+     * other combinations can be created by combining any of the basic bands above
+     */
+    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
+    public static final int WIFI_BAND_BOTH = WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ;
+    /**
+     * 2.4Ghz band + DFS channels from 5 GHz band only
+     * @hide
+     */
+    public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS  =
+            WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+    /** 5 GHz band including DFS channels */
+    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+    /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
+    public static final int WIFI_BAND_BOTH_WITH_DFS =
+            WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"WIFI_BAND_"}, value = {
             WIFI_BAND_UNSPECIFIED,
@@ -71,25 +125,6 @@
             WIFI_BAND_BOTH_WITH_DFS})
     public @interface WifiBand {}
 
-    /** no band specified; use channel list instead */
-    public static final int WIFI_BAND_UNSPECIFIED = 0;
-    /** 2.4 GHz band */
-    public static final int WIFI_BAND_24_GHZ = 1;
-    /** 5 GHz band excluding DFS channels */
-    public static final int WIFI_BAND_5_GHZ = 2;
-    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
-    public static final int WIFI_BAND_BOTH = 3;
-    /** DFS channels from 5 GHz band only */
-    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;
-    /**
-     * 2.4Ghz band + DFS channels from 5 GHz band only
-     * @hide
-     */
-    public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS  = 5;
-    /** 5 GHz band including DFS channels */
-    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;
-    /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
-    public static final int WIFI_BAND_BOTH_WITH_DFS = 7;
     /**
      * Max band value
      * @hide
@@ -398,7 +433,6 @@
                         return new ScanSettings[size];
                     }
                 };
-
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index b3b5b29..2d3cc1e 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -18,8 +18,6 @@
 
 import android.annotation.Nullable;
 
-import libcore.io.Memory;
-
 import java.nio.BufferOverflowException;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -266,7 +264,7 @@
         public TlvConstructor putShort(int type, short data) {
             checkLength(2);
             addHeader(type, 2);
-            Memory.pokeShort(mArray, mPosition, data, mByteOrder);
+            pokeShort(mArray, mPosition, data, mByteOrder);
             mPosition += 2;
             return this;
         }
@@ -284,7 +282,7 @@
         public TlvConstructor putInt(int type, int data) {
             checkLength(4);
             addHeader(type, 4);
-            Memory.pokeInt(mArray, mPosition, data, mByteOrder);
+            pokeInt(mArray, mPosition, data, mByteOrder);
             mPosition += 4;
             return this;
         }
@@ -349,14 +347,14 @@
             if (mTypeSize == 1) {
                 mArray[mPosition] = (byte) type;
             } else if (mTypeSize == 2) {
-                Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
+                pokeShort(mArray, mPosition, (short) type, mByteOrder);
             }
             mPosition += mTypeSize;
 
             if (mLengthSize == 1) {
                 mArray[mPosition] = (byte) length;
             } else if (mLengthSize == 2) {
-                Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
+                pokeShort(mArray, mPosition, (short) length, mByteOrder);
             }
             mPosition += mLengthSize;
         }
@@ -445,7 +443,7 @@
                 throw new IllegalArgumentException(
                         "Accesing a short from a TLV element of length " + length);
             }
-            return Memory.peekShort(mRefArray, offset, byteOrder);
+            return peekShort(mRefArray, offset, byteOrder);
         }
 
         /**
@@ -460,7 +458,7 @@
                 throw new IllegalArgumentException(
                         "Accesing an int from a TLV element of length " + length);
             }
-            return Memory.peekInt(mRefArray, offset, byteOrder);
+            return peekInt(mRefArray, offset, byteOrder);
         }
 
         /**
@@ -590,7 +588,7 @@
                     if (mTypeSize == 1) {
                         type = mArray[mOffset];
                     } else if (mTypeSize == 2) {
-                        type = Memory.peekShort(mArray, mOffset, mByteOrder);
+                        type = peekShort(mArray, mOffset, mByteOrder);
                     }
                     mOffset += mTypeSize;
 
@@ -598,7 +596,7 @@
                     if (mLengthSize == 1) {
                         length = mArray[mOffset];
                     } else if (mLengthSize == 2) {
-                        length = Memory.peekShort(mArray, mOffset, mByteOrder);
+                        length = peekShort(mArray, mOffset, mByteOrder);
                     }
                     mOffset += mLengthSize;
 
@@ -661,10 +659,56 @@
             if (lengthSize == 1) {
                 nextTlvIndex += lengthSize + array[nextTlvIndex];
             } else {
-                nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
+                nextTlvIndex += lengthSize + peekShort(array, nextTlvIndex, byteOrder);
             }
         }
 
         return nextTlvIndex == array.length;
     }
+
+    private static void pokeShort(byte[] dst, int offset, short value, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            dst[offset++] = (byte) ((value >> 8) & 0xff);
+            dst[offset  ] = (byte) ((value >> 0) & 0xff);
+        } else {
+            dst[offset++] = (byte) ((value >> 0) & 0xff);
+            dst[offset  ] = (byte) ((value >> 8) & 0xff);
+        }
+    }
+
+    private static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            dst[offset++] = (byte) ((value >> 24) & 0xff);
+            dst[offset++] = (byte) ((value >> 16) & 0xff);
+            dst[offset++] = (byte) ((value >>  8) & 0xff);
+            dst[offset  ] = (byte) ((value >>  0) & 0xff);
+        } else {
+            dst[offset++] = (byte) ((value >>  0) & 0xff);
+            dst[offset++] = (byte) ((value >>  8) & 0xff);
+            dst[offset++] = (byte) ((value >> 16) & 0xff);
+            dst[offset  ] = (byte) ((value >> 24) & 0xff);
+        }
+    }
+
+    private static short peekShort(byte[] src, int offset, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            return (short) ((src[offset] << 8) | (src[offset + 1] & 0xff));
+        } else {
+            return (short) ((src[offset + 1] << 8) | (src[offset] & 0xff));
+        }
+    }
+
+    private static int peekInt(byte[] src, int offset, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            return ((src[offset++] & 0xff) << 24)
+                    | ((src[offset++] & 0xff) << 16)
+                    | ((src[offset++] & 0xff) <<  8)
+                    | ((src[offset  ] & 0xff) <<  0);
+        } else {
+            return ((src[offset++] & 0xff) <<  0)
+                    | ((src[offset++] & 0xff) <<  8)
+                    | ((src[offset++] & 0xff) << 16)
+                    | ((src[offset  ] & 0xff) << 24);
+        }
+    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index 9164d04..5ec4c8b 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -207,14 +207,14 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeBlob(mData);
+            dest.writeByteArray(mData);
         }
 
         public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
                 new Creator<ByteArrayWrapper>() {
                     @Override
                     public ByteArrayWrapper createFromParcel(Parcel in) {
-                        return new ByteArrayWrapper(in.readBlob());
+                        return new ByteArrayWrapper(in.createByteArray());
                     }
 
                     @Override
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 3bef502..f0a0607 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
 import android.os.Bundle;
@@ -86,23 +85,16 @@
      */
     private final List<Integer> mMethodList;
 
-    /**
-     * Icon data for the OSU (Online Sign-Up) provider.
-     */
-    private final Icon mIcon;
-
     /** @hide */
     public OsuProvider(String osuSsid, Map<String, String> friendlyNames,
-            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
-            Icon icon) {
+            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
         this(WifiSsid.createFromByteArray(osuSsid.getBytes(StandardCharsets.UTF_8)),
-                friendlyNames, serviceDescription, serverUri, nai, methodList, icon);
+                friendlyNames, serviceDescription, serverUri, nai, methodList);
     }
 
     /** @hide */
     public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
-            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
-            Icon icon) {
+            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
         mOsuSsid = osuSsid;
         mFriendlyNames = friendlyNames;
         mServiceDescription = serviceDescription;
@@ -113,7 +105,6 @@
         } else {
             mMethodList = new ArrayList<>(methodList);
         }
-        mIcon = icon;
     }
 
     /**
@@ -130,7 +121,6 @@
             mServerUri = null;
             mNetworkAccessIdentifier = null;
             mMethodList = new ArrayList<>();
-            mIcon = null;
             return;
         }
 
@@ -144,7 +134,6 @@
         } else {
             mMethodList = new ArrayList<>(source.mMethodList);
         }
-        mIcon = source.mIcon;
     }
 
     /** @hide */
@@ -205,11 +194,6 @@
         return mMethodList;
     }
 
-    /** @hide */
-    public Icon getIcon() {
-        return mIcon;
-    }
-
     @Override
     public int describeContents() {
         return 0;
@@ -222,7 +206,6 @@
         dest.writeParcelable(mServerUri, flags);
         dest.writeString(mNetworkAccessIdentifier);
         dest.writeList(mMethodList);
-        dest.writeParcelable(mIcon, flags);
         Bundle bundle = new Bundle();
         bundle.putSerializable("friendlyNameMap", (HashMap<String, String>) mFriendlyNames);
         dest.writeBundle(bundle);
@@ -237,21 +220,16 @@
             return false;
         }
         OsuProvider that = (OsuProvider) thatObject;
-        return (mOsuSsid == null ? that.mOsuSsid == null : mOsuSsid.equals(that.mOsuSsid))
-                && (mFriendlyNames == null) ? that.mFriendlyNames == null
-                            : mFriendlyNames.equals(that.mFriendlyNames)
+        return Objects.equals(mOsuSsid, that.mOsuSsid)
+                && Objects.equals(mFriendlyNames, that.mFriendlyNames)
                 && TextUtils.equals(mServiceDescription, that.mServiceDescription)
-                && (mServerUri == null ? that.mServerUri == null
-                            : mServerUri.equals(that.mServerUri))
+                && Objects.equals(mServerUri, that.mServerUri)
                 && TextUtils.equals(mNetworkAccessIdentifier, that.mNetworkAccessIdentifier)
-                && (mMethodList == null ? that.mMethodList == null
-                            : mMethodList.equals(that.mMethodList))
-                && (mIcon == null ? that.mIcon == null : mIcon.sameAs(that.mIcon));
+                && Objects.equals(mMethodList, that.mMethodList);
     }
 
     @Override
     public int hashCode() {
-        // mIcon is not hashable, skip the variable.
         return Objects.hash(mOsuSsid, mServiceDescription, mFriendlyNames,
                 mServerUri, mNetworkAccessIdentifier, mMethodList);
     }
@@ -264,8 +242,7 @@
                 + " mServiceDescription=" + mServiceDescription
                 + " mServerUri=" + mServerUri
                 + " mNetworkAccessIdentifier=" + mNetworkAccessIdentifier
-                + " mMethodList=" + mMethodList
-                + " mIcon=" + mIcon;
+                + " mMethodList=" + mMethodList;
     }
 
     public static final @android.annotation.NonNull Creator<OsuProvider> CREATOR =
@@ -278,12 +255,11 @@
                     String nai = in.readString();
                     List<Integer> methodList = new ArrayList<>();
                     in.readList(methodList, null);
-                    Icon icon = in.readParcelable(null);
                     Bundle bundle = in.readBundle();
                     Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
                             "friendlyNameMap");
                     return new OsuProvider(osuSsid, friendlyNamesMap, serviceDescription,
-                            serverUri, nai, methodList, icon);
+                            serverUri, nai, methodList);
                 }
 
             @Override
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index e639282..4a32f52 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -37,5 +37,9 @@
 <pre>
     getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
 </pre>
+
+<p>For an example of this functionality, see
+<a href="{@docRoot}guide/topics/connectivity/wifi-rtt" class="external">Wi-Fi location: ranging
+with RTT</a>.</p>
 </BODY>
 </HTML>
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
index 43ee249..2ded849 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
 import android.os.Parcel;
@@ -56,7 +55,6 @@
     private static final String TEST_NAI = "test.access.com";
     private static final List<Integer> TEST_METHOD_LIST =
             Arrays.asList(OsuProvider.METHOD_SOAP_XML_SPP);
-    private static final Icon TEST_ICON = Icon.createWithData(new byte[10], 0, 10);
 
     /**
      * Verify parcel write and read consistency for the given {@link OsuProvider}.
@@ -82,7 +80,7 @@
      */
     @Test
     public void verifyParcelWithEmptyProviderInfo() throws Exception {
-        verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null, null));
+        verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null));
     }
 
     /**
@@ -93,7 +91,7 @@
     @Test
     public void verifyParcelWithFullProviderInfo() throws Exception {
         verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
-                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON));
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST));
     }
 
     /**
@@ -102,7 +100,7 @@
      */
     @Test
     public void verifyCopyConstructorWithNullSource() throws Exception {
-        OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null, null);
+        OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null);
         assertEquals(expected, new OsuProvider(null));
     }
 
@@ -114,7 +112,7 @@
     @Test
     public void verifyCopyConstructorWithValidSource() throws Exception {
         OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
-                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
         assertEquals(source, new OsuProvider(source));
     }
 
@@ -126,7 +124,7 @@
     @Test
     public void verifyGetters() throws Exception {
         OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
-                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
 
         assertTrue(TEST_SSID.equals(provider.getOsuSsid()));
         assertTrue(TEST_FRIENDLY_NAME.equals(provider.getFriendlyName()));
@@ -135,6 +133,5 @@
         assertTrue(TEST_SERVER_URI.equals(provider.getServerUri()));
         assertTrue(TEST_NAI.equals(provider.getNetworkAccessIdentifier()));
         assertTrue(TEST_METHOD_LIST.equals(provider.getMethodList()));
-        assertTrue(TEST_ICON.sameAs(provider.getIcon()));
     }
 }