Merge "DO NOT MERGE: Only restore the positions of types which are controlled" into rvc-qpr-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index bb94275..ba83483 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -22,6 +22,7 @@
 
 import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 
+import android.annotation.Nullable;
 import android.app.job.JobInfo;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -86,9 +87,12 @@
     @GuardedBy("mLock")
     private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>();
 
-    /** List of currently available networks. */
+    /**
+     * Set of currently available networks mapped to their latest network capabilities. Cache the
+     * latest capabilities to avoid unnecessary calls into ConnectivityManager.
+     */
     @GuardedBy("mLock")
-    private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
+    private final ArrayMap<Network, NetworkCapabilities> mAvailableNetworks = new ArrayMap<>();
 
     private static final int MSG_DATA_SAVER_TOGGLED = 0;
     private static final int MSG_UID_RULES_CHANGES = 1;
@@ -165,9 +169,8 @@
     public boolean isNetworkAvailable(JobStatus job) {
         synchronized (mLock) {
             for (int i = 0; i < mAvailableNetworks.size(); ++i) {
-                final Network network = mAvailableNetworks.valueAt(i);
-                final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(
-                        network);
+                final Network network = mAvailableNetworks.keyAt(i);
+                final NetworkCapabilities capabilities = mAvailableNetworks.valueAt(i);
                 final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
                 if (DEBUG) {
                     Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
@@ -427,9 +430,33 @@
         return false;
     }
 
+    @Nullable
+    private NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
+        if (network == null) {
+            return null;
+        }
+        synchronized (mLock) {
+            // There is technically a race here if the Network object is reused. This can happen
+            // only if that Network disconnects and the auto-incrementing network ID in
+            // ConnectivityService wraps. This should no longer be a concern if/when we only make
+            // use of asynchronous calls.
+            if (mAvailableNetworks.get(network) != null) {
+                return mAvailableNetworks.get(network);
+            }
+
+            // This should almost never happen because any time a new network connects, the
+            // NetworkCallback would populate mAvailableNetworks. However, it's currently necessary
+            // because we also call synchronous methods such as getActiveNetworkForUid.
+            // TODO(134978280): remove after switching to callback-based APIs
+            final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
+            mAvailableNetworks.put(network, capabilities);
+            return capabilities;
+        }
+    }
+
     private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
         final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
-        final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
+        final NetworkCapabilities capabilities = getNetworkCapabilities(network);
         return updateConstraintsSatisfied(jobStatus, network, capabilities);
     }
 
@@ -470,19 +497,13 @@
      */
     private void updateTrackedJobs(int filterUid, Network filterNetwork) {
         synchronized (mLock) {
-            // Since this is a really hot codepath, temporarily cache any
-            // answers that we get from ConnectivityManager.
-            final ArrayMap<Network, NetworkCapabilities> networkToCapabilities = new ArrayMap<>();
-
             boolean changed = false;
             if (filterUid == -1) {
                 for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
-                    changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i),
-                            filterNetwork, networkToCapabilities);
+                    changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), filterNetwork);
                 }
             } else {
-                changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid),
-                        filterNetwork, networkToCapabilities);
+                changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), filterNetwork);
             }
             if (changed) {
                 mStateChangedListener.onControllerStateChanged();
@@ -490,18 +511,13 @@
         }
     }
 
-    private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork,
-            ArrayMap<Network, NetworkCapabilities> networkToCapabilities) {
+    private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
         if (jobs == null || jobs.size() == 0) {
             return false;
         }
 
         final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
-        NetworkCapabilities capabilities = networkToCapabilities.get(network);
-        if (capabilities == null) {
-            capabilities = mConnManager.getNetworkCapabilities(network);
-            networkToCapabilities.put(network, capabilities);
-        }
+        final NetworkCapabilities capabilities = getNetworkCapabilities(network);
         final boolean networkMatch = (filterNetwork == null
                 || Objects.equals(filterNetwork, network));
 
@@ -544,9 +560,9 @@
         @Override
         public void onAvailable(Network network) {
             if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
-            synchronized (mLock) {
-                mAvailableNetworks.add(network);
-            }
+            // Documentation says not to call getNetworkCapabilities here but wait for
+            // onCapabilitiesChanged instead.  onCapabilitiesChanged should be called immediately
+            // after this, so no need to update mAvailableNetworks here.
         }
 
         @Override
@@ -554,6 +570,9 @@
             if (DEBUG) {
                 Slog.v(TAG, "onCapabilitiesChanged: " + network);
             }
+            synchronized (mLock) {
+                mAvailableNetworks.put(network, capabilities);
+            }
             updateTrackedJobs(-1, network);
         }
 
@@ -630,6 +649,8 @@
             pw.println("Available networks:");
             pw.increaseIndent();
             for (int i = 0; i < mAvailableNetworks.size(); i++) {
+                pw.print(mAvailableNetworks.keyAt(i));
+                pw.print(": ");
                 pw.println(mAvailableNetworks.valueAt(i));
             }
             pw.decreaseIndent();
@@ -667,7 +688,7 @@
                     mRequestedWhitelistJobs.keyAt(i));
         }
         for (int i = 0; i < mAvailableNetworks.size(); i++) {
-            Network network = mAvailableNetworks.valueAt(i);
+            Network network = mAvailableNetworks.keyAt(i);
             if (network != null) {
                 network.dumpDebug(proto,
                         StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 4417b68..f0ef22f 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -35,7 +35,6 @@
     libs: [
         "framework_media_annotation",
     ],
-
     static_libs: [
         "exoplayer2-extractor"
     ],
@@ -110,10 +109,32 @@
     ],
 }
 
-
 java_library {
     name: "framework_media_annotation",
     srcs: [":framework-media-annotation-srcs"],
     installable: false,
     sdk_version: "core_current",
 }
+
+cc_library_shared {
+    name: "libmediaparser-jni",
+    srcs: [
+        "jni/android_media_MediaParserJNI.cpp",
+    ],
+    shared_libs: [
+        "libandroid",
+        "liblog",
+        "libmediametrics",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wunreachable-code",
+        "-Wunused",
+    ],
+    apex_available: [
+        "com.android.media",
+    ],
+    min_sdk_version: "29",
+}
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index e4b5d19..8bdca76 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -75,6 +75,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.Function;
 
 /**
  * Parses media container formats and extracts contained media samples and metadata.
@@ -882,6 +884,7 @@
     // Private constants.
 
     private static final String TAG = "MediaParser";
+    private static final String JNI_LIBRARY_NAME = "mediaparser-jni";
     private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
     private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME;
     private static final String TS_MODE_SINGLE_PMT = "single_pmt";
@@ -889,6 +892,14 @@
     private static final String TS_MODE_HLS = "hls";
     private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6;
     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    private static final String MEDIAMETRICS_ELEMENT_SEPARATOR = "|";
+    private static final int MEDIAMETRICS_MAX_STRING_SIZE = 200;
+    private static final int MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH;
+    /**
+     * Intentional error introduced to reported metrics to prevent identification of the parsed
+     * media. Note: Increasing this value may cause older hostside CTS tests to fail.
+     */
+    private static final float MEDIAMETRICS_DITHER = .02f;
 
     @IntDef(
             value = {
@@ -920,7 +931,7 @@
             @NonNull @ParserName String name, @NonNull OutputConsumer outputConsumer) {
         String[] nameAsArray = new String[] {name};
         assertValidNames(nameAsArray);
-        return new MediaParser(outputConsumer, /* sniff= */ false, name);
+        return new MediaParser(outputConsumer, /* createdByName= */ true, name);
     }
 
     /**
@@ -940,7 +951,7 @@
         if (parserNames.length == 0) {
             parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
         }
-        return new MediaParser(outputConsumer, /* sniff= */ true, parserNames);
+        return new MediaParser(outputConsumer, /* createdByName= */ false, parserNames);
     }
 
     // Misc static methods.
@@ -1052,6 +1063,14 @@
     private long mPendingSeekPosition;
     private long mPendingSeekTimeMicros;
     private boolean mLoggedSchemeInitDataCreationException;
+    private boolean mReleased;
+
+    // MediaMetrics fields.
+    private final boolean mCreatedByName;
+    private final SparseArray<Format> mTrackFormats;
+    private String mLastObservedExceptionName;
+    private long mDurationMillis;
+    private long mResourceByteCount;
 
     // Public methods.
 
@@ -1166,11 +1185,15 @@
         if (mExtractorInput == null) {
             // TODO: For efficiency, the same implementation should be used, by providing a
             // clearBuffers() method, or similar.
+            long resourceLength = seekableInputReader.getLength();
+            if (mResourceByteCount == 0) {
+                // For resource byte count metric collection, we only take into account the length
+                // of the first provided input reader.
+                mResourceByteCount = resourceLength;
+            }
             mExtractorInput =
                     new DefaultExtractorInput(
-                            mExoDataReader,
-                            seekableInputReader.getPosition(),
-                            seekableInputReader.getLength());
+                            mExoDataReader, seekableInputReader.getPosition(), resourceLength);
         }
         mExoDataReader.mInputReader = seekableInputReader;
 
@@ -1195,7 +1218,10 @@
                     }
                 }
                 if (mExtractor == null) {
-                    throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
+                    UnrecognizedInputFormatException exception =
+                            UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
+                    mLastObservedExceptionName = exception.getClass().getName();
+                    throw exception;
                 }
                 return true;
             }
@@ -1223,8 +1249,13 @@
         int result;
         try {
             result = mExtractor.read(mExtractorInput, mPositionHolder);
-        } catch (ParserException e) {
-            throw new ParsingException(e);
+        } catch (Exception e) {
+            mLastObservedExceptionName = e.getClass().getName();
+            if (e instanceof ParserException) {
+                throw new ParsingException((ParserException) e);
+            } else {
+                throw e;
+            }
         }
         if (result == Extractor.RESULT_END_OF_INPUT) {
             mExtractorInput = null;
@@ -1264,21 +1295,64 @@
      * invoked.
      */
     public void release() {
-        // TODO: Dump media metrics here.
         mExtractorInput = null;
         mExtractor = null;
+        if (mReleased) {
+            // Nothing to do.
+            return;
+        }
+        mReleased = true;
+
+        String trackMimeTypes = buildMediaMetricsString(format -> format.sampleMimeType);
+        String trackCodecs = buildMediaMetricsString(format -> format.codecs);
+        int videoWidth = -1;
+        int videoHeight = -1;
+        for (int i = 0; i < mTrackFormats.size(); i++) {
+            Format format = mTrackFormats.valueAt(i);
+            if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) {
+                videoWidth = format.width;
+                videoHeight = format.height;
+                break;
+            }
+        }
+
+        String alteredParameters =
+                String.join(
+                        MEDIAMETRICS_ELEMENT_SEPARATOR,
+                        mParserParameters.keySet().toArray(new String[0]));
+        alteredParameters =
+                alteredParameters.substring(
+                        0,
+                        Math.min(
+                                alteredParameters.length(),
+                                MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH));
+
+        nativeSubmitMetrics(
+                mParserName,
+                mCreatedByName,
+                String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool),
+                mLastObservedExceptionName,
+                addDither(mResourceByteCount),
+                addDither(mDurationMillis),
+                trackMimeTypes,
+                trackCodecs,
+                alteredParameters,
+                videoWidth,
+                videoHeight);
     }
 
     // Private methods.
 
-    private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
+    private MediaParser(
+            OutputConsumer outputConsumer, boolean createdByName, String... parserNamesPool) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
             throw new UnsupportedOperationException("Android version must be R or greater.");
         }
         mParserParameters = new HashMap<>();
         mOutputConsumer = outputConsumer;
         mParserNamesPool = parserNamesPool;
