Merge "AudioService: manage hearing aid volume for calls" into qt-dev
diff --git a/Android.mk b/Android.mk
index c58f7af..9bda2dc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,27 +32,6 @@
 # ============================================================
 include $(CLEAR_VARS)
 
-aidl_parcelables :=
-define stubs-to-aidl-parcelables
-  gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/$1.aidl
-  aidl_parcelables += $$(gen)
-  $$(gen): $(call java-lib-header-files,$1) $(HOST_OUT_EXECUTABLES)/sdkparcelables
-	@echo Extract SDK parcelables: $$@
-	rm -f $$@
-	$(HOST_OUT_EXECUTABLES)/sdkparcelables $$< $$@
-endef
-
-$(foreach stubs,android_stubs_current android_test_stubs_current android_system_stubs_current,\
-  $(eval $(call stubs-to-aidl-parcelables,$(stubs))))
-
-gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
-.KATI_RESTAT: $(gen)
-$(gen): $(aidl_parcelables)
-	@echo Combining SDK parcelables: $@
-	rm -f $@.tmp
-	cat $^ | sort -u > $@.tmp
-	$(call commit-change-for-toc,$@)
-
 # This is used by ide.mk as the list of source files that are
 # always included.
 INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
diff --git a/api/current.txt b/api/current.txt
index 44b11e1..d2f63fa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1223,8 +1223,8 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
-    field public static final int sharedUserId = 16842763; // 0x101000b
-    field public static final int sharedUserLabel = 16843361; // 0x1010261
+    field @Deprecated public static final int sharedUserId = 16842763; // 0x101000b
+    field @Deprecated public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int shell = 16844180; // 0x1010594
     field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
     field public static final int shortcutId = 16844072; // 0x1010528
diff --git a/api/system-current.txt b/api/system-current.txt
index d08039d..99779de 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9479,7 +9479,7 @@
 package android.view.accessibility {
 
   public final class AccessibilityManager {
-    method public int getAccessibilityWindowId(android.os.IBinder);
+    method public int getAccessibilityWindowId(@Nullable android.os.IBinder);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
   }
 
diff --git a/cmds/incidentd/tests/ProtoFileReader_test.cpp b/cmds/incidentd/tests/ProtoFileReader_test.cpp
new file mode 100644
index 0000000..acb1bbb
--- /dev/null
+++ b/cmds/incidentd/tests/ProtoFileReader_test.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2017 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.
+#define DEBUG false
+#include "Log.h"
+
+#include <android-base/file.h>
+#include <android/util/ProtoFileReader.h>
+#include <android/util/ProtoOutputStream.h>
+#include <android/util/protobuf.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <signal.h>
+#include <string.h>
+
+#include "FdBuffer.h"
+#include "incidentd_util.h"
+
+using namespace android;
+using namespace android::base;
+using namespace android::os::incidentd;
+using ::testing::Test;
+
+const std::string kTestPath = GetExecutableDirectory();
+const std::string kTestDataPath = kTestPath + "/testdata/";
+
+status_t read(sp<ProtoFileReader> reader, size_t size) {
+    uint8_t const* buf;
+    while (size > 0 && (buf = reader->readBuffer()) != nullptr) {
+        size_t amt = reader->currentToRead();
+        if (size < amt) {
+            amt = size;
+        }
+        reader->move(amt);
+        size -= amt;
+    }
+
+    return NO_ERROR;
+}
+
+TEST(ProtoFileReaderTest, ParseOneLevel) {
+    const std::string testFile = kTestDataPath + "protoFile.txt";
+    size_t msg1Size = 10;
+    size_t msg2Size = 5 * 1024;
+    {
+        // Create a proto file
+        // TestProto {
+        //    optional Section1 section1 = 1;
+        //    optional Section2 section2 = 2;
+        // }
+
+        unique_fd fd(open(testFile.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
+        ASSERT_NE(fd.get(), -1);
+        ProtoOutputStream proto;
+        string field1;
+        field1.resize(msg1Size, 'h');
+        string field2;
+        field2.resize(msg2Size, 'a');
+        proto.write(FIELD_TYPE_MESSAGE | 1, field1.data(), field1.length());
+        proto.write(FIELD_TYPE_MESSAGE | 2, field2.data(), field2.length());
+        proto.flush(fd);
+    }
+
+    int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
+    ASSERT_NE(fd, -1);
+
+    status_t err;
+    sp<ProtoFileReader> reader = new ProtoFileReader(fd);
+    int i = 0;
+    size_t msg_size[2];
+    while (reader->hasNext()) {
+        uint64_t fieldTag = reader->readRawVarint();
+        uint32_t fieldId = read_field_id(fieldTag);
+        uint8_t wireType = read_wire_type(fieldTag);
+        ASSERT_EQ(WIRE_TYPE_LENGTH_DELIMITED, wireType);
+        size_t sectionSize = reader->readRawVarint();
+        if (i < 2) {
+            msg_size[i] = sectionSize;
+        }
+        err = read(reader, sectionSize);
+        ASSERT_EQ(NO_ERROR, err);
+        i++;
+    }
+
+    ASSERT_EQ(2, i);
+
+    ASSERT_EQ(msg1Size, msg_size[0]);
+    ASSERT_EQ(msg2Size, msg_size[1]);
+    close(fd);
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0d22f3a..c8bd275 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -127,6 +127,7 @@
 import android.view.autofill.IAutofillWindowPresenter;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
@@ -723,7 +724,7 @@
         Window.Callback, KeyEvent.Callback,
         OnCreateContextMenuListener, ComponentCallbacks2,
         Window.OnWindowDismissedCallback, WindowControllerCallback,
-        AutofillManager.AutofillClient {
+        AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
@@ -1125,6 +1126,12 @@
         return this;
     }
 
+    /** @hide */
+    @Override
+    public final ContentCaptureClient getContentCaptureClient() {
+        return this;
+    }
+
     /**
      * Register an {@link Application.ActivityLifecycleCallbacks} instance that receives
      * lifecycle callbacks for only this Activity.
@@ -6511,6 +6518,12 @@
         return getComponentName();
     }
 
+    /** @hide */
+    @Override
+    public final ComponentName contentCaptureClientGetComponentName() {
+        return getComponentName();
+    }
+
     /**
      * Retrieve a {@link SharedPreferences} object for accessing preferences
      * that are private to this activity.  This simply calls the underlying
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index b93aaa2..40cb29f 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -236,7 +236,7 @@
             config.screenLayout = Configuration.reduceScreenLayout(sl,
                     config.screenHeightDp, config.screenWidthDp);
         }
-        config.smallestScreenWidthDp = config.screenWidthDp; // assume screen does not rotate
+        config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp);
         config.compatScreenWidthDp = config.screenWidthDp;
         config.compatScreenHeightDp = config.screenHeightDp;
         config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 98b658d..c48c878 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1143,7 +1143,7 @@
                 Context outerContext = ctx.getOuterContext();
                 ContentCaptureOptions options = outerContext.getContentCaptureOptions();
                 // Options is null when the service didn't whitelist the activity or package
-                if (options != null) {
+                if (options != null && (options.lite || options.isWhitelisted(outerContext))) {
                     IBinder b = ServiceManager
                             .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
                     IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 76c4fb8..cb2142c 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -24,6 +24,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
+
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
 
@@ -78,12 +81,19 @@
      */
     public final boolean lite;
 
+    /**
+     * Constructor for "lite" objects that are just used to enable a {@link ContentCaptureManager}
+     * for contexts belonging to the content capture service app.
+     */
     public ContentCaptureOptions(int loggingLevel) {
         this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
                 /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
                 /* logHistorySize= */ 0, /* whitelistedComponents= */ null);
     }
 
+    /**
+     * Default constructor.
+     */
     public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
             int textChangeFlushingFrequencyMs, int logHistorySize,
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
@@ -91,6 +101,16 @@
                 textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents);
     }
 
+    /** @hide */
+    @VisibleForTesting
+    public ContentCaptureOptions(@Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this(ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
+                ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
+                ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
+                ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
+                ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, whitelistedComponents);
+    }
+
     private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
             int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
             @Nullable ArraySet<ComponentName> whitelistedComponents) {
@@ -103,10 +123,6 @@
         this.whitelistedComponents = whitelistedComponents;
     }
 
-    /**
-     * @hide
-     */
-    @TestApi
     public static ContentCaptureOptions forWhitelistingItself() {
         final ActivityThread at = ActivityThread.currentActivityThread();
         if (at == null) {
@@ -120,19 +136,27 @@
             throw new SecurityException("Thou shall not pass!");
         }
 
-        final ContentCaptureOptions options = new ContentCaptureOptions(
-                ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
-                ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
-                ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
-                ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
-                ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
-                /* whitelistedComponents= */ null);
+        final ContentCaptureOptions options =
+                new ContentCaptureOptions(/* whitelistedComponents= */ null);
         // Always log, as it's used by test only
         Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
 
         return options;
     }
 
