Merge "Sharesheet - Give shortcut api results priority"
diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
index 1f26188..da9ed6e 100644
--- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
@@ -40,7 +40,7 @@
     public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private final KernelCpuThreadReader mKernelCpuThreadReader =
-            KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000, 0);
+            KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000);
 
     @Test
     public void timeReadCurrentProcessCpuUsage() {
diff --git a/apct-tests/perftests/textclassifier/AndroidTest.xml b/apct-tests/perftests/textclassifier/AndroidTest.xml
index 29f9f94..3df51b8 100644
--- a/apct-tests/perftests/textclassifier/AndroidTest.xml
+++ b/apct-tests/perftests/textclassifier/AndroidTest.xml
@@ -13,16 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Runs AutofillPerfTests metric instrumentation.">
+<configuration description="Runs TextClassifierPerfTests metric instrumentation.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-metric-instrumentation" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="AutofillPerfTests.apk" />
+        <option name="test-file-name" value="TextClassifierPerfTests.apk" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.perftests.autofill" />
+        <option name="package" value="com.android.perftests.textclassifier" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 286e76e..df84b6a 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -602,6 +602,19 @@
 
 void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
+
+    const int64_t timeNs = getElapsedRealtimeNs();
+    // Do not write to disk if we already have in the last few seconds.
+    // This is to avoid overwriting files that would have the same name if we
+    //   write twice in the same second.
+    if (static_cast<unsigned long long> (timeNs) <
+            mLastActiveMetricsWriteNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
+        ALOGI("Statsd skipping writing active metrics to disk. Already wrote data in last %d seconds",
+                WRITE_DATA_COOL_DOWN_SEC);
+        return;
+    }
+    mLastActiveMetricsWriteNs = timeNs;
+
     ProtoOutputStream proto;
 
     for (const auto& pair : mMetricsManagers) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index e92b897..8de1881 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -207,6 +207,9 @@
     // Last time we wrote data to disk.
     int64_t mLastWriteTimeNs = 0;
 
+    // Last time we wrote active metrics to disk.
+    int64_t mLastActiveMetricsWriteNs = 0;
+
 #ifdef VERY_VERBOSE_PRINTING
     bool mPrintAllLogs = false;
 #endif
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 3bcebd9..1433252 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1028,6 +1028,7 @@
     ALOGI("StatsService::Terminating");
     if (mProcessor != nullptr) {
         mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
+        mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
     }
 }
 