-        mParserName = sniff ? PARSER_NAME_UNKNOWN : parserNamesPool[0];
+        mCreatedByName = createdByName;
+        mParserName = createdByName ? parserNamesPool[0] : PARSER_NAME_UNKNOWN;
         mPositionHolder = new PositionHolder();
         mExoDataReader = new InputReadingDataReader();
         removePendingSeek();
@@ -1286,6 +1360,24 @@
         mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
         mSchemeInitDataConstructor = getSchemeInitDataConstructor();
         mMuxedCaptionFormats = new ArrayList<>();
+
+        // MediaMetrics.
+        mTrackFormats = new SparseArray<>();
+        mLastObservedExceptionName = "";
+        mDurationMillis = -1;
+    }
+
+    private String buildMediaMetricsString(Function<Format, String> formatFieldGetter) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (int i = 0; i < mTrackFormats.size(); i++) {
+            if (i > 0) {
+                stringBuilder.append(MEDIAMETRICS_ELEMENT_SEPARATOR);
+            }
+            String fieldValue = formatFieldGetter.apply(mTrackFormats.valueAt(i));
+            stringBuilder.append(fieldValue != null ? fieldValue : "");
+        }
+        return stringBuilder.substring(
+                0, Math.min(stringBuilder.length(), MEDIAMETRICS_MAX_STRING_SIZE));
     }
 
     private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) {
@@ -1528,6 +1620,10 @@
 
         @Override
         public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
+            long durationUs = exoplayerSeekMap.getDurationUs();
+            if (durationUs != C.TIME_UNSET) {
+                mDurationMillis = C.usToMs(durationUs);
+            }
             if (mExposeChunkIndexAsMediaFormat && exoplayerSeekMap instanceof ChunkIndex) {
                 ChunkIndex chunkIndex = (ChunkIndex) exoplayerSeekMap;
                 MediaFormat mediaFormat = new MediaFormat();
@@ -1575,6 +1671,7 @@
 
         @Override
         public void format(Format format) {
+            mTrackFormats.put(mTrackIndex, format);
             mOutputConsumer.onTrackDataFound(
                     mTrackIndex,
                     new TrackData(
@@ -2031,6 +2128,20 @@
         return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position);
     }
 
+    /**
+     * Introduces random error to the given metric value in order to prevent the identification of
+     * the parsed media.
+     */
+    private static long addDither(long value) {
+        // Generate a random in [0, 1].
+        double randomDither = ThreadLocalRandom.current().nextFloat();
+        // Clamp the random number to [0, 2 * MEDIAMETRICS_DITHER].
+        randomDither *= 2 * MEDIAMETRICS_DITHER;
+        // Translate the random number to [1 - MEDIAMETRICS_DITHER, 1 + MEDIAMETRICS_DITHER].
+        randomDither += 1 - MEDIAMETRICS_DITHER;
+        return value != -1 ? (long) (value * randomDither) : -1;
+    }
+
     private static void assertValidNames(@NonNull String[] names) {
         for (String name : names) {
             if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) {
@@ -2070,9 +2181,26 @@
         }
     }
 
+    // Native methods.
+
+    private native void nativeSubmitMetrics(
+            String parserName,
+            boolean createdByName,
+            String parserPool,
+            String lastObservedExceptionName,
+            long resourceByteCount,
+            long durationMillis,
+            String trackMimeTypes,
+            String trackCodecs,
+            String alteredParameters,
+            int videoWidth,
+            int videoHeight);
+
     // Static initialization.
 
     static {
+        System.loadLibrary(JNI_LIBRARY_NAME);
+
         // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
         LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
         // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering,
@@ -2125,6 +2253,15 @@
         // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters
         // instead. Checking that the value is a List is insufficient to catch wrong parameter
         // value types.
+        int sumOfParameterNameLengths =
+                expectedTypeByParameterName.keySet().stream()
+                        .map(String::length)
+                        .reduce(0, Integer::sum);
+        sumOfParameterNameLengths += PARAMETER_EXPOSE_CAPTION_FORMATS.length();
+        // Add space for any required separators.
+        MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH =
+                sumOfParameterNameLengths + expectedTypeByParameterName.size();
+
         EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
     }
 }
diff --git a/apex/media/framework/jni/android_media_MediaParserJNI.cpp b/apex/media/framework/jni/android_media_MediaParserJNI.cpp
new file mode 100644
index 0000000..7fc4628
--- /dev/null
+++ b/apex/media/framework/jni/android_media_MediaParserJNI.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <media/MediaMetrics.h>
+
+#define JNI_FUNCTION(RETURN_TYPE, NAME, ...)                                               \
+    extern "C" {                                                                           \
+    JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \
+                                                                ##__VA_ARGS__);            \
+    }                                                                                      \
+    JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \
+                                                                ##__VA_ARGS__)
+
+namespace {
+
+constexpr char kMediaMetricsKey[] = "mediaparser";
+
+constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName";
+constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName";
+constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool";
+constexpr char kAttributeLastException[] = "android.media.mediaparser.lastException";
+constexpr char kAttributeResourceByteCount[] = "android.media.mediaparser.resourceByteCount";
+constexpr char kAttributeDurationMillis[] = "android.media.mediaparser.durationMillis";
+constexpr char kAttributeTrackMimeTypes[] = "android.media.mediaparser.trackMimeTypes";
+constexpr char kAttributeTrackCodecs[] = "android.media.mediaparser.trackCodecs";
+constexpr char kAttributeAlteredParameters[] = "android.media.mediaparser.alteredParameters";
+constexpr char kAttributeVideoWidth[] = "android.media.mediaparser.videoWidth";
+constexpr char kAttributeVideoHeight[] = "android.media.mediaparser.videoHeight";
+
+// Util class to handle string resource management.
+class JstringHandle {
+public:
+    JstringHandle(JNIEnv* env, jstring value) : mEnv(env), mJstringValue(value) {
+        mCstringValue = env->GetStringUTFChars(value, /* isCopy= */ nullptr);
+    }
+
+    ~JstringHandle() {
+        if (mCstringValue != nullptr) {
+            mEnv->ReleaseStringUTFChars(mJstringValue, mCstringValue);
+        }
+    }
+
+    [[nodiscard]] const char* value() const {
+        return mCstringValue != nullptr ? mCstringValue : "";
+    }
+
+    JNIEnv* mEnv;
+    jstring mJstringValue;
+    const char* mCstringValue;
+};
+
+} // namespace
+
+JNI_FUNCTION(void, nativeSubmitMetrics, jstring parserNameJstring, jboolean createdByName,
+             jstring parserPoolJstring, jstring lastExceptionJstring, jlong resourceByteCount,
+             jlong durationMillis, jstring trackMimeTypesJstring, jstring trackCodecsJstring,
+             jstring alteredParameters, jint videoWidth, jint videoHeight) {
+    mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey));
+    mediametrics_setCString(item, kAttributeParserName,
+                            JstringHandle(env, parserNameJstring).value());
+    mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0);
+    mediametrics_setCString(item, kAttributeParserPool,
+                            JstringHandle(env, parserPoolJstring).value());
+    mediametrics_setCString(item, kAttributeLastException,
+                            JstringHandle(env, lastExceptionJstring).value());
+    mediametrics_setInt64(item, kAttributeResourceByteCount, resourceByteCount);
+    mediametrics_setInt64(item, kAttributeDurationMillis, durationMillis);
+    mediametrics_setCString(item, kAttributeTrackMimeTypes,
+                            JstringHandle(env, trackMimeTypesJstring).value());
+    mediametrics_setCString(item, kAttributeTrackCodecs,
+                            JstringHandle(env, trackCodecsJstring).value());
+    mediametrics_setCString(item, kAttributeAlteredParameters,
+                            JstringHandle(env, alteredParameters).value());
+    mediametrics_setInt32(item, kAttributeVideoWidth, videoWidth);
+    mediametrics_setInt32(item, kAttributeVideoHeight, videoHeight);
+    mediametrics_selfRecord(item);
+    mediametrics_delete(item);
+}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 285eb4a..2222267 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -486,6 +486,8 @@
             303 [(module) = "network_tethering"];
         ImeTouchReported ime_touch_reported = 304 [(module) = "sysui"];
 
+        MediametricsMediaParserReported mediametrics_mediaparser_reported = 316;
+
         // StatsdStats tracks platform atoms with ids upto 500.
         // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
     }
@@ -4440,7 +4442,7 @@
         UNKNOWN = 0;
         CHIP_VIEWED = 1;
         CHIP_CLICKED = 2;
-        reserved 3; // Used only in beta builds, never shipped 
+        reserved 3; // Used only in beta builds, never shipped
         DIALOG_DISMISS = 4;
         DIALOG_LINE_ITEM = 5;
     }