+    /** @hide */
+    @VisibleForTesting
+    public boolean isWhitelisted(@NonNull Context context) {
+        if (whitelistedComponents == null) return true; // whole package is whitelisted
+        final ContentCaptureClient client = context.getContentCaptureClient();
+        if (client == null) {
+            // Shouldn't happen, but it doesn't hurt to check...
+            Log.w(TAG, "isWhitelisted(): no ContentCaptureClient on " + context);
+            return false;
+        }
+        return whitelistedComponents.contains(client.contentCaptureClientGetComponentName());
+    }
+
     @Override
     public String toString() {
         if (lite) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index de04829..00238bf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -70,6 +70,7 @@
 import android.view.ViewDebug;
 import android.view.WindowManager;
 import android.view.autofill.AutofillManager.AutofillClient;
+import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
 import android.view.textclassifier.TextClassificationManager;
 
 import java.io.File;
@@ -5414,6 +5415,14 @@
     /**
      * @hide
      */
+    @Nullable
+    public ContentCaptureClient getContentCaptureClient() {
+        return null;
+    }
+
+    /**
+     * @hide
+     */
     public final boolean isAutofillCompatibilityEnabled() {
         final AutofillOptions options = getAutofillOptions();
         return options != null && options.compatModeEnabled;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 83e15e8..abb68e7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2030,9 +2030,10 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan native API
-     * will enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate
-     * what level of optional hardware features limits it supports.
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan
+     * implementation on this device is hardware accelerated, and the Vulkan native API will
+     * enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate what
+     * level of optional hardware features limits it supports.
      * <p>
      * Level 0 includes the base Vulkan requirements as well as:
      * <ul><li>{@code VkPhysicalDeviceFeatures::textureCompressionETC2}</li></ul>
@@ -2057,10 +2058,10 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan native API
-     * will enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate
-     * what level of optional compute features that device supports beyond the Vulkan 1.0
-     * requirements.
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan
+     * implementation on this device is hardware accelerated, and the Vulkan native API will
+     * enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate what
+     * level of optional compute features that device supports beyond the Vulkan 1.0 requirements.
      * <p>
      * Compute level 0 indicates:
      * <ul>
@@ -2075,10 +2076,11 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature(String, int)}: The version of this feature indicates the highest
-     * {@code VkPhysicalDeviceProperties::apiVersion} supported by the physical devices that support
-     * the hardware level indicated by {@link #FEATURE_VULKAN_HARDWARE_LEVEL}. The feature version
-     * uses the same encoding as Vulkan version numbers:
+     * {@link #hasSystemFeature(String, int)}: If this feature is supported, the Vulkan
+     * implementation on this device is hardware accelerated, and the feature version will indicate
+     * the highest {@code VkPhysicalDeviceProperties::apiVersion} supported by the physical devices
+     * that support the hardware level indicated by {@link #FEATURE_VULKAN_HARDWARE_LEVEL}. The
+     * feature version uses the same encoding as Vulkan version numbers:
      * <ul>
      * <li>Major version number in bits 31-22</li>
      * <li>Minor version number in bits 21-12</li>
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index a51a871..232869d 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -453,14 +453,22 @@
         final boolean appIsProfileable = isProfileable(context);
         final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
         if (appIsDebuggable || appIsProfileable || deviceIsDebuggable) {
+            String debugPackage;
 
-            String debugPackage =
-                    coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+            if (coreSettings != null) {
+                debugPackage =
+                        coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+            } else {
+                ContentResolver contentResolver = context.getContentResolver();
+                debugPackage = Settings.Global.getString(contentResolver,
+                        Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+            }
 
             if ((debugPackage != null) && (!debugPackage.isEmpty())) {
                 return debugPackage;
             }
         }
+
         return "";
     }
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index f2aaead..e8b0d92 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -53,7 +53,6 @@
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
         DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
-        DEFAULT_FLAGS.put("settings_slice_injection", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
diff --git a/core/java/android/util/SparseSetArray.java b/core/java/android/util/SparseSetArray.java
index 680e85f..c1873d7 100644
--- a/core/java/android/util/SparseSetArray.java
+++ b/core/java/android/util/SparseSetArray.java
@@ -44,6 +44,13 @@
     }
 
     /**
+     * Removes all mappings from this SparseSetArray.
+     */
+    public void clear() {
+        mData.clear();
+    }
+
+    /**
      * @return whether a value exists at index n.
      */
     public boolean contains(int n, T value) {
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index d12777f..882e6fd 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1015,7 +1015,7 @@
      * @hide
      */
     @SystemApi
-    public int getAccessibilityWindowId(IBinder windowToken) {
+    public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
         if (windowToken == null) {
             return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
         }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index a977073..c2ad82f 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -294,6 +294,15 @@
     private MainContentCaptureSession mMainSession;
 
     /** @hide */
+    public interface ContentCaptureClient {
+        /**
+         * Gets the component name of the client.
+         */
+        @NonNull
+        ComponentName contentCaptureClientGetComponentName();
+    }
+
+    /** @hide */
     public ContentCaptureManager(@NonNull Context context,
             @NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) {
         mContext = Preconditions.checkNotNull(context, "context cannot be null");
diff --git a/core/java/com/android/internal/infra/GlobalWhitelistState.java b/core/java/com/android/internal/infra/GlobalWhitelistState.java
index dfa59b7..a0b2f94 100644
--- a/core/java/com/android/internal/infra/GlobalWhitelistState.java
+++ b/core/java/com/android/internal/infra/GlobalWhitelistState.java
@@ -35,11 +35,13 @@
  *
  * <p>This class is thread safe.
  */
+// TODO: add unit tests
 public class GlobalWhitelistState {
 
     // Uses full-name to avoid collision with service-provided mLock
     protected final Object mGlobalWhitelistStateLock = new Object();
 
+    // TODO: should not be exposed directly
     @Nullable
     @GuardedBy("mGlobalWhitelistStateLock")
     protected SparseArray<WhitelistHelper> mWhitelisterHelpers;
diff --git a/core/java/com/android/internal/infra/WhitelistHelper.java b/core/java/com/android/internal/infra/WhitelistHelper.java
index d7753db..9d653ba 100644
--- a/core/java/com/android/internal/infra/WhitelistHelper.java
+++ b/core/java/com/android/internal/infra/WhitelistHelper.java
@@ -98,9 +98,9 @@
             @Nullable List<ComponentName> components) {
         final ArraySet<String> packageNamesSet = packageNames == null ? null
                 : new ArraySet<>(packageNames);
-        final ArraySet<ComponentName> componentssSet = components == null ? null
+        final ArraySet<ComponentName> componentsSet = components == null ? null
                 : new ArraySet<>(components);
-        setWhitelist(packageNamesSet, componentssSet);
+        setWhitelist(packageNamesSet, componentsSet);
     }
 
     /**
@@ -170,7 +170,7 @@
 
             pw.print("["); pw.print(components.valueAt(0));
             for (int j = 1; j < components.size(); j++) {
-                pw.print(", "); pw.print(components.valueAt(i));
+                pw.print(", "); pw.print(components.valueAt(j));
             }
             pw.println("]");
         }
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 6179918..dcf8d28 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -19,10 +19,10 @@
 import static android.os.Process.*;
 
 import android.annotation.UnsupportedAppUsage;
-import android.os.FileUtils;
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
 import android.util.Slog;
@@ -247,6 +247,7 @@
             pid = _pid;
             if (parentPid < 0) {
                 final File procDir = new File("/proc", Integer.toString(pid));
+                uid = getUid(procDir.toString());
                 statFile = new File(procDir, "stat").toString();
                 cmdlineFile = new File(procDir, "cmdline").toString();
                 threadsDir = (new File(procDir, "task")).toString();
@@ -262,13 +263,22 @@
                         parentPid));
                 final File taskDir = new File(
                         new File(procDir, "task"), Integer.toString(pid));
+                uid = getUid(taskDir.toString());
                 statFile = new File(taskDir, "stat").toString();
                 cmdlineFile = null;
                 threadsDir = null;
                 threadStats = null;
                 workingThreads = null;
             }
-            uid = FileUtils.getUid(statFile.toString());
+        }
+
+        private static int getUid(String path) {
+            try {
+                return Os.stat(path).st_uid;
+            } catch (ErrnoException e) {
+                Slog.w(TAG, "Failed to stat(" + path + "): " + e);
+                return -1;
+            }
         }
     }
 
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index ace88f5..c828cac 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2336,4 +2336,13 @@
     // CATEGORY: SETTINGS
     // OS: Q
     ACTION_DISPLAY_WHITE_BALANCE_SETTING_CHANGED = 1703;
+
+    // OPEN: Settings > Pick SIM dialog
+    DIALOG_SIM_LIST = 1707;
+
+    // OPEN: Settings > Pick SIM (that supports calling) dialog
+    DIALOG_CALL_SIM_LIST = 1708;
+
+    // OPEN: Settings > Pick preferred SIM dialog
+    DIALOG_PREFERRED_SIM_PICKER = 1709;
 }
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 1e0b0d8..dc2e6d5 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -478,6 +478,54 @@
         }
         repeated TrackedJob tracked_jobs = 4;
 
+        message ExecutionStats {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+            optional JobStatusDumpProto.Bucket standby_bucket = 1;
+
+            // The time after which this record should be considered invalid (out of date), in the
+            // elapsed realtime timebase.
+            optional int64 expiration_time_elapsed = 2;
+            optional int64 window_size_ms = 3;
+
+            /** The total amount of time the app ran in its respective bucket window size. */
+            optional int64 execution_time_in_window_ms = 4;
+            optional int32 bg_job_count_in_window = 5;
+
+            /**
+             * The total amount of time the app ran in the last
+             * {@link QuotaController#MAX_PERIOD_MS}.
+             */
+            optional int64 execution_time_in_max_period_ms = 6;
+            optional int32 bg_job_count_in_max_period = 7;
+
+            /**
+             * The time after which the sum of all the app's sessions plus
+             * ConstantsProto.QuotaController.in_quota_buffer_ms equals the quota. This is only
+             * valid if
+             * execution_time_in_window_ms >=
+             *   ConstantsProto.QuotaController.allowed_time_per_period_ms
+             * or
+             * execution_time_in_max_period_ms >=
+             *   ConstantsProto.QuotaController.max_execution_time_ms.
+             */
+            optional int64 quota_cutoff_time_elapsed = 8;
+
+            /**
+             * The time after which job_count_in_allowed_time should be considered invalid, in the
+             * elapsed realtime timebase.
+             */
+            optional int64 job_count_expiration_time_elapsed = 9;
+
+            /**
+             * The number of jobs that ran in at least the last
+             * ConstantsProto.QuotaController.allowed_time_per_period_ms.
+             * It may contain a few stale entries since cleanup won't happen exactly every
+             * ConstantsProto.QuotaController.allowed_time_per_period_ms.
+             */
+            optional int32 job_count_in_allowed_time = 10;
+        }
+
         message Package {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -517,6 +565,8 @@
             optional Timer timer = 2;
 
             repeated TimingSession saved_sessions = 3;
+
+            repeated ExecutionStats execution_stats = 4;
         }
         repeated PackageStats package_stats = 5;
     }
diff --git a/core/res/res/drawable/ic_content_copy_gm2.xml b/core/res/res/drawable/ic_content_copy_gm2.xml
index 940da94..ee58738 100644
--- a/core/res/res/drawable/ic_content_copy_gm2.xml
+++ b/core/res/res/drawable/ic_content_copy_gm2.xml
@@ -20,6 +20,6 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="#F999"
+      android:fillColor="?android:attr/textColorSecondary"
       android:pathData="M18,21L4,21L4,7L2,7v14c0,1.1 0.9,2 2,2h14v-2zM21,17L21,3c0,-1.1 -0.9,-2 -2,-2L8,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2zM19,17L8,17L8,3h11v14z"/>
 </vector>
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 138e24e3..4d5e262 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -28,6 +28,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alwaysShow="true"
+        android:elevation="1dp"
         android:background="@drawable/bottomsheet_background">
 
         <ImageView
@@ -66,6 +67,7 @@
         android:listSelector="@color/transparent"
         android:divider="@null"
         android:scrollIndicators="top"
+        android:elevation="1dp"
         android:nestedScrollingEnabled="true"/>
 
     <TextView android:id="@+id/empty"
@@ -76,6 +78,7 @@
               android:text="@string/noApplications"
               android:padding="@dimen/chooser_edge_margin_normal"
               android:gravity="center"
+              android:elevation="1dp"
               android:visibility="gone"/>
 
 </com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index bbc784a..26a9f57 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -346,13 +346,21 @@
          By setting this value on two or more packages, each of these packages
          will be given a single shared user ID, so they can for example run
          in the same process.  Note that for them to actually get the same
-         user ID, they must also be signed with the same signature. -->
+         user ID, they must also be signed with the same signature.
+         @deprecated Shared user id's cause non-deterministic behaviour within the
+         package manager. As such, it's use is discouraged, deprecated, and will
+         be removed altogether in a future version of Android. Instead, proper
+         communication mechanisms such as services and providers should be used
+         to facilitate interoperability between shared components. -->
     <attr name="sharedUserId" format="string" />
 
     <!-- Specify a label for the shared user UID of this package.  This is
          only used if you have also used android:sharedUserId.  This must
          be a reference to a string resource; it can not be an explicit
-         string. -->
+         string.
+         @deprecated There is no replacement for this attribute.
+         {@link android.R.attr#sharedUserId} has been deprecated making
+         this attribute unnecessary. -->
     <attr name="sharedUserLabel" format="reference" />
 
     <!-- Internal version code.  This is the number used to determine whether
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 03fb1fc..0ed9860 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -802,6 +802,8 @@
         <item name="textAppearanceListItemSmall">@style/TextAppearance.DeviceDefault.ListItem</item>
         <item name="textAppearanceListItemSecondary">@style/TextAppearance.DeviceDefault.ListItemSecondary</item>
 
+        <item name="backgroundDimAmount">0.7</item>
+
         <!-- Button styles -->
         <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
         <item name="buttonStyle">@style/Widget.DeviceDefault.Light.Button</item>
diff --git a/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java b/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
new file mode 100644
index 0000000..c6f4fa2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ContentCaptureOptionsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArraySet;
+import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Unit test for {@link ContentCaptureOptions}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.content.ContentCaptureOptionsTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ContentCaptureOptionsTest {
+
+    private final ComponentName mContextComponent = new ComponentName("marco", "polo");
+    private final ComponentName mComp1 = new ComponentName("comp", "one");
+    private final ComponentName mComp2 = new ComponentName("two", "comp");
+
+    @Mock private Context mContext;
+    @Mock private ContentCaptureClient mClient;
+
+    @Before
+    public void setExpectation() {
+        when(mClient.contentCaptureClientGetComponentName()).thenReturn(mContextComponent);
+        when(mContext.getContentCaptureClient()).thenReturn(mClient);
+    }
+
+    @Test
+    public void testIsWhitelisted_nullWhitelistedComponents() {
+        ContentCaptureOptions options = new ContentCaptureOptions(null);
+        assertThat(options.isWhitelisted(mContext)).isTrue();
+    }
+
+    @Test
+    public void testIsWhitelisted_emptyWhitelistedComponents() {
+        ContentCaptureOptions options = new ContentCaptureOptions(toSet((ComponentName) null));
+        assertThat(options.isWhitelisted(mContext)).isFalse();
+    }
+
+    @Test
+    public void testIsWhitelisted_notWhitelisted() {
+        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mComp1, mComp2));
+        assertThat(options.isWhitelisted(mContext)).isFalse();
+    }
+
+    @Test
+    public void testIsWhitelisted_whitelisted() {
+        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mComp1, mContextComponent));
+        assertThat(options.isWhitelisted(mContext)).isTrue();
+    }
+
+    @Test
+    public void testIsWhitelisted_invalidContext() {
+        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mContextComponent));
+        Context invalidContext = mock(Context.class); // has no client
+        assertThat(options.isWhitelisted(invalidContext)).isFalse();
+    }
+
+    @Test
+    public void testIsWhitelisted_clientWithNullComponentName() {
+        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mContextComponent));
+        ContentCaptureClient client = mock(ContentCaptureClient.class);
+        Context context = mock(Context.class);
+        when(context.getContentCaptureClient()).thenReturn(client);
+
+        assertThat(options.isWhitelisted(context)).isFalse();
+    }
+
+    @NonNull
+    private ArraySet<ComponentName> toSet(@Nullable ComponentName... comps) {
+        ArraySet<ComponentName> set = new ArraySet<>();
+        if (comps != null) {
+            for (int i = 0; i < comps.length; i++) {
+                set.add(comps[i]);
+            }
+        }
+        return set;
+    }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e4a93e7..dbbe1b4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -41,6 +41,7 @@
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
+        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.defcontainer">
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index cf5d7ce..0a9d965 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -45,12 +45,12 @@
         1920,   // viewportH
 };
 