diff --git a/config/hiddenapi-greylist-packages.txt b/config/hiddenapi-greylist-packages.txt
new file mode 100644
index 0000000..cae3bd9
--- /dev/null
+++ b/config/hiddenapi-greylist-packages.txt
@@ -0,0 +1,2 @@
+org.ccil.cowan.tagsoup
+org.ccil.cowan.tagsoup.jaxp
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 95bdc36..c267e77 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2488,108 +2488,3 @@
 Lorg/apache/xpath/XPathContext;->setCurrentNodeStack(Lorg/apache/xml/utils/IntStack;)V
 Lorg/apache/xpath/XPathContext;->setSecureProcessing(Z)V
 Lorg/apache/xpath/XPathContext;->setVarStack(Lorg/apache/xpath/VariableStack;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;-><init>(Lorg/xml/sax/Attributes;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->addAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->setValue(ILjava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AutoDetector;->autoDetectingReader(Ljava/io/InputStream;)Ljava/io/Reader;
-Lorg/ccil/cowan/tagsoup/Element;-><init>(Lorg/ccil/cowan/tagsoup/ElementType;Z)V
-Lorg/ccil/cowan/tagsoup/Element;->anonymize()V
-Lorg/ccil/cowan/tagsoup/Element;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/Element;->canContain(Lorg/ccil/cowan/tagsoup/Element;)Z
-Lorg/ccil/cowan/tagsoup/Element;->clean()V
-Lorg/ccil/cowan/tagsoup/Element;->flags()I
-Lorg/ccil/cowan/tagsoup/Element;->localName()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->name()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->namespace()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->next()Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Element;->parent()Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Element;->preclosed:Z
-Lorg/ccil/cowan/tagsoup/Element;->setAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/Element;->setNext(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Element;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/Element;->theNext:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Element;->theType:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/ElementType;-><init>(Ljava/lang/String;IIILorg/ccil/cowan/tagsoup/Schema;)V
-Lorg/ccil/cowan/tagsoup/ElementType;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/ElementType;->setAttribute(Lorg/ccil/cowan/tagsoup/AttributesImpl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theMemberOf:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theModel:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
-Lorg/ccil/cowan/tagsoup/HTMLScanner;-><init>()V
-Lorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXFactoryImpl;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;->newInstance(Ljava/util/Map;)Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;
-Lorg/ccil/cowan/tagsoup/Parser;-><init>()V
-Lorg/ccil/cowan/tagsoup/Parser;->bogonsEmpty:Z
-Lorg/ccil/cowan/tagsoup/Parser;->CDATAElements:Z
-Lorg/ccil/cowan/tagsoup/Parser;->cleanPublicid(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->defaultAttributes:Z
-Lorg/ccil/cowan/tagsoup/Parser;->etagchars:[C
-Lorg/ccil/cowan/tagsoup/Parser;->expandEntities(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->getInputStream(Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;
-Lorg/ccil/cowan/tagsoup/Parser;->ignorableWhitespace:Z
-Lorg/ccil/cowan/tagsoup/Parser;->ignoreBogons:Z
-Lorg/ccil/cowan/tagsoup/Parser;->lookupEntity([CII)I
-Lorg/ccil/cowan/tagsoup/Parser;->makeName([CII)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->pop()V
-Lorg/ccil/cowan/tagsoup/Parser;->push(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->rectify(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->restart(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->restartablyPop()V
-Lorg/ccil/cowan/tagsoup/Parser;->rootBogons:Z
-Lorg/ccil/cowan/tagsoup/Parser;->schemaProperty:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->split(Ljava/lang/String;)[Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theAttributeName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theAutoDetector:Lorg/ccil/cowan/tagsoup/AutoDetector;
-Lorg/ccil/cowan/tagsoup/Parser;->theContentHandler:Lorg/xml/sax/ContentHandler;
-Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeIsPresent:Z
-Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeSystemId:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theFeatures:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Parser;->theLexicalHandler:Lorg/xml/sax/ext/LexicalHandler;
-Lorg/ccil/cowan/tagsoup/Parser;->theNewElement:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->thePCDATA:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->thePITarget:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theSaved:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->theScanner:Lorg/ccil/cowan/tagsoup/Scanner;
-Lorg/ccil/cowan/tagsoup/Parser;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
-Lorg/ccil/cowan/tagsoup/Parser;->theStack:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->trimquotes(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->virginStack:Z
-Lorg/ccil/cowan/tagsoup/PYXScanner;-><init>()V
-Lorg/ccil/cowan/tagsoup/PYXWriter;-><init>(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->aname([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->aval([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->entity([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->eof([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->etag([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->gi([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->pcdata([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->pi([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->stagc([CII)V
-Lorg/ccil/cowan/tagsoup/Scanner;->startCDATA()V
-Lorg/ccil/cowan/tagsoup/Schema;->elementType(Ljava/lang/String;III)V
-Lorg/ccil/cowan/tagsoup/Schema;->getElementType(Ljava/lang/String;)Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Schema;->getEntity(Ljava/lang/String;)I
-Lorg/ccil/cowan/tagsoup/Schema;->getPrefix()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->getURI()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->parent(Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/XMLWriter;-><init>(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 11fa343..0ab1a85 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5571,7 +5571,7 @@
                     button.setTextColor(R.id.action0, textColor);
                     rippleColor = textColor;
                 } else if (getRawColor(p) != COLOR_DEFAULT && !isColorized(p)
-                        && mTintActionButtons) {
+                        && mTintActionButtons && !mInNightMode) {
                     rippleColor = resolveContrastColor(p);
                     button.setTextColor(R.id.action0, rippleColor);
                 } else {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index ea245a4..ed7cddc 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -123,6 +123,11 @@
  * app must promote itself to the foreground after it's launched or the system
  * will shut down the app.
  *
+ * <h3>Developer's guide</h3>
+ *
+ * <p>To learn more about developing VPN apps, read the
+ * <a href="{@docRoot}guide/topics/connectivity/vpn">VPN developer's guide</a>.
+ *
  * @see Builder
  */
 public class VpnService extends Service {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 43ac574..53503f4 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -337,6 +337,25 @@
     }
 
     /**
+     * Check for ANGLE debug package, but only for apps that can load them (dumpable)
+     */
+    private String getAngleDebugPackage(Context context, Bundle coreSettings) {
+        final boolean appIsDebuggable = isDebuggable(context);
+        final boolean appIsProfileable = isProfileable(context);
+        final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
+        if (appIsDebuggable || appIsProfileable || deviceIsDebuggable) {
+
+            String debugPackage =
+                    coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+
+            if ((debugPackage != null) && (!debugPackage.isEmpty())) {
+                return debugPackage;
+            }
+        }
+        return "";
+    }
+
+    /**
      * Attempt to setup ANGLE with a temporary rules file.
      * True: Temporary rules file was loaded.
      * False: Temporary rules file was *not* loaded.
@@ -502,11 +521,23 @@
         }
 
         final ApplicationInfo angleInfo;
-        try {
-            angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
-            return false;
+        String angleDebugPackage = getAngleDebugPackage(context, bundle);
+        if (!angleDebugPackage.isEmpty()) {
+            Log.i(TAG, "ANGLE debug package enabled: " + angleDebugPackage);
+            try {
+                // Note the debug package does not have to be pre-installed
+                angleInfo = pm.getApplicationInfo(angleDebugPackage, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, "ANGLE debug package '" + angleDebugPackage + "' not installed");
+                return false;
+            }
+        } else {
+            try {
+                angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
+                return false;
+            }
         }
 
         final String abi = chooseAbi(angleInfo);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8eac66b..227c9d4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11528,15 +11528,6 @@
                 "background_activity_starts_enabled";
 
         /**
-         * The packages temporarily whitelisted to be able so start activities from background.
-         * The list of packages is {@code ":"} colon delimited.
-         *
-         * @hide
-         */
-        public static final String BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST =
-                "background_activity_starts_package_names_whitelist";
-
-        /**
          * @hide
          * @see com.android.server.appbinding.AppBindingConstants
          */
@@ -12460,6 +12451,14 @@
         public static final String GPU_DEBUG_APP = "gpu_debug_app";
 
         /**
+         * Package containing ANGLE libraries other than system, which are only available
+         * to dumpable apps that opt-in.
+         * @hide
+         */
+        public static final String GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE =
+                "angle_debug_package";
+
+        /**
          * Force all PKGs to use ANGLE, regardless of any other settings
          * The value is a boolean (1 or 0).
          * @hide
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index da6ef4c..7f6423a 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -55,7 +55,7 @@
         DEFAULT_FLAGS.put("settings_dynamic_system", "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
-        DEFAULT_FLAGS.put(SAFETY_HUB, "false");
+        DEFAULT_FLAGS.put(SAFETY_HUB, "true");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0043d32..e3b0b7a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -978,17 +978,6 @@
         }
     }
 
-    private static void closeTransaction(boolean sync) {
-        synchronized(SurfaceControl.class) {
-            if (sTransactionNestCount == 0) {
-                Log.e(TAG, "Call to SurfaceControl.closeTransaction without matching openTransaction");
-            } else if (--sTransactionNestCount > 0) {
-                return;
-            }
-            sGlobalTransaction.apply(sync);
-        }
-    }
-
     /**
      * Merge the supplied transaction in to the deprecated "global" transaction.
      * This clears the supplied transaction in an identical fashion to {@link Transaction#merge}.
@@ -1003,19 +992,20 @@
         }
     }
 
-    /** end a transaction 
-     * @hide 
+    /** end a transaction
+     * @hide
      */
     @UnsupportedAppUsage
     public static void closeTransaction() {
-        closeTransaction(false);
-    }
-
-    /**
-     * @hide
-     */
-    public static void closeTransactionSync() {
-        closeTransaction(true);
+        synchronized(SurfaceControl.class) {
+            if (sTransactionNestCount == 0) {
+                Log.e(TAG,
+                        "Call to SurfaceControl.closeTransaction without matching openTransaction");
+            } else if (--sTransactionNestCount > 0) {
+                return;
+            }
+            sGlobalTransaction.apply();
+        }
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/ConfigParser.java b/core/java/android/view/textclassifier/ConfigParser.java
index 8e0bdf9..b475412 100644
--- a/core/java/android/view/textclassifier/ConfigParser.java
+++ b/core/java/android/view/textclassifier/ConfigParser.java
@@ -33,6 +33,10 @@
 
     private final KeyValueListParser mParser;
 
+    // TODO: Re-enable DeviceConfig when it has reasonable performance or just delete the
+    // option of using DeviceConfig entirely.
+    static final boolean ENABLE_DEVICE_CONFIG = false;
+
     public ConfigParser(@Nullable String textClassifierConstants) {
         final KeyValueListParser parser = new KeyValueListParser(',');
         try {
@@ -48,39 +52,55 @@
      * Reads a boolean flag.
      */
     public boolean getBoolean(String key, boolean defaultValue) {
-        return DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
-                key,
-                mParser.getBoolean(key, defaultValue));
+        if (ENABLE_DEVICE_CONFIG) {
+            return DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+                    key,
+                    mParser.getBoolean(key, defaultValue));
+        } else {
+            return mParser.getBoolean(key, defaultValue);
+        }
     }
 
     /**
      * Reads an integer flag.
      */
     public int getInt(String key, int defaultValue) {
-        return DeviceConfig.getInt(
-                DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
-                key,
-                mParser.getInt(key, defaultValue));
+        if (ENABLE_DEVICE_CONFIG) {
+            return DeviceConfig.getInt(
+                    DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+                    key,
+                    mParser.getInt(key, defaultValue));
+        } else {
+            return mParser.getInt(key, defaultValue);
+        }
     }
 
     /**
      * Reads a float flag.
      */
     public float getFloat(String key, float defaultValue) {
-        return DeviceConfig.getFloat(
-                DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
-                key,
-                mParser.getFloat(key, defaultValue));
+        if (ENABLE_DEVICE_CONFIG) {
+            return DeviceConfig.getFloat(
+                    DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+                    key,
+                    mParser.getFloat(key, defaultValue));
+        } else {
+            return mParser.getFloat(key, defaultValue);
+        }
     }
 
     /**
      * Reads a string flag.
      */
     public String getString(String key, String defaultValue) {
-        return DeviceConfig.getString(
-                DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
-                key,
-                mParser.getString(key, defaultValue));
+        if (ENABLE_DEVICE_CONFIG) {
+            return DeviceConfig.getString(
+                    DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+                    key,
+                    mParser.getString(key, defaultValue));
+        } else {
+            return mParser.getString(key, defaultValue);
+        }
     }
 }
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 868cbb1..fa898c3 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -197,7 +197,9 @@
             if (mSettingsObserver != null) {
                 getApplicationContext().getContentResolver()
                         .unregisterContentObserver(mSettingsObserver);
-                DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver);
+                if (ConfigParser.ENABLE_DEVICE_CONFIG) {
+                    DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver);
+                }
             }
         } finally {
             super.finalize();
@@ -292,10 +294,12 @@
                     Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS),
                     false /* notifyForDescendants */,
                     this);
-            DeviceConfig.addOnPropertyChangedListener(
-                    DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
-                    ActivityThread.currentApplication().getMainExecutor(),
-                    this);
+            if (ConfigParser.ENABLE_DEVICE_CONFIG) {
+                DeviceConfig.addOnPropertyChangedListener(
+                        DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+                        ActivityThread.currentApplication().getMainExecutor(),
+                        this);
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index cc7a7a3..a1d0cdc 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -942,8 +942,6 @@
         if (isSendAction(in)) {
             in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                     Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-
-            in.fixUris(getUserId());
         }
     }
 
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 3811fe4..a5f055f 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -115,6 +115,7 @@
                 // At this point, innerIntent is not null. Otherwise, canForward would have returned
                 // false.
                 innerIntent.prepareToLeaveUser(callingUserId);
+                innerIntent.fixUris(callingUserId);
             } else {
                 newIntent.prepareToLeaveUser(callingUserId);
             }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f47469a..f671a75 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -509,10 +509,11 @@
         @Nullable abstract String getAppSubLabelInternal();
 
         private Context mCtx;
-        protected PackageManager mPm;
-        private final ApplicationInfo mAi;
         private final int mIconDpi;
         private final boolean mHasSubstitutePermission;
+        private final ApplicationInfo mAi;
+
+        protected PackageManager mPm;
 
         TargetPresentationGetter(Context ctx, int iconDpi, ApplicationInfo ai) {
             mCtx = ctx;
@@ -590,10 +591,10 @@
      * Loads the icon and label for the provided ResolveInfo.
      */
     @VisibleForTesting
-    public static class ResolveInfoPresentationGetter extends TargetPresentationGetter {
+    public static class ResolveInfoPresentationGetter extends ActivityInfoPresentationGetter {
         private final ResolveInfo mRi;
         public ResolveInfoPresentationGetter(Context ctx, int iconDpi, ResolveInfo ri) {
-            super(ctx, iconDpi, ri.activityInfo.applicationInfo);
+            super(ctx, iconDpi, ri.activityInfo);
             mRi = ri;
         }
 
@@ -611,6 +612,9 @@
                         + "couldn't find resources for package", e);
             }
 
+            // Fall back to ActivityInfo if no icon is found via ResolveInfo
+            if (dr == null) dr = super.getIconSubstituteInternal();
+
             return dr;
         }
 
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index e4de158..3686048 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -92,24 +92,12 @@
     /** Value returned when there was an error getting an integer ID value (e.g. PID, UID) */
     private static final int ID_ERROR = -1;
 
-    /** Thread ID used when reporting CPU used by other threads */
-    private static final int OTHER_THREADS_ID = -1;
-
-    /** Thread name used when reporting CPU used by other threads */
-    private static final String OTHER_THREADS_NAME = "__OTHER_THREADS";
-
     /**
      * When checking whether to report data for a thread, we check the UID of the thread's owner
      * against this predicate
      */
     private Predicate<Integer> mUidPredicate;
 
-    /**
-     * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
-     * will not be reported
-     */
-    private int mMinimumTotalCpuUsageMillis;
-
     /** Where the proc filesystem is mounted */
     private final Path mProcPath;
 
@@ -138,13 +126,11 @@
     public KernelCpuThreadReader(
             int numBuckets,
             Predicate<Integer> uidPredicate,
-            int minimumTotalCpuUsageMillis,
             Path procPath,
             Path initialTimeInStatePath,
             Injector injector)
             throws IOException {
         mUidPredicate = uidPredicate;
-        mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
         mProcPath = procPath;
         mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath);
         mInjector = injector;
@@ -157,13 +143,11 @@
      * @return the reader, null if an exception was thrown during creation
      */
     @Nullable
-    public static KernelCpuThreadReader create(
-            int numBuckets, Predicate<Integer> uidPredicate, int minimumTotalCpuUsageMillis) {
+    public static KernelCpuThreadReader create(int numBuckets, Predicate<Integer> uidPredicate) {
         try {
             return new KernelCpuThreadReader(
                     numBuckets,
                     uidPredicate,
-                    minimumTotalCpuUsageMillis,
                     DEFAULT_PROC_PATH,
                     DEFAULT_INITIAL_TIME_IN_STATE_PATH,
                     new Injector());
@@ -259,18 +243,6 @@
     }
 
     /**
-     * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
-     * will not be reported
-     */
-    void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
-        if (minimumTotalCpuUsageMillis < 0) {
-            Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
-            return;
-        }
-        mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
-    }
-
-    /**
      * Read all of the CPU usage statistics for each child thread of a process
      *
      * @param processPath the {@code /proc} path of the thread
@@ -292,7 +264,6 @@
                             + uid);
         }
 
-        int[] filteredThreadsCpuUsage = null;
         final Path allThreadsPath = processPath.resolve("task");
         final ArrayList<ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
         try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(allThreadsPath)) {
@@ -301,14 +272,6 @@
                 if (threadCpuUsage == null) {
                     continue;
                 }
-                if (mMinimumTotalCpuUsageMillis > totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
-                    if (filteredThreadsCpuUsage == null) {
-                        filteredThreadsCpuUsage = new int[mFrequenciesKhz.length];
-                    }
-                    filteredThreadsCpuUsage =
-                            sumCpuUsage(filteredThreadsCpuUsage, threadCpuUsage.usageTimesMillis);
-                    continue;
-                }
                 threadCpuUsages.add(threadCpuUsage);
             }
         } catch (IOException e) {
@@ -320,14 +283,6 @@
         if (threadCpuUsages.isEmpty()) {
             return null;
         }
-
-        // Add the filtered out thread CPU usage under an "other threads" ThreadCpuUsage
-        if (filteredThreadsCpuUsage != null) {
-            threadCpuUsages.add(
-                    new ThreadCpuUsage(
-                            OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
-        }
-
         if (DEBUG) {
             Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
         }
@@ -404,25 +359,6 @@
         }
     }
 
-    /** Get the sum of all CPU usage across all frequencies */
-    @SuppressWarnings("ForLoopReplaceableByForEach")
-    private static int totalCpuUsage(int[] cpuUsage) {
-        int total = 0;
-        for (int i = 0; i < cpuUsage.length; i++) {
-            total += cpuUsage[i];
-        }
-        return total;
-    }
-
-    /** Add two CPU frequency usages together */
-    private static int[] sumCpuUsage(int[] a, int[] b) {
-        int[] summed = new int[a.length];
-        for (int i = 0; i < a.length; i++) {
-            summed[i] = a[i] + b[i];
-        }
-        return summed;
-    }
-
     /** Puts frequencies and usage times into buckets */
     @VisibleForTesting
     public static class FrequencyBucketCreator {
@@ -553,9 +489,10 @@
         public final int processId;
         public final String processName;
         public final int uid;
-        public final ArrayList<ThreadCpuUsage> threadCpuUsages;
+        public ArrayList<ThreadCpuUsage> threadCpuUsages;
 
-        ProcessCpuUsage(
+        @VisibleForTesting
+        public ProcessCpuUsage(
                 int processId,
                 String processName,
                 int uid,
@@ -571,9 +508,10 @@
     public static class ThreadCpuUsage {
         public final int threadId;
         public final String threadName;
-        public final int[] usageTimesMillis;
+        public int[] usageTimesMillis;
 
-        ThreadCpuUsage(int threadId, String threadName, int[] usageTimesMillis) {
+        @VisibleForTesting
+        public ThreadCpuUsage(int threadId, String threadName, int[] usageTimesMillis) {
             this.threadId = threadId;
             this.threadName = threadName;
             this.usageTimesMillis = usageTimesMillis;
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
new file mode 100644
index 0000000..ffdc33c
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Delegates per-thread CPU collection to {@link KernelCpuThreadReader}, and calculates the
+ * difference between CPU usage at each call of {@link #getProcessCpuUsageDiffed()}.
+ *
+ * <p>Some notes on the diff calculation:
+ *
+ * <ul>
+ *   <li>The diffing is done between each call of {@link #getProcessCpuUsageDiffed()}, i.e. call N
+ *       of this method will return CPU used by threads between call N-1 and N.
+ *   <li>The first call of {@link #getProcessCpuUsageDiffed()} will return no processes ("first
+ *       call" is the first call in the lifetime of a {@link KernelCpuThreadReaderDiff} object).
+ *   <li>If a thread does not exist at call N, but does exist at call N+1, the diff will assume that
+ *       the CPU usage at call N was zero. Thus, the diff reported will be equivalent to the value
+ *       returned by {@link KernelCpuThreadReader#getProcessCpuUsage()} at call N+1.
+ *   <li>If an error occurs in {@link KernelCpuThreadReader} at call N, we will return no
+ *       information for CPU usage between call N-1 and N (as we don't know the start value) and
+ *       between N and N+1 (as we don't know the end value). Assuming all other calls are
+ *       successful, the next call to return data will be N+2, for the period between N+1 and N+2.
+ *   <li>If an error occurs in this class (but not in {@link KernelCpuThreadReader}) at call N, the
+ *       data will only be dropped for call N, as we can still use the CPU data for the surrounding
+ *       calls.
+ * </ul>
+ *
+ * <p>Additionally to diffing, this class also contains logic for thresholding reported threads. A
+ * thread will not be reported unless its total CPU usage is at least equal to the value set in
+ * {@link #setMinimumTotalCpuUsageMillis}. Filtered thread CPU usage is summed and reported under
+ * one "other threads" thread. This reduces the cardinality of the {@link
+ * #getProcessCpuUsageDiffed()} result.
+ *
+ * <p>Thresholding is done in this class, instead of {@link KernelCpuThreadReader}, and instead of
+ * WestWorld, because the thresholding should be done after diffing, not before. This is because of
+ * two issues with thresholding before diffing:
+ *
+ * <ul>
+ *   <li>We would threshold less and less threads as thread uptime increases.
+ *   <li>We would encounter errors as the filtered threads become unfiltered, as the "other threads"
+ *       result could have negative diffs, and the newly unfiltered threads would have incorrect
+ *       diffs that include CPU usage from when they were filtered.
+ * </ul>
+ *
+ * @hide Only for use within the system server
+ */
+@SuppressWarnings("ForLoopReplaceableByForEach")
+public class KernelCpuThreadReaderDiff {
+    private static final String TAG = "KernelCpuThreadReaderDiff";
+
+    /** Thread ID used when reporting CPU used by other threads */
+    private static final int OTHER_THREADS_ID = -1;
+
+    /** Thread name used when reporting CPU used by other threads */
+    private static final String OTHER_THREADS_NAME = "__OTHER_THREADS";
+
+    private final KernelCpuThreadReader mReader;
+
+    /**
+     * CPU usage from the previous call of {@link #getProcessCpuUsageDiffed()}. Null if there was no
+     * previous call, or if the previous call failed
+     *
+     * <p>Maps the thread's identifier to the per-frequency CPU usage for that thread. The
+     * identifier contains the minimal amount of information to identify a thread (see {@link
+     * ThreadKey} for more information), thus reducing memory consumption.
+     */
+    @Nullable private Map<ThreadKey, int[]> mPreviousCpuUsage;
+
+    /**
+     * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+     * will not be reported
+     */
+    private int mMinimumTotalCpuUsageMillis;
+
+    @VisibleForTesting
+    public KernelCpuThreadReaderDiff(KernelCpuThreadReader reader, int minimumTotalCpuUsageMillis) {
+        mReader = reader;
+        mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
+        mPreviousCpuUsage = null;
+    }
+
+    /**
+     * Returns the difference in CPU usage since the last time this method was called.
+     *
+     * @see KernelCpuThreadReader#getProcessCpuUsage()
+     */
+    @Nullable
+    public ArrayList<KernelCpuThreadReader.ProcessCpuUsage> getProcessCpuUsageDiffed() {
+        Map<ThreadKey, int[]> newCpuUsage = null;
+        try {
+            // Get the thread CPU usage and index them by ThreadKey
+            final ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
+                    mReader.getProcessCpuUsage();
+            newCpuUsage = createCpuUsageMap(processCpuUsages);
+            // If there is no previous CPU usage, return nothing
+            if (mPreviousCpuUsage == null) {
+                return null;
+            }
+
+            // Do diffing and thresholding for each process
+            for (int i = 0; i < processCpuUsages.size(); i++) {
+                KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
+                changeToDiffs(mPreviousCpuUsage, processCpuUsage);
+                applyThresholding(processCpuUsage);
+            }
+            return processCpuUsages;
+        } finally {
+            // Always update the previous CPU usage. If we haven't got an update, it will be set to
+            // null, so the next call knows there no previous values
+            mPreviousCpuUsage = newCpuUsage;
+        }
+    }
+
+    /** @see KernelCpuThreadReader#getCpuFrequenciesKhz() */
+    @Nullable
+    public int[] getCpuFrequenciesKhz() {
+        return mReader.getCpuFrequenciesKhz();
+    }
+
+    /**
+     * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+     * will not be reported
+     */
+    void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
+        if (minimumTotalCpuUsageMillis < 0) {
+            Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
+            return;
+        }
+        mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
+    }
+
+    /**
+     * Create a map of a thread's identifier to a thread's CPU usage. Used for fast indexing when
+     * calculating diffs
+     */
+    private static Map<ThreadKey, int[]> createCpuUsageMap(
+            List<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages) {
+        final Map<ThreadKey, int[]> cpuUsageMap = new ArrayMap<>();
+        for (int i = 0; i < processCpuUsages.size(); i++) {
+            KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
+            for (int j = 0; j < processCpuUsage.threadCpuUsages.size(); j++) {
+                KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage =
+                        processCpuUsage.threadCpuUsages.get(j);
+                cpuUsageMap.put(
+                        new ThreadKey(
+                                processCpuUsage.processId,
+                                threadCpuUsage.threadId,
+                                processCpuUsage.processName,
+                                threadCpuUsage.threadName),
+                        threadCpuUsage.usageTimesMillis);
+            }
+        }
+        return cpuUsageMap;
+    }
+
+    /**
+     * Calculate the difference in per-frequency CPU usage for all threads in a process
+     *
+     * @param previousCpuUsage CPU usage from the last call, the base of the diff
+     * @param processCpuUsage CPU usage from the current call, this value is modified to contain the
+     *     diffed values
+     */
+    private static void changeToDiffs(
+            Map<ThreadKey, int[]> previousCpuUsage,
+            KernelCpuThreadReader.ProcessCpuUsage processCpuUsage) {
+        for (int i = 0; i < processCpuUsage.threadCpuUsages.size(); i++) {
+            KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage =
+                    processCpuUsage.threadCpuUsages.get(i);
+            final ThreadKey key =
+                    new ThreadKey(
+                            processCpuUsage.processId,
+                            threadCpuUsage.threadId,
+                            processCpuUsage.processName,
+                            threadCpuUsage.threadName);
+            int[] previous = previousCpuUsage.get(key);
+            if (previous == null) {
+                // If there's no previous CPU usage, assume that it's zero
+                previous = new int[threadCpuUsage.usageTimesMillis.length];
+            }
+            threadCpuUsage.usageTimesMillis =
+                    cpuTimeDiff(threadCpuUsage.usageTimesMillis, previous);
+        }
+    }
+
+    /**
+     * Filter out any threads with less than {@link #mMinimumTotalCpuUsageMillis} total CPU usage
+     *
+     * <p>The sum of the CPU usage of filtered threads is added under a single thread, labeled with
+     * {@link #OTHER_THREADS_ID} and {@link #OTHER_THREADS_NAME}.
+     *
+     * @param processCpuUsage CPU usage to apply thresholding to, this value is modified to change
+     *     the threads it contains
+     */
+    private void applyThresholding(KernelCpuThreadReader.ProcessCpuUsage processCpuUsage) {
+        int[] filteredThreadsCpuUsage = null;
+        final ArrayList<KernelCpuThreadReader.ThreadCpuUsage> thresholded = new ArrayList<>();
+        for (int i = 0; i < processCpuUsage.threadCpuUsages.size(); i++) {
+            KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage =
+                    processCpuUsage.threadCpuUsages.get(i);
+            if (mMinimumTotalCpuUsageMillis > totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
+                if (filteredThreadsCpuUsage == null) {
+                    filteredThreadsCpuUsage = new int[threadCpuUsage.usageTimesMillis.length];
+                }
+                addToCpuUsage(filteredThreadsCpuUsage, threadCpuUsage.usageTimesMillis);
+                continue;
+            }
+            thresholded.add(threadCpuUsage);
+        }
+        if (filteredThreadsCpuUsage != null) {
+            thresholded.add(
+                    new KernelCpuThreadReader.ThreadCpuUsage(
+                            OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
+        }
+        processCpuUsage.threadCpuUsages = thresholded;
+    }
+
+    /** Get the sum of all CPU usage across all frequencies */
+    private static int totalCpuUsage(int[] cpuUsage) {
+        int total = 0;
+        for (int i = 0; i < cpuUsage.length; i++) {
+            total += cpuUsage[i];
+        }
+        return total;
+    }
+
+    /** Add two CPU frequency usages together */
+    private static void addToCpuUsage(int[] a, int[] b) {
+        for (int i = 0; i < a.length; i++) {
+            a[i] += b[i];
+        }
+    }
+
+    /** Subtract two CPU frequency usages from each other */
+    private static int[] cpuTimeDiff(int[] a, int[] b) {
+        int[] difference = new int[a.length];
+        for (int i = 0; i < a.length; i++) {
+            difference[i] = a[i] - b[i];
+        }
+        return difference;
+    }
+
+    /**
+     * Identifies a thread
+     *
+     * <p>Only stores the minimum amount of information to identify a thread. This includes the
+     * PID/TID, but as both are recycled as processes/threads end and begin, we also store the hash
+     * of the name of the process/thread.
+     */
+    private static class ThreadKey {
+        private final int mProcessId;
+        private final int mThreadId;
+        private final int mProcessNameHash;
+        private final int mThreadNameHash;
+
+        ThreadKey(int processId, int threadId, String processName, String threadName) {
+            this.mProcessId = processId;
+            this.mThreadId = threadId;
+            // Only store the hash to reduce memory consumption
+            this.mProcessNameHash = Objects.hash(processName);
+            this.mThreadNameHash = Objects.hash(threadName);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mProcessId, mThreadId, mProcessNameHash, mThreadNameHash);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof ThreadKey)) {
+                return false;
+            }
+            ThreadKey other = (ThreadKey) obj;
+            return mProcessId == other.mProcessId
+                    && mThreadId == other.mThreadId
+                    && mProcessNameHash == other.mProcessNameHash
+                    && mThreadNameHash == other.mThreadNameHash;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index 3851ce6..f8c0d9e 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -67,12 +67,14 @@
 
     @Nullable private final KernelCpuThreadReader mKernelCpuThreadReader;
 
+    @Nullable private final KernelCpuThreadReaderDiff mKernelCpuThreadReaderDiff;
+
     /**
      * @return returns a created {@link KernelCpuThreadReader} that will be modified by any change
      *     in settings, returns null if creation failed
      */
     @Nullable
-    public static KernelCpuThreadReader getSettingsModifiedReader(Context context) {
+    public static KernelCpuThreadReaderDiff getSettingsModifiedReader(Context context) {
         // Create the observer
         KernelCpuThreadReaderSettingsObserver settingsObserver =
                 new KernelCpuThreadReaderSettingsObserver(context);
@@ -82,7 +84,7 @@
                 .registerContentObserver(
                         settingsUri, false, settingsObserver, UserHandle.USER_SYSTEM);
         // Return the observer's reader
-        return settingsObserver.mKernelCpuThreadReader;
+        return settingsObserver.mKernelCpuThreadReaderDiff;
     }
 
     private KernelCpuThreadReaderSettingsObserver(Context context) {
@@ -90,9 +92,10 @@
         mContext = context;
         mKernelCpuThreadReader =
                 KernelCpuThreadReader.create(
-                        NUM_BUCKETS_DEFAULT,
-                        UidPredicate.fromString(COLLECTED_UIDS_DEFAULT),
-                        MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
+                        NUM_BUCKETS_DEFAULT, UidPredicate.fromString(COLLECTED_UIDS_DEFAULT));
+        mKernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(
+                        mKernelCpuThreadReader, MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
     }
 
     @Override
@@ -130,7 +133,7 @@
         mKernelCpuThreadReader.setNumBuckets(
                 parser.getInt(NUM_BUCKETS_SETTINGS_KEY, NUM_BUCKETS_DEFAULT));
         mKernelCpuThreadReader.setUidPredicate(uidPredicate);
-        mKernelCpuThreadReader.setMinimumTotalCpuUsageMillis(
+        mKernelCpuThreadReaderDiff.setMinimumTotalCpuUsageMillis(
                 parser.getInt(
                         MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY,
                         MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT));
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d124feb..b47097d 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -455,6 +455,8 @@
         optional SettingProto show_angle_in_use_dialog = 15;
         // Game Driver - List of libraries in sphal accessible by Game Driver
         optional SettingProto game_driver_sphal_libraries = 16;
+        // ANGLE - External package containing ANGLE libraries
+        optional SettingProto angle_debug_package = 17;
     }
     optional Gpu gpu = 59;
 
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0673e75..c36ca82 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -131,7 +131,6 @@
                     Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
                     Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
-                    Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST,
                     Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
                     Settings.Global.BROADCAST_BG_CONSTANTS,
                     Settings.Global.BROADCAST_FG_CONSTANTS,
@@ -488,6 +487,7 @@
                     Settings.Global.GPU_DEBUG_APP,
                     Settings.Global.GPU_DEBUG_LAYERS,
                     Settings.Global.GPU_DEBUG_LAYERS_GLES,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
diff --git a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
index 1b3c724..f1cfe24 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
@@ -26,6 +26,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +59,7 @@
     }
 
     @Test
+    @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
     public void getBoolean_deviceConfig() {
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -77,6 +79,7 @@
     }
 
     @Test
+    @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
     public void getInt_deviceConfig() {
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -94,6 +97,7 @@
     }
 
     @Test
+    @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
     public void getFloat_deviceConfig() {
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -111,6 +115,7 @@
     }
 
     @Test
+    @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
     public void getString_deviceConfig() {
         DeviceConfig.setProperty(
                 DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
new file mode 100644
index 0000000..460fe47
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import static java.util.stream.Collectors.toList;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelCpuThreadReaderDiffTest {
+
+    private MockitoSession mMockingSessions;
+    @Mock KernelCpuThreadReader mMockReader;
+
+    @Before
+    public void setUp() {
+        mMockingSessions = mockitoSession().initMocks(this).startMocking();
+    }
+
+    @After
+    public void tearDown() {
+        if (mMockingSessions != null) {
+            mMockingSessions.finishMocking();
+        }
+    }
+
+    @Test
+    public void test_empty() {
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isEmpty();
+    }
+
+    @Test
+    public void test_simple() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {100, 100, 100}))
+                .thenReturn(createProcess(new int[] {150, 160, 170}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+                .containsExactly(Arrays.asList(50, 60, 70));
+    }
+
+    @Test
+    public void test_failure() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {1}))
+                .thenReturn(createProcess(new int[] {2}))
+                .thenThrow(new RuntimeException())
+                .thenReturn(createProcess(new int[] {4}))
+                .thenReturn(createProcess(new int[] {6}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+                .containsExactly(Collections.singletonList(1));
+        assertThrows(
+                RuntimeException.class,
+                () -> cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()));
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+                .containsExactly(Collections.singletonList(2));
+    }
+
+    @Test
+    public void test_twoFailures() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {1}))
+                .thenReturn(createProcess(new int[] {2}))
+                .thenThrow(new RuntimeException())
+                .thenThrow(new RuntimeException())
+                .thenReturn(createProcess(new int[] {4}))
+                .thenReturn(createProcess(new int[] {6}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+                .containsExactly(Collections.singletonList(1));
+        assertThrows(
+                RuntimeException.class,
+                () -> cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()));
+        assertThrows(
+                RuntimeException.class,
+                () -> cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()));
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+                .containsExactly(Collections.singletonList(2));
+    }
+
+    @Test
+    public void test_negativeDiff() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {2}))
+                .thenReturn(createProcess(new int[] {1}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+        assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+                .containsExactly(Collections.singletonList(-1));
+    }
+
+    @Test
+    public void test_threshold() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {1}))
+                .thenReturn(createProcess(new int[] {10}))
+                .thenReturn(createProcess(new int[] {12}))
+                .thenReturn(createProcess(new int[] {20}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 5);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes1 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes1)).containsExactly(Collections.singletonList(9));
+        assertThat(threadNames(processes1)).containsExactly("thread0");
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes2 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes2)).containsExactly(Collections.singletonList(2));
+        assertThat(threadNames(processes2)).containsExactly("__OTHER_THREADS");
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes3 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes3)).containsExactly(Collections.singletonList(8));
+        assertThat(threadNames(processes3)).containsExactly("thread0");
+    }
+
+    @Test
+    public void test_newThread() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {1}))
+                .thenReturn(createProcess(new int[] {2}))
+                .thenReturn(createProcess(new int[] {4}, new int[] {5}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes1 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes1)).containsExactly(Collections.singletonList(1));
+        assertThat(threadNames(processes1)).containsExactly("thread0");
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes2 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes2))
+                .containsExactly(Collections.singletonList(2), Collections.singletonList(5));
+        assertThat(threadNames(processes2)).containsExactly("thread0", "thread1");
+    }
+
+    @Test
+    public void test_stoppedThread() {
+        when(mMockReader.getProcessCpuUsage())
+                .thenReturn(createProcess(new int[] {1}, new int[] {1}))
+                .thenReturn(createProcess(new int[] {2}, new int[] {3}))
+                .thenReturn(createProcess(new int[] {4}));
+        KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+                new KernelCpuThreadReaderDiff(mMockReader, 0);
+        assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes1 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes1))
+                .containsExactly(Collections.singletonList(1), Collections.singletonList(2));
+        assertThat(threadNames(processes1)).containsExactly("thread0", "thread1");
+
+        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes2 =
+                kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+        assertThat(cpuUsages(processes2)).containsExactly(Collections.singletonList(2));
+        assertThat(threadNames(processes2)).containsExactly("thread0");
+    }
+
+    private ArrayList<KernelCpuThreadReader.ProcessCpuUsage> createProcess(
+            int[]... cpuUsageMillis) {
+        ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
+        for (int i = 0; i < cpuUsageMillis.length; i++) {
+            int[] cpuUsage = cpuUsageMillis[i];
+            threadCpuUsages.add(
+                    new KernelCpuThreadReader.ThreadCpuUsage(0, "thread" + i, cpuUsage));
+        }
+        return new ArrayList<>(
+                Collections.singletonList(
+                        new KernelCpuThreadReader.ProcessCpuUsage(
+                                0, "process", 0, threadCpuUsages)));
+    }
+
+    private Collection<Collection<Integer>> cpuUsages(
+            Collection<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages) {
+        return processCpuUsages.stream()
+                .flatMap(p -> p.threadCpuUsages.stream())
+                .map(t -> Arrays.stream(t.usageTimesMillis).boxed().collect(toList()))
+                .collect(toList());
+    }
+
+    private Collection<String> threadNames(
+            Collection<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages) {
+        return processCpuUsages.stream()
+                .flatMap(p -> p.threadCpuUsages.stream())
+                .map(t -> t.threadName)
+                .collect(toList());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index e9cad0a..d43989c 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -125,7 +125,7 @@
 
         // Get thread data from KernelCpuThreadReader
         final KernelCpuThreadReader kernelCpuThreadReader =
-                KernelCpuThreadReader.create(8, uid -> uid == Process.myUid(), 0);
+                KernelCpuThreadReader.create(8, uid -> uid == Process.myUid());
         assertNotNull(kernelCpuThreadReader);
         kernelCpuThreadReader.setUidPredicate(uid -> uid == Process.myUid());
         final Optional<ProcessCpuUsage> currentProcessCpuUsage =
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index 61209e2..ae847c1 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -84,7 +84,6 @@
         final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
                 8,
                 uidPredicate,
-                0,
                 mProcDirectory.toPath(),
                 mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
                 processUtils);
@@ -103,90 +102,6 @@
         }
     }
 
-    @Test
-    public void testReader_filtersLowUsage() throws IOException {
-        int[] uids = new int[]{0, 1, 2, 3, 4};
-        int[] cpuUsage = new int[]{10, 0, 2, 100, 3};
-        int[] expectedUids = new int[]{0, 3, 4};
-        Predicate<Integer> uidPredicate = uid -> true;
-        KernelCpuThreadReader.Injector processUtils =
-                new KernelCpuThreadReader.Injector() {
-                    @Override
-                    public int getUidForPid(int pid) {
-                        return pid;
-                    }
-                };
-
-        for (int i = 0; i < uids.length; i++) {
-            int uid = uids[i];
-            setupDirectory(
-                    mProcDirectory.toPath().resolve(String.valueOf(uid)),
-                    new int[]{uid * 10},
-                    "process" + uid,
-                    new String[]{"thread" + uid},
-                    new int[]{1000},
-                    new int[][]{{cpuUsage[i]}});
-        }
-        final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
-                8,
-                uidPredicate,
-                30,
-                mProcDirectory.toPath(),
-                mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
-                processUtils);
-        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
-                kernelCpuThreadReader.getProcessCpuUsage();
-        processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.uid));
-
-        assertEquals(expectedUids.length, processCpuUsageByUids.size());
-        for (int i = 0; i < expectedUids.length; i++) {
-            KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
-                    processCpuUsageByUids.get(i);
-            assertEquals(expectedUids[i], processCpuUsage.uid);
-        }
-
-    }
-
-    @Test
-    public void testReader_otherThreads() throws IOException {
-        final Path processPath = mProcDirectory.toPath().resolve("1000");
-        setupDirectory(
-                processPath,
-                new int[]{1, 2, 3},
-                "process",
-                new String[]{"thread1", "thread2", "thread3"},
-                new int[]{1000, 2000},
-                new int[][]{{0, 100}, {10, 0}, {0, 300}});
-        KernelCpuThreadReader.Injector injector =
-                new KernelCpuThreadReader.Injector() {
-                    @Override
-                    public int getUidForPid(int pid) {
-                        return 0;
-                    }
-                };
-        final KernelCpuThreadReader kernelCpuThreadReader =
-                new KernelCpuThreadReader(
-                        8,
-                        uid -> true,
-                        2000,
-                        mProcDirectory.toPath(),
-                        processPath.resolve("task/1/time_in_state"),
-                        injector);
-        ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
-                kernelCpuThreadReader.getProcessCpuUsage();
-        assertEquals(1, processCpuUsages.size());
-        checkResults(
-                processCpuUsages.get(0),
-                kernelCpuThreadReader.getCpuFrequenciesKhz(),
-                0,
-                1000,
-                new int[] {-1, 3},
-                "process",
-                new String[] {"__OTHER_THREADS", "thread3"},
-                new int[] {1000, 2000},
-                new int[][] {{10, 100}, {0, 300}});
-    }
-
     private void setupDirectory(Path processPath, int[] threadIds, String processName,
             String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) throws IOException {
         // Make /proc/$PID
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bfce17c..f21fa5e 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -17,7 +17,6 @@
 package android.security;
 
 import android.annotation.UnsupportedAppUsage;
-import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.KeyguardManager;
@@ -45,24 +44,24 @@
 import android.security.keystore.KeyNotYetValidException;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
 import android.security.keystore.KeyProperties;
-import android.security.keystore.KeyProtection;
 import android.security.keystore.KeystoreResponse;
-import android.security.keystore.StrongBoxUnavailableException;
 import android.security.keystore.UserNotAuthenticatedException;
 import android.util.Log;
+
 import com.android.org.bouncycastle.asn1.ASN1InputStream;
 import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import java.math.BigInteger;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
+
 import sun.security.util.ObjectIdentifier;
 import sun.security.x509.AlgorithmId;
 
@@ -492,8 +491,9 @@
     }
 
     public boolean addRngEntropy(byte[] data, int flags) {
+        KeystoreResultPromise promise = new KeystoreResultPromise();
         try {
-            KeystoreResultPromise promise = new KeystoreResultPromise();
+            mBinder.asBinder().linkToDeath(promise, 0);
             int errorCode = mBinder.addRngEntropy(promise, data, flags);
             if (errorCode == NO_ERROR) {
                 return promise.getFuture().get().getErrorCode() == NO_ERROR;
@@ -506,6 +506,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "AddRngEntropy completed with exception", e);
             return false;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
@@ -537,7 +539,8 @@
     }
 
     private class KeyCharacteristicsPromise
-    extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub {
+            extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
+            implements IBinder.DeathRecipient {
         final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
                 new CompletableFuture<KeyCharacteristicsCallbackResult>();
         @Override
@@ -550,19 +553,30 @@
         public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
             return future;
         }
+        @Override
+        public void binderDied() {
+            future.completeExceptionally(new RemoteException("Keystore died"));
+        }
     };
 
     private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
             int flags, KeyCharacteristics outCharacteristics)
                     throws RemoteException, ExecutionException, InterruptedException {
         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        int error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
-        if (error != NO_ERROR) {
-            Log.e(TAG, "generateKeyInternal failed on request " + error);
-            return error;
+        int error = NO_ERROR;
+        KeyCharacteristicsCallbackResult result = null;
+        try {
+            mBinder.asBinder().linkToDeath(promise, 0);
+            error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
+            if (error != NO_ERROR) {
+                Log.e(TAG, "generateKeyInternal failed on request " + error);
+                return error;
+            }
+            result = promise.getFuture().get();
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
 
-        KeyCharacteristicsCallbackResult result = promise.getFuture().get();
         error = result.getKeystoreResponse().getErrorCode();
         if (error != NO_ERROR) {
             Log.e(TAG, "generateKeyInternal failed on response " + error);
@@ -604,10 +618,12 @@
 
     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
             int uid, KeyCharacteristics outCharacteristics) {
+        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
-            KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
+
             int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
             if (error != NO_ERROR) return error;
 
@@ -625,6 +641,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
             return SYSTEM_ERROR;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
@@ -637,17 +655,23 @@
             int uid, int flags, KeyCharacteristics outCharacteristics)
                     throws RemoteException, ExecutionException, InterruptedException {
         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
-        if (error != NO_ERROR) return error;
+        mBinder.asBinder().linkToDeath(promise, 0);
+        try {
+            int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
+            if (error != NO_ERROR) return error;
 
-        KeyCharacteristicsCallbackResult result = promise.getFuture().get();
-        error = result.getKeystoreResponse().getErrorCode();
-        if (error != NO_ERROR) return error;
+            KeyCharacteristicsCallbackResult result = promise.getFuture().get();
 
-        KeyCharacteristics characteristics = result.getKeyCharacteristics();
-        if (characteristics == null) return SYSTEM_ERROR;
-        outCharacteristics.shallowCopyFrom(characteristics);
-        return NO_ERROR;
+            error = result.getKeystoreResponse().getErrorCode();
+            if (error != NO_ERROR) return error;
+
+            KeyCharacteristics characteristics = result.getKeyCharacteristics();
+            if (characteristics == null) return SYSTEM_ERROR;
+            outCharacteristics.shallowCopyFrom(characteristics);
+            return NO_ERROR;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
+        }
     }
 
     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
@@ -738,18 +762,25 @@
             KeyCharacteristics outCharacteristics)
                     throws RemoteException, ExecutionException, InterruptedException {
         KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
-        int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
-                maskingKey, args, rootSid, fingerprintSid);
-        if (error != NO_ERROR) return error;
+        mBinder.asBinder().linkToDeath(promise, 0);
+        try {
+            KeyCharacteristicsCallbackResult result = null;
+            int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
+                    wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
+            if (error != NO_ERROR) return error;
 
-        KeyCharacteristicsCallbackResult result = promise.getFuture().get();
-        error = result.getKeystoreResponse().getErrorCode();
-        if (error != NO_ERROR) return error;
+            KeyCharacteristicsCallbackResult esult = promise.getFuture().get();
 
-        KeyCharacteristics characteristics = result.getKeyCharacteristics();
-        if (characteristics == null) return SYSTEM_ERROR;
-        outCharacteristics.shallowCopyFrom(characteristics);
-        return NO_ERROR;
+            error = result.getKeystoreResponse().getErrorCode();
+            if (error != NO_ERROR) return error;
+
+            KeyCharacteristics characteristics = result.getKeyCharacteristics();
+            if (characteristics == null) return SYSTEM_ERROR;
+            outCharacteristics.shallowCopyFrom(characteristics);
+            return NO_ERROR;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
+        }
     }
 
     public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
@@ -776,7 +807,8 @@
     }
 
     private class ExportKeyPromise
-    extends android.security.keystore.IKeystoreExportKeyCallback.Stub {
+            extends android.security.keystore.IKeystoreExportKeyCallback.Stub
+            implements IBinder.DeathRecipient {
         final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
         @Override
         public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
@@ -785,14 +817,19 @@
         public final CompletableFuture<ExportResult> getFuture() {
             return future;
         }
+        @Override
+        public void binderDied() {
+            future.completeExceptionally(new RemoteException("Keystore died"));
+        }
     };
 
     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
             KeymasterBlob appId, int uid) {
+        ExportKeyPromise promise = new ExportKeyPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
             appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
-            ExportKeyPromise promise = new ExportKeyPromise();
             int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
             if (error == NO_ERROR) {
                 return promise.getFuture().get();
@@ -805,6 +842,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "ExportKey completed with exception", e);
             return null;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
@@ -813,7 +852,8 @@
     }
 
     private class OperationPromise
-    extends android.security.keystore.IKeystoreOperationResultCallback.Stub {
+            extends android.security.keystore.IKeystoreOperationResultCallback.Stub
+            implements IBinder.DeathRecipient {
         final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
         @Override
         public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
@@ -822,14 +862,19 @@
         public final CompletableFuture<OperationResult> getFuture() {
             return future;
         }
+        @Override
+        public void binderDied() {
+            future.completeExceptionally(new RemoteException("Keystore died"));
+        }
     };
 
     public OperationResult begin(String alias, int purpose, boolean pruneable,
             KeymasterArguments args, byte[] entropy, int uid) {
+        OperationPromise promise = new OperationPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             args = args != null ? args : new KeymasterArguments();
             entropy = entropy != null ? entropy : new byte[0];
-            OperationPromise promise = new OperationPromise();
             int errorCode =  mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
                                            entropy, uid);
             if (errorCode == NO_ERROR) {
@@ -843,6 +888,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "Begin completed with exception", e);
             return null;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
@@ -854,10 +901,11 @@
     }
 
     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
+        OperationPromise promise = new OperationPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             arguments = arguments != null ? arguments : new KeymasterArguments();
             input = input != null ? input : new byte[0];
-            OperationPromise promise = new OperationPromise();
             int errorCode =  mBinder.update(promise, token, arguments, input);
             if (errorCode == NO_ERROR) {
                 return promise.getFuture().get();
@@ -870,16 +918,19 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "Update completed with exception", e);
             return null;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
             byte[] entropy) {
+        OperationPromise promise = new OperationPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             arguments = arguments != null ? arguments : new KeymasterArguments();
             entropy = entropy != null ? entropy : new byte[0];
             signature = signature != null ? signature : new byte[0];
-            OperationPromise promise = new OperationPromise();
             int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
             if (errorCode == NO_ERROR) {
                 return promise.getFuture().get();
@@ -892,6 +943,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "Finish completed with exception", e);
             return null;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
@@ -900,7 +953,8 @@
     }
 
     private class KeystoreResultPromise
-    extends android.security.keystore.IKeystoreResponseCallback.Stub {
+            extends android.security.keystore.IKeystoreResponseCallback.Stub
+            implements IBinder.DeathRecipient {
         final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
         @Override
         public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
@@ -909,11 +963,16 @@
         public final CompletableFuture<KeystoreResponse> getFuture() {
             return future;
         }
+        @Override
+        public void binderDied() {
+            future.completeExceptionally(new RemoteException("Keystore died"));
+        }
     };
 
     public int abort(IBinder token) {
+        KeystoreResultPromise promise = new KeystoreResultPromise();
         try {
-            KeystoreResultPromise promise = new KeystoreResultPromise();
+            mBinder.asBinder().linkToDeath(promise, 0);
             int errorCode = mBinder.abort(promise, token);
             if (errorCode == NO_ERROR) {
                 return promise.getFuture().get().getErrorCode();
@@ -926,6 +985,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "Abort completed with exception", e);
             return SYSTEM_ERROR;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
@@ -1035,7 +1096,8 @@
     }
 
     private class CertificateChainPromise
-    extends android.security.keystore.IKeystoreCertificateChainCallback.Stub {
+            extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
+            implements IBinder.DeathRecipient {
         final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
         @Override
         public void onFinished(KeystoreResponse keystoreResponse,
@@ -1045,19 +1107,24 @@
         public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
             return future;
         }
+        @Override
+        public void binderDied() {
+            future.completeExceptionally(new RemoteException("Keystore died"));
+        }
     };
 
 
     public int attestKey(
             String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
+        CertificateChainPromise promise = new CertificateChainPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             if (params == null) {
                 params = new KeymasterArguments();
             }
             if (outChain == null) {
                 outChain = new KeymasterCertificateChain();
             }
-            CertificateChainPromise promise = new CertificateChainPromise();
             int error = mBinder.attestKey(promise, alias, params);
             if (error != NO_ERROR) return error;
             KeyAttestationCallbackResult result = promise.getFuture().get();
@@ -1072,18 +1139,21 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "AttestKey completed with exception", e);
             return SYSTEM_ERROR;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
     public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
+        CertificateChainPromise promise = new CertificateChainPromise();
         try {
+            mBinder.asBinder().linkToDeath(promise, 0);
             if (params == null) {
                 params = new KeymasterArguments();
             }
             if (outChain == null) {
                 outChain = new KeymasterCertificateChain();
             }
-            CertificateChainPromise promise = new CertificateChainPromise();
             int error = mBinder.attestDeviceIds(promise, params);
             if (error != NO_ERROR) return error;
             KeyAttestationCallbackResult result = promise.getFuture().get();
@@ -1098,6 +1168,8 @@
         } catch (ExecutionException | InterruptedException e) {
             Log.e(TAG, "AttestDevicdeIds completed with exception", e);
             return SYSTEM_ERROR;
+        } finally {
+            mBinder.asBinder().unlinkToDeath(promise, 0);
         }
     }
 
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ac62ff4..4011329 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -172,6 +172,8 @@
     LOG_ALWAYS_FATAL_IF(physDeviceProperties.apiVersion < VK_MAKE_VERSION(1, 1, 0));
     mDriverVersion = physDeviceProperties.driverVersion;
 
+    mIsQualcomm = physDeviceProperties.vendorID == 20803;
+
     // query to get the initial queue props size
     uint32_t queueCount;
     mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 54333f3..a7a43cc 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -181,6 +181,13 @@
     SwapBehavior mSwapBehavior = SwapBehavior::Discard;
     GrVkExtensions mExtensions;
     uint32_t mDriverVersion = 0;
+
+    // TODO: Remove once fix has landed. Temporaryly needed for workaround for setting up AHB
+    // surfaces on Qualcomm. Currently if you don't use VkSwapchain Qualcomm is not setting
+    // reporting that we need to use one of their private vendor usage bits which greatly effects
+    // performance if it is not used.
+    bool mIsQualcomm = false;
+    bool isQualcomm() const { return mIsQualcomm; }
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 3fed6b0..36f540c 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -299,6 +299,10 @@
         }
 
         windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage;
+        if (vkManager.isQualcomm()) {
+            windowInfo.windowUsageFlags =
+                    windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0;
+        }
 
     } else {
         ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing");
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index 4b91bbb..209b2cb 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -20,13 +20,13 @@
     <color name="usage_graph_dots">@*android:color/tertiary_device_default_settings</color>
     <color name="list_divider_color">#64000000</color>
 
-    <color name="bt_color_icon_1">#48a50e0e</color> <!-- 72% Material Red 900 -->
-    <color name="bt_color_icon_2">#480d652d</color> <!-- 72% Material Green 900 -->
-    <color name="bt_color_icon_3">#48e37400</color> <!-- 72% Material Yellow 900 -->
-    <color name="bt_color_icon_4">#48b06000</color> <!-- 72% Material Orange 900 -->
-    <color name="bt_color_icon_5">#489c166b</color> <!-- 72% Material Pink 900 -->
-    <color name="bt_color_icon_6">#48681da8</color> <!-- 72% Material Purple 900 -->
-    <color name="bt_color_icon_7">#48007b83</color> <!-- 72% Material Cyan 900 -->
+    <color name="bt_color_icon_1">#b4a50e0e</color> <!-- 72% Material Red 900 -->
+    <color name="bt_color_icon_2">#b40d652d</color> <!-- 72% Material Green 900 -->
+    <color name="bt_color_icon_3">#b4e37400</color> <!-- 72% Material Yellow 900 -->
+    <color name="bt_color_icon_4">#b4b06000</color> <!-- 72% Material Orange 900 -->
+    <color name="bt_color_icon_5">#b49c166b</color> <!-- 72% Material Pink 900 -->
+    <color name="bt_color_icon_6">#b4681da8</color> <!-- 72% Material Purple 900 -->
+    <color name="bt_color_icon_7">#b4007b83</color> <!-- 72% Material Cyan 900 -->
 
     <color name="bt_color_bg_1">#fad2cf</color> <!-- Material Red 100 -->
     <color name="bt_color_bg_2">#ceead6</color> <!-- Material Green 100 -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 867efb4..148046b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -6,7 +6,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.MediaStore;
@@ -135,7 +134,7 @@
         final BluetoothDevice bluetoothDevice = cachedDevice.getDevice();
         final boolean untetheredHeadset = bluetoothDevice != null
                 ? Boolean.parseBoolean(bluetoothDevice.getMetadata(
-                        BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
+                BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
                 : false;
         final int iconSize = context.getResources().getDimensionPixelSize(
                 R.dimen.bt_nearby_icon_size);
@@ -181,8 +180,8 @@
         final int[] iconBgColors = resources.getIntArray(R.array.bt_icon_bg_colors);
 
         // get color index based on mac address
-        final int index =  Math.abs(hashCode % iconBgColors.length);
-        drawable.setColorFilter(iconFgColors[index], PorterDuff.Mode.SRC_ATOP);
+        final int index = Math.abs(hashCode % iconBgColors.length);
+        drawable.setTint(iconFgColors[index]);
         final Drawable adaptiveIcon = new AdaptiveIcon(context, drawable);
         ((AdaptiveIcon) adaptiveIcon).setBackgroundColor(iconBgColors[index]);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e374db3..f597a1a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -686,6 +686,9 @@
                 Settings.Global.GPU_DEBUG_LAYERS,
                 GlobalSettingsProto.Gpu.DEBUG_LAYERS);
         dumpSetting(s, p,
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE,
+                GlobalSettingsProto.Gpu.ANGLE_DEBUG_PACKAGE);
+        dumpSetting(s, p,
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                 GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_ALL_ANGLE);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index d0fff74..64e56f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -41,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Supplier;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -52,14 +53,9 @@
 public final class ClockManager {
 
     private static final String TAG = "ClockOptsProvider";
-    private static final String DEFAULT_CLOCK_ID = "default";
 
-    private final List<ClockInfo> mClockInfos = new ArrayList<>();
-    /**
-     * Map from expected value stored in settings to supplier of custom clock face.
-     */
-    private final Map<String, ClockPlugin> mClocks = new ArrayMap<>();
-    @Nullable private ClockPlugin mCurrentClock;
+    private final AvailableClocks mPreviewClocks;
+    private final List<Supplier<ClockPlugin>> mBuiltinClocks = new ArrayList<>();
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
@@ -78,21 +74,6 @@
                 }
             };
 
-    private final PluginListener<ClockPlugin> mClockPluginListener =
-            new PluginListener<ClockPlugin>() {
-                @Override
-                public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
-                    addClockPlugin(plugin);
-                    reload();
-                }
-
-                @Override
-                public void onPluginDisconnected(ClockPlugin plugin) {
-                    removeClockPlugin(plugin);
-                    reload();
-                }
-            };
-
     private final PluginManager mPluginManager;
 
     /**
@@ -108,13 +89,22 @@
                 }
             };
     @Nullable private DockManager mDockManager;
+
     /**
      * When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face
      * to show.
      */
     private boolean mIsDocked;
 
-    private final List<ClockChangedListener> mListeners = new ArrayList<>();
+    /**
+     * Listeners for onClockChanged event.
+     *
+     * Each listener must receive a separate clock plugin instance. Otherwise, there could be
+     * problems like attempting to attach a view that already has a parent. To deal with this issue,
+     * each listener is associated with a collection of available clocks. When onClockChanged is
+     * fired the current clock plugin instance is retrieved from that listeners available clocks.
+     */
+    private final Map<ClockChangedListener, AvailableClocks> mListeners = new ArrayMap<>();
 
     private final int mWidth;
     private final int mHeight;
@@ -133,14 +123,16 @@
         mPluginManager = pluginManager;
         mContentResolver = contentResolver;
         mSettingsWrapper = settingsWrapper;
+        mPreviewClocks = new AvailableClocks();
 
         Resources res = context.getResources();
         LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context));
 
-        addClockPlugin(new DefaultClockController(res, layoutInflater, colorExtractor));
-        addClockPlugin(new BubbleClockController(res, layoutInflater, colorExtractor));
-        addClockPlugin(new StretchAnalogClockController(res, layoutInflater, colorExtractor));
-        addClockPlugin(new TypeClockController(res, layoutInflater, colorExtractor));
+        addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
+        addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
+        addBuiltinClock(() -> new StretchAnalogClockController(res, layoutInflater,
+                colorExtractor));
+        addBuiltinClock(() -> new TypeClockController(res, layoutInflater, colorExtractor));
 
         // Store the size of the display for generation of clock preview.
         DisplayMetrics dm = res.getDisplayMetrics();
@@ -155,7 +147,12 @@
         if (mListeners.isEmpty()) {
             register();
         }
-        mListeners.add(listener);
+        AvailableClocks availableClocks = new AvailableClocks();
+        for (int i = 0; i < mBuiltinClocks.size(); i++) {
+            availableClocks.addClockPlugin(mBuiltinClocks.get(i).get());
+        }
+        mListeners.put(listener, availableClocks);
+        mPluginManager.addPluginListener(availableClocks, ClockPlugin.class, true);
         reload();
     }
 
@@ -163,7 +160,8 @@
      * Remove listener added with {@link addOnClockChangedListener}.
      */
     public void removeOnClockChangedListener(ClockChangedListener listener) {
-        mListeners.remove(listener);
+        AvailableClocks availableClocks = mListeners.remove(listener);
+        mPluginManager.removePluginListener(availableClocks);
         if (mListeners.isEmpty()) {
             unregister();
         }
@@ -173,16 +171,16 @@
      * Get information about available clock faces.
      */
     List<ClockInfo> getClockInfos() {
-        return mClockInfos;
+        return mPreviewClocks.getInfo();
     }
 
     /**
      * Get the current clock.
-     * @returns current custom clock or null for default.
+     * @return current custom clock or null for default.
      */
     @Nullable
     ClockPlugin getCurrentClock() {
-        return mCurrentClock;
+        return mPreviewClocks.getCurrentClock();
     }
 
     @VisibleForTesting
@@ -195,39 +193,14 @@
         return mContentObserver;
     }
 
-    private void addClockPlugin(ClockPlugin plugin) {
-        final String id = plugin.getClass().getName();
-        mClocks.put(plugin.getClass().getName(), plugin);
-        mClockInfos.add(ClockInfo.builder()
-                .setName(plugin.getName())
-                .setTitle(plugin.getTitle())
-                .setId(id)
-                .setThumbnail(() -> plugin.getThumbnail())
-                .setPreview(() -> plugin.getPreview(mWidth, mHeight))
-                .build());
-    }
-
-    private void removeClockPlugin(ClockPlugin plugin) {
-        final String id = plugin.getClass().getName();
-        mClocks.remove(id);
-        for (int i = 0; i < mClockInfos.size(); i++) {
-            if (id.equals(mClockInfos.get(i).getId())) {
-                mClockInfos.remove(i);
-                break;
-            }
-        }
-    }
-
-    private void notifyClockChanged(ClockPlugin plugin) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            // It probably doesn't make sense to supply the same plugin instances to multiple
-            // listeners. This should be fine for now since there is only a single listener.
-            mListeners.get(i).onClockChanged(plugin);
-        }
+    private void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
+        ClockPlugin plugin = pluginSupplier.get();
+        mPreviewClocks.addClockPlugin(plugin);
+        mBuiltinClocks.add(pluginSupplier);
     }
 
     private void register() {
-        mPluginManager.addPluginListener(mClockPluginListener, ClockPlugin.class, true);
+        mPluginManager.addPluginListener(mPreviewClocks, ClockPlugin.class, true);
         mContentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
                 false, mContentObserver);
@@ -243,7 +216,7 @@
     }
 
     private void unregister() {
-        mPluginManager.removePluginListener(mClockPluginListener);
+        mPluginManager.removePluginListener(mPreviewClocks);
         mContentResolver.unregisterContentObserver(mContentObserver);
         if (mDockManager != null) {
             mDockManager.removeListener(mDockEventListener);
@@ -251,30 +224,16 @@
     }
 
     private void reload() {
-        mCurrentClock = getClockPlugin();
-        if (mCurrentClock instanceof DefaultClockController) {
-            notifyClockChanged(null);
-        } else {
-            notifyClockChanged(mCurrentClock);
-        }
-    }
-
-    private ClockPlugin getClockPlugin() {
-        ClockPlugin plugin = null;
-        if (mIsDocked) {
-            final String name = mSettingsWrapper.getDockedClockFace();
-            if (name != null) {
-                plugin = mClocks.get(name);
-                if (plugin != null) {
-                    return plugin;
-                }
+        mPreviewClocks.reload();
+        mListeners.forEach((listener, clocks) -> {
+            clocks.reload();
+            ClockPlugin clock = clocks.getCurrentClock();
+            if (clock instanceof DefaultClockController) {
+                listener.onClockChanged(null);
+            } else {
+                listener.onClockChanged(clock);
             }
-        }
-        final String name = mSettingsWrapper.getLockScreenCustomClockFace();
-        if (name != null) {
-            plugin = mClocks.get(name);
-        }
-        return plugin;
+        });
     }
 
     /**
@@ -288,4 +247,106 @@
          */
         void onClockChanged(ClockPlugin clock);
     }
+
+    /**
+     * Collection of available clocks.
+     */
+    private final class AvailableClocks implements PluginListener<ClockPlugin> {
+
+        /**
+         * Map from expected value stored in settings to plugin for custom clock face.
+         */
+        private final Map<String, ClockPlugin> mClocks = new ArrayMap<>();
+
+        /**
+         * Metadata about available clocks, such as name and preview images.
+         */
+        private final List<ClockInfo> mClockInfo = new ArrayList<>();
+
+        /**
+         * Active ClockPlugin.
+         */
+        @Nullable private ClockPlugin mCurrentClock;
+
+        @Override
+        public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
+            addClockPlugin(plugin);
+            reload();
+        }
+
+        @Override
+        public void onPluginDisconnected(ClockPlugin plugin) {
+            removeClockPlugin(plugin);
+            reload();
+        }
+
+        /**
+         * Get the current clock.
+         * @return current custom clock or null for default.
+         */
+        @Nullable
+        ClockPlugin getCurrentClock() {
+            return mCurrentClock;
+        }
+
+        /**
+         * Get information about available clock faces.
+         */
+        List<ClockInfo> getInfo() {
+            return mClockInfo;
+        }
+
+        /**
+         * Adds a clock plugin to the collection of available clocks.
+         *
+         * @param plugin The plugin to add.
+         */
+        void addClockPlugin(ClockPlugin plugin) {
+            final String id = plugin.getClass().getName();
+            mClocks.put(plugin.getClass().getName(), plugin);
+            mClockInfo.add(ClockInfo.builder()
+                    .setName(plugin.getName())
+                    .setTitle(plugin.getTitle())
+                    .setId(id)
+                    .setThumbnail(plugin::getThumbnail)
+                    .setPreview(() -> plugin.getPreview(mWidth, mHeight))
+                    .build());
+        }
+
+        private void removeClockPlugin(ClockPlugin plugin) {
+            final String id = plugin.getClass().getName();
+            mClocks.remove(id);
+            for (int i = 0; i < mClockInfo.size(); i++) {
+                if (id.equals(mClockInfo.get(i).getId())) {
+                    mClockInfo.remove(i);
+                    break;
+                }
+            }
+        }
+
+        /**
+         * Update the current clock.
+         */
+        void reload() {
+            mCurrentClock = getClockPlugin();
+        }
+
+        private ClockPlugin getClockPlugin() {
+            ClockPlugin plugin = null;
+            if (ClockManager.this.isDocked()) {
+                final String name = mSettingsWrapper.getDockedClockFace();
+                if (name != null) {
+                    plugin = mClocks.get(name);
+                    if (plugin != null) {
+                        return plugin;
+                    }
+                }
+            }
+            final String name = mSettingsWrapper.getLockScreenCustomClockFace();
+            if (name != null) {
+                plugin = mClocks.get(name);
+            }
+            return plugin;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index f07887e..dcacd0f 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -439,6 +439,9 @@
     @Override
     public void onUiModeChanged() {
         mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
+        if (mDialog.isShowing()) {
+            mDialog.refreshDialog();
+        }
     }
 
     public void destroy() {
@@ -1577,7 +1580,9 @@
 
             boolean panelEnabled = initializePanel();
             if (!panelEnabled) {
-                mBackgroundDrawable = new GradientDrawable(mContext);
+                if (mBackgroundDrawable == null) {
+                    mBackgroundDrawable = new GradientDrawable(mContext);
+                }
                 mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
             } else {
                 mBackgroundDrawable = mContext.getDrawable(
@@ -1720,10 +1725,14 @@
             mKeyguardShowing = keyguardShowing;
         }
 
+        public void refreshDialog() {
+            initializeLayout();
+            mGlobalActionsLayout.updateList();
+        }
+
         public void onRotate(int from, int to) {
             if (mShowing && isGridEnabled(mContext)) {
-                initializeLayout();
-                mGlobalActionsLayout.updateList();
+                refreshDialog();
             }
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 46b1833..f2ad958 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -18,6 +18,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -31,6 +33,7 @@
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.plugins.ClockPlugin;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.InjectionInflationController;
 
@@ -38,6 +41,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -57,7 +61,8 @@
     @Mock SysuiColorExtractor mMockColorExtractor;
     @Mock ContentResolver mMockContentResolver;
     @Mock SettingsWrapper mMockSettingsWrapper;
-    @Mock ClockManager.ClockChangedListener mMockListener;
+    @Mock ClockManager.ClockChangedListener mMockListener1;
+    @Mock ClockManager.ClockChangedListener mMockListener2;
 
     @Before
     public void setUp() {
@@ -73,13 +78,17 @@
                 mMockPluginManager, mMockColorExtractor, mMockContentResolver,
                 mMockSettingsWrapper);
 
-        mClockManager.addOnClockChangedListener(mMockListener);
+        mClockManager.addOnClockChangedListener(mMockListener1);
+        mClockManager.addOnClockChangedListener(mMockListener2);
+        reset(mMockListener1, mMockListener2);
+
         mContentObserver = mClockManager.getContentObserver();
     }
 
     @After
     public void tearDown() {
-        mClockManager.removeOnClockChangedListener(mMockListener);
+        mClockManager.removeOnClockChangedListener(mMockListener1);
+        mClockManager.removeOnClockChangedListener(mMockListener2);
     }
 
     @Test
@@ -116,6 +125,34 @@
     }
 
     @Test
+    public void onClockChanged_customClock() {
+        // GIVEN that settings is set to the bubble clock face
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+        // WHEN settings change event is fired
+        mContentObserver.onChange(false);
+        // THEN the plugin is the bubble clock face.
+        ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
+        verify(mMockListener1).onClockChanged(captor.capture());
+        assertThat(captor.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
+    }
+
+    @Test
+    public void onClockChanged_uniqueInstances() {
+        // GIVEN that settings is set to the bubble clock face
+        when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+        // WHEN settings change event is fired
+        mContentObserver.onChange(false);
+        // THEN the listeners receive separate instances of the Bubble clock plugin.
+        ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
+        ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
+        verify(mMockListener1).onClockChanged(captor1.capture());
+        verify(mMockListener2).onClockChanged(captor2.capture());
+        assertThat(captor1.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
+        assertThat(captor2.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
+        assertThat(captor1.getValue()).isNotSameAs(captor2.getValue());
+    }
+
+    @Test
     public void getCurrentClock_badSettingsValue() {
         // GIVEN that settings contains a value that doesn't correspond to a
         // custom clock face.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index 096f205..50fadef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -199,6 +199,7 @@
     }
 
     @Test
+    @Ignore("Flaky")
     public void testRestoredAtRestingPosition() throws InterruptedException {
         mStackController.flingStackThenSpringToEdge(0, 5000, 5000);
 
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 1646cc1e..6212a51 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -15,6 +15,6 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M22,15.89v-2.57c0-1.1-0.65-2.09-1.67-2.53L14.5,8.28V3.75c0-1.38-1.12-2.5-2.5-2.5s-2.5,1.12-2.5,2.5v4.53l-5.83,2.51 C2.65,11.22,2,12.22,2,13.32v2.57l7.5-1.28v3.03l-1.47,1.17C7.38,19.34,7,20.12,7,20.96v1.33l4.96-0.3L17,22.3v-1.33 c0-0.84-0.38-1.62-1.03-2.15l-1.47-1.17v-3.03L22,15.89z M15.03,19.98c0.23,0.18,0.38,0.44,0.44,0.72l-3.52-0.2l-3.43,0.2 c0.06-0.28,0.21-0.53,0.44-0.72L11,18.36v-5.53l-7.5,1.28v-0.79c0-0.5,0.3-0.95,0.76-1.15L11,9.27V3.75c0-0.55,0.45-1,1-1 s1,0.45,1,1v5.52l6.74,2.9c0.46,0.2,0.76,0.65,0.76,1.15v0.79L13,12.83v5.53L15.03,19.98z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
index 545e0dd..ccbaecd 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M12,7a0.76 0.76 ,0,0,0-0.75 0.75 v3.5H7.75a0.75 0.75 ,0,0,0,0,1.5h3.5v3.5a0.75 0.75 ,0,0,0,1.5,0v-3.5h3.5a0.75 0.75 ,0,0,0,0-1.5h-3.5V7.75A0.76 0.76 ,0,0,0,12,7Z"/>
   <path android:fillColor="@android:color/white" android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z"/>
   <path android:fillColor="@android:color/white" android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z"/>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
index b5cde8f..dcf507a 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M12,14c-0.83,0-1.5-0.67-1.5-1.5S11.17,11,12,11s1.5,0.67,1.5,1.5S12.83,14,12,14z"/>
   <path android:fillColor="@android:color/white" android:pathData="M8.46,16.79c-0.19,0-0.38-0.07-0.53-0.22c-1.09-1.09-1.68-2.53-1.68-4.07s0.6-2.98,1.68-4.07 c2.24-2.24,5.89-2.24,8.13,0c1.09,1.09,1.68,2.53,1.68,4.07s-0.6,2.98-1.68,4.07c-0.29,0.29-0.77,0.29-1.06,0 s-0.29-0.77,0-1.06c0.8-0.8,1.24-1.87,1.24-3c0-1.14-0.44-2.2-1.24-3.01c-1.66-1.66-4.35-1.66-6.01,0 c-0.8,0.8-1.24,1.87-1.24,3c0,1.14,0.44,2.2,1.24,3.01c0.29,0.29,0.29,0.77,0,1.06C8.85,16.71,8.66,16.79,8.46,16.79z"/>
   <path android:fillColor="@android:color/white" android:pathData="M18.36,19.61c-0.19,0-0.38-0.07-0.53-0.22c-0.29-0.29-0.29-0.77,0-1.06c1.56-1.56,2.42-3.63,2.42-5.83 s-0.86-4.28-2.42-5.83c-3.22-3.22-8.45-3.22-11.67,0C4.61,8.22,3.75,10.3,3.75,12.5s0.86,4.28,2.42,5.83 c0.29,0.29,0.29,0.77,0,1.06s-0.77,0.29-1.06,0c-1.84-1.84-2.86-4.29-2.86-6.89s1.01-5.05,2.86-6.89c3.8-3.8,9.99-3.8,13.79,0 c1.84,1.84,2.86,4.29,2.86,6.89s-1.01,5.05-2.86,6.89C18.75,19.54,18.56,19.61,18.36,19.61z"/>
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dialog_close.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dialog_close.xml
deleted file mode 100644
index 4c2e143..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dialog_close.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-<!--
-   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.
--->
-
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-  <path android:fillColor="@android:color/white" android:pathData="M20.03,3.97c-0.29-0.29-0.77-0.29-1.06,0L12,10.94L5.03,3.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-6.97,6.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L12,13.06l6.97,6.97 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06L13.06,12l6.97-6.97 C20.32,4.74,20.32,4.26,20.03,3.97z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 533b5f9..ebd7a28 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -15,6 +15,6 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M2.65,15.8L10,13.5V19l-1.6,1.2C8.15,20.39,8,20.69,8,21v0.67c0,0.17,0.14,0.28,0.31,0.24c1.94-0.55,1.3-0.37,3.19-0.91 c1.21,0.35,1.99,0.57,3.19,0.91c0.17,0.04,0.31-0.07,0.31-0.24V21c0-0.31-0.15-0.61-0.4-0.8L13,19v-5.5l7.35,2.3 c0.32,0.1,0.65-0.14,0.65-0.48v-0.49c0-0.52-0.27-1-0.7-1.27L13,9V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-7.3,4.56 C2.27,13.83,2,14.31,2,14.83v0.49C2,15.66,2.33,15.9,2.65,15.8z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
index 3079539..103985b 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M11,11H9c-0.55,0-1,0.45-1,1s0.45,1,1,1h2v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2h2c0.55,0,1-0.45,1-1s-0.45-1-1-1h-2V9 c0-0.55-0.45-1-1-1s-1,0.45-1,1V11z"/>
   <path android:fillColor="@android:color/white" android:pathData="M13,2.05v2.52c3.66,0.49,6.5,3.63,6.5,7.43c0,1.01-0.2,1.97-0.56,2.85l2.18,1.26C21.68,14.85,22,13.46,22,12 C22,6.81,18.05,2.55,13,2.05z"/>
   <path android:fillColor="@android:color/white" android:pathData="M12,19.5c-4.14,0-7.5-3.36-7.5-7.5c0-3.8,2.84-6.93,6.5-7.43V2.05C5.95,2.55,2,6.81,2,12c0,5.52,4.48,10,10,10 c3.34,0,6.3-1.65,8.11-4.17l-2.18-1.26C16.56,18.35,14.41,19.5,12,19.5z"/>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
index f6ae09b..43ca3cfae 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M15.46,16.46L15.46,16.46c0.44,0.44,1.17,0.4,1.51-0.1C17.62,15.4,18,14.25,18,13c0-3.75-3.45-6.7-7.34-5.86 c-2.24,0.48-4.04,2.3-4.52,4.54c-0.37,1.75,0.02,3.38,0.89,4.67c0.34,0.51,1.08,0.54,1.51,0.11l0.01-0.01 c0.34-0.34,0.37-0.88,0.1-1.28c-0.5-0.76-0.75-1.71-0.61-2.74c0.23-1.74,1.67-3.17,3.41-3.4C13.9,8.71,16,10.61,16,13 c0,0.8-0.24,1.54-0.64,2.17C15.09,15.58,15.11,16.11,15.46,16.46z"/>
   <path android:fillColor="@android:color/white" android:pathData="M10.86,3.06c-4.65,0.51-8.39,4.34-8.82,9c-0.25,2.72,0.6,5.25,2.15,7.18c0.37,0.46,1.07,0.49,1.49,0.07 C6.04,18.96,6.07,18.4,5.75,18c-1.4-1.75-2.09-4.1-1.6-6.61c0.61-3.13,3.14-5.65,6.28-6.24C15.54,4.18,20,8.07,20,13 c0,1.9-0.66,3.63-1.77,5c-0.32,0.39-0.28,0.96,0.08,1.31l0,0c0.42,0.42,1.12,0.39,1.49-0.08c1.38-1.7,2.2-3.88,2.2-6.24 C22,7.1,16.89,2.4,10.86,3.06z"/>
   <path android:fillColor="@android:color/white" android:pathData="M 12 11 C 13.1045694997 11 14 11.8954305003 14 13 C 14 14.1045694997 13.1045694997 15 12 15 C 10.8954305003 15 10 14.1045694997 10 13 C 10 11.8954305003 10.8954305003 11 12 11 Z"/>
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dialog_close.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dialog_close.xml
deleted file mode 100644
index 2047109..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dialog_close.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-<!--
-   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.
--->
-
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-  <path android:fillColor="@android:color/white" android:pathData="M5.7,18.3c0.39,0.39,1.02,0.39,1.41,0L12,13.41l4.89,4.89c0.39,0.39,1.02,0.39,1.41,0s0.39-1.02,0-1.41L13.41,12l4.89-4.89 c0.38-0.38,0.38-1.02,0-1.4c-0.39-0.39-1.02-0.39-1.41,0c0,0,0,0,0,0L12,10.59L7.11,5.7c-0.39-0.39-1.02-0.39-1.41,0 s-0.39,1.02,0,1.41L10.59,12L5.7,16.89C5.31,17.28,5.31,17.91,5.7,18.3z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 9182207..ed64277 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -15,6 +15,6 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M2.52,16.17c0.32,0.23,0.74,0.31,1.11,0.19l5.87-1.84v3.87L8,19.52c-0.31,0.24-0.5,0.61-0.5,1v0.75 c0,0.69,0.56,1.25,1.25,1.25h6.5c0.69,0,1.25-0.56,1.25-1.25v-0.75c0-0.39-0.19-0.76-0.5-1l-1.5-1.12v-3.87l5.88,1.84 c0.38,0.12,0.79,0.05,1.11-0.19c0.32-0.23,0.51-0.61,0.51-1.01l0-1.84c0-0.63-0.34-1.21-0.89-1.52L14.5,8.06V4 c0-1.38-1.12-2.5-2.5-2.5S9.5,2.62,9.5,4v4.07L2.89,11.8C2.35,12.11,2,12.7,2,13.33l0,1.83C2.01,15.56,2.2,15.94,2.52,16.17z M3.63,13.11L11,8.94V4c0-0.55,0.45-1,1-1s1,0.45,1,1v4.94l7.37,4.17c0.08,0.04,0.13,0.13,0.13,0.22l0,1.5L13,12.48v6.66l2,1.5 v0.38H9v-0.38l2-1.5v-6.66l-7.5,2.34l0-1.49C3.5,13.24,3.55,13.15,3.63,13.11z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
index 29f6ccb..5fa15f4 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z"/>
   <path android:fillColor="@android:color/white" android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z"/>
   <path android:fillColor="@android:color/white" android:pathData="M8,12a0.76 0.76 ,0,0,0,0.75 0.75 h2.5v2.5a0.75 0.75 ,0,0,0,1.5,0v-2.5h2.5a0.75 0.75 ,0,0,0,0-1.5h-2.5V8.75a0.75 0.75 ,0,0,0-1.5,0v2.5H8.75A0.76 0.76 ,0,0,0,8,12Z"/>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
index 6b2d8f0..419710d 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
   <path android:fillColor="@android:color/white" android:pathData="M 12 11 C 12.8284271247 11 13.5 11.6715728753 13.5 12.5 C 13.5 13.3284271247 12.8284271247 14 12 14 C 11.1715728753 14 10.5 13.3284271247 10.5 12.5 C 10.5 11.6715728753 11.1715728753 11 12 11 Z"/>
   <path android:fillColor="@android:color/white" android:pathData="M15.01,16.57c0.29,0.29,0.77,0.29,1.06,0c1.09-1.09,1.68-2.53,1.68-4.07s-0.6-2.98-1.68-4.07c-2.24-2.24-5.89-2.24-8.13,0 c-1.09,1.09-1.68,2.53-1.68,4.07s0.6,2.98,1.68,4.07c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22 c0.29-0.29,0.29-0.77,0-1.06c-0.8-0.8-1.24-1.87-1.24-3.01c0-1.13,0.44-2.2,1.24-3c1.66-1.66,4.35-1.66,6.01,0 c0.8,0.8,1.24,1.87,1.24,3.01c0,1.13-0.44,2.2-1.24,3C14.71,15.8,14.71,16.27,15.01,16.57z"/>
   <path android:fillColor="@android:color/white" android:pathData="M18.36,19.61c0.19,0,0.38-0.07,0.53-0.22c1.84-1.84,2.86-4.29,2.86-6.89s-1.01-5.05-2.86-6.89c-3.8-3.8-9.99-3.8-13.79,0 C3.26,7.45,2.25,9.9,2.25,12.5s1.01,5.05,2.86,6.89c0.29,0.29,0.77,0.29,1.06,0s0.29-0.77,0-1.06c-1.56-1.56-2.42-3.63-2.42-5.83 s0.86-4.28,2.42-5.83c3.22-3.22,8.45-3.22,11.67,0c1.56,1.56,2.42,3.63,2.42,5.83s-0.86,4.28-2.42,5.83 c-0.29,0.29-0.29,0.77,0,1.06C17.98,19.54,18.17,19.61,18.36,19.61z"/>
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dialog_close.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dialog_close.xml
deleted file mode 100644
index 2243cab..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dialog_close.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-<!--
-   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.
--->
-
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
-  <path android:fillColor="@android:color/white" android:pathData="M18.78,5.22c-0.29-0.29-0.77-0.29-1.06,0L12,10.94L6.28,5.22c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.72,5.72c-0.29,0.29-0.29,0.77,0,1.06C5.37,18.93,5.56,19,5.75,19s0.38-0.07,0.53-0.22L12,13.06l5.72,5.72 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06L13.06,12l5.72-5.72 C19.07,5.99,19.07,5.51,18.78,5.22z"/>
-</vector>
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index b759dd4..d7decb4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -116,6 +116,22 @@
      */
     private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
 
+    /**
+     * Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
+     * Settings.Global. This allows it to be set experimentally unless it has been
+     * enabled/disabled in developer options. Defaults to true.
+     */
+    private static final String KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED =
+            "default_background_activity_starts_enabled";
+
+    /**
+     * The packages temporarily whitelisted to be able to start activities from background.
+     * The list of packages is {@code ":"} colon delimited.
+     */
+    private static final String KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST =
+            "background_activity_starts_package_names_whitelist";
+
+
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
 
@@ -242,7 +258,8 @@
     volatile boolean mFlagActivityStartsLoggingEnabled;
 
     // Indicates whether the background activity starts is enabled.
-    // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED
+    // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED.
+    // If not set explicitly the default is controlled by DeviceConfig.
     volatile boolean mFlagBackgroundActivityStartsEnabled;
 
     volatile ArraySet<String> mPackageNamesWhitelistedForBgActivityStarts = new ArraySet<>();
@@ -295,10 +312,6 @@
                 Settings.Global.getUriFor(
                         Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED);
 
-    private static final Uri BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI =
-                Settings.Global.getUriFor(
-                        Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
-
     private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
             Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
 
@@ -306,8 +319,19 @@
             new OnPropertyChangedListener() {
                 @Override
                 public void onPropertyChanged(String namespace, String name, String value) {
-                    if (KEY_MAX_CACHED_PROCESSES.equals(name)) {
-                        updateMaxCachedProcesses();
+                    if (name == null) {
+                        return;
+                    }
+                    switch (name) {
+                        case KEY_MAX_CACHED_PROCESSES:
+                            updateMaxCachedProcesses();
+                            break;
+                        case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
+                        case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST:
+                            updateBackgroundActivityStarts();
+                            break;
+                        default:
+                            break;
                     }
                 }
             };
@@ -330,16 +354,11 @@
         mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this);
         mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
         mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_ENABLED_URI, false, this);
-        mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI,
-                false, this);
         if (mSystemServerAutomaticHeapDumpEnabled) {
             mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
                     false, this);
         }
         updateConstants();
-        updateActivityStartsLoggingEnabled();
-        updateBackgroundActivityStartsEnabled();
-        updateBackgroundActivityStartsPackageNamesWhitelist();
         if (mSystemServerAutomaticHeapDumpEnabled) {
             updateEnableAutomaticSystemServerHeapDumps();
         }
@@ -347,7 +366,8 @@
                 ActivityThread.currentApplication().getMainExecutor(),
                 mOnDeviceConfigChangedListener);
         updateMaxCachedProcesses();
-
+        updateActivityStartsLoggingEnabled();
+        updateBackgroundActivityStarts();
     }
 
     public void setOverrideMaxCachedProcesses(int value) {
@@ -371,9 +391,7 @@
         } else if (ACTIVITY_STARTS_LOGGING_ENABLED_URI.equals(uri)) {
             updateActivityStartsLoggingEnabled();
         } else if (BACKGROUND_ACTIVITY_STARTS_ENABLED_URI.equals(uri)) {
-            updateBackgroundActivityStartsEnabled();
-        } else if (BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI.equals(uri)) {
-            updateBackgroundActivityStartsPackageNamesWhitelist();
+            updateBackgroundActivityStarts();
         } else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
             updateEnableAutomaticSystemServerHeapDumps();
         }
@@ -463,24 +481,40 @@
                 Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
     }
 
-    private void updateBackgroundActivityStartsEnabled() {
-        mFlagBackgroundActivityStartsEnabled = Settings.Global.getInt(mResolver,
-                Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, 1) == 1;
-    }
+    private void updateBackgroundActivityStarts() {
+        String whitelistedPackageNames = null;
+        int settingsValue = Settings.Global.getInt(mResolver,
+                Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, -1);
 
-    private void updateBackgroundActivityStartsPackageNamesWhitelist() {
-        final String setting = Settings.Global.getString(mResolver,
-                Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
-        if (TextUtils.isEmpty(setting)) {
-            return;
+        // If the user has explicitly enabled or disabled, that affects all apps.
+        // Otherwise we take the default state and whitelist from DeviceConfig.
+        if (settingsValue >= 0) {
+            mFlagBackgroundActivityStartsEnabled = settingsValue != 0;
+        } else {
+            boolean enabledInDeviceConfig = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED,
+                    /*defaultValue*/ true);
+            mFlagBackgroundActivityStartsEnabled = enabledInDeviceConfig;
+            if (!enabledInDeviceConfig) {
+                whitelistedPackageNames = DeviceConfig.getProperty(
+                        DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                        KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
+            }
         }
-        ArraySet<String> newSet = new ArraySet<>();
-        SimpleStringSplitter splitter = new SimpleStringSplitter(':');
-        splitter.setString(setting);
-        while (splitter.hasNext()) {
-            newSet.add(splitter.next());
+        if (TextUtils.isEmpty(whitelistedPackageNames)) {
+            if (!mPackageNamesWhitelistedForBgActivityStarts.isEmpty()) {
+                mPackageNamesWhitelistedForBgActivityStarts = new ArraySet<>();
+            }
+        } else {
+            ArraySet<String> newSet = new ArraySet<>();
+            SimpleStringSplitter splitter = new SimpleStringSplitter(':');
+            splitter.setString(whitelistedPackageNames);
+            while (splitter.hasNext()) {
+                newSet.add(splitter.next());
+            }
+            mPackageNamesWhitelistedForBgActivityStarts = newSet;
         }
-        mPackageNamesWhitelistedForBgActivityStarts = newSet;
     }
 
     private void updateEnableAutomaticSystemServerHeapDumps() {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 06d0152..cb587de0 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -58,6 +58,8 @@
         sGlobalSettingToTypeMap.put(
                 Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, String.class);
         sGlobalSettingToTypeMap.put(
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE, String.class);
+        sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index d7a57b9..35f7ea3 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -132,6 +132,7 @@
         private static final int NOT_STARTED = 1;
         private static final int STARTING = 2;
         private static final int STARTED = 3;
+        private static final int STOPPING = 4;
         private int mStartedState = NOT_STARTED;
 
         KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@@ -314,6 +315,7 @@
                 }
             }
             if (NOT_STARTED != mStartedState) {
+                mStartedState = STOPPING;
                 Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
                 if (mType == TYPE_NATT) {
                     mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
@@ -456,8 +458,8 @@
             ki = mKeepalives.get(nai).get(slot);
         } catch(NullPointerException e) {}
         if (ki == null) {
-            Log.e(TAG, "Event " + message.what + " for unknown keepalive " + slot + " on "
-                    + nai.name());
+            Log.e(TAG, "Event " + message.what + "," + slot + "," + reason
+                    + " for unknown keepalive " + slot + " on " + nai.name());
             return;
         }
 
@@ -476,27 +478,30 @@
         // messages in order.
         // TODO : clarify this code and get rid of mStartedState. Using a StateMachine is an
         // option.
-        if (reason == SUCCESS && KeepaliveInfo.STARTING == ki.mStartedState) {
-            // Keepalive successfully started.
-            if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
-            ki.mStartedState = KeepaliveInfo.STARTED;
-            try {
-                ki.mCallback.onStarted(slot);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
-            }
-        } else {
-            // Keepalive successfully stopped, or error.
-            if (reason == SUCCESS) {
-                // The message indicated success stopping : don't call handleStopKeepalive.
-                if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name());
+        if (KeepaliveInfo.STARTING == ki.mStartedState) {
+            if (SUCCESS == reason) {
+                // Keepalive successfully started.
+                if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
+                ki.mStartedState = KeepaliveInfo.STARTED;
+                try {
+                    ki.mCallback.onStarted(slot);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
+                }
             } else {
-                // The message indicated some error trying to start or during the course of
-                // keepalive : do call handleStopKeepalive.
+                Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.name()
+                        + ": " + reason);
+                // The message indicated some error trying to start: do call handleStopKeepalive.
                 handleStopKeepalive(nai, slot, reason);
-                if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason);
             }
+        } else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
+            // The message indicated result of stopping : don't call handleStopKeepalive.
+            Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name()
+                    + " stopped: " + reason);
             ki.mStartedState = KeepaliveInfo.NOT_STARTED;
+        } else {
+            Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason
+                    + " for keepalive in wrong state: " + ki.toString());
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 190610c..a0f0a31 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -384,8 +384,10 @@
         PackageInstaller.SessionParams params = originalSession.params.copy();
         params.isStaged = false;
         params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
+        // TODO(b/129744602): use the userid from the original session.
         int apkSessionId = mPi.createSession(
-                params, originalSession.getInstallerPackageName(), originalSession.userId);
+                params, originalSession.getInstallerPackageName(),
+                0 /* UserHandle.SYSTEM */);
         PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
 
         try {
@@ -465,8 +467,10 @@
             }
             PackageInstaller.SessionParams params = session.params.copy();
             params.isStaged = false;
+            // TODO(b/129744602): use the userid from the original session.
             int apkParentSessionId = mPi.createSession(
-                    params, session.getInstallerPackageName(), session.userId);
+                    params, session.getInstallerPackageName(),
+                    0 /* UserHandle.SYSTEM */);
             PackageInstallerSession apkParentSession = mPi.getSession(apkParentSessionId);
             try {
                 apkParentSession.open();
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 15148f3..f83b3ea 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -110,6 +110,7 @@
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
 import com.android.internal.os.KernelCpuSpeedReader;
 import com.android.internal.os.KernelCpuThreadReader;
+import com.android.internal.os.KernelCpuThreadReaderDiff;
 import com.android.internal.os.KernelCpuThreadReaderSettingsObserver;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
@@ -262,7 +263,7 @@
     private StoragedUidIoStatsReader mStoragedUidIoStatsReader =
             new StoragedUidIoStatsReader();
     @Nullable
-    private final KernelCpuThreadReader mKernelCpuThreadReader;
+    private final KernelCpuThreadReaderDiff mKernelCpuThreadReader;
 
     private long mDebugElapsedClockPreviousValue = 0;
     private long mDebugElapsedClockPullCount = 0;
@@ -1726,7 +1727,7 @@
             throw new IllegalStateException("mKernelCpuThreadReader is null");
         }
         ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
-                this.mKernelCpuThreadReader.getProcessCpuUsage();
+                this.mKernelCpuThreadReader.getProcessCpuUsageDiffed();
         if (processCpuUsages == null) {
             throw new IllegalStateException("processCpuUsages is null");
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index bd28be1..cfa9944 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,17 +15,10 @@
  */
 package com.android.server.devicepolicy;
 
-import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
-import android.app.admin.StartInstallingUpdateCallback;
-import android.content.ComponentName;
-import android.os.ParcelFileDescriptor;
 
 import com.android.server.SystemService;
 
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Defines the required interface for IDevicePolicyManager implemenation.
  *
@@ -63,82 +56,4 @@
 
     public void clearSystemUpdatePolicyFreezePeriodRecord() {
     }
-
-    @Override
-    public long forceNetworkLogs() {
-        return 0;
-    }
-
-    @Override
-    public long forceSecurityLogs() {
-        return 0;
-    }
-
-    @Override
-    public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
-        return false;
-    }
-
-    @Override
-    public int setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
-        return DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
-    }
-
-    @Override
-    public int getGlobalPrivateDnsMode(ComponentName who) {
-        return DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
-    }
-
-    @Override
-    public String getGlobalPrivateDnsHost(ComponentName who) {
-        return null;
-    }
-
-    @Override
-    public void grantDeviceIdsAccessToProfileOwner(ComponentName who, int userId) { }
-
-    @Override
-    public int getPasswordComplexity() {
-        return DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
-    }
-
-    @Override
-    public void installUpdateFromFile(ComponentName admin,
-            ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback listener) {}
-
-    @Override
-    public void setCrossProfileCalendarPackages(ComponentName admin, List<String> packageNames) {
-    }
-
-    @Override
-    public List<String> getCrossProfileCalendarPackages(ComponentName admin) {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public boolean isPackageAllowedToAccessCalendarForUser(String packageName,
-            int userHandle) {
-        return false;
-    }
-
-    @Override
-    public List<String> getCrossProfileCalendarPackagesForUser(int userHandle) {
-        return Collections.emptyList();
-    }
-
-    @Override
-    public boolean isManagedKiosk() {
-        return false;
-    }
-
-    @Override
-    public boolean isUnattendedManagedKiosk() {
-        return false;
-    }
-
-    @Override
-    public boolean startViewCalendarEventInManagedProfile(String packageName, long eventId,
-            long start, long end, boolean allDay, int flags) {
-        return false;
-    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 042c9d9..3b15376 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -415,6 +415,39 @@
     }
 
     @Test
+    public void testIsAlarmInSchedule_alarmAndNowInSchedule_sameScheduleTrigger_daylightSavings() {
+        Calendar alarm = getDaylightSavingsDay();
+        alarm.set(Calendar.HOUR_OF_DAY, 23);
+        alarm.set(Calendar.MINUTE, 15);
+        alarm.set(Calendar.SECOND, 0);
+        alarm.set(Calendar.MILLISECOND, 0);
+
+        Calendar now = getDaylightSavingsDay();
+        now.set(Calendar.HOUR_OF_DAY, 2);
+        now.set(Calendar.MINUTE, 10);
+        now.set(Calendar.SECOND, 0);
+        now.set(Calendar.MILLISECOND, 0);
+        now.add(Calendar.DATE, 1); // add a day, on daylight savings this becomes 3:10am
+
+        final Calendar tempToday = getDaylightSavingsDay();
+        final Calendar tempTomorrow = getDaylightSavingsDay();
+        tempTomorrow.add(Calendar.DATE, 1);
+        mScheduleInfo.days = new int[] {tempToday.get(Calendar.DAY_OF_WEEK),
+                tempTomorrow.get(Calendar.DAY_OF_WEEK)};
+
+        mScheduleInfo.startHour = 22;
+        mScheduleInfo.startMinute = 15;
+        mScheduleInfo.endHour = 3;
+        mScheduleInfo.endMinute = 15;
+        mScheduleCalendar.setSchedule(mScheduleInfo);
+
+        assertTrue(mScheduleCalendar.isInSchedule(alarm.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isInSchedule(now.getTimeInMillis()));
+        assertTrue(mScheduleCalendar.isAlarmInSchedule(alarm.getTimeInMillis(),
+                now.getTimeInMillis()));
+    }
+
+    @Test
     public void testIsAlarmInSchedule_alarmAndNowInSchedule_sameScheduleTrigger() {
         Calendar alarm = new GregorianCalendar();
         alarm.set(Calendar.HOUR_OF_DAY, 23);
@@ -424,10 +457,10 @@
 
         Calendar now = new GregorianCalendar();
         now.set(Calendar.HOUR_OF_DAY, 2);
-        now.set(Calendar.MINUTE, 15);
+        now.set(Calendar.MINUTE, 10);
         now.set(Calendar.SECOND, 0);
         now.set(Calendar.MILLISECOND, 0);
-        now.add(Calendar.DATE, 1); // add a day
+        now.add(Calendar.DATE, 1); // add a day, on daylight savings this becomes 3:10am
 
         mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
         mScheduleInfo.startHour = 22;
@@ -481,4 +514,11 @@
         cal.add(Calendar.DATE, offset);
         return cal.get(Calendar.DAY_OF_WEEK);
     }
+
+
+    private Calendar getDaylightSavingsDay() {
+        // the day before daylight savings in the US - March 9, 2019
+        Calendar daylightSavingsDay = new GregorianCalendar(2019, 2, 9);
+        return daylightSavingsDay;
+    }
 }
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 6781eba..c856cc3 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -21,6 +21,7 @@
 import os
 import sys
 import re
+import functools
 
 # Names of flags recognized by the `hiddenapi` tool.
 FLAG_WHITELIST = "whitelist"
@@ -58,6 +59,10 @@
 # script to skip any entries which do not exist any more.
 FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts"
 
+# Suffix used in command line args to express that all apis within a given set
+# of packages should be assign the given flag.
+FLAG_PACKAGES_SUFFIX = "-packages"
+
 # Regex patterns of fields/methods used in serialization. These are
 # considered public API despite being hidden.
 SERIALIZATION_PATTERNS = [
@@ -91,12 +96,16 @@
 
     for flag in ALL_FLAGS:
         ignore_conflicts_flag = flag + FLAG_IGNORE_CONFLICTS_SUFFIX
+        packages_flag = flag + FLAG_PACKAGES_SUFFIX
         parser.add_argument('--' + flag, dest=flag, nargs='*', default=[], metavar='TXT_FILE',
             help='lists of entries with flag "' + flag + '"')
         parser.add_argument('--' + ignore_conflicts_flag, dest=ignore_conflicts_flag, nargs='*',
             default=[], metavar='TXT_FILE',
             help='lists of entries with flag "' + flag +
                  '". skip entry if missing or flag conflict.')
+        parser.add_argument('--' + packages_flag, dest=packages_flag, nargs='*',
+            default=[], metavar='TXT_FILE',
+            help='lists of packages to be added to ' + flag + ' list')
 
     return parser.parse_args()
 
@@ -128,6 +137,19 @@
     with open(filename, 'w') as f:
         f.writelines(lines)
 
+def extract_package(signature):
+    """Extracts the package from a signature.
+
+    Args:
+        signature (string): JNI signature of a method or field.
+
+    Returns:
+        The package name of the class containing the field/method.
+    """
+    full_class_name = signature.split(";->")[0]
+    package_name = full_class_name[1:full_class_name.rindex("/")]
+    return package_name.replace('/', '.')
+
 class FlagsDict:
     def __init__(self):
         self._dict_keyset = set()
@@ -206,7 +228,10 @@
         self._dict_keyset.update([ csv[0] for csv in csv_values ])
 
         # Check that all flags are known.
-        csv_flags = set(reduce(lambda x, y: set(x).union(y), [ csv[1:] for csv in csv_values ], []))
+        csv_flags = set(functools.reduce(
+            lambda x, y: set(x).union(y),
+            [ csv[1:] for csv in csv_values ],
+            []))
         self._check_flags_set(csv_flags, source)
 
         # Iterate over all CSV lines, find entry in dict and append flags to it.
@@ -273,6 +298,15 @@
             valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(filename))
             flags.assign_flag(flag, valid_entries, filename)
 
+    # All members in the specified packages will be assigned the appropriate flag.
+    for flag in ALL_FLAGS:
+        for filename in args[flag + FLAG_PACKAGES_SUFFIX]:
+            packages_needing_list = set(read_lines(filename))
+            should_add_signature_to_list = lambda sig,lists: extract_package(
+                sig) in packages_needing_list and not lists
+            valid_entries = flags.filter_apis(should_add_signature_to_list)
+            flags.assign_flag(flag, valid_entries)
+
     # Assign all remaining entries to the blacklist.
     flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
 
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 249f37d..4dc880b 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -18,33 +18,23 @@
 from generate_hiddenapi_lists import *
 
 class TestHiddenapiListGeneration(unittest.TestCase):
-    def test_init(self):
-        # Check empty lists
-        flags = FlagsDict([], [])
-        self.assertEquals(flags.generate_csv(), [])
-
-        # Check valid input - two public and two private API signatures.
-        flags = FlagsDict(['A', 'B'], ['C', 'D'])
-        self.assertEquals(flags.generate_csv(),
-                          [ 'A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST, 'C', 'D' ])
-
-        # Check invalid input - overlapping public/private API signatures.
-        with self.assertRaises(AssertionError):
-            flags = FlagsDict(['A', 'B'], ['B', 'C', 'D'])
 
     def test_filter_apis(self):
         # Initialize flags so that A and B are put on the whitelist and
         # C, D, E are left unassigned. Try filtering for the unassigned ones.
-        flags = FlagsDict(['A', 'B'], ['C', 'D', 'E'])
+        flags = FlagsDict()
+        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST,
+                        'C', 'D', 'E'])
         filter_set = flags.filter_apis(lambda api, flags: not flags)
         self.assertTrue(isinstance(filter_set, set))
         self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
 
     def test_get_valid_subset_of_unassigned_keys(self):
         # Create flags where only A is unassigned.
-        flags = FlagsDict(['A'], ['B', 'C'])
+        flags = FlagsDict()
+        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C'])
         flags.assign_flag(FLAG_GREYLIST, set(['C']))
-        self.assertEquals(flags.generate_csv(),
+        self.assertEqual(flags.generate_csv(),
             [ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ])
 
         # Check three things:
@@ -55,44 +45,30 @@
             flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
 
     def test_parse_and_merge_csv(self):
-        flags = FlagsDict(['A'], ['B'])
-        self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+        flags = FlagsDict()
 
         # Test empty CSV entry.
-        flags.parse_and_merge_csv(['B'])
-        self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
-
-        # Test assigning an already assigned flag.
-        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST])
-        self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+        self.assertEqual(flags.generate_csv(), [])
 
         # Test new additions.
         flags.parse_and_merge_csv([
             'A,' + FLAG_GREYLIST,
             'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O ])
         self.assertEqual(flags.generate_csv(),
-            [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST,
+            [ 'A,' + FLAG_GREYLIST,
               'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O ])
 
-        # Test unknown API signature.
-        with self.assertRaises(AssertionError):
-            flags.parse_and_merge_csv([ 'C' ])
-
         # Test unknown flag.
         with self.assertRaises(AssertionError):
-            flags.parse_and_merge_csv([ 'A,foo' ])
+            flags.parse_and_merge_csv([ 'C,foo' ])
 
     def test_assign_flag(self):
-        flags = FlagsDict(['A'], ['B'])
-        self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
-
-        # Test assigning an already assigned flag.
-        flags.assign_flag(FLAG_WHITELIST, set([ 'A' ]))
-        self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+        flags = FlagsDict()
+        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B'])
 
         # Test new additions.
         flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ]))
-        self.assertEquals(flags.generate_csv(),
+        self.assertEqual(flags.generate_csv(),
             [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ])
 
         # Test invalid API signature.
@@ -103,5 +79,18 @@
         with self.assertRaises(AssertionError):
             flags.assign_flag('foo', set([ 'A' ]))
 
+    def test_extract_package(self):
+        signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
+        expected_package = 'com.foo.bar'
+        self.assertEqual(extract_package(signature), expected_package)
+
+        signature = 'Lcom/foo1/bar/MyClass;->method2()V'
+        expected_package = 'com.foo1.bar'
+        self.assertEqual(extract_package(signature), expected_package)
+
+        signature = 'Lcom/foo_bar/baz/MyClass;->method3()V'
+        expected_package = 'com.foo_bar.baz'
+        self.assertEqual(extract_package(signature), expected_package)
+
 if __name__ == '__main__':
     unittest.main()