@@ -7919,6 +7921,72 @@
 }
 
 /**
+ * Track MediaParser (parsing video/audio streams from containers) usage
+ * Logged from:
+ *
+ *   frameworks/av/services/mediametrics/statsd_mediaparser.cpp
+ *   frameworks/base/apex/media/framework/jni/android_media_MediaParserJNI.cpp
+ */
+message MediametricsMediaParserReported {
+    optional int64 timestamp_nanos = 1;
+    optional string package_name = 2;
+    optional int64 package_version_code = 3;
+
+    // MediaParser specific data.
+    /**
+     * The name of the parser selected for parsing the media, or an empty string
+     * if no parser was selected.
+     */
+    optional string parser_name = 4;
+    /**
+     * Whether the parser was created by name. 1 represents true, and 0
+     * represents false.
+     */
+    optional int32 created_by_name = 5;
+    /**
+     * The parser names in the sniffing pool separated by "|".
+     */
+    optional string parser_pool = 6;
+    /**
+     * The fully qualified name of the last encountered exception, or an empty
+     * string if no exception was encountered.
+     */
+    optional string last_exception = 7;
+    /**
+     * The size of the parsed media in bytes, or -1 if unknown. Note this value
+     * contains intentional random error to prevent media content
+     * identification.
+     */
+    optional int64 resource_byte_count = 8;
+    /**
+     * The duration of the media in milliseconds, or -1 if unknown. Note this
+     * value contains intentional random error to prevent media content
+     * identification.
+     */
+    optional int64 duration_millis = 9;
+    /**
+     * The MIME types of the tracks separated by "|".
+     */
+    optional string track_mime_types = 10;
+    /**
+     * The tracks' RFC 6381 codec strings separated by "|".
+     */
+    optional string track_codecs = 11;
+    /**
+     * Concatenation of the parameters altered by the client, separated by "|".
+     */
+    optional string altered_parameters = 12;
+    /**
+     * The video width in pixels, or -1 if unknown or not applicable.
+     */
+    optional int32 video_width = 13;
+    /**
+     * The video height in pixels, or -1 if unknown or not applicable.
+     */
+    optional int32 video_height = 14;
+}
+
+/**
  * Track how we arbitrate between microphone/input requests.
  * Logged from
  *   frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index af74b03..5dc6e60 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -16,16 +16,23 @@
 package android.accounts;
 
 import android.app.Activity;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.widget.TextView;
-import android.widget.LinearLayout;
-import android.view.View;
-import android.view.LayoutInflater;
+import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
 import com.android.internal.R;
 
 import java.io.IOException;
@@ -42,11 +49,15 @@
     private Account mAccount;
     private String mAuthTokenType;
     private int mUid;
+    private int mCallingUid;
     private Bundle mResultBundle = null;
     protected LayoutInflater mInflater;
 
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        getWindow().addSystemFlags(
+                android.view.WindowManager.LayoutParams
+                        .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         setContentView(R.layout.grant_credentials_permission);
         setTitle(R.string.grant_permissions_header_text);
 
@@ -74,6 +85,20 @@
             return;
         }
 
+        try {
+            IBinder activityToken = getActivityToken();
+            mCallingUid = ActivityTaskManager.getService().getLaunchedFromUid(activityToken);
+        } catch (RemoteException re) {
+            // Couldn't figure out caller details
+            Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
+        }
+
+        if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) && mCallingUid != mUid) {
+            setResult(Activity.RESULT_CANCELED);
+            finish();
+            return;
+        }
+
         String accountTypeLabel;
         try {
             accountTypeLabel = getAccountLabel(mAccount);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index eea5d62..fd0ba02 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -31,6 +31,7 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -52,6 +53,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LongSparseArray;
@@ -7619,8 +7621,9 @@
                     collectNotedOpForSelf(op, proxiedAttributionTag);
                 } else if (collectionMode == COLLECT_SYNC
                         // Only collect app-ops when the proxy is trusted
-                        && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
-                        myUid) == PackageManager.PERMISSION_GRANTED) {
+                        && (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
+                        myUid) == PackageManager.PERMISSION_GRANTED
+                        || isTrustedVoiceServiceProxy(mContext, mContext.getOpPackageName(), op))) {
                     collectNotedOpSync(op, proxiedAttributionTag);
                 }
             }
@@ -7632,6 +7635,38 @@
     }
 
     /**
+     * Checks if the voice recognition service is a trust proxy.
+     *
+     * @return {@code true} if the package is a trust voice recognition service proxy
+     * @hide
+     */
+    public static boolean isTrustedVoiceServiceProxy(Context context, String packageName,
+            int code) {
+        // This is a workaround for R QPR, new API change is not allowed. We only allow the current
+        // voice recognizer is also the voice interactor to noteproxy op.
+        if (code != OP_RECORD_AUDIO) {
+            return false;
+        }
+        final String voiceRecognitionComponent = Settings.Secure.getString(
+                context.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
+        final String voiceInteractionComponent = Settings.Secure.getString(
+                context.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
+
+        final String voiceRecognitionServicePackageName =
+                getComponentPackagenameFromString(voiceRecognitionComponent);
+        final String voiceInteractionServicePackageName =
+                getComponentPackagenameFromString(voiceInteractionComponent);
+
+        return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
+                voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
+    }
+
+    private static String getComponentPackagenameFromString(String from) {
+        ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
+        return componentName != null ? componentName.getPackageName() : "";
+    }
+
+    /**
      * Do a quick check for whether an application might be able to perform an operation.
      * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
      * String, String)} or {@link #startOp(int, int, String, boolean, String, String)} for your
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 1f57c7d..417cbc6b 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -46,6 +46,7 @@
 
     private final boolean mSingleDevice;
     private final List<DeviceFilter<?>> mDeviceFilters;
+    private String mCallingPackage;
 
     private AssociationRequest(
             boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters) {
@@ -57,6 +58,7 @@
         this(
             in.readByte() != 0,
             in.readParcelableList(new ArrayList<>(), AssociationRequest.class.getClassLoader()));
+        setCallingPackage(in.readString());
     }
 
     /** @hide */
@@ -72,32 +74,45 @@
         return mDeviceFilters;
     }
 
+    /** @hide */
+    public String getCallingPackage() {
+        return mCallingPackage;
+    }
+
+    /** @hide */
+    public void setCallingPackage(String pkg) {
+        mCallingPackage = pkg;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         AssociationRequest that = (AssociationRequest) o;
-        return mSingleDevice == that.mSingleDevice &&
-                Objects.equals(mDeviceFilters, that.mDeviceFilters);
+        return mSingleDevice == that.mSingleDevice
+                && Objects.equals(mDeviceFilters, that.mDeviceFilters)
+                && Objects.equals(mCallingPackage, that.mCallingPackage);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSingleDevice, mDeviceFilters);
+        return Objects.hash(mSingleDevice, mDeviceFilters, mCallingPackage);
     }
 
     @Override
     public String toString() {
-        return "AssociationRequest{" +
-                "mSingleDevice=" + mSingleDevice +
-                ", mDeviceFilters=" + mDeviceFilters +
-                '}';
+        return "AssociationRequest{"
+                + "mSingleDevice=" + mSingleDevice
+                + ", mDeviceFilters=" + mDeviceFilters
+                + ", mCallingPackage=" + mCallingPackage
+                + '}';
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByte((byte) (mSingleDevice ? 1 : 0));
         dest.writeParcelableList(mDeviceFilters, flags);
+        dest.writeString(mCallingPackage);
     }
 
     @Override
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8a7214d..1270362 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1689,6 +1689,15 @@
     public static final int DELETE_FAILED_USED_SHARED_LIBRARY = -6;
 
     /**
+     * Deletion failed return code: this is passed to the
+     * {@link IPackageDeleteObserver} if the system failed to delete the package
+     * because there is an app pinned.
+     *
+     * @hide
+     */
+    public static final int DELETE_FAILED_APP_PINNED = -7;
+
+    /**
      * Return code that is passed to the {@link IPackageMoveObserver} when the
      * package has been successfully moved by the system.
      *
@@ -7545,6 +7554,7 @@
             case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED";
             case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED";
             case DELETE_FAILED_USED_SHARED_LIBRARY: return "DELETE_FAILED_USED_SHARED_LIBRARY";
+            case DELETE_FAILED_APP_PINNED: return "DELETE_FAILED_APP_PINNED";
             default: return Integer.toString(status);
         }
     }
@@ -7559,6 +7569,7 @@
             case DELETE_FAILED_OWNER_BLOCKED: return PackageInstaller.STATUS_FAILURE_BLOCKED;
             case DELETE_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;
             case DELETE_FAILED_USED_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_CONFLICT;
+            case DELETE_FAILED_APP_PINNED: return PackageInstaller.STATUS_FAILURE_BLOCKED;
             default: return PackageInstaller.STATUS_FAILURE;
         }
     }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4f0c84e..1e78153 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -71,6 +71,7 @@
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowInsets.Side;
+import android.view.WindowInsets.Type;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.CompletionInfo;
@@ -104,7 +105,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
+import java.util.ArrayList;
 
 /**
  * InputMethodService provides a standard implementation of an InputMethod,
@@ -850,10 +851,19 @@
 
     /** Set region of the keyboard to be avoided from back gesture */
     private void setImeExclusionRect(int visibleTopInsets) {
-        View inputFrameRootView = mInputFrame.getRootView();
-        Rect r = new Rect(0, visibleTopInsets, inputFrameRootView.getWidth(),
-                inputFrameRootView.getHeight());
-        inputFrameRootView.setSystemGestureExclusionRects(Collections.singletonList(r));
+        View rootView = mInputFrame.getRootView();
+        android.graphics.Insets systemGesture =
+                rootView.getRootWindowInsets().getInsetsIgnoringVisibility(Type.systemGestures());
+        ArrayList<Rect> exclusionRects = new ArrayList<>();
+        exclusionRects.add(new Rect(0,
+                visibleTopInsets,
+                systemGesture.left,
+                rootView.getHeight()));
+        exclusionRects.add(new Rect(rootView.getWidth() - systemGesture.right,
+                visibleTopInsets,
+                rootView.getWidth(),
+                rootView.getHeight()));
+        rootView.setSystemGestureExclusionRects(exclusionRects);
     }
 
     /**
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 21fd819..ab5637c 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -16,7 +16,6 @@
 
 package android.os;
 
-import static android.system.OsConstants.AF_UNIX;
 import static android.system.OsConstants.SOCK_STREAM;
 
 import android.system.ErrnoException;
@@ -58,17 +57,19 @@
     /** CMD_CLOSE */
     private static final int CMD_CLOSE = 3;
 
-    private FileDescriptor mTarget;
+    private ParcelFileDescriptor mTarget;
 
-    private final FileDescriptor mServer = new FileDescriptor();
-    private final FileDescriptor mClient = new FileDescriptor();
+    private ParcelFileDescriptor mServer;
+    private ParcelFileDescriptor mClient;
 
     private volatile boolean mClosed;
 
     public FileBridge() {
         try {
-            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient);
-        } catch (ErrnoException e) {
+            ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(SOCK_STREAM);
+            mServer = fds[0];
+            mClient = fds[1];
+        } catch (IOException e) {
             throw new RuntimeException("Failed to create bridge");
         }
     }
@@ -80,15 +81,14 @@
     public void forceClose() {
         IoUtils.closeQuietly(mTarget);
         IoUtils.closeQuietly(mServer);
-        IoUtils.closeQuietly(mClient);
         mClosed = true;
     }
 
-    public void setTargetFile(FileDescriptor target) {
+    public void setTargetFile(ParcelFileDescriptor target) {
         mTarget = target;
     }
 
-    public FileDescriptor getClientSocket() {
+    public ParcelFileDescriptor getClientSocket() {
         return mClient;
     }
 
@@ -96,32 +96,33 @@
     public void run() {
         final byte[] temp = new byte[8192];
         try {
-            while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {
+            while (IoBridge.read(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH) == MSG_LENGTH) {
                 final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);
                 if (cmd == CMD_WRITE) {
                     // Shuttle data into local file
                     int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
                     while (len > 0) {
-                        int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len));
+                        int n = IoBridge.read(mServer.getFileDescriptor(), temp, 0,
+                                              Math.min(temp.length, len));
                         if (n == -1) {
                             throw new IOException(
                                     "Unexpected EOF; still expected " + len + " bytes");
                         }
-                        IoBridge.write(mTarget, temp, 0, n);
+                        IoBridge.write(mTarget.getFileDescriptor(), temp, 0, n);
                         len -= n;
                     }
 
                 } else if (cmd == CMD_FSYNC) {
                     // Sync and echo back to confirm
-                    Os.fsync(mTarget);
-                    IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+                    Os.fsync(mTarget.getFileDescriptor());
+                    IoBridge.write(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH);
 
                 } else if (cmd == CMD_CLOSE) {
                     // Close and echo back to confirm
-                    Os.fsync(mTarget);
-                    Os.close(mTarget);
+                    Os.fsync(mTarget.getFileDescriptor());
+                    mTarget.close();
                     mClosed = true;
-                    IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+                    IoBridge.write(mServer.getFileDescriptor(), temp, 0, MSG_LENGTH);
                     break;
                 }
             }
@@ -143,17 +144,11 @@
             mClient = clientPfd.getFileDescriptor();
         }
 
-        public FileBridgeOutputStream(FileDescriptor client) {
-            mClientPfd = null;
-            mClient = client;
-        }
-
         @Override
         public void close() throws IOException {
             try {
                 writeCommandAndBlock(CMD_CLOSE, "close()");
             } finally {
-                IoBridge.closeAndSignalBlockedThreads(mClient);
                 IoUtils.closeQuietly(mClientPfd);
             }
         }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 187fd59..f171441 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -94,6 +94,8 @@
     boolean isAmbientDisplaySuppressedForToken(String token);
     // returns whether ambient display is suppressed by any app with any token.
     boolean isAmbientDisplaySuppressed();
+    // returns whether ambient display is suppressed by the given app with the given token.
+    boolean isAmbientDisplaySuppressedForTokenByApp(String token, int appUid);
 
     // Forces the system to suspend even if there are held wakelocks.
     boolean forceSuspend();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index be2de0e..e3a0d18 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2127,6 +2127,27 @@
     }
 
     /**
+     * Returns true if ambient display is suppressed by the given {@code appUid} with the given
+     * {@code token}.
+     *
+     * <p>This method will return false if {@link #isAmbientDisplayAvailable()} is false.
+     *
+     * @param token The identifier of the ambient display suppression.
+     * @param appUid The uid of the app that suppressed ambient display.
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.READ_DREAM_STATE,
+            android.Manifest.permission.READ_DREAM_SUPPRESSION })
+    public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) {
+        try {
+            return mService.isAmbientDisplaySuppressedForTokenByApp(token, appUid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the reason the phone was last shutdown. Calling app must have the
      * {@link android.Manifest.permission#DEVICE_POWER} permission to request this information.
      * @return Reason for shutdown as an int, {@link #SHUTDOWN_REASON_UNKNOWN} if the file could
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index cc94d6f..4220c1d 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -321,7 +321,7 @@
                                     jboolean(focusEvent->getHasFocus()),
                                     jboolean(focusEvent->getInTouchMode()));
                 finishInputEvent(seq, true /* handled */);