-const DeviceInfo* DeviceInfo::get() {
+DeviceInfo* DeviceInfo::get() {
         static DeviceInfo sDeviceInfo;
         return &sDeviceInfo;
 }
 
-DisplayInfo QueryDisplayInfo() {
+static DisplayInfo QueryDisplayInfo() {
     if (Properties::isolatedProcess) {
         return sDummyDisplay;
     }
@@ -65,6 +65,27 @@
     return displayInfo;
 }
 
+static float QueryMaxRefreshRate() {
+    if (Properties::isolatedProcess) {
+        return sDummyDisplay.fps;
+    }
+
+    const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
+    LOG_ALWAYS_FATAL_IF(token == nullptr,
+                        "Failed to get display info because internal display is disconnected");
+
+    Vector<DisplayInfo> configs;
+    configs.reserve(10);
+    status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to getDisplayConfigs, error %d", status);
+    LOG_ALWAYS_FATAL_IF(configs.size() == 0, "getDisplayConfigs returned 0 configs?");
+    float max = 0.0f;
+    for (auto& info : configs) {
+        max = std::max(max, info.fps);
+    }
+    return max;
+}
+
 static void queryWideColorGamutPreference(sk_sp<SkColorSpace>* colorSpace, SkColorType* colorType) {
     if (Properties::isolatedProcess) {
         *colorSpace = SkColorSpace::MakeSRGB();
@@ -103,7 +124,7 @@
     }
 }
 
-DeviceInfo::DeviceInfo() {
+DeviceInfo::DeviceInfo() : mMaxRefreshRate(QueryMaxRefreshRate()) {
 #if HWUI_NULL_GPU
         mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
 #else
@@ -119,7 +140,11 @@
 }
 
 void DeviceInfo::setMaxTextureSize(int maxTextureSize) {
-    const_cast<DeviceInfo*>(DeviceInfo::get())->mMaxTextureSize = maxTextureSize;
+    DeviceInfo::get()->mMaxTextureSize = maxTextureSize;
+}
+
+void DeviceInfo::onDisplayConfigChanged() {
+    mDisplayInfo = QueryDisplayInfo();
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 2bab5d3..0e3f119 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -32,7 +32,7 @@
     PREVENT_COPY_AND_ASSIGN(DeviceInfo);
 
 public:
-    static const DeviceInfo* get();
+    static DeviceInfo* get();
 
     // this value is only valid after the GPU has been initialized and there is a valid graphics
     // context or if you are using the HWUI_NULL_GPU
@@ -40,6 +40,9 @@
     const DisplayInfo& displayInfo() const { return mDisplayInfo; }
     sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
     SkColorType getWideColorType() const { return mWideColorType; }
+    float getMaxRefreshRate() const { return mMaxRefreshRate; }
+
+    void onDisplayConfigChanged();
 
 private:
     friend class renderthread::RenderThread;
@@ -51,6 +54,7 @@
     DisplayInfo mDisplayInfo;
     sk_sp<SkColorSpace> mWideColorSpace;
     SkColorType mWideColorType;
+    const float mMaxRefreshRate;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 9998854..19f509c 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -67,7 +67,7 @@
 bool Properties::isolatedProcess = false;
 
 int Properties::contextPriority = 0;
-uint32_t Properties::defaultRenderAhead = 0;
+int Properties::defaultRenderAhead = -1;
 
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {
@@ -130,9 +130,8 @@
 
     enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
 
-    defaultRenderAhead =
-            std::max(0u, std::min(2u, static_cast<uint32_t>(property_get_int(
-                                              PROPERTY_RENDERAHEAD, render_ahead().value_or(0)))));
+    defaultRenderAhead = std::max(-1, std::min(2, property_get_int(PROPERTY_RENDERAHEAD,
+            render_ahead().value_or(0))));
 
     return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
 }
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 3105e58..3e91c63 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -253,7 +253,7 @@
 
     ANDROID_API static int contextPriority;
 
-    static uint32_t defaultRenderAhead;
+    static int defaultRenderAhead;
 
 private:
     static ProfileType sProfileType;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 2957b14..f326ce8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -105,13 +105,13 @@
         , mGenerationID(0)
         , mOpaque(!translucent)
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
-        , mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo())
+        , mJankTracker(&thread.globalProfileData(), DeviceInfo::get()->displayInfo())
         , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
         , mContentDrawBounds(0, 0, 0, 0)
         , mRenderPipeline(std::move(renderPipeline)) {
     rootRenderNode->makeRoot();
     mRenderNodes.emplace_back(rootRenderNode);
-    mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
+    mProfiler.setDensity(DeviceInfo::get()->displayInfo().density);
     setRenderAheadDepth(Properties::defaultRenderAhead);
 }
 
@@ -153,16 +153,23 @@
         mNativeSurface = nullptr;
     }
 
+    if (mRenderAheadDepth == 0 && DeviceInfo::get()->getMaxRefreshRate() > 66.6f) {
+        mFixedRenderAhead = false;
+        mRenderAheadCapacity = 1;
+    } else {
+        mFixedRenderAhead = true;
+        mRenderAheadCapacity = mRenderAheadDepth;
+    }
+
     ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
     bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
-                                                  mRenderAheadDepth);
+                                                  mRenderAheadCapacity);
 
     mFrameNumber = -1;
 
     if (hasSurface) {
         mHaveNewSurface = true;
         mSwapHistory.clear();
-        applyRenderAheadSettings();
     } else {
         mRenderThread.removeFrameCallback(this);
         mGenerationID++;
@@ -403,6 +410,23 @@
     mRenderThread.pushBackFrameCallback(this);
 }
 
+void CanvasContext::setPresentTime() {
+    int64_t presentTime = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    int renderAhead = 0;
+    const auto frameIntervalNanos = mRenderThread.timeLord().frameIntervalNanos();
+    if (mFixedRenderAhead) {
+        renderAhead = std::min(mRenderAheadDepth, mRenderAheadCapacity);
+    } else if (frameIntervalNanos < 15_ms) {
+        renderAhead = std::min(1, static_cast<int>(mRenderAheadCapacity));
+    }
+
+    if (renderAhead) {
+        presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
+                (frameIntervalNanos * (renderAhead + 1));
+    }
+    native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+}
+
 void CanvasContext::draw() {
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
@@ -415,14 +439,9 @@
     mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     Frame frame = mRenderPipeline->getFrame();
+    setPresentTime();
 
     SkRect windowDirty = computeDirtyRect(frame, &dirty);
-    if (mRenderAheadDepth) {
-        auto presentTime =
-                mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
-                (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1));
-        native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
-    }
 
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
                                       mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
@@ -656,18 +675,12 @@
     return width == mLastFrameWidth && height == mLastFrameHeight;
 }
 
-void CanvasContext::applyRenderAheadSettings() {
-    if (mNativeSurface && !mRenderAheadDepth) {
-        native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO);
-    }
-}
-
-void CanvasContext::setRenderAheadDepth(uint32_t renderAhead) {
-    if (renderAhead > 2 || renderAhead == mRenderAheadDepth || mNativeSurface) {
+void CanvasContext::setRenderAheadDepth(int renderAhead) {
+    if (renderAhead > 2 || renderAhead < 0 || mNativeSurface) {
         return;
     }
-    mRenderAheadDepth = renderAhead;
-    applyRenderAheadSettings();
+    mFixedRenderAhead = true;
+    mRenderAheadDepth = static_cast<uint32_t>(renderAhead);
 }
 
 SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 912b125..f9de002 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -204,7 +204,7 @@
     }
 
     // Must be called before setSurface
-    void setRenderAheadDepth(uint32_t renderAhead);
+    void setRenderAheadDepth(int renderAhead);
 
     SkISize getNextFrameSize() const;
 
@@ -221,7 +221,7 @@
 
     bool isSwapChainStuffed();
     bool surfaceRequiresRedraw();
-    void applyRenderAheadSettings();
+    void setPresentTime();
 
     SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
 
@@ -240,7 +240,9 @@
     // painted onto its surface.
     bool mIsDirty = false;
     SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default;
+    bool mFixedRenderAhead = false;
     uint32_t mRenderAheadDepth = 0;
+    uint32_t mRenderAheadCapacity = 0;
     struct SwapHistory {
         SkRect damage;
         nsecs_t vsyncTime;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index eca7d88..41cb8fd 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -60,8 +60,10 @@
 
 class DisplayEventReceiverWrapper : public VsyncSource {
 public:
-    DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver)
-            : mDisplayEventReceiver(std::move(receiver)) {}
+    DisplayEventReceiverWrapper(std::unique_ptr<DisplayEventReceiver>&& receiver,
+            const std::function<void()>& onDisplayConfigChanged)
+            : mDisplayEventReceiver(std::move(receiver))
+            , mOnDisplayConfigChanged(onDisplayConfigChanged) {}
 
     virtual void requestNextVsync() override {
         status_t status = mDisplayEventReceiver->requestNextVsync();
@@ -79,6 +81,9 @@
                     case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
                         latest = ev.header.timestamp;
                         break;
+                    case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+                        mOnDisplayConfigChanged();
+                        break;
                 }
             }
         }
@@ -90,6 +95,7 @@
 
 private:
     std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
+    std::function<void()> mOnDisplayConfigChanged;
 };
 
 class DummyVsyncSource : public VsyncSource {
@@ -160,22 +166,29 @@
         // Register the FD
         mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
                        RenderThread::displayEventReceiverCallback, this);
-        mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver));
+        mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver), [this] {
+            DeviceInfo::get()->onDisplayConfigChanged();
+            setupFrameInterval();
+        });
     } else {
         mVsyncSource = new DummyVsyncSource(this);
     }
 }
 
 void RenderThread::initThreadLocals() {
-    mDisplayInfo = DeviceInfo::get()->displayInfo();
-    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
-    mTimeLord.setFrameInterval(frameIntervalNanos);
-    mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
+    setupFrameInterval();
     initializeDisplayEventReceiver();
     mEglManager = new EglManager();
     mRenderState = new RenderState(*this);
     mVkManager = new VulkanManager();
-    mCacheManager = new CacheManager(mDisplayInfo);
+    mCacheManager = new CacheManager(DeviceInfo::get()->displayInfo());
+}
+
+void RenderThread::setupFrameInterval() {
+    auto& displayInfo = DeviceInfo::get()->displayInfo();
+    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / displayInfo.fps);
+    mTimeLord.setFrameInterval(frameIntervalNanos);
+    mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
 }
 
 void RenderThread::requireGlContext() {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 6bb26fd..c96e284 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -102,8 +102,6 @@
     ProfileDataContainer& globalProfileData() { return mGlobalProfileData; }
     Readback& readback();
 
-    const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
-
     GrContext* getGrContext() const { return mGrContext.get(); }
     void setGrContext(sk_sp<GrContext> cxt);
 
@@ -149,13 +147,12 @@
 
     void initThreadLocals();
     void initializeDisplayEventReceiver();
+    void setupFrameInterval();
     static int displayEventReceiverCallback(int fd, int events, void* data);
     void drainDisplayEventQueue();
     void dispatchFrameCallbacks();
     void requestVsync();
 
-    DisplayInfo mDisplayInfo;
-
     VsyncSource* mVsyncSource;
     bool mVsyncRequested;
     std::set<IFrameCallback*> mFrameCallbacks;
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index 210fced..3f1ef93 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -33,7 +33,7 @@
 }
 
 RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
-    DisplayInfo displayInfo = renderThread.mainDisplayInfo();
+    DisplayInfo displayInfo = DeviceInfo::get()->displayInfo();
     GrContext* grContext = renderThread.getGrContext();
     ASSERT_TRUE(grContext != nullptr);
 
diff --git a/libs/protoutil/src/ProtoFileReader.cpp b/libs/protoutil/src/ProtoFileReader.cpp
index 4017979..bbb1fe3 100644
--- a/libs/protoutil/src/ProtoFileReader.cpp
+++ b/libs/protoutil/src/ProtoFileReader.cpp
@@ -127,7 +127,8 @@
         if (!ensure_data()) {
             return;
         }
-        const size_t chunk = mMaxOffset - mOffset < amt ? amt : mMaxOffset - mOffset;
+        const size_t chunk =
+                mMaxOffset - mOffset > amt ? amt : mMaxOffset - mOffset;
         mOffset += chunk;
         amt -= chunk;
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index a7f8933..ae99126 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -472,7 +472,10 @@
                 }
                 boolean isTracking = mIsTracking;
                 Rect rect = mNotificationList.getClipBounds();