-                return OK;
+                continue;
             }
 
             default:
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bb134f1..162fa70 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4295,6 +4295,10 @@
     <permission android:name="android.permission.WRITE_DREAM_STATE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows applications to read whether ambient display is suppressed. -->
+    <permission android:name="android.permission.READ_DREAM_SUPPRESSION"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allow an application to read and write the cache partition.
          @hide -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
diff --git a/core/tests/coretests/src/android/os/FileBridgeTest.java b/core/tests/coretests/src/android/os/FileBridgeTest.java
index d4f6b1f..708bfa6 100644
--- a/core/tests/coretests/src/android/os/FileBridgeTest.java
+++ b/core/tests/coretests/src/android/os/FileBridgeTest.java
@@ -16,6 +16,9 @@
 
 package android.os;
 
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+
 import android.os.FileBridge.FileBridgeOutputStream;
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
@@ -25,7 +28,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Random;
@@ -33,7 +35,7 @@
 public class FileBridgeTest extends AndroidTestCase {
 
     private File file;
-    private FileOutputStream fileOs;
+    private ParcelFileDescriptor outputFile;
     private FileBridge bridge;
     private FileBridgeOutputStream client;
 
@@ -44,17 +46,17 @@
         file = getContext().getFileStreamPath("meow.dat");
         file.delete();
 
-        fileOs = new FileOutputStream(file);
+        outputFile = ParcelFileDescriptor.open(file, MODE_CREATE | MODE_READ_WRITE);
 
         bridge = new FileBridge();
-        bridge.setTargetFile(fileOs.getFD());
+        bridge.setTargetFile(outputFile);
         bridge.start();
         client = new FileBridgeOutputStream(bridge.getClientSocket());
     }
 
     @Override
     protected void tearDown() throws Exception {
-        fileOs.close();
+        outputFile.close();
         file.delete();
     }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index a2dd9a8..5ed5d8f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -327,7 +327,7 @@
      * 1) Create Typeface from ttf file.
      * <pre>
      * <code>
-     * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
+     * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf");
      * Typeface typeface = builder.build();
      * </code>
      * </pre>
@@ -335,7 +335,7 @@
      * 2) Create Typeface from ttc file in assets directory.
      * <pre>
      * <code>
-     * Typeface.Builder buidler = new Typeface.Builder(getAssets(), "your_font_file.ttc");
+     * Typeface.Builder builder = new Typeface.Builder(getAssets(), "your_font_file.ttc");
      * builder.setTtcIndex(2);  // Set index of font collection.
      * Typeface typeface = builder.build();
      * </code>
@@ -344,7 +344,7 @@
      * 3) Create Typeface with variation settings.
      * <pre>
      * <code>
-     * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
+     * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf");
      * builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1");
      * builder.setWeight(700);  // Tell the system that this is a bold font.
      * builder.setItalic(true);  // Tell the system that this is an italic style font.
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index 16ef59f..e501e12 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -18,6 +18,8 @@
 
 import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress;
 
+import static java.util.Objects.requireNonNull;
+
 import android.app.Activity;
 import android.companion.CompanionDeviceManager;
 import android.content.Intent;
@@ -117,6 +119,11 @@
     }
 
     @Override
+    public String getCallingPackage() {
+        return requireNonNull(getService().mRequest.getCallingPackage());
+    }
+
+    @Override
     public void setTitle(CharSequence title) {
         final TextView titleView = findViewById(R.id.title);
         final int padding = getPadding(getResources());
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index 4f85eea..bbc33c3 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -339,6 +339,10 @@
             try {
                 session = getPackageManager().getPackageInstaller().openSession(mSessionId);
             } catch (IOException e) {
+                synchronized (this) {
+                    isDone = true;
+                    notifyAll();
+                }
                 return null;
             }
 
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 6fbee16..861a8ef 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -105,7 +105,8 @@
         }
 
         Intent nextActivity = new Intent(intent);
-        nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+        nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                | Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
         // The the installation source as the nextActivity thinks this activity is the source, hence
         // set the originating UID and sourceInfo explicitly
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
index be778e9..94829b5 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -17,6 +17,7 @@
 package com.android.packageinstaller;
 
 import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
 import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid;
 
@@ -87,6 +88,8 @@
 
     @Override
     public void onCreate(Bundle icicle) {
+        getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
         // Never restore any state, esp. never create any fragments. The data in the fragment might
         // be stale, if e.g. the app was uninstalled while the activity was destroyed.
         super.onCreate(null);
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index b280806..9e59ce3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -14,6 +14,9 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.location.LocationManager;
@@ -303,6 +306,36 @@
     }
 
     /**
+    * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but
+    * preserves the alpha for a given drawable
+    * @param color
+    * @return a color matrix that uses the source alpha and given color
+    */
+    public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) {
+        int r = Color.red(color);
+        int g = Color.green(color);
+        int b = Color.blue(color);
+
+        ColorMatrix cm = new ColorMatrix(new float[] {
+                0, 0, 0, 0, r,
+                0, 0, 0, 0, g,
+                0, 0, 0, 0, b,
+                0, 0, 0, 1, 0 });
+
+        return cm;
+    }
+
+    /**
+     * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics
+     *
+     * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on
+     * the source alpha
+     */
+    public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) {
+        return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color));
+    }
+
+    /**
      * Determine whether a package is a "system package", in which case certain things (like
      * disabling notifications or disabling the package altogether) should be disallowed.
      */
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
index a5b5312..5fa04f9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
@@ -108,6 +108,7 @@
 
     private val fillColorStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).also { p ->
         p.color = frameColor
+        p.alpha = 255
         p.isDither = true
         p.strokeWidth = 5f
         p.style = Paint.Style.STROKE
@@ -145,7 +146,7 @@
     // Only used if dualTone is set to true
     private val dualToneBackgroundFill = Paint(Paint.ANTI_ALIAS_FLAG).also { p ->
         p.color = frameColor
-        p.alpha = 255
+        p.alpha = 85 // ~0.3 alpha by default
         p.isDither = true
         p.strokeWidth = 0f
         p.style = Paint.Style.FILL_AND_STROKE
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 6e9df78..10e3f9d 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -33,10 +33,10 @@
     <string name="invalid_charger_title" msgid="938685362320735167">"No es pot carregar per USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Fes servir el carregador original del dispositiu"</string>
     <string name="battery_low_why" msgid="2056750982959359863">"Configuració"</string>
-    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar l\'estalvi de bateria?"</string>
+    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar la funció Estalvi de bateria?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre la funció Estalvi de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activa"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa l\'estalvi de bateria"</string>
+    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa la funció Estalvi de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"Configuració"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Gira pantalla automàticament"</string>
@@ -499,7 +499,7 @@
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Suprimeix"</string>
     <string name="battery_saver_notification_title" msgid="8419266546034372562">"S\'ha activat l\'estalvi de bateria"</string>
     <string name="battery_saver_notification_text" msgid="2617841636449016951">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
-    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva l\'estalvi de bateria"</string>
+    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva la funció Estalvi de bateria"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio que reprodueixis."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f71ad58..a298158 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -786,8 +786,8 @@
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"قبلی"</string>
     <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"عقب بردن"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"جلو بردن سریع"</string>
-    <string name="keyboard_key_page_up" msgid="173914303254199845">"صفحه بعدی"</string>
-    <string name="keyboard_key_page_down" msgid="9035902490071829731">"صفحه قبلی"</string>
+    <string name="keyboard_key_page_up" msgid="173914303254199845">"صفحه بعد"</string>
+    <string name="keyboard_key_page_down" msgid="9035902490071829731">"صفحه قبل"</string>
     <string name="keyboard_key_forward_del" msgid="5325501825762733459">"حذف"</string>
     <string name="keyboard_key_move_home" msgid="3496502501803911971">"ابتدا"</string>
     <string name="keyboard_key_move_end" msgid="99190401463834854">"انتها"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3d09b10..f3f19cb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -855,7 +855,7 @@
     <string name="right_icon" msgid="1103955040645237425">"Icône droite"</string>
     <string name="drag_to_add_tiles" msgid="8933270127508303672">"Sélectionnez et faites glisser les icônes pour les ajouter"</string>
     <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Sélectionnez et faites glisser les icônes pour réorganiser"</string>
-    <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les tuiles ici pour les supprimer."</string>
+    <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les icônes ici pour les supprimer."</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"Au minimum <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tuiles sont nécessaires"</string>
     <string name="qs_edit" msgid="5583565172803472437">"Modifier"</string>
     <string name="tuner_time" msgid="2450785840990529997">"Heure"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 0b25382..fcd24f2 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -553,7 +553,7 @@
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"તમે <xliff:g id="VPN_APP_0">%1$s</xliff:g> અને <xliff:g id="VPN_APP_1">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
     <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"તમારી વ્યક્તિગત પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
-    <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"તમારું ઉપકરણ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે."</string>
+    <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"તમારું ડિવાઇસ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા મેનેજ થાય છે."</string>
     <string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, તમારા ઉપકરણનું સંચાલન કરવા માટે <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> નો ઉપયોગ કરે છે."</string>
     <string name="monitoring_description_do_body" msgid="7700878065625769970">"વ્યવસ્થાપક સેટિંગ્સ, કૉર્પોરેટ ઍક્સેસ, ઍપ્સ, તમારા ઉપકરણ સંબંદ્ધ ડેટા અને ઉપકરણની સ્થાન માહિતીનું નિરીક્ષણ અને સંચાલન કરી શકે છે."</string>
     <string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
@@ -570,8 +570,8 @@
     <string name="monitoring_description_app" msgid="376868879287922929">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયા છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
     <string name="monitoring_description_app_personal" msgid="1970094872688265987">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
-    <string name="monitoring_description_app_work" msgid="3713084153786663662">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિત તમારા કાર્યાલયના નેટવર્કની પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
-    <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ કરેલું છે, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
+    <string name="monitoring_description_app_work" msgid="3713084153786663662">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા મેનેજ થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ, ઍપ અને વેબસાઇટ સહિત તમારા કાર્યાલયના નેટવર્કની પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
+    <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા મેનેજ થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ અને વેબસાઇટ સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ કરેલું છે, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent દ્વારા અનલૉક રાખેલું"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"તમે ઉપકરણને મેન્યુઅલી અનલૉક કરશો નહીં ત્યાં સુધી તે લૉક રહેશે"</string>
     <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5188962..4d64341 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Бичлэгийг эхлүүлэх үү?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, зурвас болон аудио багтана."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, мессеж болон аудио багтана."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио бичих"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Төхөөрөмжийн аудио"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Хөгжим, дуудлага болон хонхны ая зэрэг таны төхөөрөмжийн дуу"</string>
@@ -948,7 +948,7 @@
     <string name="notification_channel_alerts" msgid="3385787053375150046">"Сэрэмжлүүлэг"</string>
     <string name="notification_channel_battery" msgid="9219995638046695106">"Батарей"</string>
     <string name="notification_channel_screenshot" msgid="7665814998932211997">"Дэлгэцийн зураг дарах"</string>
-    <string name="notification_channel_general" msgid="4384774889645929705">"Энгийн зурвас"</string>
+    <string name="notification_channel_general" msgid="4384774889645929705">"Энгийн мессеж"</string>
     <string name="notification_channel_storage" msgid="2720725707628094977">"Хадгалах сан"</string>
     <string name="notification_channel_hints" msgid="7703783206000346876">"Заавар"</string>
     <string name="instant_apps" msgid="8337185853050247304">"Шуурхай апп"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 33e446e..5516b78 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -119,7 +119,7 @@
     <string name="installer_cd_button_title" msgid="5499998592841984743">"Macకు Android ఫైల్ బదిలీ యాప్ ఇన్‌స్టాల్ చేయండి"</string>
     <string name="accessibility_back" msgid="6530104400086152611">"వెనుకకు"</string>
     <string name="accessibility_home" msgid="5430449841237966217">"హోమ్"</string>
-    <string name="accessibility_menu" msgid="2701163794470513040">"మెను"</string>
+    <string name="accessibility_menu" msgid="2701163794470513040">"మెనూ"</string>
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"యాక్సెస్ సామర్థ్యం"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"స్క్రీన్‌ను తిప్పండి"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"ఓవర్‌వ్యూ"</string>
@@ -912,7 +912,7 @@
     <string name="pip_phone_close" msgid="8801864042095341824">"మూసివేయి"</string>
     <string name="pip_phone_settings" msgid="5687538631925004341">"సెట్టింగ్‌లు"</string>
     <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"తీసివేయడానికి కిందికి లాగండి"</string>
-    <string name="pip_menu_title" msgid="6365909306215631910">"మెను"</string>
+    <string name="pip_menu_title" msgid="6365909306215631910">"మెనూ"</string>
     <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> చిత్రంలో చిత్రం రూపంలో ఉంది"</string>
     <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> ఈ లక్షణాన్ని ఉపయోగించకూడదు అని మీరు అనుకుంటే, సెట్టింగ్‌లను తెరవడానికి ట్యాప్ చేసి, దీన్ని ఆఫ్ చేయండి."</string>
     <string name="pip_play" msgid="333995977693142810">"ప్లే చేయి"</string>
@@ -943,7 +943,7 @@
     <string name="tuner_minus" msgid="5258518368944598545">"తీసివేత చిహ్నం"</string>
     <string name="tuner_left" msgid="5758862558405684490">"ఎడమ"</string>
     <string name="tuner_right" msgid="8247571132790812149">"కుడి"</string>
-    <string name="tuner_menu" msgid="363690665924769420">"మెను"</string>
+    <string name="tuner_menu" msgid="363690665924769420">"మెనూ"</string>
     <string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> అనురవర్తనం"</string>
     <string name="notification_channel_alerts" msgid="3385787053375150046">"హెచ్చరికలు"</string>
     <string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index fba8942..59f5314 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -28,15 +28,15 @@
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
     <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
     <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pangtipid sa Baterya."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pantipid ng Baterya."</string>
     <string name="invalid_charger" msgid="4370074072117767416">"Hindi makapag-charge sa pamamagitan ng USB. Gamitin ang charger na kasama ng iyong device."</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Hindi makapag-charge sa pamamagitan ng USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gamitin ang charger na kasama ng iyong device"</string>
     <string name="battery_low_why" msgid="2056750982959359863">"Mga Setting"</string>
-    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pangtipid sa Baterya?"</string>
-    <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pangtipid sa Baterya"</string>
+    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pantipid ng Baterya?"</string>
+    <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pantipid ng Baterya"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"I-on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pangtipid sa Baterya"</string>
+    <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pantipid ng Baterya"</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"Mga Setting"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"I-auto rotate ang screen"</string>
@@ -419,7 +419,7 @@
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Mao-on sa ganap na <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Madilim na tema"</string>
-    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Pangtipid sa Baterya"</string>
+    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Pantipid ng Baterya"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Mao-on sa sunset"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -497,9 +497,9 @@
     <string name="user_remove_user_title" msgid="9124124694835811874">"Gusto mo bang alisin ang user?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Made-delete ang lahat ng app at data ng user na ito."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Alisin"</string>
-    <string name="battery_saver_notification_title" msgid="8419266546034372562">"Naka-on ang Pangtipid sa Baterya"</string>
+    <string name="battery_saver_notification_title" msgid="8419266546034372562">"Naka-on ang Pantipid ng Baterya"</string>
     <string name="battery_saver_notification_text" msgid="2617841636449016951">"Binabawasan ang performance at data sa background"</string>
-    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"I-off ang Pangtipid sa Baterya"</string>
+    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"I-off ang Pantipid ng Baterya"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Magkakaroon ng access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ang serbisyong nagbibigay ng function na ito ay magkakaroon ng access sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Magsimulang mag-record o mag-cast?"</string>
@@ -765,8 +765,8 @@
       <item quantity="other">%d na minuto</item>
     </plurals>
     <string name="battery_panel_title" msgid="5931157246673665963">"Paggamit ng baterya"</string>
-    <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
-    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Pangtipid sa Baterya"</string>
+    <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Hindi available ang Pantipid ng Baterya kapag nagcha-charge"</string>
+    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Pantipid ng Baterya"</string>
     <string name="battery_detail_switch_summary" msgid="3668748557848025990">"Binabawasan ang performance at data sa background"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -981,11 +981,11 @@
     <string name="slice_permission_checkbox" msgid="4242888137592298523">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na ipakita ang mga slice mula sa anumang app"</string>
     <string name="slice_permission_allow" msgid="6340449521277951123">"Payagan"</string>
     <string name="slice_permission_deny" msgid="6870256451658176895">"Tanggihan"</string>
-    <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pangtipid sa Baterya"</string>
+    <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pantipid ng Baterya"</string>
     <string name="auto_saver_text" msgid="3214960308353838764">"I-on kapag malamang na maubos ang baterya"</string>
     <string name="no_auto_saver_action" msgid="7467924389609773835">"Hindi, salamat na lang"</string>
-    <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Na-on ang iskedyul ng Pangtipid sa Baterya"</string>
-    <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Awtomatikong mao-on ang Pangtipid sa Baterya kapag mas mababa na sa <xliff:g id="PERCENTAGE">%d</xliff:g>%% ang baterya."</string>
+    <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Na-on ang iskedyul ng Pantipid ng Baterya"</string>
+    <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Awtomatikong mao-on ang Pantipid ng Baterya kapag mas mababa na sa <xliff:g id="PERCENTAGE">%d</xliff:g>%% ang baterya."</string>
     <string name="open_saver_setting_action" msgid="2111461909782935190">"Mga Setting"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
     <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index bb11efe..2be509a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -609,7 +609,8 @@
             // Move to resume key (aka package name) if that key doesn't already exist.
             val resumeAction = getResumeMediaAction(removed.resumeAction!!)
             val updated = removed.copy(token = null, actions = listOf(resumeAction),
-                    actionsToShowInCompact = listOf(0), active = false, resumption = true)
+                    actionsToShowInCompact = listOf(0), active = false, resumption = true,
+                    isClearable = true)
             val pkg = removed?.packageName
             val migrate = mediaEntries.put(pkg, updated) == null
             // Notify listeners of "new" controls when migrating or removed and update when not
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index bfb59f4..71d2c2c 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -221,6 +221,8 @@
         mSendTouchInteractionEndDelayed.cancel();
         // Clear the gesture detector
         mGestureDetector.clear();
+        // Clear the offset data by long pressing.
+        mDispatcher.clear();
         // Go to initial state.
         mState.clear();
         mAms.onTouchInteractionEnd();
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index d6759b3..bd8ce7b 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -300,6 +300,7 @@
             mFindDeviceCallback = callback;
             mRequest = request;
             mCallingPackage = callingPackage;
+            request.setCallingPackage(callingPackage);
             callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0);
 
             final long callingIdentity = Binder.clearCallingIdentity();
@@ -308,7 +309,7 @@
                     AndroidFuture<Association> future = new AndroidFuture<>();
                     service.startDiscovery(request, callingPackage, callback, future);
                     return future;