-                float clippedHeight = rect.bottom;
+                float clippedHeight = 0;
+                if (rect != null) {
+                    clippedHeight = rect.bottom;
+                }
                 if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP
                         && mIsSwipingVerticallyToClose) {
                     if (mSettleClosePercentage < mPercentageFromBottom && isTracking) {
diff --git a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
index 1a47afc..f532caa 100644
--- a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
@@ -42,6 +42,7 @@
             android:layout_height="wrap_content"
             android:gravity="start|center_vertical"
             android:minWidth="56dp"
+            android:minHeight="48dp"
             android:orientation="horizontal"
             android:clipToPadding="false"
             android:paddingTop="4dp"
diff --git a/packages/SystemUI/docs/clock-plugins.md b/packages/SystemUI/docs/clock-plugins.md
new file mode 100644
index 0000000..5e4f6c7
--- /dev/null
+++ b/packages/SystemUI/docs/clock-plugins.md
@@ -0,0 +1,92 @@
+# Clock Plugins
+
+## Introduction
+
+The clock appearing on the lock screen and always on display (AOD) can be
+customized via the ClockPlugin plugin interface.
+
+## System Health
+
+Clocks are high risk for battery consumption and screen burn-in because they
+modify the UI of AOD.
+
+To reduce battery consumption, it is recommended to
+target a maximum on-pixel-ratio (OPR) of 5%. Clocks that are composed of
+large blocks of color that cause the OPR to exceed 5% should be avoided.
+
+To prevent screen burn-in, clocks should not be composed of large solid
+blocks of color, and the clock should be moved around the screen to
+distribute the on pixels across a large number of pixels. Software
+burn-in testing is a good starting point to assess the pixel shifting
+(clock movement) scheme and shape of the clock.
+
+### Software Burn-In Test
+
+The goal is to look for bright spots in the luminosity average over a period of
+time. It is difficult to define a threshold where burn-in will occur. It is,
+therefore, recommended to compare against an element on AOD that is known not
+to cause problems.
+
+For clock face that contain color, it is recommended to use an all white
+version of the face. Since white has the highest luminosity, this version of
+the clock face represents the worst case scenario.
+
+To start, generate a sequence of screenshots for each minute over a 12 hr interval.
+
+```
+serial = '84TY004MS' # serial number for the device
+count = 1
+t = datetime.datetime(2019, 1, 1)
+stop = t + datetime.timedelta(hours=12)
+if not os.path.exists(OUTPUT_FOLDER):
+  raise RuntimeError('output folder "%s" does not exist' % OUTPUT_FOLDER)
+while t <= stop:
+  os.system("adb -s %s shell 'date %s ; am broadcast -a android.intent.action.TIME_SET'" % (serial, t.strftime('%m%d%H%M%Y.%S')))
+  os.system('adb -s %s shell screencap -p > %s/screencap_%06d.png' % (serial, OUTPUT_FOLDER, count))
+  t += datetime.timedelta(minutes=1)
+  count += 1
+```
+
+Average the luminosity of the screenshots.
+
+```
+#!python
+import numpy
+import scipy.ndimage
+from imageio import imread, imwrite
+import matplotlib.pylab as plt
+import os
+import os.path
+
+def images(path):
+  return [os.path.join(path, name) for name in os.listdir(path) if name.endswith('.png')]
+
+def average(images):
+  AVG = None
+  for name in images:
+    IM = scipy.ndimage.imread(name, mode='L')
+    A = numpy.array(IM, dtype=numpy.double)
+    if AVG is None:
+      AVG = A
+    else:
+      AVG += A
+  AVG /= len(images)
+  return numpy.array(AVG, dtype=numpy.uint8)
+
+def main(path):
+  ims = images(path)
+  if len(ims) == 0:
+    raise ValueError("folder '%s' doesn't contain any png files" % path)
+  AVG = average(ims)
+  imwrite('average.png', AVG)
+  plt.imshow(AVG)
+  plt.show()
+
+if __name__=='__main__':
+  import sys
+  main(sys.argv[1])
+```
+
+Look for bright spots in the luminosity average. If bright spots are found,
+action should be taken to change the shape of the clock face or increase the
+amount of pixel shifting.
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png
index 83d714b..4a0972f 100644
--- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png
index 8d0e6ed..a7d5a0d 100644
--- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/bubble_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png
index 1ac0113..812dc9d 100644
--- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png
+++ b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java b/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
index 922c65e..b3fc69e 100644
--- a/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
@@ -59,7 +59,10 @@
         } else if (SliceBroadcastRelay.ACTION_UNREGISTER.equals(intent.getAction())) {
             Uri uri = intent.getParcelableExtra(SliceBroadcastRelay.EXTRA_URI);
             if (DEBUG) Log.d(TAG, "Unregister " + uri);
-            getAndRemoveRelay(uri).unregister(mContext);
+            BroadcastRelay relay = getAndRemoveRelay(uri);
+            if (relay != null) {
+                relay.unregister(mContext);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index b2302cc..898f64b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -354,17 +354,22 @@
     private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            mHandler.removeCallbacks(mDeferredConnectionCallback);
-            mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
             mConnectionBackoffAttempts = 0;
-            mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
-            // Listen for launcher's death
+            mHandler.removeCallbacks(mDeferredConnectionCallback);
             try {
                 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
             } catch (RemoteException e) {
+                // Failed to link to death (process may have died between binding and connecting),
+                // just unbind the service for now and retry again
                 Log.e(TAG_OPS, "Lost connection to launcher service", e);
+                disconnectFromLauncherService();
+                retryConnectionWithBackoff();
+                return;
             }
 
+            mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
+            mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
+
             Bundle params = new Bundle();
             params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
             params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
@@ -550,7 +555,6 @@
             mHandler.post(()-> {
                 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
                 if (bar != null) {
-                    System.out.println("MERONG dispatchNotificationPanelTouchEvent");
                     mStatusBarGestureDownEvent.setAction(MotionEvent.ACTION_CANCEL);
                     bar.dispatchNotificationsPanelTouchEvent(mStatusBarGestureDownEvent);
                     mStatusBarGestureDownEvent.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 6101593..ebafb81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -693,6 +693,9 @@
 
         @Override
         public void onKeyguardBouncerChanged(boolean bouncer) {
+            if (mLockIcon == null) {
+                return;
+            }
             mLockIcon.setBouncerVisible(bouncer);
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 058cb2d..ebda585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1193,6 +1193,20 @@
         }
     }
 
+    /**
+     * Returns best effort count of visible notifications.
+     */
+    public int getVisibleNotificationCount() {
+        int count = 0;
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
+                count++;
+            }
+        }
+        return count;
+    }
+
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private boolean isCurrentlyAnimating() {
         return mStateAnimator.isRunning();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 0171d7f..26e0a70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -59,6 +59,16 @@
     private int mClockPreferredY;
 
     /**
+     * Whether or not there is a custom clock face on keyguard.
+     */
+    private boolean mHasCustomClock;
+
+    /**
+     * Whether or not the NSSL contains any visible notifications.
+     */
+    private boolean mHasVisibleNotifs;
+
+    /**
      * Height of notification stack: Sum of height of each notification.
      */
     private int mNotificationStackHeight;
@@ -117,7 +127,7 @@
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
-            float dark, float emptyDragAmount) {
+            boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
@@ -125,6 +135,8 @@
         mHeight = parentHeight;
         mKeyguardStatusHeight = keyguardStatusHeight;
         mClockPreferredY = clockPreferredY;
+        mHasCustomClock = hasCustomClock;
+        mHasVisibleNotifs = hasVisibleNotifs;
         mDarkAmount = dark;
         mEmptyDragAmount = emptyDragAmount;
     }
@@ -179,6 +191,9 @@
         clockYDark = MathUtils.max(0, clockYDark);
 
         float clockYRegular = getExpandedClockPosition();
+        if (mHasCustomClock && !mHasVisibleNotifs) {
+            clockYRegular = clockYDark;
+        }
         float clockYBouncer = -mKeyguardStatusHeight;
 
         // Move clock up while collapsing the shade
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 2207e04..c39a494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -637,6 +637,8 @@
                     totalHeight,
                     mKeyguardStatusView.getHeight(),
                     clockPreferredY,
+                    hasCustomClock(),
+                    mNotificationStackScroller.getVisibleNotificationCount() != 0,
                     mInterpolatedDarkAmount,
                     mEmptyDragAmount);
             mClockPositionAlgorithm.run(mClockPositionResult);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
index c6e85c3..19e1a5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
@@ -95,6 +95,22 @@
     }
 
     @Test
+    public void testUnregisterWithoutRegister() {
+        Uri testUri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority("something")
+                .path("test")
+                .build();
+        SliceBroadcastRelayHandler relayHandler = new SliceBroadcastRelayHandler();
+        relayHandler.mContext = spy(mContext);
+
+        Intent intent = new Intent(SliceBroadcastRelay.ACTION_UNREGISTER);
+        intent.putExtra(SliceBroadcastRelay.EXTRA_URI, ContentProvider.maybeAddUserId(testUri, 0));
+        relayHandler.handleIntent(intent);
+        // No crash
+    }
+
+    @Test
     public void testRelay() {
         Receiver.sReceiver = mock(BroadcastReceiver.class);
         Uri testUri = new Uri.Builder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 9354648..f191cab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -41,6 +41,8 @@
     private static final float ZERO_DRAG = 0.f;
     private static final float OPAQUE = 1.f;
     private static final float TRANSPARENT = 0.f;
+    private static final boolean HAS_CUSTOM_CLOCK = false;
+    private static final boolean HAS_VISIBLE_NOTIFS = false;
 
     private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
     private KeyguardClockPositionAlgorithm.Result mClockPosition;
@@ -48,11 +50,18 @@
     private float mPanelExpansion;
     private int mKeyguardStatusHeight;
     private float mDark;
+    private int mPreferredClockY;
+    private boolean mHasCustomClock;
+    private boolean mHasVisibleNotifs;
 
     @Before
     public void setUp() {
         mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
         mClockPosition = new KeyguardClockPositionAlgorithm.Result();
+
+        mPreferredClockY = PREFERRED_CLOCK_Y;
+        mHasCustomClock = HAS_CUSTOM_CLOCK;
+        mHasVisibleNotifs = HAS_VISIBLE_NOTIFS;
     }
 
     @Test
@@ -293,6 +302,71 @@
         assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
     }
 
+    @Test
+    public void preferredCustomClockPositionNoNotifications() {
+        // GIVEN on the lock screen with a custom clock and no visible notifications
+        givenLockScreen();
+        mPreferredClockY = 100;
+        mHasCustomClock = true;
+        mHasVisibleNotifs = false;
+        // AND given empty height for clock and stack scroller
+        mNotificationStackHeight = EMPTY_HEIGHT;
+        mKeyguardStatusHeight = EMPTY_HEIGHT;
+        // WHEN the clock position algorithm is run
+        positionClock();
+        // THEN the clock Y position is the preferred Y position.
+        assertThat(mClockPosition.clockY).isEqualTo(100);
+    }
+
+    @Test
+    public void preferredDefaultClockPositionNoNotifications() {
+        // GIVEN on the lock screen with a custom clock and no visible notifications
+        givenLockScreen();
+        mPreferredClockY = 100;
+        mHasCustomClock = false;
+        mHasVisibleNotifs = false;
+        // AND given empty height for clock and stack scroller
+        mNotificationStackHeight = EMPTY_HEIGHT;
+        mKeyguardStatusHeight = EMPTY_HEIGHT;
+        // WHEN the clock position algorithm is run
+        positionClock();
+        // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2) and not
+        // preferred.
+        assertThat(mClockPosition.clockY).isEqualTo(1000);
+    }
+
+    @Test
+    public void preferredCustomClockPositionWithVisibleNotifications() {
+        // GIVEN on the lock screen with a custom clock and visible notifications
+        givenLockScreen();
+        mPreferredClockY = 100;
+        mHasCustomClock = true;
+        mHasVisibleNotifs = true;
+        // AND given empty height for clock and stack scroller
+        mNotificationStackHeight = EMPTY_HEIGHT;
+        mKeyguardStatusHeight = EMPTY_HEIGHT;
+        // WHEN the clock position algorithm is run
+        positionClock();
+        // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2).
+        assertThat(mClockPosition.clockY).isEqualTo(1000);
+    }
+
+    @Test
+    public void preferredCustomClockPositionWithVisibleNotificationsOnAod() {
+        // GIVEN on the lock screen with a custom clock and visible notifications
+        givenAOD();
+        mPreferredClockY = 100;
+        mHasCustomClock = true;
+        mHasVisibleNotifs = true;
+        // AND given empty height for clock and stack scroller
+        mNotificationStackHeight = EMPTY_HEIGHT;
+        mKeyguardStatusHeight = EMPTY_HEIGHT;
+        // WHEN the clock position algorithm is run
+        positionClock();
+        // THEN the clock Y position is the preferred Y position.
+        assertThat(mClockPosition.clockY).isEqualTo(100);
+    }
+
     private void givenAOD() {
         mPanelExpansion = 1.f;
         mDark = 1.f;
@@ -305,8 +379,8 @@
 
     private void positionClock() {
         mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
-                mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, PREFERRED_CLOCK_Y, mDark,
-                ZERO_DRAG);
+                mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mPreferredClockY,
+                mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG);
         mClockPositionAlgorithm.run(mClockPosition);
     }
 }
diff --git a/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml
index c420ab6..a99f705 100644
--- a/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml
+++ b/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml
@@ -18,5 +18,5 @@
 -->
 <resources>
     <color name="accent_device_default_light">#AF6050</color>
-    <color name="accent_device_default_dark">#9D6962</color>
+    <color name="accent_device_default_dark">#C3A6A2</color>
 </resources>
diff --git a/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml
index 6aec805..449639b 100644
--- a/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml
+++ b/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml
@@ -18,5 +18,5 @@
 -->
 <resources>
     <color name="accent_device_default_light">#0C80A7</color>
-    <color name="accent_device_default_dark">#347D98</color>
+    <color name="accent_device_default_dark">#28BDD7</color>
 </resources>
diff --git a/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml
index 049f8b8..47079a8 100644
--- a/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml
+++ b/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml
@@ -18,5 +18,5 @@
 -->
 <resources>
     <color name="accent_device_default_light">#C42CC9</color>
-    <color name="accent_device_default_dark">#C42CC9</color>
+    <color name="accent_device_default_dark">#E68AED</color>
 </resources>
diff --git a/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml
index b6f757c..f147aeb 100644
--- a/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml
+++ b/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml
@@ -18,5 +18,5 @@
 -->
 <resources>
     <color name="accent_device_default_light">#47618A</color>
-    <color name="accent_device_default_dark">#5D7A92</color>
+    <color name="accent_device_default_dark">#99ACCC</color>
 </resources>
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3babb6d..bf76fdb 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7182,6 +7182,21 @@
     // OS: Q
     QS_UI_MODE_NIGHT = 1706;
 
+    // OPEN: Settings > Pick SIM dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    DIALOG_SIM_LIST = 1707;
+
+    // OPEN: Settings > Pick SIM (that supports calling) dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    DIALOG_CALL_SIM_LIST = 1708;
+
+    // OPEN: Settings > Pick preferred SIM dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    DIALOG_PREFERRED_SIM_PICKER = 1709;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6e2c228..334262f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2504,7 +2504,7 @@
      *   registered.
      */
     @Override
-    public int getAccessibilityWindowId(IBinder windowToken) {
+    public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
         synchronized (mLock) {
             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
                 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId");
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 7f411d8..a2d3d4c 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -781,36 +781,46 @@
         @GuardedBy("mGlobalWhitelistStateLock")
         public ContentCaptureOptions getOptions(@UserIdInt int userId,
                 @NonNull String packageName) {
+            boolean packageWhitelisted;
+            ArraySet<ComponentName> whitelistedComponents = null;
             synchronized (mGlobalWhitelistStateLock) {
-                if (!isWhitelisted(userId, packageName)) {
-                    if (packageName.equals(mServicePackages.get(userId))) {
+                packageWhitelisted = isWhitelisted(userId, packageName);
+                if (!packageWhitelisted) {
+                    // Full package is not whitelisted: check individual components first
+                    whitelistedComponents = getWhitelistedComponents(userId, packageName);
+                    if (whitelistedComponents == null
+                            && packageName.equals(mServicePackages.get(userId))) {
+                        // No components whitelisted either, but let it go because it's the
+                        // service's own package
                         if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
                         return new ContentCaptureOptions(mDevCfgLoggingLevel);
                     }
-                    if (verbose) {
-                        Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
-                    }
+                }
+            } // synchronized
+
+            // Restrict what temporary services can whitelist
+            if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
+                if (!packageName.equals(mServicePackages.get(userId))) {
+                    Slog.w(mTag, "Ignoring package " + packageName + " while using temporary "
+                            + "service " + mServicePackages.get(userId));
                     return null;
                 }
-
-                final ArraySet<ComponentName> whitelistedComponents =
-                        getWhitelistedComponents(userId, packageName);
-                if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
-                    if (!packageName.equals(mServicePackages.get(userId))) {
-                        Slog.w(mTag, "Ignoring package " + packageName
-                                + " while using temporary service " + mServicePackages.get(userId));
-                        return null;
-                    }
-                }
-                final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
-                        mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
-                        mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
-                        whitelistedComponents);
-                if (verbose) {
-                    Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
-                }
-                return options;
             }
+
+            if (!packageWhitelisted && whitelistedComponents == null) {
+                // No can do!
+                if (verbose) {
+                    Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+                }
+                return null;
+            }
+
+            final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
+                    mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
+                    mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
+                    whitelistedComponents);
+            if (verbose) Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+            return options;
         }
 
         @Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 5a42e78..a7921b5 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -35,13 +35,11 @@
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
-import android.content.ContentCaptureOptions;
 import android.content.pm.ActivityPresentationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
@@ -60,7 +58,6 @@
 import android.view.contentcapture.DataRemovalRequest;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.WhitelistHelper;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.contentcapture.RemoteContentCaptureService.ContentCaptureServiceCallbacks;