-                }).whenComplete(uncheckExceptions((association, err) -> {
+                }).cancelTimeout().whenComplete(uncheckExceptions((association, err) -> {
                     if (err == null) {
                         addAssociation(association);
                     } else {
@@ -372,7 +373,10 @@
 
             checkArgument(getCallingUserId() == userId,
                     "Must be called by either same user or system");
-            mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+            int callingUid = Binder.getCallingUid();
+            if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) {
+                throw new SecurityException(pkg + " doesn't belong to uid " + callingUid);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a2eea13..9a6f130 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -791,7 +791,10 @@
                 mService.updateOomAdjLocked(r.curApp, true,
                         OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
             }
+        } else if (filter.receiverList.app != null) {
+            mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
         }
+
         try {
             if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                     "Delivering to " + filter + " : " + r);
@@ -1121,6 +1124,10 @@
                         }
                     }
                     if (sendResult) {
+                        if (r.callerApp != null) {
+                            mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
+                                    r.callerApp);
+                        }
                         try {
                             if (DEBUG_BROADCAST) {
                                 Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 8112bb8..36d4a38 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -720,6 +720,16 @@
         }
     }
 
+    // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS
+    void unfreezeTemporarily(ProcessRecord app) {
+        synchronized (mAm) {
+            if (app.frozen) {
+                unfreezeAppLocked(app);
+                freezeAppAsync(app);
+            }
+        }
+    }
+
     @GuardedBy("mAm")
     void freezeAppAsync(ProcessRecord app) {
         mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
@@ -777,27 +787,27 @@
         long freezeTime = app.freezeUnfreezeTime;
 
         try {
+            freezeBinder(app.pid, false);
+        } catch (RuntimeException e) {
+            Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName
+                    + ". Killing it");
+            app.kill("Unable to unfreeze",
+                    ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+            return;
+        }
+
+        try {
             Process.setProcessFrozen(app.pid, app.uid, false);
 
             app.freezeUnfreezeTime = SystemClock.uptimeMillis();
             app.frozen = false;
         } catch (Exception e) {
             Slog.e(TAG_AM, "Unable to unfreeze " + app.pid + " " + app.processName
-                    + ". Any related user experience might be hanged.");
+                    + ". This might cause inconsistency or UI hangs.");
         }
 
         if (!app.frozen) {
-            try {
-                freezeBinder(app.pid, false);
-            } catch (RuntimeException e) {
-                Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName
-                        + ". Killing it");
-                app.kill("Unable to unfreeze",
-                        ApplicationExitInfo.REASON_OTHER,
-                        ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
-                return;
-            }
-
             if (DEBUG_FREEZER) {
                 Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
             }
@@ -1110,14 +1120,6 @@
                     return;
                 }
 
-                try {
-                    freezeBinder(pid, true);
-                } catch (RuntimeException e) {
-                    // TODO: it might be preferable to kill the target pid in this case
-                    Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
-                    return;
-                }
-
                 if (pid == 0 || proc.frozen) {
                     // Already frozen or not a real process, either one being
                     // launched or one being killed
@@ -1146,6 +1148,15 @@
 
                 EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
 
+                try {
+                    freezeBinder(pid, true);
+                } catch (RuntimeException e) {
+                    Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
+                    proc.kill("Unable to freeze binder interface",
+                            ApplicationExitInfo.REASON_OTHER,
+                            ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+                }
+
                 // See above for why we're not taking mPhenotypeFlagLock here
                 if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
                     FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6cecb6a..847be51 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2989,9 +2989,13 @@
             return AppOpsManager.MODE_IGNORED;
         }
 
+        // This is a workaround for R QPR, new API change is not allowed. We only allow the current
+        // voice recognizer is also the voice interactor to noteproxy op.
+        final boolean isTrustVoiceServiceProxy =
+                AppOpsManager.isTrustedVoiceServiceProxy(mContext, proxyPackageName, code);
         final boolean isProxyTrusted = mContext.checkPermission(
                 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
-                == PackageManager.PERMISSION_GRANTED;
+                == PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy;
 
         final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index bcfbcd1..47008a7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3275,9 +3275,6 @@
 
     boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
-        if (mCurClient == null || mCurClient.curSession == null) {
-            return false;
-        }
         if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mShowExplicitlyRequested || mShowForced)) {
             if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 5c9350a..3bb55a5 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -906,9 +906,26 @@
                 if (enabled == null) {
                     // this generally shouldn't occur, but might be possible due to race conditions
                     // on when we are notified of new users
+
+                    // hack to fix b/171910679. mutating the user enabled state within this method
+                    // may cause unexpected changes to other state (for instance, this could cause
+                    // provider enable/disable notifications to be sent to clients, which could
+                    // result in a dead client being detected, which could result in the client
+                    // being removed, which means that if this function is called while clients are
+                    // being iterated over we have now unexpectedly mutated the iterated
+                    // collection). instead, we return a correct value immediately here, and
+                    // schedule the actual update for later. this has been completely rewritten and
+                    // is no longer a problem in the next version of android.
+                    enabled = mProvider.getState().allowed
+                            && mUserInfoHelper.isCurrentUserId(userId)
+                            && mSettingsHelper.isLocationEnabled(userId);
+
                     Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
-                    onEnabledChangedLocked(userId);
-                    enabled = Objects.requireNonNull(mEnabled.get(userId));
+                    mHandler.post(() -> {
+                        synchronized (mLock) {
+                            onEnabledChangedLocked(userId);
+                        }
+                    });
                 }
 
                 return enabled;
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 7c1c1c7..72559b4 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -28,6 +28,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.Process;
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 
@@ -113,10 +114,11 @@
                         TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
         boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
                 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        final int appId = UserHandle.getAppId(callingUid);
         if (hasCarrierPrivileges || isDeviceOwner
-                || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) {
-            // Carrier-privileged apps and device owners, and the system can access data usage for
-            // all apps on the device.
+                || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
+            // Carrier-privileged apps and device owners, and the system (including the
+            // network stack) can access data usage for all apps on the device.
             return NetworkStatsAccess.Level.DEVICE;
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 330f995..56ef468 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -393,6 +393,8 @@
                             Slog.w(TAG, "Abandoning old session created at "
                                         + session.createdMillis);
                             valid = false;
+                        } else if (isExtraSessionForStagedInstall(session)) {
+                            valid = false;
                         } else {
                             valid = true;
                         }
@@ -423,6 +425,13 @@
         }
     }
 
+    // Extra sessions are created during staged install on temporary basis. They should not be
+    // allowed to live across system server restart.
+    private boolean isExtraSessionForStagedInstall(PackageInstallerSession session) {
+        return (session.params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0
+                || (session.params.installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0;
+    }
+
     @GuardedBy("mSessions")
     private void addHistoricalSessionLocked(PackageInstallerSession session) {
         CharArrayWriter writer = new CharArrayWriter();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ea53132..33193df 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -947,6 +947,23 @@
         }
     }
 
+    private ParcelFileDescriptor openTargetInternal(String path, int flags, int mode)
+            throws IOException, ErrnoException {
+        // TODO: this should delegate to DCS so the system process avoids
+        // holding open FDs into containers.
+        final FileDescriptor fd = Os.open(path, flags, mode);
+        return new ParcelFileDescriptor(fd);
+    }
+
+    private ParcelFileDescriptor createRevocableFdInternal(RevocableFileDescriptor fd,
+            ParcelFileDescriptor pfd) throws IOException {
+        int releasedFdInt = pfd.detachFd();
+        FileDescriptor releasedFd = new FileDescriptor();
+        releasedFd.setInt$(releasedFdInt);
+        fd.init(mContext, releasedFd);
+        return fd.getRevocableFileDescriptor();
+    }
+
     private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
             ParcelFileDescriptor incomingFd) throws IOException {
         // Quick sanity check of state, and allocate a pipe for ourselves. We
@@ -979,21 +996,20 @@
                 Binder.restoreCallingIdentity(identity);
             }
 
-            // TODO: this should delegate to DCS so the system process avoids
-            // holding open FDs into containers.
-            final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
+            ParcelFileDescriptor targetPfd = openTargetInternal(target.getAbsolutePath(),
                     O_CREAT | O_WRONLY, 0644);
             Os.chmod(target.getAbsolutePath(), 0644);
 
             // If caller specified a total length, allocate it for them. Free up
             // cache space to grow, if needed.
             if (stageDir != null && lengthBytes > 0) {
-                mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
+                mContext.getSystemService(StorageManager.class).allocateBytes(
+                        targetPfd.getFileDescriptor(), lengthBytes,
                         PackageHelper.translateAllocateFlags(params.installFlags));
             }
 
             if (offsetBytes > 0) {
-                Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
+                Os.lseek(targetPfd.getFileDescriptor(), offsetBytes, OsConstants.SEEK_SET);
             }
 
             if (incomingFd != null) {
@@ -1003,8 +1019,9 @@
                 // inserted above to hold the session active.
                 try {
                     final Int64Ref last = new Int64Ref(0);
-                    FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
-                            Runnable::run, (long progress) -> {
+                    FileUtils.copy(incomingFd.getFileDescriptor(), targetPfd.getFileDescriptor(),
+                            lengthBytes, null, Runnable::run,
+                            (long progress) -> {
                                 if (params.sizeBytes > 0) {
                                     final long delta = progress - last.value;
                                     last.value = progress;
@@ -1015,7 +1032,7 @@
                                 }
                             });
                 } finally {
-                    IoUtils.closeQuietly(targetFd);
+                    IoUtils.closeQuietly(targetPfd);
                     IoUtils.closeQuietly(incomingFd);
 
                     // We're done here, so remove the "bridge" that was holding
@@ -1031,12 +1048,11 @@
                 }
                 return null;
             } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
-                fd.init(mContext, targetFd);
-                return fd.getRevocableFileDescriptor();
+                return createRevocableFdInternal(fd, targetPfd);
             } else {
-                bridge.setTargetFile(targetFd);
+                bridge.setTargetFile(targetPfd);
                 bridge.start();
-                return new ParcelFileDescriptor(bridge.getClientSocket());
+                return bridge.getClientSocket();
             }
 
         } catch (ErrnoException e) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c20a912..0af4ff4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -330,6 +330,7 @@
 import com.android.internal.os.Zygote;
 import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
@@ -12441,12 +12442,17 @@
                 mPermissionManager.addAllPermissionGroups(pkg, chatty);
             }
 
+            // If a permission has had its defining app changed, or it has had its protection
+            // upgraded, we need to revoke apps that hold it
+            final List<String> permissionsWithChangedDefinition;
             // Don't allow ephemeral applications to define new permissions.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
+                permissionsWithChangedDefinition = null;
                 Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
                         + " ignored: instant apps cannot define new permissions.");
             } else {
-                mPermissionManager.addAllPermissions(pkg, chatty);
+                permissionsWithChangedDefinition =
+                        mPermissionManager.addAllPermissions(pkg, chatty);
             }
 
             int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
@@ -12475,7 +12481,10 @@
                 }
             }
 
-            if (oldPkg != null) {
+            boolean hasOldPkg = oldPkg != null;
+            boolean hasPermissionDefinitionChanges =
+                    !CollectionUtils.isEmpty(permissionsWithChangedDefinition);
+            if (hasOldPkg || hasPermissionDefinitionChanges) {
                 // We need to call revokeRuntimePermissionsIfGroupChanged async as permission
                 // revoke callbacks from this method might need to kill apps which need the
                 // mPackages lock on a different thread. This would dead lock.
@@ -12486,9 +12495,16 @@
                 // won't be granted yet, hence new packages are no problem.
                 final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
 
-                AsyncTask.execute(() ->
+                AsyncTask.execute(() -> {
+                    if (hasOldPkg) {
                         mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
-                                allPackageNames));
+                                allPackageNames);
+                    }
+                    if (hasPermissionDefinitionChanges) {
+                        mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                                permissionsWithChangedDefinition, allPackageNames);
+                    }
+                });
             }
         }
 
@@ -18162,6 +18178,19 @@
         final String packageName = versionedPackage.getPackageName();
         final long versionCode = versionedPackage.getLongVersionCode();
         final String internalPackageName;
+
+        try {
+            if (LocalServices.getService(ActivityTaskManagerInternal.class)
+                    .isBaseOfLockedTask(packageName)) {
+                observer.onPackageDeleted(
+                        packageName, PackageManager.DELETE_FAILED_APP_PINNED, null);
+                EventLog.writeEvent(0x534e4554, "127605586", -1, "");
+                return;
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+
         synchronized (mLock) {
             // Normalize package name to handle renamed packages and static libs
             internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 600357b..f779b6e 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -564,7 +564,8 @@
         }
     }
 
-    private void resumeSession(@NonNull PackageInstallerSession session) {
+    private void resumeSession(@NonNull PackageInstallerSession session)
+            throws PackageManagerException {
         Slog.d(TAG, "Resuming session " + session.sessionId);
 
         final boolean hasApex = sessionContainsApex(session);
@@ -628,10 +629,8 @@
             if (apexSessionInfo == null) {
                 final String errorMsg = "apexd did not know anything about a staged session "
                         + "supposed to be activated";
-                session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                        errorMsg);
-                abortCheckpoint(session.sessionId, errorMsg);
-                return;
+                throw new PackageManagerException(
+                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
             }
             if (isApexSessionFailed(apexSessionInfo)) {
                 String errorMsg = "APEX activation failed. Check logcat messages from apexd "
@@ -640,10 +639,8 @@
                     errorMsg = "Session reverted due to crashing native process: "
                             + mNativeFailureReason;
                 }
-                session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                        errorMsg);
-                abortCheckpoint(session.sessionId, errorMsg);
-                return;
+                throw new PackageManagerException(
+                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
             }
             if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
                 // Apexd did not apply the session for some unknown reason. There is no
@@ -651,42 +648,20 @@
                 // it as failed.
                 final String errorMsg = "Staged session " + session.sessionId + "at boot "
                         + "didn't activate nor fail. Marking it as failed anyway.";
-                session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                        errorMsg);
-                abortCheckpoint(session.sessionId, errorMsg);
-                return;
+                throw new PackageManagerException(
+                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
             }
         }
         // Handle apk and apk-in-apex installation
-        try {
-            if (hasApex) {
-                checkInstallationOfApkInApexSuccessful(session);
-                snapshotAndRestoreForApexSession(session);
-                Slog.i(TAG, "APEX packages in session " + session.sessionId
-                        + " were successfully activated. Proceeding with APK packages, if any");
-            }
-            // The APEX part of the session is activated, proceed with the installation of APKs.
-            Slog.d(TAG, "Installing APK packages in session " + session.sessionId);
-            installApksInSession(session);
-        } catch (PackageManagerException e) {
-            session.setStagedSessionFailed(e.error, e.getMessage());
-            abortCheckpoint(session.sessionId, e.getMessage());
-
-            // If checkpoint is not supported, we have to handle failure for one staged session.
-            if (!hasApex) {
-                return;
-            }
-
-            if (!mApexManager.revertActiveSessions()) {
-                Slog.e(TAG, "Failed to abort APEXd session");
-            } else {
-                Slog.e(TAG,
-                        "Successfully aborted apexd session. Rebooting device in order to revert "
-                                + "to the previous state of APEXd.");
-                mPowerManager.reboot(null);
-            }
-            return;
+        if (hasApex) {
+            checkInstallationOfApkInApexSuccessful(session);
+            snapshotAndRestoreForApexSession(session);
+            Slog.i(TAG, "APEX packages in session " + session.sessionId
+                    + " were successfully activated. Proceeding with APK packages, if any");
         }
+        // The APEX part of the session is activated, proceed with the installation of APKs.
+        Slog.d(TAG, "Installing APK packages in session " + session.sessionId);
+        installApksInSession(session);
 
         Slog.d(TAG, "Marking session " + session.sessionId + " as applied");
         session.setStagedSessionApplied();
@@ -722,6 +697,25 @@
         return ret;
     }
 