@@ -97,12 +94,6 @@
             new ContentCaptureServiceRemoteCallback();
 
     /**
-     * List of packages that are whitelisted to be content captured.
-     */
-    @GuardedBy("mLock")
-    private final WhitelistHelper mWhitelistHelper = new WhitelistHelper();
-
-    /**
      * List of conditions keyed by package.
      */
     @GuardedBy("mLock")
@@ -131,6 +122,7 @@
      * Updates the reference to the remote service.
      */
     private void updateRemoteServiceLocked(boolean disabled) {
+        if (mMaster.verbose) Slog.v(TAG, "updateRemoteService(disabled=" + disabled + ")");
         if (mRemoteService != null) {
             if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): destroying old remote service");
             mRemoteService.destroy();
@@ -247,7 +239,8 @@
         final int displayId = activityPresentationInfo.displayId;
         final ComponentName componentName = activityPresentationInfo.componentName;
         final boolean whiteListed = mMaster.mGlobalContentCaptureOptions.isWhitelisted(mUserId,
-                componentName);
+                componentName) || mMaster.mGlobalContentCaptureOptions.isWhitelisted(mUserId,
+                        componentName.getPackageName());
         final ComponentName serviceComponentName = getServiceComponentName();
         final boolean enabled = isEnabledLocked();
         if (mMaster.mRequestsHistory != null) {
@@ -462,40 +455,6 @@
 
     @GuardedBy("mLock")
     @Nullable
-    ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
-        if (!mWhitelistHelper.isWhitelisted(packageName)) {
-            if (packageName.equals(getServicePackageName())) {
-                if (mMaster.verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
-                return new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel);
-            }
-            if (mMaster.verbose) {
-                Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
-            }
-            return null;
-        }
-
-        final ArraySet<ComponentName> whitelistedComponents = mWhitelistHelper
-                .getWhitelistedComponents(packageName);
-        if (Build.IS_USER && isTemporaryServiceSetLocked()) {
-            final String servicePackageName = getServicePackageName();
-            if (!packageName.equals(servicePackageName)) {
-                Slog.w(mTag, "Ignoring package " + packageName
-                        + " while using temporary service " + servicePackageName);
-                return null;
-            }
-        }
-        final ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
-                mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
-                mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
-                whitelistedComponents);
-        if (mMaster.verbose) {
-            Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
-        }
-        return options;
-    }
-
-    @GuardedBy("mLock")
-    @Nullable
     ArraySet<ContentCaptureCondition> getContentCaptureConditionsLocked(
             @NonNull String packageName) {
         return mConditionsByPkg.get(packageName);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 1bd367c..1fa62ce 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3152,7 +3152,7 @@
 
     void removeLocked(final int uid) {
         if (uid == Process.SYSTEM_UID) {
-            Slog.wtf(TAG, "removeLocked: Shouldn't for UID=" + uid);
+            // If a force-stop occurs for a system-uid package, ignore it.
             return;
         }
         boolean didRemove = false;
@@ -3247,7 +3247,7 @@
     // Only called for ephemeral apps
     void removeForStoppedLocked(final int uid) {
         if (uid == Process.SYSTEM_UID) {
-            Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid);
+            // If a force-stop occurs for a system-uid package, ignore it.
             return;
         }
         boolean didRemove = false;
@@ -3291,7 +3291,7 @@
 
     void removeUserLocked(int userHandle) {
         if (userHandle == UserHandle.USER_SYSTEM) {
-            Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for user=" + userHandle);
+            // If we're told we're removing the system user, ignore it.
             return;
         }
         boolean didRemove = false;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 3410d8d..44fc45e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -88,6 +88,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
@@ -3567,6 +3568,10 @@
                 return;
             }
             pw.println("Current Location Manager state:");
+            pw.print("  Current System Time: "
+                    + TimeUtils.logTimeOfDay(System.currentTimeMillis()));
+            pw.println(", Current Elapsed Time: "
+                    + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
             pw.println("  Current user: " + mCurrentUserId + " " + Arrays.toString(
                     mCurrentUserProfiles));
             pw.println("  Location mode: " + isLocationEnabled());
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index cc3b43a..c2b35c18 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -96,6 +96,7 @@
         "media.extractor", // system/bin/mediaextractor
         "media.metrics", // system/bin/mediametrics
         "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
+        "media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
         "com.android.bluetooth",  // Bluetooth service
         "/system/bin/statsd",  // Stats daemon
     };
@@ -108,6 +109,7 @@
             "android.hardware.graphics.allocator@2.0::IAllocator",
             "android.hardware.graphics.composer@2.1::IComposer",
             "android.hardware.health@2.0::IHealth",
+            "android.hardware.media.c2@1.0::IComponentStore",
             "android.hardware.media.omx@1.0::IOmx",
             "android.hardware.media.omx@1.0::IOmxStore",
             "android.hardware.sensors@1.0::ISensors",
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0271354..24f8fc2 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3830,8 +3830,11 @@
 
     void serviceTimeout(ProcessRecord proc) {
         String anrMessage = null;
-
         synchronized(mAm) {
+            if (proc.isDebugging()) {
+                // The app's being debugged, ignore timeout.
+                return;
+            }
             if (proc.executingServices.size() == 0 || proc.thread == null) {
                 return;
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0b60282..6da7f5f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7894,8 +7894,9 @@
         synchronized (this) {
             boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
             if (!isDebuggable) {
-                if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
-                    throw new SecurityException("Process not debuggable: " + app.packageName);
+                if (!app.isProfileableByShell()) {
+                    throw new SecurityException("Process not debuggable, "
+                            + "and not profileable by shell: " + app.packageName);
                 }
             }
             mProfileData.setProfileApp(processName);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 49930c1..e891e6e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1557,7 +1557,7 @@
                 mService.mBatteryStatsService.noteProcessAnr(processName, uid);
             }
 
-            if (isSilentAnr()) {
+            if (isSilentAnr() && !isDebugging()) {
                 kill("bg anr", true);
                 return;
             }
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 1820acf..ccd1db4 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -29,6 +29,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.AppGlobals;
 import android.app.IUidObserver;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
@@ -49,6 +50,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseSetArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -277,9 +279,9 @@
                     .append(", ")
                     .append("bgJobCountInMaxPeriod=").append(bgJobCountInMaxPeriod).append(", ")
                     .append("quotaCutoffTime=").append(quotaCutoffTimeElapsed).append(", ")
-                    .append("jobCountExpirationTime").append(jobCountExpirationTimeElapsed)
+                    .append("jobCountExpirationTime=").append(jobCountExpirationTimeElapsed)
                     .append(", ")
-                    .append("jobCountInAllowedTime").append(jobCountInAllowedTime)
+                    .append("jobCountInAllowedTime=").append(jobCountInAllowedTime)
                     .toString();
         }
 
@@ -338,6 +340,9 @@
     /** List of UIDs currently in the foreground. */
     private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
 
+    /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
+    private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
+
     /**
      * List of jobs that started while the UID was in the TOP state. There will be no more than
      * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
@@ -421,6 +426,22 @@
         }
     };
 
+    private final BroadcastReceiver mPackageAddedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                return;
+            }
+            final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+            synchronized (mLock) {
+                mUidToPackageCache.remove(uid);
+            }
+        }
+    };
+
     /**
      * The rolling window size for each standby bucket. Within each window, an app will have 10
      * minutes to run its jobs.
@@ -469,6 +490,9 @@
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
+        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
+
         // Set up the app standby bucketing tracker
         UsageStatsManagerInternal usageStats = LocalServices.getService(
                 UsageStatsManagerInternal.class);
@@ -502,10 +526,15 @@
 
     @Override
     public void prepareForExecutionLocked(JobStatus jobStatus) {
-        if (DEBUG) Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
+        if (DEBUG) {
+            Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
+        }
 
         final int uid = jobStatus.getSourceUid();
         if (mActivityManagerInternal.getUidProcessState(uid) <= ActivityManager.PROCESS_STATE_TOP) {
+            if (DEBUG) {
+                Slog.d(TAG, jobStatus.toShortString() + " is top started job");
+            }
             mTopStartedJobs.add(jobStatus);
             // Top jobs won't count towards quota so there's no need to involve the Timer.
             return;
@@ -518,7 +547,7 @@
             timer = new Timer(uid, userId, packageName);
             mPkgTimers.add(userId, packageName, timer);
         }
-        timer.startTrackingJob(jobStatus);
+        timer.startTrackingJobLocked(jobStatus);
     }
 
     @Override
@@ -645,7 +674,7 @@
         if (timer != null) {
             if (timer.isActive()) {
                 Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off.");
-                timer.dropEverything();
+                timer.dropEverythingLocked();
             }
             mPkgTimers.delete(userId, packageName);
         }
@@ -657,6 +686,7 @@
         }
         mExecutionStatsCache.delete(userId, packageName);
         mForegroundUids.delete(uid);
+        mUidToPackageCache.remove(uid);
     }
 
     @Override
@@ -666,6 +696,7 @@
         mTimingSessions.delete(userId);
         mInQuotaAlarmListeners.delete(userId);
         mExecutionStatsCache.delete(userId);
+        mUidToPackageCache.clear();
     }
 
     private boolean isUidInForeground(int uid) {
@@ -678,7 +709,7 @@
     }
 
     /** @return true if the job was started while the app was in the TOP state. */
-    private boolean isTopStartedJob(@NonNull final JobStatus jobStatus) {
+    private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) {
         return mTopStartedJobs.contains(jobStatus);
     }
 
@@ -695,14 +726,14 @@
         return jobStatus.getStandbyBucket();
     }
 
-    private boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
+    @VisibleForTesting
+    boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
         final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
-        Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
         // A job is within quota if one of the following is true:
         //   1. it was started while the app was in the TOP state
         //   2. the app is currently in the foreground
         //   3. the app overall is within its quota
-        return isTopStartedJob(jobStatus)
+        return isTopStartedJobLocked(jobStatus)
                 || isUidInForeground(jobStatus.getSourceUid())
                 || isWithinQuotaLocked(
                 jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
@@ -1081,7 +1112,9 @@
         if (earliestEndElapsed == Long.MAX_VALUE) {
             // Couldn't find a good time to clean up. Maybe this was called after we deleted all
             // timing sessions.
-            if (DEBUG) Slog.d(TAG, "Didn't find a time to schedule cleanup");
+            if (DEBUG) {
+                Slog.d(TAG, "Didn't find a time to schedule cleanup");
+            }
             return;
         }
         // Need to keep sessions for all apps up to the max period, regardless of their current
@@ -1095,15 +1128,19 @@
         mNextCleanupTimeElapsed = nextCleanupElapsed;
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextCleanupElapsed, ALARM_TAG_CLEANUP,
                 mSessionCleanupAlarmListener, mHandler);
-        if (DEBUG) Slog.d(TAG, "Scheduled next cleanup for " + mNextCleanupTimeElapsed);
+        if (DEBUG) {
+            Slog.d(TAG, "Scheduled next cleanup for " + mNextCleanupTimeElapsed);
+        }
     }
 
     private void handleNewChargingStateLocked() {
         final long nowElapsed = sElapsedRealtimeClock.millis();
         final boolean isCharging = mChargeTracker.isCharging();
-        if (DEBUG) Slog.d(TAG, "handleNewChargingStateLocked: " + isCharging);
+        if (DEBUG) {
+            Slog.d(TAG, "handleNewChargingStateLocked: " + isCharging);
+        }
         // Deal with Timers first.
-        mPkgTimers.forEach((t) -> t.onStateChanged(nowElapsed, isCharging));
+        mPkgTimers.forEach((t) -> t.onStateChangedLocked(nowElapsed, isCharging));
         // Now update jobs.
         maybeUpdateAllConstraintsLocked();
     }
@@ -1140,7 +1177,7 @@
         boolean changed = false;
         for (int i = jobs.size() - 1; i >= 0; --i) {
             final JobStatus js = jobs.valueAt(i);
-            if (isTopStartedJob(js)) {
+            if (isTopStartedJobLocked(js)) {
                 // Job was started while the app was in the TOP state so we should allow it to
                 // finish.
                 changed |= js.setQuotaConstraintSatisfied(true);
@@ -1282,7 +1319,9 @@
         if (!alarmListener.isWaiting()
                 || inQuotaTimeElapsed < alarmListener.getTriggerTimeElapsed() - 3 * MINUTE_IN_MILLIS
                 || alarmListener.getTriggerTimeElapsed() < inQuotaTimeElapsed) {
-            if (DEBUG) Slog.d(TAG, "Scheduling start alarm for " + pkgString);
+            if (DEBUG) {
+                Slog.d(TAG, "Scheduling start alarm for " + pkgString);
+            }
             // If the next time this app will have quota is at least 3 minutes before the
             // alarm is supposed to go off, reschedule the alarm.
             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, inQuotaTimeElapsed,
@@ -1430,8 +1469,8 @@
             mUid = uid;
         }
 
-        void startTrackingJob(@NonNull JobStatus jobStatus) {
-            if (isTopStartedJob(jobStatus)) {
+        void startTrackingJobLocked(@NonNull JobStatus jobStatus) {
+            if (isTopStartedJobLocked(jobStatus)) {
                 // We intentionally don't pay attention to fg state changes after a TOP job has
                 // started.
                 if (DEBUG) {
@@ -1440,27 +1479,28 @@
                 }
                 return;
             }
-            if (DEBUG) Slog.v(TAG, "Starting to track " + jobStatus.toShortString());
-            synchronized (mLock) {
-                // Always track jobs, even when charging.
-                mRunningBgJobs.add(jobStatus);
-                if (shouldTrackLocked()) {
-                    mBgJobCount++;
-                    incrementJobCount(mPkg.userId, mPkg.packageName, 1);
-                    if (mRunningBgJobs.size() == 1) {
-                        // Started tracking the first job.
-                        mStartTimeElapsed = sElapsedRealtimeClock.millis();
-                        // Starting the timer means that all cached execution stats are now
-                        // incorrect.
-                        invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
-                        scheduleCutoff();
-                    }
+            if (DEBUG) {
+                Slog.v(TAG, "Starting to track " + jobStatus.toShortString());
+            }
+            // Always track jobs, even when charging.
+            mRunningBgJobs.add(jobStatus);
+            if (shouldTrackLocked()) {
+                mBgJobCount++;
+                incrementJobCount(mPkg.userId, mPkg.packageName, 1);
+                if (mRunningBgJobs.size() == 1) {
+                    // Started tracking the first job.
+                    mStartTimeElapsed = sElapsedRealtimeClock.millis();
+                    // Starting the timer means that all cached execution stats are now incorrect.
+                    invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
+                    scheduleCutoff();
                 }
             }
         }
 
         void stopTrackingJob(@NonNull JobStatus jobStatus) {
-            if (DEBUG) Slog.v(TAG, "Stopping tracking of " + jobStatus.toShortString());
+            if (DEBUG) {
+                Slog.v(TAG, "Stopping tracking of " + jobStatus.toShortString());
+            }
             synchronized (mLock) {
                 if (mRunningBgJobs.size() == 0) {
                     // maybeStopTrackingJobLocked can be called when an app cancels a job, so a
@@ -1482,7 +1522,7 @@
          * Stops tracking all jobs and cancels any pending alarms. This should only be called if
          * the Timer is not going to be used anymore.
          */
-        void dropEverything() {
+        void dropEverythingLocked() {
             mRunningBgJobs.clear();
             cancelCutoff();
         }
@@ -1531,25 +1571,23 @@
             return !mChargeTracker.isCharging() && !mForegroundUids.get(mUid);
         }
 
-        void onStateChanged(long nowElapsed, boolean isQuotaFree) {
-            synchronized (mLock) {
-                if (isQuotaFree) {
-                    emitSessionLocked(nowElapsed);
-                } else if (shouldTrackLocked()) {
-                    // Start timing from unplug.
-                    if (mRunningBgJobs.size() > 0) {
-                        mStartTimeElapsed = nowElapsed;
-                        // NOTE: this does have the unfortunate consequence that if the device is
-                        // repeatedly plugged in and unplugged, or an app changes foreground state
-                        // very frequently, the job count for a package may be artificially high.
-                        mBgJobCount = mRunningBgJobs.size();
-                        incrementJobCount(mPkg.userId, mPkg.packageName, mBgJobCount);
-                        // Starting the timer means that all cached execution stats are now
-                        // incorrect.
-                        invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
-                        // Schedule cutoff since we're now actively tracking for quotas again.
-                        scheduleCutoff();
-                    }
+        void onStateChangedLocked(long nowElapsed, boolean isQuotaFree) {
+            if (isQuotaFree) {
+                emitSessionLocked(nowElapsed);
+            } else if (!isActive() && shouldTrackLocked()) {
+                // Start timing from unplug.
+                if (mRunningBgJobs.size() > 0) {
+                    mStartTimeElapsed = nowElapsed;
+                    // NOTE: this does have the unfortunate consequence that if the device is
+                    // repeatedly plugged in and unplugged, or an app changes foreground state
+                    // very frequently, the job count for a package may be artificially high.
+                    mBgJobCount = mRunningBgJobs.size();
+                    incrementJobCount(mPkg.userId, mPkg.packageName, mBgJobCount);
+                    // Starting the timer means that all cached execution stats are now
+                    // incorrect.
+                    invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
+                    // Schedule cutoff since we're now actively tracking for quotas again.
+                    scheduleCutoff();
                 }
             }
         }
@@ -1604,7 +1642,6 @@
                     pw.println(js.toShortString());
                 }
             }
-
             pw.decreaseIndent();
         }
 
@@ -1667,7 +1704,9 @@
         @Override
         public void onParoleStateChanged(final boolean isParoleOn) {
             mInParole = isParoleOn;
-            if (DEBUG) Slog.i(TAG, "Global parole state now " + (isParoleOn ? "ON" : "OFF"));
+            if (DEBUG) {
+                Slog.i(TAG, "Global parole state now " + (isParoleOn ? "ON" : "OFF"));
+            }
             // Update job bookkeeping out of band.
             BackgroundThread.getHandler().post(() -> {
                 synchronized (mLock) {
@@ -1712,7 +1751,9 @@
                 switch (msg.what) {
                     case MSG_REACHED_QUOTA: {
                         Package pkg = (Package) msg.obj;
-                        if (DEBUG) Slog.d(TAG, "Checking if " + pkg + " has reached its quota.");
+                        if (DEBUG) {
+                            Slog.d(TAG, "Checking if " + pkg + " has reached its quota.");
+                        }
 
                         long timeRemainingMs = getRemainingExecutionTimeLocked(pkg.userId,
                                 pkg.packageName);
@@ -1737,7 +1778,9 @@
                         break;
                     }
                     case MSG_CLEAN_UP_SESSIONS:
-                        if (DEBUG) Slog.d(TAG, "Cleaning up timing sessions.");
+                        if (DEBUG) {
+                            Slog.d(TAG, "Cleaning up timing sessions.");
+                        }
                         deleteObsoleteSessionsLocked();
                         maybeScheduleCleanupAlarmLocked();
 
@@ -1745,7 +1788,9 @@
                     case MSG_CHECK_PACKAGE: {
                         String packageName = (String) msg.obj;
                         int userId = msg.arg1;
-                        if (DEBUG) Slog.d(TAG, "Checking pkg " + string(userId, packageName));
+                        if (DEBUG) {
+                            Slog.d(TAG, "Checking pkg " + string(userId, packageName));
+                        }
                         if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
                             mStateChangedListener.onControllerStateChanged();
                         }
@@ -1767,13 +1812,28 @@
                                 isQuotaFree = false;
                             }
                             // Update Timers first.
-                            final int userIndex = mPkgTimers.indexOfKey(userId);
-                            if (userIndex != -1) {
-                                final int numPkgs = mPkgTimers.numPackagesForUser(userId);
-                                for (int p = 0; p < numPkgs; ++p) {
-                                    Timer t = mPkgTimers.valueAt(userIndex, p);
-                                    if (t != null) {
-                                        t.onStateChanged(nowElapsed, isQuotaFree);
+                            if (mPkgTimers.indexOfKey(userId) >= 0) {
+                                ArraySet<String> packages = mUidToPackageCache.get(uid);
+                                if (packages == null) {
+                                    try {
+                                        String[] pkgs = AppGlobals.getPackageManager()
+                                                .getPackagesForUid(uid);
+                                        if (pkgs != null) {
+                                            for (String pkg : pkgs) {
+                                                mUidToPackageCache.add(uid, pkg);
+                                            }
+                                            packages = mUidToPackageCache.get(uid);
+                                        }
+                                    } catch (RemoteException e) {
+                                        Slog.wtf(TAG, "Failed to get package list", e);
+                                    }
+                                }
+                                if (packages != null) {
+                                    for (int i = packages.size() - 1; i >= 0; --i) {
+                                        Timer t = mPkgTimers.get(userId, packages.valueAt(i));
+                                        if (t != null) {
+                                            t.onStateChangedLocked(nowElapsed, isQuotaFree);
+                                        }
                                     }
                                 }
                             }
@@ -1883,6 +1943,17 @@
         pw.println(mForegroundUids.toString());
         pw.println();
 
+        pw.println("Cached UID->package map:");
+        pw.increaseIndent();
+        for (int i = 0; i < mUidToPackageCache.size(); ++i) {
+            final int uid = mUidToPackageCache.keyAt(i);
+            pw.print(uid);
+            pw.print(": ");
+            pw.println(mUidToPackageCache.get(uid));
+        }
+        pw.decreaseIndent();
+        pw.println();
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
@@ -1936,6 +2007,29 @@
                 }
             }
         }
+
+        pw.println("Cached execution stats:");
+        pw.increaseIndent();
+        for (int u = 0; u < mExecutionStatsCache.numUsers(); ++u) {
+            final int userId = mExecutionStatsCache.keyAt(u);
+            for (int p = 0; p < mExecutionStatsCache.numPackagesForUser(userId); ++p) {
+                final String pkgName = mExecutionStatsCache.keyAt(u, p);
+                ExecutionStats[] stats = mExecutionStatsCache.valueAt(u, p);
+
+                pw.println(string(userId, pkgName));
+                pw.increaseIndent();
+                for (int i = 0; i < stats.length; ++i) {
+                    ExecutionStats executionStats = stats[i];
+                    if (executionStats != null) {
+                        pw.print(JobStatus.bucketName(i));
+                        pw.print(": ");
+                        pw.println(executionStats);
+                    }
+                }
+                pw.decreaseIndent();
+            }
+        }
+        pw.decreaseIndent();
     }
 
     @Override
@@ -1995,6 +2089,49 @@
                     }
                 }
 
+                ExecutionStats[] stats = mExecutionStatsCache.get(userId, pkgName);
+                if (stats != null) {
+                    for (int bucketIndex = 0; bucketIndex < stats.length; ++bucketIndex) {
+                        ExecutionStats es = stats[bucketIndex];
+                        if (es == null) {
+                            continue;
+                        }
+                        final long esToken = proto.start(
+                                StateControllerProto.QuotaController.PackageStats.EXECUTION_STATS);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.STANDBY_BUCKET,
+                                bucketIndex);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.EXPIRATION_TIME_ELAPSED,
+                                es.expirationTimeElapsed);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.WINDOW_SIZE_MS,
+                                es.windowSizeMs);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.EXECUTION_TIME_IN_WINDOW_MS,
+                                es.executionTimeInWindowMs);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.BG_JOB_COUNT_IN_WINDOW,
+                                es.bgJobCountInWindow);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.EXECUTION_TIME_IN_MAX_PERIOD_MS,
+                                es.executionTimeInMaxPeriodMs);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.BG_JOB_COUNT_IN_MAX_PERIOD,
+                                es.bgJobCountInMaxPeriod);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.QUOTA_CUTOFF_TIME_ELAPSED,
+                                es.quotaCutoffTimeElapsed);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.JOB_COUNT_EXPIRATION_TIME_ELAPSED,
+                                es.jobCountExpirationTimeElapsed);
+                        proto.write(
+                                StateControllerProto.QuotaController.ExecutionStats.JOB_COUNT_IN_ALLOWED_TIME,
+                                es.jobCountInAllowedTime);
+                        proto.end(esToken);
+                    }
+                }
+
                 proto.end(psToken);
             }
         }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 96fc6ec..ec0f8b8 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -66,6 +66,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.StatsLog;
+import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
@@ -332,9 +333,16 @@
     // true if low power mode for the GNSS chipset is part of the latest request.
     private boolean mLowPowerMode = false;
 
-    // true if we started navigation
+    // true if we started navigation in the HAL, only change value of this in setStarted
     private boolean mStarted;
 
+    // for logging of latest change, and warning of ongoing location after a stop
+    private long mStartedChangedElapsedRealtime;
+
+    // threshold for delay in GNSS engine turning off before warning & error
+    private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
+    private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
+
     // capabilities reported through the top level IGnssCallback.hal
     private volatile int mTopHalCapabilities;
 
@@ -927,6 +935,9 @@
             mGnssMeasurementsProvider.onGpsEnabledChanged();
             mGnssNavigationMessageProvider.onGpsEnabledChanged();
             mGnssBatchingProvider.enable();
+            if (mGnssVisibilityControl != null) {
+                mGnssVisibilityControl.onGpsEnabledChanged(mEnabled);
+            }
         } else {
             mEnabled = false;
             Log.w(TAG, "Failed to enable location provider");
@@ -943,6 +954,9 @@
         mAlarmManager.cancel(mWakeupIntent);
         mAlarmManager.cancel(mTimeoutIntent);
 
+        if (mGnssVisibilityControl != null) {
+            mGnssVisibilityControl.onGpsEnabledChanged(mEnabled);
+        }
         mGnssBatchingProvider.disable();
         // do this before releasing wakelock
         native_cleanup();
@@ -1192,7 +1206,7 @@
             if (DEBUG) Log.d(TAG, "startNavigating");
             mTimeToFirstFix = 0;
             mLastFixTime = 0;
-            mStarted = true;
+            setStarted(true);
             mPositionMode = GPS_POSITION_MODE_STANDALONE;
             // Notify about suppressed output, if speed limit was previously exceeded.
             // Elsewhere, we check again with every speed output reported.
@@ -1230,12 +1244,12 @@
             mLowPowerMode = mProviderRequest.lowPowerMode;
             if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
                     interval, 0, 0, mLowPowerMode)) {
-                mStarted = false;
+                setStarted(false);
                 Log.e(TAG, "set_position_mode failed in startNavigating()");
                 return;
             }
             if (!native_start()) {
-                mStarted = false;
+                setStarted(false);
                 Log.e(TAG, "native_start failed in startNavigating()");
                 return;
             }
@@ -1258,7 +1272,7 @@
     private void stopNavigating() {
         if (DEBUG) Log.d(TAG, "stopNavigating");
         if (mStarted) {
-            mStarted = false;
+            setStarted(false);
             native_stop();
             mLastFixTime = 0;
             // native_stop() may reset the position mode in hardware.
@@ -1270,6 +1284,13 @@
         }
     }
 
+    private void setStarted(boolean started) {
+        if (mStarted != started) {
+            mStarted = started;
+            mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime();
+        }
+    }
+
     private void hibernate() {
         // stop GPS until our next fix interval arrives
         stopNavigating();
@@ -1319,6 +1340,21 @@
                     mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
                 }
             }