+    void onInstallationFailure(PackageInstallerSession session, PackageManagerException e) {
+        session.setStagedSessionFailed(e.error, e.getMessage());
+        abortCheckpoint(session.sessionId, e.getMessage());
+
+        // If checkpoint is not supported, we have to handle failure for one staged session.
+        if (!sessionContainsApex(session)) {
+            return;
+        }
+
+        if (!mApexManager.revertActiveSessions()) {
+            Slog.e(TAG, "Failed to abort APEXd session");
+        } else {
+            Slog.e(TAG,
+                    "Successfully aborted apexd session. Rebooting device in order to revert "
+                            + "to the previous state of APEXd.");
+            mPowerManager.reboot(null);
+        }
+    }
+
     @NonNull
     private PackageInstallerSession createAndWriteApkSession(
             @NonNull PackageInstallerSession originalSession, boolean preReboot)
@@ -1072,6 +1066,26 @@
         return true;
     }
 
+    /**
+     * Ensure that there is no active apex session staged in apexd for the given session.
+     *
+     * @return returns true if it is ensured that there is no active apex session, otherwise false
+     */
+    private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) {
+        if (!sessionContainsApex(session)) {
+            return true;
+        }
+        final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
+        if (apexSession == null || isApexSessionFinalized(apexSession)) {
+            return true;
+        }
+        try {
+            return mApexManager.abortStagedSession(session.sessionId);
+        } catch (PackageManagerException ignore) {
+            return false;
+        }
+    }
+
     private boolean isApexSessionFinalized(ApexSessionInfo session) {
         /* checking if the session is in a final state, i.e., not active anymore */
         return session.isUnknown || session.isActivationFailed || session.isSuccess
@@ -1165,7 +1179,16 @@
         } else {
             // Session had already being marked ready. Start the checks to verify if there is any
             // follow-up work.
-            resumeSession(session);
+            try {
+                resumeSession(session);
+            } catch (PackageManagerException e) {
+                onInstallationFailure(session, e);
+            } catch (Exception e) {
+                Slog.e(TAG, "Staged install failed due to unhandled exception", e);
+                onInstallationFailure(session, new PackageManagerException(
+                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                        "Staged install failed due to unhandled exception: " + e));
+            }
         }
     }
 
@@ -1303,19 +1326,26 @@
                 onPreRebootVerificationComplete(sessionId);
                 return;
             }
-            switch (msg.what) {
-                case MSG_PRE_REBOOT_VERIFICATION_START:
-                    handlePreRebootVerification_Start(session);
-                    break;
-                case MSG_PRE_REBOOT_VERIFICATION_APEX:
-                    handlePreRebootVerification_Apex(session);
-                    break;
-                case MSG_PRE_REBOOT_VERIFICATION_APK:
-                    handlePreRebootVerification_Apk(session);
-                    break;
-                case MSG_PRE_REBOOT_VERIFICATION_END:
-                    handlePreRebootVerification_End(session);
-                    break;
+            try {
+                switch (msg.what) {
+                    case MSG_PRE_REBOOT_VERIFICATION_START:
+                        handlePreRebootVerification_Start(session);
+                        break;
+                    case MSG_PRE_REBOOT_VERIFICATION_APEX:
+                        handlePreRebootVerification_Apex(session);
+                        break;
+                    case MSG_PRE_REBOOT_VERIFICATION_APK:
+                        handlePreRebootVerification_Apk(session);
+                        break;
+                    case MSG_PRE_REBOOT_VERIFICATION_END:
+                        handlePreRebootVerification_End(session);
+                        break;
+                }
+            } catch (Exception e) {
+                Slog.e(TAG, "Pre-reboot verification failed due to unhandled exception", e);
+                onPreRebootVerificationFailure(session,
+                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                        "Pre-reboot verification failed due to unhandled exception: " + e);
             }
         }
 
@@ -1352,6 +1382,17 @@
             obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
         }
 
+        private void onPreRebootVerificationFailure(PackageInstallerSession session,
+                @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) {
+            if (!ensureActiveApexSessionIsAborted(session)) {
+                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+                // Safe to ignore active apex session abortion failure since session will be marked
+                // failed on next step and staging directory for session will be deleted.
+            }
+            session.setStagedSessionFailed(errorCode, errorMessage);
+            onPreRebootVerificationComplete(session.sessionId);
+        }
+
         // Things to do when pre-reboot verification completes for a particular sessionId
         private void onPreRebootVerificationComplete(int sessionId) {
             // Remove it from mVerificationRunning so that verification is considered complete
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 8000c63..3a74f30 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -727,10 +727,14 @@
                                        "compiled_trace.pb");
             try {
                 boolean exists =  Files.exists(tracePath);
-                Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist"));
+                if (DEBUG) {
+                    Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist"));
+                }
                 if (exists) {
                     long bytes = Files.size(tracePath);
-                    Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes));
+                    if (DEBUG) {
+                        Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes));
+                    }
                     return bytes > 0L;
                 }
                 return exists;
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index cfa0449..5e04171 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -83,6 +83,8 @@
 
     final @PermissionType int type;
 
+    private boolean mPermissionDefinitionChanged;
+
     String sourcePackageName;
 
     int protectionLevel;
@@ -126,6 +128,11 @@
     public String getSourcePackageName() {
         return sourcePackageName;
     }
+
+    public boolean isPermissionDefinitionChanged() {
+        return mPermissionDefinitionChanged;
+    }
+
     public int getType() {
         return type;
     }
@@ -140,6 +147,10 @@
         this.perm = perm;
     }
 
+    public void setPermissionDefinitionChanged(boolean shouldOverride) {
+        mPermissionDefinitionChanged = shouldOverride;
+    }
+
     public int[] computeGids(int userId) {
         if (perUser) {
             final int[] userGids = new int[gids.length];
@@ -322,6 +333,7 @@
         final PackageSettingBase pkgSetting =
                 (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName());
         // Allow system apps to redefine non-system permissions
+        boolean ownerChanged = false;
         if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) {
             final boolean currentOwnerIsSystem;
             if (bp.perm == null) {
@@ -347,6 +359,7 @@
                     String msg = "New decl " + pkg + " of permission  "
                             + p.getName() + " is system; overriding " + bp.sourcePackageName;
                     PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    ownerChanged = true;
                     bp = null;
                 }
             }
@@ -354,6 +367,7 @@
         if (bp == null) {
             bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL);
         }
+        boolean wasNonRuntime = !bp.isRuntime();
         StringBuilder r = null;
         if (bp.perm == null) {
             if (bp.sourcePackageName == null
@@ -397,6 +411,11 @@
                 && Objects.equals(bp.perm.getName(), p.getName())) {
             bp.protectionLevel = p.getProtectionLevel();
         }
+        if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) {
+            // If this is a runtime permission and the owner has changed, or this was a normal
+            // permission, then permission state should be cleaned up
+            bp.mPermissionDefinitionChanged = true;
+        }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
             Log.d(TAG, "  Permissions: " + r);
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 66d8b59..3ffca02 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2344,8 +2344,74 @@
         }
     }
 
-    private void addAllPermissions(AndroidPackage pkg, boolean chatty) {
+    /**
+     * If permissions are upgraded to runtime, or their owner changes to the system, then any
+     * granted permissions must be revoked.
+     *
+     * @param permissionsToRevoke A list of permission names to revoke
+     * @param allPackageNames All package names
+     * @param permissionCallback Callback for permission changed
+     */
+    private void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+            @NonNull List<String> permissionsToRevoke,
+            @NonNull ArrayList<String> allPackageNames,
+            @NonNull PermissionCallback permissionCallback) {
+
+        final int[] userIds = mUserManagerInt.getUserIds();
+        final int numPermissions = permissionsToRevoke.size();
+        final int numUserIds = userIds.length;
+        final int numPackages = allPackageNames.size();
+        final int callingUid = Binder.getCallingUid();
+
+        for (int permNum = 0; permNum < numPermissions; permNum++) {
+            String permName = permissionsToRevoke.get(permNum);
+            BasePermission bp = mSettings.getPermission(permName);
+            if (bp == null || !bp.isRuntime()) {
+                continue;
+            }
+            for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
+                final int userId = userIds[userIdNum];
+                for (int packageNum = 0; packageNum < numPackages; packageNum++) {
+                    final String packageName = allPackageNames.get(packageNum);
+                    final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
+                    if (uid < Process.FIRST_APPLICATION_UID) {
+                        // do not revoke from system apps
+                        continue;
+                    }
+                    final int permissionState = checkPermissionImpl(permName, packageName,
+                            userId);
+                    final int flags = getPermissionFlags(permName, packageName, userId);
+                    final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
+                            | FLAG_PERMISSION_POLICY_FIXED
+                            | FLAG_PERMISSION_GRANTED_BY_DEFAULT
+                            | FLAG_PERMISSION_GRANTED_BY_ROLE;
+                    if (permissionState == PackageManager.PERMISSION_GRANTED
+                            && (flags & flagMask) == 0) {
+                        EventLog.writeEvent(0x534e4554, "154505240", uid,
+                                "Revoking permission " + permName + " from package "
+                                        + packageName + " due to definition change");
+                        EventLog.writeEvent(0x534e4554, "168319670", uid,
+                                "Revoking permission " + permName + " from package "
+                                        + packageName + " due to definition change");
+                        Slog.e(TAG, "Revoking permission " + permName + " from package "
+                                + packageName + " due to definition change");
+                        try {
+                            revokeRuntimePermissionInternal(permName, packageName,
+                                    false, callingUid, userId, null, permissionCallback);
+                        } catch (Exception e) {
+                            Slog.e(TAG, "Could not revoke " + permName + " from "
+                                    + packageName, e);
+                        }
+                    }
+                }
+            }
+            bp.setPermissionDefinitionChanged(false);
+        }
+    }
+
+    private List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) {
         final int N = ArrayUtils.size(pkg.getPermissions());
+        ArrayList<String> definitionChangedPermissions = new ArrayList<>();
         for (int i=0; i<N; i++) {
             ParsedPermission p = pkg.getPermissions().get(i);
 
@@ -2367,21 +2433,26 @@
                     }
                 }
 
+                final BasePermission bp;
                 if (p.isTree()) {
-                    final BasePermission bp = BasePermission.createOrUpdate(
+                    bp = BasePermission.createOrUpdate(
                             mPackageManagerInt,
                             mSettings.getPermissionTreeLocked(p.getName()), p, pkg,
                             mSettings.getAllPermissionTreesLocked(), chatty);
                     mSettings.putPermissionTreeLocked(p.getName(), bp);
                 } else {
-                    final BasePermission bp = BasePermission.createOrUpdate(
+                    bp = BasePermission.createOrUpdate(
                             mPackageManagerInt,
                             mSettings.getPermissionLocked(p.getName()),
                             p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
                     mSettings.putPermissionLocked(p.getName(), bp);
                 }
+                if (bp.isPermissionDefinitionChanged()) {
+                    definitionChangedPermissions.add(p.getName());
+                }
             }
         }
+        return definitionChangedPermissions;
     }
 
     private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
@@ -4672,9 +4743,18 @@
             PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
                     oldPackage, allPackageNames, mDefaultPermissionCallback);
         }
+
         @Override