+        } else {
+            // Warn or error about long delayed GNSS engine shutdown as this generally wastes
+            // power and sends location when not expected.
+            long locationAfterStartedFalseMillis =
+                    SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime;
+            if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) {
+                String logMessage = "Unexpected GNSS Location report "
+                        + TimeUtils.formatDuration(locationAfterStartedFalseMillis)
+                        + " after location turned off";
+                if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) {
+                    Log.e(TAG, logMessage);
+                } else {
+                    Log.w(TAG, logMessage);
+                }
+            }
         }
 
         mLastFixTime = SystemClock.elapsedRealtime();
@@ -1538,7 +1574,7 @@
 
     private void restartLocationRequest() {
         if (DEBUG) Log.d(TAG, "restartLocationRequest");
-        mStarted = false;
+        setStarted(false);
         updateRequirements();
     }
 
@@ -2152,7 +2188,10 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         StringBuilder s = new StringBuilder();
-        s.append("  mStarted=").append(mStarted).append('\n');
+        s.append("  mStarted=").append(mStarted).append("   (changed ");
+        TimeUtils.formatDuration(SystemClock.elapsedRealtime()
+                - mStartedChangedElapsedRealtime, s);
+        s.append(" ago)").append('\n');
         s.append("  mFixInterval=").append(mFixInterval).append('\n');
         s.append("  mLowPowerMode=").append(mLowPowerMode).append('\n');
         s.append("  mGnssMeasurementsProvider.isRegistered()=")
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index 24ee389..60be70e 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -23,13 +23,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.location.LocationManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -49,18 +46,14 @@
     private static final String TAG = "GnssVisibilityControl";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    // Constants related to non-framework (NFW) location access permission proxy apps.
-    private static final String NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX =
-            ".NonFrameworkLocationAccessActivity";
-    private static final String NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX =
-            ".intent.action.NON_FRAMEWORK_LOCATION_ACCESS";
-    private static final String NFW_INTENT_TYPE = "text/plain";
-
     private static final String LOCATION_PERMISSION_NAME =
             "android.permission.ACCESS_FINE_LOCATION";
 
     private static final String[] NO_LOCATION_ENABLED_PROXY_APPS = new String[0];
 
+    // Max wait time for synchronous method onGpsEnabledChanged() to run.
+    private static final long ON_GPS_ENABLED_CHANGED_TIMEOUT_MILLIS = 3 * 1000;
+
     // Wakelocks
     private static final String WAKELOCK_KEY = TAG;
     private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
@@ -72,7 +65,7 @@
     private final Handler mHandler;
     private final Context mContext;
 
-    private boolean mIsDeviceLocationSettingsEnabled;
+    private boolean mIsGpsEnabled;
 
     // Number of non-framework location access proxy apps is expected to be small (< 5).
     private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -95,6 +88,30 @@
         runOnHandler(this::handleInitialize);
     }
 
+    void onGpsEnabledChanged(boolean isEnabled) {
+        // The GnssLocationProvider's methods: handleEnable() calls this method after native_init()
+        // and handleDisable() calls this method before native_cleanup(). This method must be
+        // executed synchronously so that the NFW location access permissions are disabled in
+        // the HAL before native_cleanup() method is called.
+        //
+        // NOTE: Since improper use of runWithScissors() method can result in deadlocks, the method
+        // doc recommends limiting its use to cases where some initialization steps need to be
+        // executed in sequence before continuing which fits this scenario.
+        if (mHandler.runWithScissors(() -> handleGpsEnabledChanged(isEnabled),
+                ON_GPS_ENABLED_CHANGED_TIMEOUT_MILLIS)) {
+            return;
+        }
+
+        // After timeout, the method remains posted in the queue and hence future enable/disable
+        // calls to this method will all get executed in the correct sequence. But this timeout
+        // situation should not even arise because runWithScissors() will run in the caller's
+        // thread without blocking as it is the same thread as mHandler's thread.
+        if (!isEnabled) {
+            Log.w(TAG, "Native call to disable non-framework location access in GNSS HAL may"
+                    + " get executed after native_cleanup().");
+        }
+    }
+
     void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
         runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
     }
@@ -110,12 +127,6 @@
     private void handleInitialize() {
         disableNfwLocationAccess(); // Disable until config properties are loaded.
         listenForProxyAppsPackageUpdates();
-        listenForDeviceLocationSettingsUpdate();
-        mIsDeviceLocationSettingsEnabled = getDeviceLocationSettings();
-    }
-
-    private boolean getDeviceLocationSettings() {
-        return mContext.getSystemService(LocationManager.class).isLocationEnabled();
     }
 
     private void listenForProxyAppsPackageUpdates() {
@@ -145,18 +156,6 @@
         }, UserHandle.ALL, intentFilter, null, mHandler);
     }
 
-    private void listenForDeviceLocationSettingsUpdate() {
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
-                true,
-                new ContentObserver(mHandler) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        handleDeviceLocationSettingsUpdated();
-                    }
-                }, UserHandle.USER_ALL);
-    }
-
     private void handleProxyAppPackageUpdate(String pkgName, String action) {
         final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName);
         if (locationPermission == null) {
@@ -213,22 +212,21 @@
         return false;
     }
 