-        public void addAllPermissions(AndroidPackage pkg, boolean chatty) {
-            PermissionManagerService.this.addAllPermissions(pkg, chatty);
+        public void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                @NonNull List<String> permissionsToRevoke,
+                @NonNull ArrayList<String> allPackageNames) {
+            PermissionManagerService.this.revokeRuntimePermissionsIfPermissionDefinitionChanged(
+                    permissionsToRevoke, allPackageNames, mDefaultPermissionCallback);
+        }
+
+        @Override
+        public List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) {
+            return PermissionManagerService.this.addAllPermissions(pkg, chatty);
         }
         @Override
         public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 2e83b23..31a65ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -254,12 +254,26 @@
             @NonNull ArrayList<String> allPackageNames);
 
     /**
+     * Some permissions might have been owned by a non-system package, and the system then defined
+     * said permission. Some other permissions may one have been install permissions, but are now
+     * runtime or higher. These permissions should be revoked.
+     *
+     * @param permissionsToRevoke A list of permission names to revoke
+     * @param allPackageNames All packages
+     */
+    public abstract void revokeRuntimePermissionsIfPermissionDefinitionChanged(
+            @NonNull List<String> permissionsToRevoke,
+            @NonNull ArrayList<String> allPackageNames);
+
+    /**
      * Add all permissions in the given package.
      * <p>
      * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
      * the permission settings.
+     *
+     * @return A list of BasePermissions that were updated, and need to be revoked from packages
      */
-    public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
+    public abstract List<String> addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
     public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty);
     public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3c42e93..c15cbb4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1466,10 +1466,17 @@
                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
         if (mHasFeatureLeanback) {
             isSetupComplete &= isTvUserSetupComplete();
+        } else if (mHasFeatureAuto) {
+            isSetupComplete &= isAutoUserSetupComplete();
         }
         return isSetupComplete;
     }
 
+    private boolean isAutoUserSetupComplete() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                "android.car.SETUP_WIZARD_IN_PROGRESS", 0, UserHandle.USER_CURRENT) == 0;
+    }
+
     private boolean isTvUserSetupComplete() {
         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
@@ -2410,6 +2417,15 @@
             wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
             view = win.getDecorView();
 
+            // Ignore to show splash screen if the decorView is not opaque.
+            if (!view.isOpaque()) {
+                if (DEBUG_SPLASH_SCREEN) {
+                    Slog.d(TAG, "addSplashScreen: the view of " + packageName
+                            + " is not opaque, cancel it");
+                }
+                return null;
+            }
+
             if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
                 + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));
 
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f965e58..dee604a 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5305,6 +5305,22 @@
         }
 
         @Override // Binder call
+        public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_DREAM_STATE, null);
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_DREAM_SUPPRESSION, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return isAmbientDisplayAvailable()
+                        && mAmbientDisplaySuppressionController.isSuppressed(token, appUid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
         public boolean isAmbientDisplaySuppressed() {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_DREAM_STATE, null);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 8f3ed74..3b73c1e 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -249,6 +249,13 @@
     // 20% as a conservative estimate.
     private static final int MAX_PROCSTATS_RAW_SHARD_SIZE = (int) (MAX_PROCSTATS_SHARD_SIZE * 1.20);
 
+    /**
+     * Threshold to filter out small CPU times at frequency per UID. Those small values appear
+     * because of more precise accounting in a BPF program. Discarding them reduces the data by at
+     * least 20% with negligible error.
+     */
+    private static final int MIN_CPU_TIME_PER_UID_FREQ = 10;
+
     private final Object mThermalLock = new Object();
     @GuardedBy("mThermalLock")
     private IThermalService mThermalService;
@@ -1556,7 +1563,7 @@
     int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) {
         mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
             for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
-                if (cpuFreqTimeMs[freqIndex] != 0) {
+                if (cpuFreqTimeMs[freqIndex] >= MIN_CPU_TIME_PER_UID_FREQ) {
                     StatsEvent e = StatsEvent.newBuilder()
                             .setAtomId(atomTag)
                             .writeInt(uid)
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index d4dd35f5..eb749f6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -568,4 +568,10 @@
 
     /** Set all associated companion app that belongs to an userId. */
     public abstract void setCompanionAppPackages(int userId, Set<String> companionAppPackages);
+
+    /**
+     * @param packageName The package to check
+     * @return Whether the package is the base of any locked task
+     */
+    public abstract boolean isBaseOfLockedTask(String packageName);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0542ef9..8dbd661 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7473,5 +7473,13 @@
                 mCompanionAppUidsMap.put(userId, result);
             }
         }
+
+
+        @Override
+        public boolean isBaseOfLockedTask(String packageName) {
+            synchronized (mGlobalLock) {
+                return getLockTaskController().isBaseOfLockedTask(packageName);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c36dede..c4a42ab 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -871,6 +871,21 @@
     }
 
     /**
+     * @param packageName The package to check
+     * @return Whether the package is the base of any locked task
+     */
+    boolean isBaseOfLockedTask(String packageName) {
+        for (int i = 0; i < mLockTaskModeTasks.size(); i++) {
+            final Intent bi = mLockTaskModeTasks.get(i).getBaseIntent();
+            if (bi != null && packageName.equals(bi.getComponent()
+                    .getPackageName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Gets the cached value of LockTask feature flags for a specific user.
      */
     private int getLockTaskFeaturesForUser(int userId) {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 6db3233..36cfcc6 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -77,6 +77,7 @@
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
     <uses-permission android:name="android.permission.DUMP"/>
     <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
+    <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION"/>
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index c18cad4..13587bc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility.gestures;
 
+import static android.view.ViewConfiguration.getDoubleTapTimeout;
+
 import static com.android.server.accessibility.gestures.TouchState.STATE_CLEAR;
 import static com.android.server.accessibility.gestures.TouchState.STATE_DELEGATING;
 import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING;
@@ -23,6 +25,7 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
@@ -53,6 +56,8 @@
 public class TouchExplorerTest {
 
     private static final String LOG_TAG = "TouchExplorerTest";
+    // The constant of mDetermineUserIntentTimeout.
+    private static final int USER_INTENT_TIMEOUT = getDoubleTapTimeout();
     private static final int FLAG_1FINGER = 0x8000;
     private static final int FLAG_2FINGERS = 0x0100;
     private static final int FLAG_3FINGERS = 0x0200;
@@ -94,7 +99,9 @@
         public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
             mEvents.add(0, event.copy());
             // LastEvent may not match if we're clearing the state
-            if (mLastEvent != null) {
+            // The last event becomes ACTION_UP event when sending the ACTION_CANCEL event,
+            // so ignoring the ACTION_CANCEL event checking.
+            if (mLastEvent != null && rawEvent.getActionMasked() != MotionEvent.ACTION_CANCEL) {
                 MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent);
                 assertThat(rawEvent, lastEventMatcher);
             }
@@ -121,6 +128,43 @@
         mTouchExplorer.setNext(mCaptor);
     }
 
+    /**
+     * Test the case where the event location is correct when clicking after the following
+     * situation happened: entering the delegate state through doubleTapAndHold gesture and
+     * receiving a cancel event to return the clear state.
+     */
+    @Test
+    public void testClick_afterCanceledDoubleTapAndHold_eventLocationIsCorrect()
+            throws InterruptedException {
+        // Generates the click position by this click operation, otherwise the offset used
+        // while delegating could not be set.
+        send(downEvent(DEFAULT_X + 10, DEFAULT_Y + 10));
+        // Waits for transition to touch exploring state.
+        Thread.sleep(2 * USER_INTENT_TIMEOUT);
+        send(upEvent());
+
+        // Simulates detecting the doubleTapAndHold gesture and enters the delegate state.
+        final MotionEvent sendEvent =
+                fromTouchscreen(downEvent(DEFAULT_X + 100, DEFAULT_Y + 100));
+        mTouchExplorer.onDoubleTapAndHold(sendEvent, sendEvent, 0);
+        assertState(STATE_DELEGATING);
+
+        send(cancelEvent());
+
+        // Generates the click operation, and checks the event location of the ACTION_HOVER_ENTER
+        // event is correct.
+        send(downEvent());
+        // Waits for transition to touch exploring state.
+        Thread.sleep(2 * USER_INTENT_TIMEOUT);
+        send(upEvent());
+
+        final List<MotionEvent> events = getCapturedEvents();
+        assertTrue(events.stream().anyMatch(
+                motionEvent -> motionEvent.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
+                        && motionEvent.getX() == DEFAULT_X
+                        && motionEvent.getY() == DEFAULT_Y));
+    }
+
     @Test
     public void testTwoFingersMove_shouldDelegatingAndInjectActionDownPointerDown() {
         goFromStateClearTo(STATE_MOVING_2FINGERS);
@@ -294,6 +338,19 @@
         return ((EventCaptor) mCaptor).mEvents;
     }
 
+    private MotionEvent cancelEvent() {
+        mLastDownTime = SystemClock.uptimeMillis();
+        return fromTouchscreen(
+                MotionEvent.obtain(mLastDownTime, mLastDownTime, MotionEvent.ACTION_CANCEL,
+                        DEFAULT_X, DEFAULT_Y, 0));
+    }
+
+    private MotionEvent downEvent(float x, float y) {
+        mLastDownTime = SystemClock.uptimeMillis();
+        return fromTouchscreen(
+                MotionEvent.obtain(mLastDownTime, mLastDownTime, MotionEvent.ACTION_DOWN, x, y, 0));
+    }
+
     private MotionEvent downEvent() {
         mLastDownTime = SystemClock.uptimeMillis();
         return fromTouchscreen(
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index d244e68..d7897db 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -77,6 +77,7 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.PowerManagerService.BatteryReceiver;
+import com.android.server.power.PowerManagerService.BinderService;
 import com.android.server.power.PowerManagerService.Injector;
 import com.android.server.power.PowerManagerService.NativeWrapper;
 import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
@@ -173,6 +174,7 @@
         when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
         when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
         when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+        when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
 
         mDisplayPowerRequest = new DisplayPowerRequest();
         addLocalServiceMock(LightsManager.class, mLightsManagerMock);
@@ -967,4 +969,72 @@
         assertThat(mService.getBinderServiceInstance().isAmbientDisplaySuppressedForToken("test2"))
             .isFalse();
     }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_ambientDisplayUnavailable()
+            throws Exception {
+        createService();
+        when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(false);
+
+        BinderService service = mService.getBinderServiceInstance();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_default()
+            throws Exception {
+        createService();
+
+        BinderService service = mService.getBinderServiceInstance();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_suppressedByCallingApp()
+            throws Exception {
+        createService();
+        BinderService service = mService.getBinderServiceInstance();
+        service.suppressAmbientDisplay("test", true);
+
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isTrue();
+        // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_notSuppressedByCallingApp()
+            throws Exception {
+        createService();
+        BinderService service = mService.getBinderServiceInstance();
+        service.suppressAmbientDisplay("test", false);
+
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+            .isFalse();
+        // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+            .isFalse();
+    }
+
+    @Test
+    public void testIsAmbientDisplaySuppressedForTokenByApp_multipleTokensSuppressedByCallingApp()
+            throws Exception {
+        createService();
+        BinderService service = mService.getBinderServiceInstance();
+        service.suppressAmbientDisplay("test1", true);
+        service.suppressAmbientDisplay("test2", true);
+
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", Binder.getCallingUid()))
+            .isTrue();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", Binder.getCallingUid()))
+            .isTrue();
+        // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", /* appUid= */ 123))
+            .isFalse();
+        assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", /* appUid= */ 123))
+            .isFalse();
+    }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index f2f1412..7bd5bdf 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -372,6 +372,14 @@
             "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
 
     /**
+     * A string value for {@link #EXTRA_CALL_DISCONNECT_MESSAGE}, indicates the call was dropped by
+     * lower layers
+     * @hide
+     */
+    public static final String CALL_AUTO_DISCONNECT_MESSAGE_STRING =
+            "Call dropped by lower layers";
+
+    /**
      * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED}
      * containing the component name of the associated connection service.
      * @hide