-    private void handleDeviceLocationSettingsUpdated() {
-        final boolean enabled = getDeviceLocationSettings();
-        Log.i(TAG, "Device location settings enabled: " + enabled);
+    private void handleGpsEnabledChanged(boolean isEnabled) {
+        if (DEBUG) Log.d(TAG, "handleGpsEnabledChanged, isEnabled: " + isEnabled);
 
-        if (mIsDeviceLocationSettingsEnabled == enabled) {
+        if (mIsGpsEnabled == isEnabled) {
             return;
         }
 
-        mIsDeviceLocationSettingsEnabled = enabled;
-        if (!mIsDeviceLocationSettingsEnabled) {
+        mIsGpsEnabled = isEnabled;
+        if (!mIsGpsEnabled) {
             disableNfwLocationAccess();
             return;
         }
 
-        // When device location settings was disabled, we already set the proxy app list
-        // to empty in GNSS HAL. Update only if the proxy app list is not empty.
+        // When GNSS was disabled, we already set the proxy app list to empty in GNSS HAL.
+        // Update only if the proxy app list is not empty.
         String[] locationPermissionEnabledProxyApps = getLocationPermissionEnabledProxyApps();
         if (locationPermissionEnabledProxyApps.length != 0) {
             setNfwLocationAccessProxyAppsInGnssHal(locationPermissionEnabledProxyApps);
@@ -335,7 +333,7 @@
     }
 
     private void updateNfwLocationAccessProxyAppsInGnssHal() {
-        if (!mIsDeviceLocationSettingsEnabled) {
+        if (!mIsGpsEnabled) {
             return; // Keep non-framework location access disabled.
         }
         setNfwLocationAccessProxyAppsInGnssHal(getLocationPermissionEnabledProxyApps());
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2e8e65b..e5ecd49 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2863,8 +2863,7 @@
 
             // Reset notification preferences
             if (!fromApp) {
-                mPreferencesHelper.onPackagesChanged(
-                        true, UserHandle.getCallingUserId(), packages, uids);
+                mPreferencesHelper.clearData(packageName, uid);
             }
 
             handleSavePolicyFile();
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 642fa7f..9e16632 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1717,6 +1717,23 @@
         }
     }
 
+    public void clearData(String pkg, int uid) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences p = getPackagePreferencesLocked(pkg, uid);
+            if (p != null) {
+                p.channels = new ArrayMap<>();
+                p.groups = new ArrayMap<>();
+                p.delegate = null;
+                p.lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+                p.allowBubble = DEFAULT_ALLOW_BUBBLE;
+                p.importance = DEFAULT_IMPORTANCE;
+                p.priority = DEFAULT_PRIORITY;
+                p.visibility = DEFAULT_VISIBILITY;
+                p.showBadge = DEFAULT_SHOW_BADGE;
+            }
+        }
+    }
+
     private LogMaker getChannelLog(NotificationChannel channel, String pkg) {
         return new LogMaker(
                 com.android.internal.logging.nano.MetricsProto.MetricsEvent
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 1edb93a..27f3387 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -455,7 +455,8 @@
         // Add in all the apps for every user/profile.
         for (UserInfo profile : users) {
             List<PackageInfo> pi =
-                    pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES, profile.id);
+                    pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES
+                            | PackageManager.MATCH_APEX, profile.id);
             for (int j = 0; j < pi.size(); j++) {
                 if (pi.get(j).applicationInfo != null) {
                     String installer;
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index a7a793f..767327a 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -102,7 +102,9 @@
         }
 
         void removeSurface() {
-            getPendingTransaction().remove(mDimLayer);
+            if (mDimLayer != null && mDimLayer.isValid()) {
+                getPendingTransaction().remove(mDimLayer);
+            }
             mDimLayer = null;
         }
     }
@@ -305,7 +307,9 @@
 
         if (!mDimState.mDimming) {
             if (!mDimState.mAnimateExit) {
-                t.remove(mDimState.mDimLayer);
+                if (mDimState.mDimLayer.isValid()) {
+                    t.remove(mDimState.mDimLayer);
+                }
             } else {
                 startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index bd874ba..a57dd6d 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -822,6 +822,10 @@
                         (int) attrs.hideTimeoutMilliseconds,
                         AccessibilityManager.FLAG_CONTENT_TEXT);
                 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
+                // Toast can show with below conditions when the screen is locked.
+                if (canToastShowWhenLocked(callingPid)) {
+                    attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+                }
                 break;
         }
 
@@ -832,6 +836,16 @@
     }
 
     /**
+     * @return {@code true} if the calling activity initiate toast and is visible with
+     * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
+     */
+    boolean canToastShowWhenLocked(int callingPid) {
+        return mDisplayContent.forAllWindows(w -> {
+            return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
+        }, true /* traverseTopToBottom */);
+    }
+
+    /**
      * Preflight adding a window to the system.
      *
      * Currently enforces that three window types are singletons per display:
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 08f6a37..f492d13 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -58,6 +58,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
@@ -224,50 +225,55 @@
     }
 
     private void setProcessState(int procState) {
+        setProcessState(procState, mSourceUid);
+    }
+
+    private void setProcessState(int procState, int uid) {
         try {
-            doReturn(procState).when(mActivityMangerInternal).getUidProcessState(mSourceUid);
+            doReturn(procState).when(mActivityMangerInternal).getUidProcessState(uid);
             SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
             spyOn(foregroundUids);
-            mUidObserver.onUidStateChanged(mSourceUid, procState, 0);
+            mUidObserver.onUidStateChanged(uid, procState, 0);
             if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-                verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1))
-                        .put(eq(mSourceUid), eq(true));
-                assertTrue(foregroundUids.get(mSourceUid));
+                verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
+                        .put(eq(uid), eq(true));
+                assertTrue(foregroundUids.get(uid));
             } else {
-                verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1)).delete(eq(mSourceUid));
-                assertFalse(foregroundUids.get(mSourceUid));
+                verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1)).delete(eq(uid));
+                assertFalse(foregroundUids.get(uid));
             }
         } catch (RemoteException e) {
             fail("registerUidObserver threw exception: " + e.getMessage());
         }
     }
 
-    private void setStandbyBucket(int bucketIndex) {
-        int bucket;
+    private int bucketIndexToUsageStatsBucket(int bucketIndex) {
         switch (bucketIndex) {
             case ACTIVE_INDEX:
-                bucket = UsageStatsManager.STANDBY_BUCKET_ACTIVE;
-                break;
+                return UsageStatsManager.STANDBY_BUCKET_ACTIVE;
             case WORKING_INDEX:
-                bucket = UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
-                break;
+                return UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
             case FREQUENT_INDEX:
-                bucket = UsageStatsManager.STANDBY_BUCKET_FREQUENT;
-                break;
+                return UsageStatsManager.STANDBY_BUCKET_FREQUENT;
             case RARE_INDEX:
-                bucket = UsageStatsManager.STANDBY_BUCKET_RARE;
-                break;
+                return UsageStatsManager.STANDBY_BUCKET_RARE;
             default:
-                bucket = UsageStatsManager.STANDBY_BUCKET_NEVER;
+                return UsageStatsManager.STANDBY_BUCKET_NEVER;
         }
+    }
+
+    private void setStandbyBucket(int bucketIndex) {
         when(mUsageStatsManager.getAppStandbyBucket(eq(SOURCE_PACKAGE), eq(SOURCE_USER_ID),
-                anyLong())).thenReturn(bucket);
+                anyLong())).thenReturn(bucketIndexToUsageStatsBucket(bucketIndex));
     }
 
     private void setStandbyBucket(int bucketIndex, JobStatus... jobs) {
         setStandbyBucket(bucketIndex);
         for (JobStatus job : jobs) {
             job.setStandbyBucket(bucketIndex);
+            when(mUsageStatsManager.getAppStandbyBucket(
+                    eq(job.getSourcePackageName()), eq(job.getSourceUserId()), anyLong()))
+                    .thenReturn(bucketIndexToUsageStatsBucket(bucketIndex));
         }
     }
 
@@ -283,8 +289,13 @@
                 new ComponentName(mContext, "TestQuotaJobService"))
                 .setMinimumLatency(Math.abs(jobId) + 1)
                 .build();
+        return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
+    }
+
+    private JobStatus createJobStatus(String testTag, String packageName, int callingUid,
+            JobInfo jobInfo) {
         JobStatus js = JobStatus.createFromJobInfo(
-                jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+                jobInfo, callingUid, packageName, SOURCE_USER_ID, testTag);
         // Make sure tests aren't passing just because the default bucket is likely ACTIVE.
         js.setStandbyBucket(FREQUENT_INDEX);
         return js;
@@ -935,6 +946,115 @@
     }
 
     @Test
+    public void testIsWithinQuotaLocked_UnderDuration_UnderJobCount_MultiStateChange_BelowFGS() {
+        setDischarging();
+
+        JobStatus jobStatus = createJobStatus(
+                "testIsWithinQuotaLocked_UnderDuration_UnderJobCount_MultiStateChange_BelowFGS", 1);
+        setStandbyBucket(ACTIVE_INDEX, jobStatus);
+        setProcessState(ActivityManager.PROCESS_STATE_BACKUP);
+
+        mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        mQuotaController.prepareForExecutionLocked(jobStatus);
+        for (int i = 0; i < 20; ++i) {
+            advanceElapsedClock(SECOND_IN_MILLIS);
+            setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+            setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        }
+        mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+
+        advanceElapsedClock(15 * SECOND_IN_MILLIS);
+
+        mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        mQuotaController.prepareForExecutionLocked(jobStatus);
+        for (int i = 0; i < 20; ++i) {
+            advanceElapsedClock(SECOND_IN_MILLIS);
+            setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+            setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+        }
+        mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+
+        advanceElapsedClock(10 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS);
+
+        assertEquals(2, mQuotaController.getExecutionStatsLocked(
+                SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX).jobCountInAllowedTime);
+        assertTrue(mQuotaController.isWithinQuotaLocked(jobStatus));
+    }
+
+    @Test
+    public void testIsWithinQuotaLocked_UnderDuration_UnderJobCount_MultiStateChange_SeparateApps()
+            throws Exception {
+        setDischarging();
+
+        final String unaffectedPkgName = "com.android.unaffected";
+        final int unaffectedUid = 10987;
+        JobInfo unaffectedJobInfo = new JobInfo.Builder(1,
+                new ComponentName(unaffectedPkgName, "foo"))
+                .build();
+        JobStatus unaffected = createJobStatus(
+                "testIsWithinQuotaLocked_UnderDuration_UnderJobCount_MultiStateChange_SeparateApps",
+                unaffectedPkgName, unaffectedUid, unaffectedJobInfo);
+        setStandbyBucket(FREQUENT_INDEX, unaffected);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE, unaffectedUid);
+
+        final String fgChangerPkgName = "com.android.foreground.changer";
+        final int fgChangerUid = 10234;
+        JobInfo fgChangerJobInfo = new JobInfo.Builder(2,
+                new ComponentName(fgChangerPkgName, "foo"))
+                .build();
+        JobStatus fgStateChanger = createJobStatus(
+                "testIsWithinQuotaLocked_UnderDuration_UnderJobCount_MultiStateChange_SeparateApps",
+                fgChangerPkgName, fgChangerUid, fgChangerJobInfo);
+        setStandbyBucket(ACTIVE_INDEX, fgStateChanger);
+        setProcessState(ActivityManager.PROCESS_STATE_BACKUP, fgChangerUid);
+
+        IPackageManager packageManager = AppGlobals.getPackageManager();
+        spyOn(packageManager);
+        doReturn(new String[]{unaffectedPkgName})
+                .when(packageManager).getPackagesForUid(unaffectedUid);
+        doReturn(new String[]{fgChangerPkgName})
+                .when(packageManager).getPackagesForUid(fgChangerUid);
+
+        mQuotaController.maybeStartTrackingJobLocked(unaffected, null);
+        mQuotaController.prepareForExecutionLocked(unaffected);
+
+        mQuotaController.maybeStartTrackingJobLocked(fgStateChanger, null);
+        mQuotaController.prepareForExecutionLocked(fgStateChanger);
+        for (int i = 0; i < 20; ++i) {
+            advanceElapsedClock(SECOND_IN_MILLIS);
+            setProcessState(ActivityManager.PROCESS_STATE_TOP, fgChangerUid);
+            setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING, fgChangerUid);
+        }
+        mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false);
+
+        advanceElapsedClock(15 * SECOND_IN_MILLIS);
+
+        mQuotaController.maybeStartTrackingJobLocked(fgStateChanger, null);
+        mQuotaController.prepareForExecutionLocked(fgStateChanger);
+        for (int i = 0; i < 20; ++i) {
+            advanceElapsedClock(SECOND_IN_MILLIS);
+            setProcessState(ActivityManager.PROCESS_STATE_TOP, fgChangerUid);
+            setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING, fgChangerUid);
+        }
+        mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false);
+
+        mQuotaController.maybeStopTrackingJobLocked(unaffected, null, false);
+
+        assertTrue(mQuotaController.isWithinQuotaLocked(unaffected));
+        assertFalse(mQuotaController.isWithinQuotaLocked(fgStateChanger));
+        assertEquals(1,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, unaffectedPkgName).size());
+        assertEquals(42,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, fgChangerPkgName).size());
+        for (int i = ACTIVE_INDEX; i < RARE_INDEX; ++i) {
+            assertEquals(42, mQuotaController.getExecutionStatsLocked(
+                    SOURCE_USER_ID, fgChangerPkgName, i).jobCountInAllowedTime);
+            assertEquals(1, mQuotaController.getExecutionStatsLocked(
+                    SOURCE_USER_ID, unaffectedPkgName, i).jobCountInAllowedTime);
+        }
+    }
+
+    @Test
     public void testMaybeScheduleCleanupAlarmLocked() {
         // No sessions saved yet.
         mQuotaController.maybeScheduleCleanupAlarmLocked();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index b34bd25..1a06490 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -1644,6 +1644,38 @@
     }
 
     @Test
+    public void testClearData() {
+        ArraySet<String> pkg = new ArraySet<>();
+        pkg.add(PKG_O);
+        mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
+        mHelper.createNotificationChannelGroup(
+                PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true);
+        mHelper.lockChannelsForOEM(pkg.toArray(new String[]{}));
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkg);
+        mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1);
+        mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
+        mHelper.setBubblesAllowed(PKG_O, UID_O, false);
+        mHelper.setShowBadge(PKG_O, UID_O, false);
+        mHelper.setAppImportanceLocked(PKG_O, UID_O);
+
+        mHelper.clearData(PKG_O, UID_O);
+
+        assertEquals(IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_O, UID_O));
+        assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
+        assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
+        assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+        assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
+        assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size());
+
+        NotificationChannel channel = getChannel();
+        mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+
+        assertTrue(channel.isImportanceLockedByCriticalDeviceFunction());
+        assertTrue(channel.isImportanceLockedByOEM());
+    }
+
+    @Test
     public void testRecordDefaults() throws Exception {
         assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
                 UID_N_MR1));
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index bfda2ea..5136705 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -42,6 +42,7 @@
                  android:testOnly="true"
                  android:largeHeap="true">
         <uses-library android:name="android.test.mock" android:required="true" />
+        <uses-library android:name="android.test.runner" />
 
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityA" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityB" />
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 5b32fe6..292a05b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -27,6 +27,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.when;
 
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -78,7 +79,9 @@
 
             @Override
             public SurfaceControl build() {
-                return mock(SurfaceControl.class);
+                SurfaceControl mSc = mock(SurfaceControl.class);
+                when(mSc.isValid()).thenReturn(true);
+                return mSc;
             }
         }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 07dd93c..1684f97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -22,13 +22,17 @@
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -38,6 +42,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.spy;
@@ -232,4 +237,40 @@
                     displayRotation, Surface.ROTATION_0, Surface.ROTATION_90));
         }
     }
+
+    @Test
+    public void testShouldShowToastWhenScreenLocked() {
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        final WindowState activity = createApplicationWindow();
+        final WindowState toast = createToastWindow();
+
+        synchronized (mWm.mGlobalLock) {
+            policy.adjustWindowParamsLw(
+                    toast, toast.mAttrs, 0 /* callingPid */, 0 /* callingUid */);
+
+            assertTrue(policy.canToastShowWhenLocked(0 /* callingUid */));
+            assertNotEquals(0, toast.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED);
+        }
+    }
+
+    private WindowState createToastWindow() {
+        final WindowState win = createWindow(null, TYPE_TOAST, "Toast");
+        final WindowManager.LayoutParams attrs = win.mAttrs;
+        attrs.width = WRAP_CONTENT;
+        attrs.height = WRAP_CONTENT;
+        attrs.flags = FLAG_KEEP_SCREEN_ON | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE;
+        attrs.format = PixelFormat.TRANSLUCENT;
+        return win;
+    }
+
+    private WindowState createApplicationWindow() {
+        final WindowState win = createWindow(null, TYPE_APPLICATION, "Application");
+        final WindowManager.LayoutParams attrs = win.mAttrs;
+        attrs.width = MATCH_PARENT;
+        attrs.height = MATCH_PARENT;
+        attrs.flags = FLAG_SHOW_WHEN_LOCKED | FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        attrs.format = PixelFormat.OPAQUE;
+        win.mHasSurface = true;
+        return win;
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 33d5c04..26745a7 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1199,6 +1199,80 @@
     public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
 
     /**
+     * Override the SPN Display Condition 2 integer bits (lsb). B2, B1 is the last two bits of the
+     * spn display condition coding.
+     *
+     * The default value -1 mean this field is not config.
+     *
+     * B1 = 0: display of registered PLMN name not required when registered PLMN is either HPLMN
+     * or a PLMN in the service provider PLMN list (see EF_SPDI).
+     * B1 = 1: display of registered PLMN name required when registered PLMN is either HPLMN or a
+     * PLMN in the service provider PLMN list(see EF_SPDI).
+     * B2 = 0: display of the service provider name is required when registered PLMN is neither
+     * HPLMN nor a PLMN in the service provider PLMN list(see EF_SPDI).
+     * B2 = 1: display of the service provider name is not required when registered PLMN is neither
+     * HPLMN nor a PLMN in the service provider PLMN list(see EF_SPDI).
+     *
+     * Reference: 3GPP TS 31.102 v15.2.0 Section 4.2.12 EF_SPN.
+     * @hide
+     */
+    public static final String KEY_SPN_DISPLAY_CONDITION_OVERRIDE_INT =
+            "spn_display_condition_override_int";
+
+    /**
+     * Override the SPDI - an array of PLMN(MCC + MNC) strings.
+     *
+     * Reference: 3GPP TS 31.102 v15.2.0 Section 4.2.66 EF_SPDI.
+     * @hide
+     */
+    public static final String KEY_SPDI_OVERRIDE_STRING_ARRAY = "spdi_override_string_array";
+
+    /**
+     * Override the EHPLMNs - an array of PLMN(MCC + MNC) strings.
+     *
+     * To allow provision for multiple HPLMN codes, PLMN codes that are present within this list
+     * shall replace the HPLMN code derived from the IMSI for PLMN selection purposes.
+     *
+     * Reference: 3GPP TS 31.102 v15.2.0 Section 4.2.84 EF_EHPLMN
+     * Reference: 3GPP TS 23.122 v15.6.0 Section 1.2 Equivalent HPLMN list
+     * @hide
+     */
+    public static final String KEY_EHPLMN_OVERRIDE_STRING_ARRAY = "ehplmn_override_string_array";
+
+    /**
+     * Override the PNN - a string array of comma-separated alpha long and short names:
+     * "alpha_long1, alpha_short1".
+     *
+     * Reference: 3GPP TS 31.102 v15.2.0 Section 4.2.58 EF_PNN.
+     * @hide
+     */
+    public static final String KEY_PNN_OVERRIDE_STRING_ARRAY = "pnn_override_string_array";
+
+    /**
+     * A string array of OPL records, each with comma-delimited data fields as follows:
+     * "plmn1,lactac_start,lactac_end,index".
+     *
+     * Reference: 3GPP TS 31.102 v15.2.0 Section 4.2.59 EF_OPL.
+     * @hide
+     */
+    public static final String KEY_OPL_OVERRIDE_STRING_ARRAY = "opl_override_opl_string_array";
+
+    /**
+     * Allow ERI rules to select a carrier name display string when using 3gpp2 access technologies.
+     *
+     * @hide
+     */
+    public static final String KEY_ALLOW_ERI_BOOL = "allow_cdma_eri_bool";
+
+    /**
+     * If true, use the carrier display name(SPN and PLMN) from the carrier display name resolver.
+     *
+     * @hide
+     */
+    public static final String KEY_ENABLE_CARRIER_DISPLAY_NAME_RESOLVER_BOOL =
+            "enable_carrier_display_name_resolver_bool";
+
+    /**
      * String to override sim country iso.
      * Sim country iso is based on sim MCC which is coarse and doesn't work with dual IMSI SIM where
      * a SIM can have multiple MCC from different countries.
@@ -3023,6 +3097,13 @@
         sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);
         sDefaults.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, false);
         sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
+        sDefaults.putInt(KEY_SPN_DISPLAY_CONDITION_OVERRIDE_INT, -1);
+        sDefaults.putStringArray(KEY_SPDI_OVERRIDE_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_PNN_OVERRIDE_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_OPL_OVERRIDE_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_EHPLMN_OVERRIDE_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_ALLOW_ERI_BOOL, false);
+        sDefaults.putBoolean(KEY_ENABLE_CARRIER_DISPLAY_NAME_RESOLVER_BOOL, false);
         sDefaults.putString(KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_CALL_SCREENING_APP_STRING, "");
         sDefaults.putString(KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING, null);
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 3ff862c..689abed 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -49,7 +49,6 @@
         "libselinux",
         "libui",
         "libutils",
-        "libvintf",
         "libvndksupport",
         "libtinyxml2",
         "libunwindstack",
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
new file mode 100644
index 0000000..ef1ad2c
--- /dev/null
+++ b/tests/net/smoketest/Android.bp
@@ -0,0 +1,17 @@
+// This test exists only because the jni_libs list for these tests is difficult to
+// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
+// fails to load that library unless *all* the dependencies of that library are explicitly
+// listed in jni_libs. This means that whenever any of the dependencies changes the test
+// starts failing and breaking presubmits in frameworks/base. We cannot easily put
+// FrameworksNetTests into global presubmit because they are at times flaky, but this
+// test is effectively empty beyond validating that the libraries load correctly, and
+// thus should be stable enough to put in global presubmit.
+//
+// TODO: remove this hack when there is a better solution for jni_libs that includes
+// dependent libraries.
+android_test {
+    name: "FrameworksNetSmokeTests",
+    defaults: ["FrameworksNetTests-jni-defaults"],
+    srcs: ["java/SmokeTest.java"],
+    test_suites: ["device-tests"],
+}
diff --git a/tests/net/smoketest/AndroidManifest.xml b/tests/net/smoketest/AndroidManifest.xml
new file mode 100644
index 0000000..f1b9feb
--- /dev/null
+++ b/tests/net/smoketest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.tests.net.smoketest">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.tests.net.smoketest"
+        android:label="Frameworks Networking Smoke Tests" />
+</manifest>
diff --git a/tests/net/smoketest/AndroidTest.xml b/tests/net/smoketest/AndroidTest.xml
new file mode 100644
index 0000000..ac366e4
--- /dev/null
+++ b/tests/net/smoketest/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Networking Smoke Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksNetSmokeTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.tests.net.smoketest" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/net/smoketest/java/SmokeTest.java b/tests/net/smoketest/java/SmokeTest.java
new file mode 100644
index 0000000..7d6655f
--- /dev/null
+++ b/tests/net/smoketest/java/SmokeTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class SmokeTest {
+
+    @Test
+    public void testLoadJni() {
+        System.loadLibrary("networkstatsfactorytestjni");
+        assertEquals(0, 0x00);
+    }
+}