Merge "Rename CrossProfileApps API as per API council feedback"
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 93a0fc3..0ac167f 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -190,8 +190,11 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final MeasuredText text = MeasuredText.build(
-                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+                    .build();
             state.resumeTiming();
 
             StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
@@ -206,8 +209,11 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final MeasuredText text = MeasuredText.build(
-                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+                    .build();
             state.resumeTiming();
 
             StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
@@ -222,8 +228,11 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final MeasuredText text = MeasuredText.build(
-                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+                    .build();
             state.resumeTiming();
 
             StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
@@ -238,8 +247,11 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final MeasuredText text = MeasuredText.build(
-                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT, LTR);
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
+                    .build();
             state.resumeTiming();
 
             StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
@@ -254,8 +266,11 @@
         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             state.pauseTiming();
-            final MeasuredText text = MeasuredText.build(
-                    generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT, LTR);
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+                    .build();
             state.resumeTiming();
 
             StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
diff --git a/api/current.txt b/api/current.txt
index 9232bfd..06f3b2a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5859,11 +5859,15 @@
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public static int getResultsSource(android.content.Intent);
     method public boolean isDataOnly();
+    method public static void setResultsSource(android.content.Intent, int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
     field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+    field public static final int SOURCE_CHOICE = 1; // 0x1
+    field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
   }
 
   public static final class RemoteInput.Builder {
@@ -42312,10 +42316,10 @@
   }
 
   public class MeasuredText implements android.text.Spanned {
-    method public static android.text.MeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic);
-    method public static android.text.MeasuredText build(java.lang.CharSequence, android.text.TextPaint, android.text.TextDirectionHeuristic, int, int);
     method public char charAt(int);
+    method public int getBreakStrategy();
     method public int getEnd();
+    method public int getHyphenationFrequency();
     method public android.text.TextPaint getPaint();
     method public int getParagraphCount();
     method public int getParagraphEnd(int);
@@ -42332,6 +42336,15 @@
     method public java.lang.CharSequence subSequence(int, int);
   }
 
+  public static final class MeasuredText.Builder {
+    ctor public MeasuredText.Builder(java.lang.CharSequence, android.text.TextPaint);
+    method public android.text.MeasuredText build();
+    method public android.text.MeasuredText.Builder setBreakStrategy(int);
+    method public android.text.MeasuredText.Builder setHyphenationFrequency(int);
+    method public android.text.MeasuredText.Builder setRange(int, int);
+    method public android.text.MeasuredText.Builder setTextDirection(android.text.TextDirectionHeuristic);
+  }
+
   public abstract interface NoCopySpan {
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 6390de6..a29d3a0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1118,9 +1118,9 @@
   }
 
   public static class BrightnessConfiguration.Builder {
-    ctor public BrightnessConfiguration.Builder();
+    ctor public BrightnessConfiguration.Builder(float[], float[]);
     method public android.hardware.display.BrightnessConfiguration build();
-    method public android.hardware.display.BrightnessConfiguration.Builder setCurve(float[], float[]);
+    method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
   }
 
   public final class DisplayManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6941731..6369bb4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -320,9 +320,9 @@
   }
 
   public static class BrightnessConfiguration.Builder {
-    ctor public BrightnessConfiguration.Builder();
+    ctor public BrightnessConfiguration.Builder(float[], float[]);
     method public android.hardware.display.BrightnessConfiguration build();
-    method public android.hardware.display.BrightnessConfiguration.Builder setCurve(float[], float[]);
+    method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
   }
 
   public final class DisplayManager {
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 2c35d41..9bddbcb 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -36,7 +36,7 @@
     src/config/ConfigManager.cpp \
     src/external/StatsPuller.cpp \
     src/external/StatsCompanionServicePuller.cpp \
-    src/external/ResourcePowerManagerPuller.cpp \
+    src/external/SubsystemSleepStatePuller.cpp \
     src/external/CpuTimePerUidPuller.cpp \
     src/external/CpuTimePerUidFreqPuller.cpp \
     src/external/StatsPullerManagerImpl.cpp \
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 0ed1c1f..ca097d0 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -185,6 +185,7 @@
  */
 void StatsService::dump_impl(FILE* out) {
     mConfigManager->Dump(out);
+    StatsdStats::getInstance().dumpStats(out);
 }
 
 /**
@@ -296,9 +297,8 @@
     fprintf(out, "  NAME          The name of the configuration\n");
     fprintf(out, "\n");
     fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats print-stats [reset]\n");
+    fprintf(out, "usage: adb shell cmd stats print-stats\n");
     fprintf(out, "  Prints some basic stats.\n");
-    fprintf(out, "  reset: 1 to reset the statsd stats. default=0.\n");
 }
 
 status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
@@ -487,14 +487,8 @@
         fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
                 mProcessor->GetMetricsSize(key));
     }
-    fprintf(out, "Detailed statsd stats in logcat...\n");
     StatsdStats& statsdStats = StatsdStats::getInstance();
-    bool reset = false;
-    if (args.size() > 1) {
-        reset = strtol(args[1].string(), NULL, 10);
-    }
-    vector<uint8_t> output;
-    statsdStats.dumpStats(&output, reset);
+    statsdStats.dumpStats(out);
     return NO_ERROR;
 }
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4a7f0c4..7d513cd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -94,9 +94,8 @@
         MobileBytesTransfer mobile_bytes_transfer = 10002;
         MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003;
         KernelWakelock kernel_wakelock = 10004;
-        PlatformSleepState platform_sleep_state = 10005;
-        SleepStateVoter sleep_state_voter = 10006;
-        SubsystemSleepState subsystem_sleep_state = 10007;
+        SubsystemSleepState subsystem_sleep_state = 10005;
+        // 10006 and 10007 are free to use.
         CpuTimePerFreq cpu_time_per_freq = 10008;
         CpuTimePerUid cpu_time_per_uid = 10009;
         CpuTimePerUidFreq cpu_time_per_uid_freq = 10010;
@@ -1027,44 +1026,21 @@
 }
 
 /**
- * Pulls PowerStatePlatformSleepState.
- *
- * Definition here:
+ * Pulls low power state information. This includes platform and subsystem sleep state information,
+ * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState as defined in
  *   hardware/interfaces/power/1.0/types.hal
- */
-message PlatformSleepState {
-    optional string name = 1;
-    optional uint64 residency_in_msec_since_boot = 2;
-    optional uint64 total_transitions = 3;
-    optional bool supported_only_in_suspend = 4;
-}
-
-/**
- * Pulls PowerStateVoter.
- *
- * Definition here:
- *   hardware/interfaces/power/1.0/types.hal
- */
-message SleepStateVoter {
-    optional string platform_sleep_state_name = 1;
-    optional string voter_name = 2;
-    optional uint64 total_time_in_msec_voted_for_since_boot = 3;
-    optional uint64 total_number_of_times_voted_since_boot = 4;
-}
-
-/**
- * Pulls PowerStateSubsystemSleepState.
- *
- * Definition here:
  *   hardware/interfaces/power/1.1/types.hal
  */
 message SubsystemSleepState {
-    optional string subsystem_name = 1;
-    optional string subsystem_sleep_state_name = 2;
-    optional uint64 residency_in_msec_since_boot = 3;
-    optional uint64 total_transitions = 4;
-    optional uint64 last_entry_timestamp_ms = 5;
-    optional bool supported_only_in_suspend = 6;
+    // Name should be in the format of XXX.YYY where XXX is subsystem name,
+    // YYY is corresponding voter name.
+    // If there are no voters, the format should just be XXX (with no dot).
+    // XXX and YYY should not contain a "." in it.
+    optional string name = 1;
+    // The number of times it entered, or voted for entering the sleep state
+    optional uint64 count = 2;
+    // The length of time spent in, or spent voting for, the sleep state
+    optional uint64 timeMs = 3;
 }
 
 /**
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 58c7b12..bb2e8c0 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -23,7 +23,7 @@
 #include <climits>
 #include "CpuTimePerUidFreqPuller.h"
 #include "CpuTimePerUidPuller.h"
-#include "ResourcePowerManagerPuller.h"
+#include "SubsystemSleepStatePuller.h"
 #include "StatsCompanionServicePuller.h"
 #include "StatsPullerManagerImpl.h"
 #include "StatsService.h"
@@ -58,13 +58,9 @@
     mPullers.insert({android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
                      make_shared<StatsCompanionServicePuller>(
                              android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)});
-    mPullers.insert({android::util::PLATFORM_SLEEP_STATE,
-                     make_shared<ResourcePowerManagerPuller>(android::util::PLATFORM_SLEEP_STATE)});
-    mPullers.insert({android::util::SLEEP_STATE_VOTER,
-                     make_shared<ResourcePowerManagerPuller>(android::util::SLEEP_STATE_VOTER)});
     mPullers.insert(
             {android::util::SUBSYSTEM_SLEEP_STATE,
-             make_shared<ResourcePowerManagerPuller>(android::util::SUBSYSTEM_SLEEP_STATE)});
+             make_shared<SubsystemSleepStatePuller>()});
     mPullers.insert({android::util::CPU_TIME_PER_FREQ, make_shared<StatsCompanionServicePuller>(android::util::CPU_TIME_PER_FREQ)});
     mPullers.insert({android::util::CPU_TIME_PER_UID, make_shared<CpuTimePerUidPuller>()});
     mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, make_shared<CpuTimePerUidFreqPuller>()});
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
similarity index 85%
rename from cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
rename to cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 2e29fb0..6d12e25 100644
--- a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -30,10 +30,10 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include "external/ResourcePowerManagerPuller.h"
+#include "external/SubsystemSleepStatePuller.h"
 #include "external/StatsPuller.h"
 
-#include "ResourcePowerManagerPuller.h"
+#include "SubsystemSleepStatePuller.h"
 #include "logd/LogEvent.h"
 #include "statslog.h"
 
@@ -73,10 +73,10 @@
     return gPowerHalV1_0 != nullptr;
 }
 
-ResourcePowerManagerPuller::ResourcePowerManagerPuller(int tagId) : StatsPuller(tagId) {
+SubsystemSleepStatePuller::SubsystemSleepStatePuller() : StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
 }
 
-bool ResourcePowerManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
     std::lock_guard<std::mutex> lock(gPowerHalMutex);
 
     if (!getPowerHal()) {
@@ -89,8 +89,6 @@
     data->clear();
 
     Return<void> ret;
-    if (mTagId == android::util::PLATFORM_SLEEP_STATE ||
-        mTagId == android::util::SLEEP_STATE_VOTER) {
         ret = gPowerHalV1_0->getPlatformLowPowerStats(
                 [&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
                     if (status != Status::SUCCESS) return;
@@ -98,12 +96,11 @@
                     for (size_t i = 0; i < states.size(); i++) {
                         const PowerStatePlatformSleepState& state = states[i];
 
-                        auto statePtr = make_shared<LogEvent>(android::util::PLATFORM_SLEEP_STATE,
+                        auto statePtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
                                                               timestamp);
                         statePtr->write(state.name);
-                        statePtr->write(state.residencyInMsecSinceBoot);
                         statePtr->write(state.totalTransitions);
-                        statePtr->write(state.supportedOnlyInSuspend);
+                        statePtr->write(state.residencyInMsecSinceBoot);
                         statePtr->init();
                         data->push_back(statePtr);
                         VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
@@ -111,12 +108,11 @@
                              (long long)state.totalTransitions,
                              state.supportedOnlyInSuspend ? 1 : 0);
                         for (auto voter : state.voters) {
-                            auto voterPtr = make_shared<LogEvent>(android::util::SLEEP_STATE_VOTER,
+                            auto voterPtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
                                                                   timestamp);
-                            voterPtr->write(state.name);
-                            voterPtr->write(voter.name);
-                            voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
+                            voterPtr->write((std::string)state.name + "." + (std::string)voter.name);
                             voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
+                            voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
                             voterPtr->init();
                             data->push_back(voterPtr);
                             VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
@@ -131,9 +127,7 @@
             gPowerHalV1_0 = nullptr;
             return false;
         }
-    }
 
-    if (mTagId == android::util::SUBSYSTEM_SLEEP_STATE) {
         // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
         sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
                 android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
@@ -149,13 +143,10 @@
                                     const PowerStateSubsystemSleepState& state =
                                             subsystem.states[j];
                                     auto subsystemStatePtr = make_shared<LogEvent>(
-                                            android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
-                                    subsystemStatePtr->write(subsystem.name);
-                                    subsystemStatePtr->write(state.name);
-                                    subsystemStatePtr->write(state.residencyInMsecSinceBoot);
+                                        android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
+                                    subsystemStatePtr->write((std::string)subsystem.name + "." + (std::string)state.name);
                                     subsystemStatePtr->write(state.totalTransitions);
-                                    subsystemStatePtr->write(state.lastEntryTimestampMs);
-                                    subsystemStatePtr->write(state.supportedOnlyInSuspend);
+                                    subsystemStatePtr->write(state.residencyInMsecSinceBoot);
                                     subsystemStatePtr->init();
                                     data->push_back(subsystemStatePtr);
                                     VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
@@ -168,7 +159,6 @@
                         }
                     });
         }
-    }
     return true;
 }
 
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.h b/cmds/statsd/src/external/SubsystemSleepStatePuller.h
similarity index 90%
rename from cmds/statsd/src/external/ResourcePowerManagerPuller.h
rename to cmds/statsd/src/external/SubsystemSleepStatePuller.h
index 3399408..17ce5b4 100644
--- a/cmds/statsd/src/external/ResourcePowerManagerPuller.h
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.h
@@ -26,9 +26,9 @@
 /**
  * Reads hal for sleep states
  */
-class ResourcePowerManagerPuller : public StatsPuller {
+class SubsystemSleepStatePuller : public StatsPuller {
 public:
-    ResourcePowerManagerPuller(int tagId);
+    SubsystemSleepStatePuller();
     bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
 };
 
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 36dd616..63bde7d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -66,8 +66,6 @@
         {android::util::MOBILE_BYTES_TRANSFER, 1},
         {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1},
         {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1},
-        {android::util::PLATFORM_SLEEP_STATE, 1},
-        {android::util::SLEEP_STATE_VOTER, 1},
         {android::util::SUBSYSTEM_SLEEP_STATE, 1},
         {android::util::CPU_TIME_PER_FREQ, 1},
         {android::util::CPU_TIME_PER_UID, 1},
@@ -357,73 +355,135 @@
     }
 }
 
+void StatsdStats::dumpStats(FILE* out) const {
+    lock_guard<std::mutex> lock(mLock);
+    time_t t = mStartTimeSec;
+    struct tm* tm = localtime(&t);
+    char timeBuffer[80];
+    strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm);
+    fprintf(out, "Stats collection start second: %s\n", timeBuffer);
+    fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
+    for (const auto& configStats : mIceBox) {
+        fprintf(out,
+                "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+                "#matcher=%d, #alert=%d,  valid=%d\n",
+                configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
+                configStats.deletion_time_sec(), configStats.metric_count(),
+                configStats.condition_count(), configStats.matcher_count(),
+                configStats.alert_count(), configStats.is_valid());
+
+        for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) {
+            fprintf(out, "\tbroadcast time: %d\n", broadcastTime);
+        }
+
+        for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
+            fprintf(out, "\tdata drop time: %d\n", dataDropTime);
+        }
+    }
+    fprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size());
+    for (auto& pair : mConfigStats) {
+        auto& key = pair.first;
+        auto& configStats = pair.second;
+
+        fprintf(out,
+                "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+                "#matcher=%d, #alert=%d,  valid=%d\n",
+                configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
+                configStats.deletion_time_sec(), configStats.metric_count(),
+                configStats.condition_count(), configStats.matcher_count(),
+                configStats.alert_count(), configStats.is_valid());
+        for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) {
+            fprintf(out, "\tbroadcast time: %d\n", broadcastTime);
+        }
+
+        for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
+            fprintf(out, "\tdata drop time: %d\n", dataDropTime);
+        }
+
+        for (const auto& dumpTime : configStats.dump_report_time_sec()) {
+            fprintf(out, "\tdump report time: %d\n", dumpTime);
+        }
+
+        // Add matcher stats
+        auto matcherIt = mMatcherStats.find(key);
+        if (matcherIt != mMatcherStats.end()) {
+            const auto& matcherStats = matcherIt->second;
+            for (const auto& stats : matcherStats) {
+                fprintf(out, "matcher %lld matched %d times\n", (long long)stats.first,
+                        stats.second);
+            }
+        }
+        // Add condition stats
+        auto conditionIt = mConditionStats.find(key);
+        if (conditionIt != mConditionStats.end()) {
+            const auto& conditionStats = conditionIt->second;
+            for (const auto& stats : conditionStats) {
+                fprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first,
+                        stats.second);
+            }
+        }
+        // Add metrics stats
+        auto metricIt = mMetricsStats.find(key);
+        if (metricIt != mMetricsStats.end()) {
+            const auto& conditionStats = metricIt->second;
+            for (const auto& stats : conditionStats) {
+                fprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first,
+                        stats.second);
+            }
+        }
+        // Add anomaly detection alert stats
+        auto alertIt = mAlertStats.find(key);
+        if (alertIt != mAlertStats.end()) {
+            const auto& alertStats = alertIt->second;
+            for (const auto& stats : alertStats) {
+                fprintf(out, "alert %lld declared %d times\n", (long long)stats.first,
+                        stats.second);
+            }
+        }
+    }
+    fprintf(out, "********Pushed Atom stats***********\n");
+    const size_t atomCounts = mPushedAtomStats.size();
+    for (size_t i = 2; i < atomCounts; i++) {
+        if (mPushedAtomStats[i] > 0) {
+            fprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
+        }
+    }
+
+    fprintf(out, "********Pulled Atom stats***********\n");
+    for (const auto& pair : mPulledAtomStats) {
+        fprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull,
+             (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec);
+    }
+
+    if (mAnomalyAlarmRegisteredStats > 0) {
+        fprintf(out, "********AnomalyAlarmStats stats***********\n");
+        fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
+    }
+
+    fprintf(out,
+            "UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
+            "lost=%d\n",
+            mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(),
+            mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes());
+}
+
 void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
     lock_guard<std::mutex> lock(mLock);
 
-    if (DEBUG) {
-        time_t t = mStartTimeSec;
-        struct tm* tm = localtime(&t);
-        char timeBuffer[80];
-        strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p", tm);
-        VLOG("=================StatsdStats dump begins====================");
-        VLOG("Stats collection start second: %s", timeBuffer);
-    }
     ProtoOutputStream proto;
     proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec);
     proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr));
 
-    VLOG("%lu Config in icebox: ", (unsigned long)mIceBox.size());
     for (const auto& configStats : mIceBox) {
         const int numBytes = configStats.ByteSize();
         vector<char> buffer(numBytes);
         configStats.SerializeToArray(&buffer[0], numBytes);
         proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0],
                     buffer.size());
-
-        // surround the whole block with DEBUG, so that compiler can strip out the code
-        // in production.
-        if (DEBUG) {
-            VLOG("*****ICEBOX*****");
-            VLOG("Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
-                 "#matcher=%d, #alert=%d,  #valid=%d",
-                 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
-                 configStats.deletion_time_sec(), configStats.metric_count(),
-                 configStats.condition_count(), configStats.matcher_count(),
-                 configStats.alert_count(), configStats.is_valid());
-
-            for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) {
-                VLOG("\tbroadcast time: %d", broadcastTime);
-            }
-
-            for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
-                VLOG("\tdata drop time: %d", dataDropTime);
-            }
-        }
     }
 
     for (auto& pair : mConfigStats) {
         auto& configStats = pair.second;
-        if (DEBUG) {
-            VLOG("********Active Configs***********");
-            VLOG("Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
-                 "#matcher=%d, #alert=%d,  #valid=%d",
-                 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
-                 configStats.deletion_time_sec(), configStats.metric_count(),
-                 configStats.condition_count(), configStats.matcher_count(),
-                 configStats.alert_count(), configStats.is_valid());
-            for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) {
-                VLOG("\tbroadcast time: %d", broadcastTime);
-            }
-
-            for (const auto& dataDropTime : configStats.data_drop_time_sec()) {
-                VLOG("\tdata drop time: %d", dataDropTime);
-            }
-
-            for (const auto& dumpTime : configStats.dump_report_time_sec()) {
-                VLOG("\tdump report time: %d", dumpTime);
-            }
-        }
-
         addSubStatsToConfigLocked(pair.first, configStats);
 
         const int numBytes = configStats.ByteSize();
@@ -439,7 +499,6 @@
         configStats.clear_alert_stats();
     }
 
-    VLOG("********Pushed Atom stats***********");
     const size_t atomCounts = mPushedAtomStats.size();
     for (size_t i = 2; i < atomCounts; i++) {
         if (mPushedAtomStats[i] > 0) {
@@ -448,34 +507,24 @@
             proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, (int32_t)i);
             proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, mPushedAtomStats[i]);
             proto.end(token);
-
-            VLOG("Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]);
         }
     }
 
-    VLOG("********Pulled Atom stats***********");
     for (const auto& pair : mPulledAtomStats) {
         android::os::statsd::writePullerStatsToStream(pair, &proto);
-        VLOG("Atom %d->%ld, %ld, %ld\n", (int) pair.first, (long) pair.second.totalPull, (long) pair.second.totalPullFromCache, (long) pair.second.minPullIntervalSec);
     }
 
     if (mAnomalyAlarmRegisteredStats > 0) {
-        VLOG("********AnomalyAlarmStats stats***********");
         long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS);
         proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED,
                     mAnomalyAlarmRegisteredStats);
         proto.end(token);
-        VLOG("Anomaly alarm registrations: %d", mAnomalyAlarmRegisteredStats);
     }
 
     const int numBytes = mUidMapStats.ByteSize();
     vector<char> buffer(numBytes);
     mUidMapStats.SerializeToArray(&buffer[0], numBytes);
     proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS, &buffer[0], buffer.size());
-    VLOG("UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
-         "lost=%d",
-         mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(),
-         mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes());
 
     output->clear();
     size_t bufferSize = proto.size();
@@ -495,7 +544,6 @@
     }
 
     VLOG("reset=%d, returned proto size %lu", reset, (unsigned long)bufferSize);
-    VLOG("=================StatsdStats dump ends====================");
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 52ab253..9178daa4 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -189,6 +189,11 @@
      */
     void dumpStats(std::vector<uint8_t>* buffer, bool reset);
 
+    /**
+     * Output statsd stats in human readable format to [out] file.
+     */
+    void dumpStats(FILE* out) const;
+
     typedef struct {
         long totalPull;
         long totalPullFromCache;
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index c542db2..1d75e20 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -111,20 +111,21 @@
 
         int index = 0;
         int uid = 0;
-        string configName;
+        int64_t configID = 0;
         char* substr = strtok(name, "-");
         // Timestamp lives at index 2 but we skip parsing it as it's not needed.
         while (substr != nullptr && index < 2) {
-            if (index) {
+            if (index == 0) {
                 uid = atoi(substr);
-            } else {
-                configName = substr;
+            } else if (index == 1) {
+                configID = StrToInt64(substr);
             }
             index++;
+            substr = strtok(nullptr, "-");
         }
         if (index < 2) continue;
 
-        sendBroadcast(ConfigKey(uid, StrToInt64(configName)));
+        sendBroadcast(ConfigKey(uid, configID));
     }
 }
 
@@ -143,19 +144,23 @@
 
         int index = 0;
         int uid = 0;
-        string configName;
+        int64_t configID = 0;
+        int64_t timestamp = 0;
         char* substr = strtok(name, "-");
-        // Timestamp lives at index 2 but we skip parsing it as it's not needed.
-        while (substr != nullptr && index < 2) {
-            if (index) {
+        while (substr != nullptr && index < 3) {
+            if (index == 0) {
                 uid = atoi(substr);
-            } else {
-                configName = substr;
+            } else if (index == 1) {
+                configID = StrToInt64(substr);
+            } else if (index == 2) {
+                timestamp = atoi(substr);
             }
             index++;
+            substr = strtok(nullptr, "-");
         }
-        if (index < 2) continue;
-        string file_name = StringPrintf("%s/%s", path, name);
+        if (index < 3) continue;
+        string file_name = StringPrintf("%s/%d-%lld-%lld", STATS_SERVICE_DIR, uid,
+                                        (long long)configID, (long long)timestamp);
         int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
         if (fd != -1) {
             string content;
@@ -186,29 +191,32 @@
 
         int index = 0;
         int uid = 0;
-        string configName;
+        int64_t configID = 0;
+        int64_t timestamp = 0;
         char* substr = strtok(name, "-");
-        // Timestamp lives at index 2 but we skip parsing it as it's not needed.
-        while (substr != nullptr && index < 2) {
-            if (index) {
+        while (substr != nullptr && index < 3) {
+            if (index == 0) {
                 uid = atoi(substr);
-            } else {
-                configName = substr;
+            } else if (index == 1) {
+                configID = StrToInt64(substr);
+            } else if (index == 2) {
+                timestamp = atoi(substr);
             }
             index++;
+            substr = strtok(nullptr, "-");
         }
-        if (index < 2) continue;
+        if (index < 3) continue;
 
-        string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
-        VLOG("full file %s", file_name.c_str());
+        string file_name = StringPrintf("%s/%d-%lld-%lld", STATS_SERVICE_DIR, uid,
+                                        (long long)configID, (long long)timestamp);
         int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
         if (fd != -1) {
             string content;
             if (android::base::ReadFdToString(fd, &content)) {
                 StatsdConfig config;
                 if (config.ParseFromString(content)) {
-                    configsMap[ConfigKey(uid, StrToInt64(configName))] = config;
-                    VLOG("map key uid=%d|name=%s", uid, name);
+                    configsMap[ConfigKey(uid, configID)] = config;
+                    VLOG("map key uid=%d|configID=%lld", uid, (long long)configID);
                 }
             }
             close(fd);
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index cc02f34..62bdba4 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -91,7 +91,7 @@
     {
         InSequence s;
 
-        manager->Startup();
+        manager->StartupForTest();
 
         // Add another one
         EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index db12c37..ccb54f9 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -334,4 +334,9 @@
      * Sets the user switcher message for switching to {@link android.os.UserHandle#SYSTEM}.
      */
     public abstract void setSwitchingToSystemUserMessage(String switchingToSystemUserMessage);
+
+    /**
+     * Returns maximum number of users that can run simultaneously.
+     */
+    public abstract int getMaxRunningUsers();
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1653430..4914ffa 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -872,13 +872,19 @@
 
         // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
         // generally not allowed, except if the caller specifies the task id the activity should
-        // be launched in.
-        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
-                && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
+        // be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
+        // maintain this for backwards compatibility.
+        final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
+
+        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+                && (targetSdkVersion < Build.VERSION_CODES.N
+                        || targetSdkVersion >= Build.VERSION_CODES.P)
+                && (options == null
+                        || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
             throw new AndroidRuntimeException(
                     "Calling startActivity() from outside of an Activity "
-                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
-                    + " Is this really what you want?");
+                            + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+                            + " Is this really what you want?");
         }
         mMainThread.getInstrumentation().execStartActivity(
                 getOuterContext(), mMainThread.getApplicationThread(), null,
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index 02a0124..b7100e6 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
+
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -73,6 +74,15 @@
     private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
             "android.remoteinput.dataTypeResultsData";
 
+    /** Extra added to a clip data intent object identifying the source of the results. */
+    private static final String EXTRA_RESULTS_SOURCE = "android.remoteinput.resultsSource";
+
+    /** The user manually entered the data. */
+    public static final int SOURCE_FREE_FORM_INPUT = 0;
+
+    /** The user selected one of the choices from {@link #getChoices}. */
+    public static final int SOURCE_CHOICE = 1;
+
     // Flags bitwise-ored to mFlags
     private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
 
@@ -416,6 +426,48 @@
         intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
     }
 
+    /**
+     * Set the source of the RemoteInput results. This method should only be called by remote
+     * input collection services (e.g.
+     * {@link android.service.notification.NotificationListenerService})
+     * when sending results to a pending intent.
+     *
+     * @see #SOURCE_FREE_FORM_INPUT
+     * @see #SOURCE_CHOICE
+     *
+     * @param intent The intent to add remote input source to. The {@link ClipData}
+     *               field of the intent will be modified to contain the source.
+     *               field of the intent will be modified to contain the source.
+     * @param source The source of the results.
+     */
+    public static void setResultsSource(Intent intent, int source) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        clipDataIntent.putExtra(EXTRA_RESULTS_SOURCE, source);
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    /**
+     * Get the source of the RemoteInput results.
+     *
+     * @see #SOURCE_FREE_FORM_INPUT
+     * @see #SOURCE_CHOICE
+     *
+     * @param intent The intent object that fired in response to an action or content intent
+     *               which also had one or more remote input requested.
+     * @return The source of the results. If no source was set, {@link #SOURCE_FREE_FORM_INPUT} will
+     * be returned.
+     */
+    public static int getResultsSource(Intent intent) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            return SOURCE_FREE_FORM_INPUT;
+        }
+        return clipDataIntent.getExtras().getInt(EXTRA_RESULTS_SOURCE, SOURCE_FREE_FORM_INPUT);
+    }
+
     private static String getExtraResultsKeyForData(String mimeType) {
         return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
     }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index db566e8..9f11d6e 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -79,8 +79,9 @@
  * {@link BluetoothDevice} objects representing all paired devices with
  * {@link #getBondedDevices()}; start device discovery with
  * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
- * listen for incoming connection requests with
- * {@link #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for
+ * listen for incoming RFComm connection requests with {@link
+ * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented
+ * Channels (CoC) connection requests with listenUsingL2capCoc(int)}; or start a scan for
  * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
  * </p>
  * <p>This class is thread safe.</p>
@@ -210,6 +211,14 @@
     public static final int STATE_BLE_TURNING_OFF = 16;
 
     /**
+     * UUID of the GATT Read Characteristics for LE_PSM value.
+     *
+     * @hide
+     */
+    public static final UUID LE_PSM_CHARACTERISTIC_UUID =
+            UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
+
+    /**
      * Human-readable string helper for AdapterState
      *
      * @hide
@@ -2160,7 +2169,9 @@
                         min16DigitPin);
         int errno = socket.mSocket.bindListen();
         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
-            socket.setChannel(socket.mSocket.getPort());
+            int assignedChannel = socket.mSocket.getPort();
+            if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel);
+            socket.setChannel(assignedChannel);
         }
         if (errno != 0) {
             //TODO(BT): Throw the same exception error code
@@ -2201,12 +2212,18 @@
      * @hide
      */
     public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
+        Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port);
         BluetoothServerSocket socket =
                 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false,
-                        false);
+                                          false);
         int errno = socket.mSocket.bindListen();
         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
-            socket.setChannel(socket.mSocket.getPort());
+            int assignedChannel = socket.mSocket.getPort();
+            if (DBG) {
+                Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to "
+                        + assignedChannel);
+            }
+            socket.setChannel(assignedChannel);
         }
         if (errno != 0) {
             //TODO(BT): Throw the same exception error code
@@ -2765,4 +2782,103 @@
             scanner.stopScan(scanCallback);
         }
     }
+
+    /**
+     * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
+     * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen
+     * for incoming connections.
+     * <p>A remote device connecting to this socket will be authenticated and communication on this
+     * socket will be encrypted.
+     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
+     * {@link BluetoothServerSocket}.
+     * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {#link
+     * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is
+     * closed, Bluetooth is turned off, or the application exits unexpectedly.
+     * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
+     * defined and performed by the application.
+     * <p>Use {@link BluetoothDevice#createL2capCocSocket(int, int)} to connect to this server
+     * socket from another Android device that is given the PSM value.
+     *
+     * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE}
+     * @return an L2CAP CoC BluetoothServerSocket
+     * @throws IOException on error, for example Bluetooth not available, or insufficient
+     * permissions, or unable to start this CoC
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothServerSocket listenUsingL2capCoc(int transport)
+            throws IOException {
+        if (transport != BluetoothDevice.TRANSPORT_LE) {
+            throw new IllegalArgumentException("Unsupported transport: " + transport);
+        }
+        BluetoothServerSocket socket =
+                            new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
+                                      SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
+        int errno = socket.mSocket.bindListen();
+        if (errno != 0) {
+            throw new IOException("Error: " + errno);
+        }
+
+        int assignedPsm = socket.mSocket.getPort();
+        if (assignedPsm == 0) {
+            throw new IOException("Error: Unable to assign PSM value");
+        }
+        if (DBG) {
+            Log.d(TAG, "listenUsingL2capCoc: set assigned PSM to "
+                    + assignedPsm);
+        }
+        socket.setChannel(assignedPsm);
+
+        return socket;
+    }
+
+    /**
+     * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
+     * assign a dynamic PSM value. This socket can be used to listen for incoming connections.
+     * <p>The link key is not required to be authenticated, i.e the communication may be vulnerable
+     * to man-in-the-middle attacks. Use {@link #listenUsingL2capCoc}, if an encrypted and
+     * authenticated communication channel is desired.
+     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
+     * {@link BluetoothServerSocket}.
+     * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value
+     * can be read from the {#link BluetoothServerSocket#getPsm()} and this value will be released
+     * when this server socket is closed, Bluetooth is turned off, or the application exits
+     * unexpectedly.
+     * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
+     * defined and performed by the application.
+     * <p>Use {@link BluetoothDevice#createInsecureL2capCocSocket(int, int)} to connect to this
+     * server socket from another Android device that is given the PSM value.
+     *
+     * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE}
+     * @return an L2CAP CoC BluetoothServerSocket
+     * @throws IOException on error, for example Bluetooth not available, or insufficient
+     * permissions, or unable to start this CoC
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
+            throws IOException {
+        if (transport != BluetoothDevice.TRANSPORT_LE) {
+            throw new IllegalArgumentException("Unsupported transport: " + transport);
+        }
+        BluetoothServerSocket socket =
+                            new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
+                                      SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
+        int errno = socket.mSocket.bindListen();
+        if (errno != 0) {
+            throw new IOException("Error: " + errno);
+        }
+
+        int assignedPsm = socket.mSocket.getPort();
+        if (assignedPsm == 0) {
+            throw new IOException("Error: Unable to assign PSM value");
+        }
+        if (DBG) {
+            Log.d(TAG, "listenUsingInsecureL2capOn: set assigned PSM to "
+                    + assignedPsm);
+        }
+        socket.setChannel(assignedPsm);
+
+        return socket;
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 9b736b7..ac21395 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1921,4 +1921,75 @@
         }
         return null;
     }
+
+    /**
+     * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
+     * be used to start a secure outgoing connection to the remote device with the same dynamic
+     * protocol/service multiplexer (PSM) value.
+     * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capCoc(int)} for
+     * peer-peer Bluetooth applications.
+     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
+     * <p>Application using this API is responsible for obtaining PSM value from remote device.
+     * <p>The remote device will be authenticated and communication on this socket will be
+     * encrypted.
+     * <p> Use this socket if an authenticated socket link is possible. Authentication refers
+     * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a
+     * secure socket connection is not possible, use {#link createInsecureLeL2capCocSocket(int,
+     * int)}.
+     *
+     * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
+     * @param psm dynamic PSM value from remote device
+     * @return a CoC #BluetoothSocket ready for an outgoing connection
+     * @throws IOException on error, for example Bluetooth not available, or insufficient
+     * permissions
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
+        if (!isBluetoothEnabled()) {
+            Log.e(TAG, "createL2capCocSocket: Bluetooth is not enabled");
+            throw new IOException();
+        }
+        if (transport != BluetoothDevice.TRANSPORT_LE) {
+            throw new IllegalArgumentException("Unsupported transport: " + transport);
+        }
+        if (DBG) Log.d(TAG, "createL2capCocSocket: transport=" + transport + ", psm=" + psm);
+        return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
+                null);
+    }
+
+    /**
+     * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
+     * be used to start a secure outgoing connection to the remote device with the same dynamic
+     * protocol/service multiplexer (PSM) value.
+     * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingInsecureL2capCoc(int)}
+     * for peer-peer Bluetooth applications.
+     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
+     * <p>Application using this API is responsible for obtaining PSM value from remote device.
+     * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
+     * to man-in-the-middle attacks. Use {@link #createL2capCocSocket(int, int)} if an encrypted and
+     * authenticated communication channel is possible.
+     *
+     * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE}
+     * @param psm dynamic PSM value from remote device
+     * @return a CoC #BluetoothSocket ready for an outgoing connection
+     * @throws IOException on error, for example Bluetooth not available, or insufficient
+     * permissions
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
+        if (!isBluetoothEnabled()) {
+            Log.e(TAG, "createInsecureL2capCocSocket: Bluetooth is not enabled");
+            throw new IOException();
+        }
+        if (transport != BluetoothDevice.TRANSPORT_LE) {
+            throw new IllegalArgumentException("Unsupported transport: " + transport);
+        }
+        if (DBG) {
+            Log.d(TAG, "createInsecureL2capCocSocket: transport=" + transport + ", psm=" + psm);
+        }
+        return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
+                null);
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 58d090d..ebb7f18 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -68,6 +68,7 @@
 public final class BluetoothServerSocket implements Closeable {
 
     private static final String TAG = "BluetoothServerSocket";
+    private static final boolean DBG = false;
     /*package*/ final BluetoothSocket mSocket;
     private Handler mHandler;
     private int mMessage;
@@ -169,6 +170,7 @@
      * close any {@link BluetoothSocket} received from {@link #accept()}.
      */
     public void close() throws IOException {
+        if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel);
         synchronized (this) {
             if (mHandler != null) {
                 mHandler.obtainMessage(mMessage).sendToTarget();
@@ -197,6 +199,20 @@
     }
 
     /**
+     * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
+     * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
+     * {#link BluetoothAdapter.listenUsingL2capCoc(int)} or {#link
+     * BluetoothAdapter.listenUsingInsecureL2capCoc(int)}. The returned value is undefined if this
+     * method is called on non-L2CAP server sockets.
+     *
+     * @return the assigned PSM or LE_PSM value depending on transport
+     * @hide
+     */
+    public int getPsm() {
+        return mChannel;
+    }
+
+    /**
      * Sets the channel on which future sockets are bound.
      * Currently used only when a channel is auto generated.
      */
@@ -227,6 +243,10 @@
                 sb.append("TYPE_L2CAP");
                 break;
             }
+            case BluetoothSocket.TYPE_L2CAP_LE: {
+                sb.append("TYPE_L2CAP_LE");
+                break;
+            }
             case BluetoothSocket.TYPE_SCO: {
                 sb.append("TYPE_SCO");
                 break;
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 0569913..09f9684 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -99,6 +99,16 @@
     /** L2CAP socket */
     public static final int TYPE_L2CAP = 3;
 
+    /** L2CAP socket on BR/EDR transport
+     * @hide
+     */
+    public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP;
+
+    /** L2CAP socket on LE transport
+     * @hide
+     */
+    public static final int TYPE_L2CAP_LE = 4;
+
     /*package*/ static final int EBADFD = 77;
     /*package*/ static final int EADDRINUSE = 98;
 
@@ -417,6 +427,7 @@
             return -1;
         }
         try {
+            if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType);
             mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName,
                     mUuid, mPort, getSecurityFlags());
         } catch (RemoteException e) {
@@ -451,7 +462,7 @@
                     mSocketState = SocketState.LISTENING;
                 }
             }
-            if (DBG) Log.d(TAG, "channel: " + channel);
+            if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort);
             if (mPort <= -1) {
                 mPort = channel;
             } // else ASSERT(mPort == channel)
@@ -515,7 +526,7 @@
     /*package*/ int read(byte[] b, int offset, int length) throws IOException {
         int ret = 0;
         if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
-        if (mType == TYPE_L2CAP) {
+        if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
             int bytesToRead = length;
             if (VDBG) {
                 Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
@@ -558,7 +569,7 @@
         //      Rfcomm uses dynamic allocation, and should not have any bindings
         //      to the actual message length.
         if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
-        if (mType == TYPE_L2CAP) {
+        if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
             if (length <= mMaxTxPacketSize) {
                 mSocketOS.write(b, offset, length);
             } else {
@@ -702,7 +713,7 @@
     }
 
     private void createL2capRxBuffer() {
-        if (mType == TYPE_L2CAP) {
+        if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
             // Allocate the buffer to use for reads.
             if (VDBG) Log.v(TAG, "  Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
             mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 44b4a33..bcf80ee 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1297,6 +1297,15 @@
      */
     public static final int INSTALL_FAILED_INSTANT_APP_INVALID = -116;
 
+    /**
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the dex metadata file is invalid or
+     * if there was no matching apk file for a dex metadata file.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_BAD_DEX_METADATA = -117;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DELETE_" }, value = {
             DELETE_KEEP_DATA,
@@ -5618,6 +5627,8 @@
             case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION";
             case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS";
             case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
+            case INSTALL_FAILED_BAD_DEX_METADATA:
+                return "INSTALL_FAILED_BAD_DEX_METADATA";
             default: return Integer.toString(status);
         }
     }
@@ -5662,6 +5673,7 @@
             case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID;
+            case INSTALL_FAILED_BAD_DEX_METADATA: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE;
             case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
             case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6d6c02a..4a71467 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -240,6 +240,9 @@
     }
 
     /** @hide */
+    public static final String APK_FILE_EXTENSION = ".apk";
+
+    /** @hide */
     public static class NewPermissionInfo {
         public final String name;
         public final int sdkVersion;
@@ -613,7 +616,7 @@
     }
 
     public static boolean isApkPath(String path) {
-        return path.endsWith(".apk");
+        return path.endsWith(APK_FILE_EXTENSION);
     }
 
     /**
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
new file mode 100644
index 0000000..c5f1c85
--- /dev/null
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -0,0 +1,230 @@
+/**
+ * Copyright 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 android.content.pm.dex;
+
+import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA;
+import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
+
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.PackageParserException;
+import android.util.ArrayMap;
+import android.util.jar.StrictJarFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class used to compute and validate the location of dex metadata files.
+ *
+ * @hide
+ */
+public class DexMetadataHelper {
+    private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
+
+    private DexMetadataHelper() {}
+
+    /** Return true if the given file is a dex metadata file. */
+    public static boolean isDexMetadataFile(File file) {
+        return isDexMetadataPath(file.getName());
+    }
+
+    /** Return true if the given path is a dex metadata path. */
+    private static boolean isDexMetadataPath(String path) {
+        return path.endsWith(DEX_METADATA_FILE_EXTENSION);
+    }
+
+    /**
+     * Return the size (in bytes) of all dex metadata files associated with the given package.
+     */
+    public static long getPackageDexMetadataSize(PackageLite pkg) {
+        long sizeBytes = 0;
+        Collection<String> dexMetadataList = DexMetadataHelper.getPackageDexMetadata(pkg).values();
+        for (String dexMetadata : dexMetadataList) {
+            sizeBytes += new File(dexMetadata).length();
+        }
+        return sizeBytes;
+    }
+
+    /**
+     * Search for the dex metadata file associated with the given target file.
+     * If it exists, the method returns the dex metadata file; otherwise it returns null.
+     *
+     * Note that this performs a loose matching suitable to be used in the InstallerSession logic.
+     * i.e. the method will attempt to match the {@code dmFile} regardless of {@code targetFile}
+     * extension (e.g. 'foo.dm' will match 'foo' or 'foo.apk').
+     */
+    public static File findDexMetadataForFile(File targetFile) {
+        String dexMetadataPath = buildDexMetadataPathForFile(targetFile);
+        File dexMetadataFile = new File(dexMetadataPath);
+        return dexMetadataFile.exists() ? dexMetadataFile : null;
+    }
+
+    /**
+     * Return the dex metadata files for the given package as a map
+     * [code path -> dex metadata path].
+     *
+     * NOTE: involves I/O checks.
+     */
+    public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) {
+        return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths());
+    }
+
+    /**
+     * Return the dex metadata files for the given package as a map
+     * [code path -> dex metadata path].
+     *
+     * NOTE: involves I/O checks.
+     */
+    private static Map<String, String> getPackageDexMetadata(PackageLite pkg) {
+        return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths());
+    }
+
+    /**
+     * Look up the dex metadata files for the given code paths building the map
+     * [code path -> dex metadata].
+     *
+     * For each code path (.apk) the method checks if a matching dex metadata file (.dm) exists.
+     * If it does it adds the pair to the returned map.
+     *
+     * Note that this method will do a strict
+     * matching based on the extension ('foo.dm' will only match 'foo.apk').
+     *
+     * This should only be used for code paths extracted from a package structure after the naming
+     * was enforced in the installer.
+     */
+    private static Map<String, String> buildPackageApkToDexMetadataMap(
+            List<String> codePaths) {
+        ArrayMap<String, String> result = new ArrayMap<>();
+        for (int i = codePaths.size() - 1; i >= 0; i--) {
+            String codePath = codePaths.get(i);
+            String dexMetadataPath = buildDexMetadataPathForApk(codePath);
+
+            if (Files.exists(Paths.get(dexMetadataPath))) {
+                result.put(codePath, dexMetadataPath);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Return the dex metadata path associated with the given code path.
+     * (replaces '.apk' extension with '.dm')
+     *
+     * @throws IllegalArgumentException if the code path is not an .apk.
+     */
+    public static String buildDexMetadataPathForApk(String codePath) {
+        if (!PackageParser.isApkPath(codePath)) {
+            throw new IllegalStateException(
+                    "Corrupted package. Code path is not an apk " + codePath);
+        }
+        return codePath.substring(0, codePath.length() - APK_FILE_EXTENSION.length())
+                + DEX_METADATA_FILE_EXTENSION;
+    }
+
+    /**
+     * Return the dex metadata path corresponding to the given {@code targetFile} using a loose
+     * matching.
+     * i.e. the method will attempt to match the {@code dmFile} regardless of {@code targetFile}
+     * extension (e.g. 'foo.dm' will match 'foo' or 'foo.apk').
+     */
+    private static String buildDexMetadataPathForFile(File targetFile) {
+        return PackageParser.isApkFile(targetFile)
+                ? buildDexMetadataPathForApk(targetFile.getPath())
+                : targetFile.getPath() + DEX_METADATA_FILE_EXTENSION;
+    }
+
+    /**
+     * Validate the dex metadata files installed for the given package.
+     *
+     * @throws PackageParserException in case of errors.
+     */
+    public static void validatePackageDexMetadata(PackageParser.Package pkg)
+            throws PackageParserException {
+        Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
+        for (String dexMetadata : apkToDexMetadataList) {
+            validateDexMetadataFile(dexMetadata);
+        }
+    }
+
+    /**
+     * Validate that the given file is a dex metadata archive.
+     * This is just a sanity validation that the file is a zip archive.
+     *
+     * @throws PackageParserException if the file is not a .dm file.
+     */
+    private static void validateDexMetadataFile(String dmaPath) throws PackageParserException {
+        StrictJarFile jarFile = null;
+        try {
+            jarFile = new StrictJarFile(dmaPath, false, false);
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_FAILED_BAD_DEX_METADATA,
+                    "Error opening " + dmaPath, e);
+        } finally {
+            if (jarFile != null) {
+                try {
+                    jarFile.close();
+                } catch (IOException ignored) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Validates that all dex metadata paths in the given list have a matching apk.
+     * (for any foo.dm there should be either a 'foo' of a 'foo.apk' file).
+     * If that's not the case it throws {@code IllegalStateException}.
+     *
+     * This is used to perform a basic sanity check during adb install commands.
+     * (The installer does not support stand alone .dm files)
+     */
+    public static void validateDexPaths(String[] paths) {
+        ArrayList<String> apks = new ArrayList<>();
+        for (int i = 0; i < paths.length; i++) {
+            if (PackageParser.isApkPath(paths[i])) {
+                apks.add(paths[i]);
+            }
+        }
+        ArrayList<String> unmatchedDmFiles = new ArrayList<>();
+        for (int i = 0; i < paths.length; i++) {
+            String dmPath = paths[i];
+            if (isDexMetadataPath(dmPath)) {
+                boolean valid = false;
+                for (int j = apks.size() - 1; j >= 0; j--) {
+                    if (dmPath.equals(buildDexMetadataPathForFile(new File(apks.get(j))))) {
+                        valid = true;
+                        break;
+                    }
+                }
+                if (!valid) {
+                    unmatchedDmFiles.add(dmPath);
+                }
+            }
+        }
+        if (!unmatchedDmFiles.isEmpty()) {
+            throw new IllegalStateException("Unmatched .dm files: " + unmatchedDmFiles);
+        }
+    }
+
+}
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 49f357e..a2991e6 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -66,7 +66,7 @@
      * created or opened until one of {@link #getWritableDatabase} or
      * {@link #getReadableDatabase} is called.
      *
-     * @param context to use to open or create the database
+     * @param context to use for locating paths to the the database
      * @param name of the database file, or null for an in-memory database
      * @param factory to use for creating cursor objects, or null for the default
      * @param version number of the database (starting at 1); if the database is older,
@@ -86,7 +86,7 @@
      * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
      * used to handle corruption when sqlite reports database corruption.</p>
      *
-     * @param context to use to open or create the database
+     * @param context to use for locating paths to the the database
      * @param name of the database file, or null for an in-memory database
      * @param factory to use for creating cursor objects, or null for the default
      * @param version number of the database (starting at 1); if the database is older,
@@ -107,7 +107,7 @@
      * created or opened until one of {@link #getWritableDatabase} or
      * {@link #getReadableDatabase} is called.
      *
-     * @param context to use to open or create the database
+     * @param context to use for locating paths to the the database
      * @param name of the database file, or null for an in-memory database
      * @param version number of the database (starting at 1); if the database is older,
      *     {@link #onUpgrade} will be used to upgrade the database; if the database is
@@ -128,7 +128,7 @@
      * minimumSupportedVersion is found, it is simply deleted and a new database is created with the
      * given name and version
      *
-     * @param context to use to open or create the database
+     * @param context to use for locating paths to the the database
      * @param name the name of the database file, null for a temporary in-memory database
      * @param factory to use for creating cursor objects, null for default
      * @param version the required version of the database
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 2156491..67e97bf 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -16,6 +16,7 @@
 
 package android.hardware.display;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -25,6 +26,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /** @hide */
 @SystemApi
@@ -32,10 +34,12 @@
 public final class BrightnessConfiguration implements Parcelable {
     private final float[] mLux;
     private final float[] mNits;
+    private final String mDescription;
 
-    private BrightnessConfiguration(float[] lux, float[] nits) {
+    private BrightnessConfiguration(float[] lux, float[] nits, String description) {
         mLux = lux;
         mNits = nits;
+        mDescription = description;
     }
 
     /**
@@ -51,10 +55,19 @@
         return Pair.create(Arrays.copyOf(mLux, mLux.length), Arrays.copyOf(mNits, mNits.length));
     }
 
+    /**
+     * Returns description string.
+     * @hide
+     */
+    public String getDescription() {
+        return mDescription;
+    }
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeFloatArray(mLux);
         dest.writeFloatArray(mNits);
+        dest.writeString(mDescription);
     }
 
     @Override
@@ -72,7 +85,9 @@
             }
             sb.append("(").append(mLux[i]).append(", ").append(mNits[i]).append(")");
         }
-        sb.append("]}");
+        sb.append("], '");
+        sb.append(mDescription);
+        sb.append("'}");
         return sb.toString();
     }
 
@@ -81,6 +96,7 @@
         int result = 1;
         result = result * 31 + Arrays.hashCode(mLux);
         result = result * 31 + Arrays.hashCode(mNits);
+        result = result * 31 + mDescription.hashCode();
         return result;
     }
 
@@ -93,16 +109,17 @@
             return false;
         }
         final BrightnessConfiguration other = (BrightnessConfiguration) o;
-        return Arrays.equals(mLux, other.mLux) && Arrays.equals(mNits, other.mNits);
+        return Arrays.equals(mLux, other.mLux) && Arrays.equals(mNits, other.mNits)
+                && Objects.equals(mDescription, other.mDescription);
     }
 
     public static final Creator<BrightnessConfiguration> CREATOR =
             new Creator<BrightnessConfiguration>() {
         public BrightnessConfiguration createFromParcel(Parcel in) {
-            Builder builder = new Builder();
             float[] lux = in.createFloatArray();
             float[] nits = in.createFloatArray();
-            builder.setCurve(lux, nits);
+            Builder builder = new Builder(lux, nits);
+            builder.setDescription(in.readString());
             return builder.build();
         }
 
@@ -117,6 +134,29 @@
     public static class Builder {
         private float[] mCurveLux;
         private float[] mCurveNits;
+        private String mDescription;
+
+        /**
+         * STOPSHIP remove when app has stopped using this.
+         * @hide
+         */
+        public Builder() {
+        }
+
+        /**
+         * Constructs the builder with the control points for the brightness curve.
+         *
+         * Brightness curves must have strictly increasing ambient brightness values in lux and
+         * monotonically increasing display brightness values in nits. In addition, the initial
+         * control point must be 0 lux.
+         *
+         * @throws IllegalArgumentException if the initial control point is not at 0 lux.
+         * @throws IllegalArgumentException if the lux levels are not strictly increasing.
+         * @throws IllegalArgumentException if the nit levels are not monotonically increasing.
+         */
+        public Builder(float[] lux, float[] nits) {
+            setCurve(lux, nits);
+        }
 
         /**
          * Sets the control points for the brightness curve.
@@ -128,6 +168,9 @@
          * @throws IllegalArgumentException if the initial control point is not at 0 lux.
          * @throws IllegalArgumentException if the lux levels are not strictly increasing.
          * @throws IllegalArgumentException if the nit levels are not monotonically increasing.
+         *
+         * STOPSHIP remove when app has stopped using this.
+         * @hide
          */
         public Builder setCurve(float[] lux, float[] nits) {
             Preconditions.checkNotNull(lux);
@@ -151,6 +194,17 @@
         }
 
         /**
+         * Set description of the brightness curve.
+         *
+         * @param description brief text describing the curve pushed. It maybe truncated
+         *                    and will not be displayed in the UI
+         */
+        public Builder setDescription(@Nullable String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
          * Builds the {@link BrightnessConfiguration}.
          *
          * A brightness curve <b>must</b> be set before calling this.
@@ -159,7 +213,7 @@
             if (mCurveLux == null || mCurveNits == null) {
                 throw new IllegalStateException("A curve must be set!");
             }
-            return new BrightnessConfiguration(mCurveLux, mCurveNits);
+            return new BrightnessConfiguration(mCurveLux, mCurveNits, mDescription);
         }
 
         private static void checkMonotonic(float[] vals, boolean strictlyIncreasing, String name) {
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 76ab35d..36673cd 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -639,7 +639,7 @@
     @TestApi
     @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS)
     public void setBrightnessConfiguration(BrightnessConfiguration c) {
-        setBrightnessConfigurationForUser(c, UserHandle.myUserId());
+        setBrightnessConfigurationForUser(c, UserHandle.myUserId(), mContext.getPackageName());
     }
 
     /**
@@ -650,8 +650,9 @@
      *
      * @hide
      */
-    public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId) {
-        mGlobal.setBrightnessConfigurationForUser(c, userId);
+    public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId,
+            String packageName) {
+        mGlobal.setBrightnessConfigurationForUser(c, userId, packageName);
     }
 
     /**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index cbb5a7d..9c851f1 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -480,9 +480,10 @@
      *
      * @hide
      */
-    public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId) {
+    public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId,
+            String packageName) {
         try {
-            mDm.setBrightnessConfigurationForUser(c, userId);
+            mDm.setBrightnessConfigurationForUser(c, userId, packageName);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 61c42e1..5b7b32f 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -90,5 +90,6 @@
     // Sets the global brightness configuration for a given user. Requires
     // CONFIGURE_DISPLAY_BRIGHTNESS, and INTERACT_ACROSS_USER if the user being configured is not
     // the same as the calling user.
-    void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId);
+    void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId,
+            String packageName);
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 24e56c0..396c897 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6562,6 +6562,14 @@
         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
 
         /**
+         * If nonzero, crashes in foreground processes will bring up a dialog.
+         * Otherwise, the process will be silently killed.
+         * @hide
+         */
+        public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION =
+                "show_first_crash_dialog_dev_option";
+
+        /**
          * The {@link ComponentName} string of the service to be used as the voice recognition
          * service.
          *
@@ -7398,6 +7406,7 @@
             SCREENSAVER_ACTIVATE_ON_DOCK,
             SCREENSAVER_ACTIVATE_ON_SLEEP,
             LOCKDOWN_IN_POWER_MENU,
+            SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
         };
 
         /** @hide */
@@ -11316,6 +11325,13 @@
          */
         public static final String ENABLE_SMART_REPLIES_IN_NOTIFICATIONS =
                 "enable_smart_replies_in_notifications";
+
+        /**
+         * If nonzero, crashes in foreground processes will bring up a dialog.
+         * Otherwise, the process will be silently killed.
+         * @hide
+         */
+        public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog";
     }
 
     /**
diff --git a/core/java/android/security/keystore/RecoveryClaim.java b/core/java/android/security/keystore/RecoveryClaim.java
new file mode 100644
index 0000000..6f566af
--- /dev/null
+++ b/core/java/android/security/keystore/RecoveryClaim.java
@@ -0,0 +1,54 @@
+/*
+ * 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 android.security.keystore;
+
+/**
+ * An attempt to recover a keychain protected by remote secure hardware.
+ *
+ * @hide
+ */
+public class RecoveryClaim {
+
+    private final RecoverySession mRecoverySession;
+    private final byte[] mClaimBytes;
+
+    RecoveryClaim(RecoverySession recoverySession, byte[] claimBytes) {
+        mRecoverySession = recoverySession;
+        mClaimBytes = claimBytes;
+    }
+
+    /**
+     * Returns the session associated with the recovery attempt. This is used to match the symmetric
+     * key, which remains internal to the framework, for decrypting the claim response.
+     *
+     * @return The session data.
+     */
+    public RecoverySession getRecoverySession() {
+        return mRecoverySession;
+    }
+
+    /**
+     * Returns the encrypted claim's bytes.
+     *
+     * <p>This should be sent by the recovery agent to the remote secure hardware, which will use
+     * it to decrypt the keychain, before sending it re-encrypted with the session's symmetric key
+     * to the device.
+     */
+    public byte[] getClaimBytes() {
+        return mClaimBytes;
+    }
+}
diff --git a/core/java/android/security/keystore/RecoveryManager.java b/core/java/android/security/keystore/RecoveryController.java
similarity index 88%
rename from core/java/android/security/keystore/RecoveryManager.java
rename to core/java/android/security/keystore/RecoveryController.java
index f01ed06..87283cb 100644
--- a/core/java/android/security/keystore/RecoveryManager.java
+++ b/core/java/android/security/keystore/RecoveryController.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
+import android.util.Log;
 
 import com.android.internal.widget.ILockSettings;
 
@@ -30,12 +31,26 @@
 import java.util.Map;
 
 /**
- * A wrapper around KeyStore which lets key be exported to trusted hardware on server side and
- * recovered later.
+ * An assistant for generating {@link javax.crypto.SecretKey} instances that can be recovered by
+ * other Android devices belonging to the user. The exported keychain is protected by the user's
+ * lock screen.
+ *
+ * <p>The RecoveryController must be paired with a recovery agent. The recovery agent is responsible
+ * for transporting the keychain to remote trusted hardware. This hardware must prevent brute force
+ * attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10).
+ * After  that number of incorrect guesses, the trusted hardware no longer allows access to the
+ * key chain.
+ *
+ * <p>For now only the recovery agent itself is able to create keys, so it is expected that the
+ * recovery agent is itself the system app.
+ *
+ * <p>A recovery agent requires the privileged permission
+ * {@code android.Manifest.permission#RECOVER_KEYSTORE}.
  *
  * @hide
  */
-public class RecoveryManager {
+public class RecoveryController {
+    private static final String TAG = "RecoveryController";
 
     /** Key has been successfully synced. */
     public static final int RECOVERY_STATUS_SYNCED = 0;
@@ -94,28 +109,28 @@
 
     private final ILockSettings mBinder;
 
-    private RecoveryManager(ILockSettings binder) {
+    private RecoveryController(ILockSettings binder) {
         mBinder = binder;
     }
 
     /**
      * Gets a new instance of the class.
      */
-    public static RecoveryManager getInstance() {
+    public static RecoveryController getInstance() {
         ILockSettings lockSettings =
                 ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
-        return new RecoveryManager(lockSettings);
+        return new RecoveryController(lockSettings);
     }
 
     /**
-     * Initializes key recovery service for the calling application. RecoveryManager
+     * Initializes key recovery service for the calling application. RecoveryController
      * randomly chooses one of the keys from the list and keeps it to use for future key export
      * operations. Collection of all keys in the list must be signed by the provided {@code
      * rootCertificateAlias}, which must also be present in the list of root certificates
-     * preinstalled on the device. The random selection allows RecoveryManager to select
+     * preinstalled on the device. The random selection allows RecoveryController to select
      * which of a set of remote recovery service devices will be used.
      *
-     * <p>In addition, RecoveryManager enforces a delay of three months between
+     * <p>In addition, RecoveryController enforces a delay of three months between
      * consecutive initialization attempts, to limit the ability of an attacker to often switch
      * remote recovery devices and significantly increase number of recovery attempts.
      *
@@ -371,7 +386,6 @@
      * The method generates symmetric key for a session, which trusted remote device can use to
      * return recovery key.
      *
-     * @param sessionId ID for recovery session.
      * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
      * used to create the recovery blob on the source device.
      * Keystore will verify the certificate using root of trust.
@@ -380,30 +394,31 @@
      * @param vaultChallenge Data passed from server for this recovery session and used to prevent
      *     replay attacks
      * @param secrets Secrets provided by user, the method only uses type and secret fields.
-     * @return Binary blob with recovery claim. It is encrypted with verifierPublicKey and contains
-     *     a proof of user secrets, session symmetric key and parameters necessary to identify the
-     *     counter with the number of failed recovery attempts.
+     * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
+     *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
+     *     key and parameters necessary to identify the counter with the number of failed recovery
+     *     attempts.
      * @throws BadCertificateFormatException if the {@code verifierPublicKey} is in an incorrect
      *     format.
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
-    public @NonNull byte[] startRecoverySession(
-            @NonNull String sessionId,
+    @NonNull public RecoveryClaim startRecoverySession(
             @NonNull byte[] verifierPublicKey,
             @NonNull byte[] vaultParams,
             @NonNull byte[] vaultChallenge,
             @NonNull List<KeychainProtectionParams> secrets)
             throws BadCertificateFormatException, InternalRecoveryServiceException {
         try {
+            RecoverySession recoverySession = RecoverySession.newInstance(this);
             byte[] recoveryClaim =
                     mBinder.startRecoverySession(
-                            sessionId,
+                            recoverySession.getSessionId(),
                             verifierPublicKey,
                             vaultParams,
                             vaultChallenge,
                             secrets);
-            return recoveryClaim;
+            return new RecoveryClaim(recoverySession, recoveryClaim);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
@@ -417,8 +432,8 @@
     /**
      * Imports keys.
      *
-     * @param sessionId Id for recovery session, same as in
-     *     {@link #startRecoverySession(String, byte[], byte[], byte[], List)}.
+     * @param session Related recovery session, as originally created by invoking
+     *        {@link #startRecoverySession(byte[], byte[], byte[], List)}.
      * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
      * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
      *     and session. KeyStore only uses package names from the application info in {@link
@@ -429,14 +444,14 @@
      * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
      */
     public Map<String, byte[]> recoverKeys(
-            @NonNull String sessionId,
+            @NonNull RecoverySession session,
             @NonNull byte[] recoveryKeyBlob,
             @NonNull List<WrappedApplicationKey> applicationKeys)
             throws SessionExpiredException, DecryptionFailedException,
             InternalRecoveryServiceException {
         try {
             return (Map<String, byte[]>) mBinder.recoverKeys(
-                    sessionId, recoveryKeyBlob, applicationKeys);
+                    session.getSessionId(), recoveryKeyBlob, applicationKeys);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (ServiceSpecificException e) {
@@ -451,6 +466,20 @@
     }
 
     /**
+     * Deletes all data associated with {@code session}. Should not be invoked directly but via
+     * {@link RecoverySession#close()}.
+     *
+     * @hide
+     */
+    void closeSession(RecoverySession session) {
+        try {
+            mBinder.closeSession(session.getSessionId());
+        } catch (RemoteException | ServiceSpecificException e) {
+            Log.e(TAG, "Unexpected error trying to close session", e);
+        }
+    }
+
+    /**
      * Generates a key called {@code alias} and loads it into the recoverable key store. Returns the
      * raw material of the key.
      *
diff --git a/core/java/android/security/keystore/RecoveryControllerException.java b/core/java/android/security/keystore/RecoveryControllerException.java
index 31fd4af..5b806b7 100644
--- a/core/java/android/security/keystore/RecoveryControllerException.java
+++ b/core/java/android/security/keystore/RecoveryControllerException.java
@@ -19,7 +19,7 @@
 import java.security.GeneralSecurityException;
 
 /**
- * Base exception for errors thrown by {@link RecoveryManager}.
+ * Base exception for errors thrown by {@link RecoveryController}.
  *
  * @hide
  */
diff --git a/core/java/android/security/keystore/RecoverySession.java b/core/java/android/security/keystore/RecoverySession.java
new file mode 100644
index 0000000..ae8d91a
--- /dev/null
+++ b/core/java/android/security/keystore/RecoverySession.java
@@ -0,0 +1,71 @@
+/*
+ * 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 android.security.keystore;
+
+import java.security.SecureRandom;
+
+/**
+ * Session to recover a {@link KeychainSnapshot} from the remote trusted hardware, initiated by a
+ * recovery agent.
+ *
+ * @hide
+ */
+public class RecoverySession implements AutoCloseable {
+
+    private static final int SESSION_ID_LENGTH_BYTES = 16;
+
+    private final String mSessionId;
+    private final RecoveryController mRecoveryController;
+
+    private RecoverySession(RecoveryController recoveryController, String sessionId) {
+        mRecoveryController = recoveryController;
+        mSessionId = sessionId;
+    }
+
+    /**
+     * A new session, started by {@code recoveryManager}.
+     */
+    static RecoverySession newInstance(RecoveryController recoveryController) {
+        return new RecoverySession(recoveryController, newSessionId());
+    }
+
+    /**
+     * Returns a new random session ID.
+     */
+    private static String newSessionId() {
+        SecureRandom secureRandom = new SecureRandom();
+        byte[] sessionId = new byte[SESSION_ID_LENGTH_BYTES];
+        secureRandom.nextBytes(sessionId);
+        StringBuilder sb = new StringBuilder();
+        for (byte b : sessionId) {
+            sb.append(Byte.toHexString(b, /*upperCase=*/ false));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * An internal session ID, used by the framework to match recovery claims to snapshot responses.
+     */
+    String getSessionId() {
+        return mSessionId;
+    }
+
+    @Override
+    public void close() {
+        mRecoveryController.closeSession(this);
+    }
+}
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index c93e036..c7d4a4a 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -356,6 +356,7 @@
             @IntRange(from = 0) int start,
             @IntRange(from = 0) int end,
             @NonNull TextDirectionHeuristic textDir,
+            boolean computeHyphenation,
             @Nullable MeasuredParagraph recycle) {
         final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
         mt.resetAndAnalyzeBidi(text, start, end, textDir);
@@ -365,7 +366,8 @@
             long nativeBuilderPtr = nInitBuilder();
             try {
                 mt.bindNativeObject(
-                        nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer));
+                        nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer,
+                              computeHyphenation));
             } finally {
                 nFreeBuilder(nativeBuilderPtr);
             }
@@ -394,7 +396,8 @@
                     mt.mSpanEndCache.append(spanEnd);
                 }
             }
-            mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer));
+            mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer,
+                      computeHyphenation));
         } finally {
             nFreeBuilder(nativeBuilderPtr);
         }
@@ -668,7 +671,8 @@
                                                   @FloatRange(from = 0) float width);
 
     private static native long nBuildNativeMeasuredParagraph(/* Non Zero */ long nativeBuilderPtr,
-                                                 @NonNull char[] text);
+                                                 @NonNull char[] text,
+                                                 boolean computeHyphenation);
 
     private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
 
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 2c30360..b96b489 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -52,70 +52,147 @@
     // The sorted paragraph end offsets.
     private final @NonNull int[] mParagraphBreakPoints;
 
-    /**
-     * Build MeasuredText from the text.
-     *
-     * @param text The text to be measured.
-     * @param paint The paint to be used for drawing.
-     * @param textDir The text direction.
-     * @return The measured text.
-     */
-    public static @NonNull MeasuredText build(@NonNull CharSequence text,
-                                              @NonNull TextPaint paint,
-                                              @NonNull TextDirectionHeuristic textDir) {
-        return MeasuredText.build(text, paint, textDir, 0, text.length());
-    }
+    // The break strategy for this measured text.
+    private final @Layout.BreakStrategy int mBreakStrategy;
+
+    // The hyphenation frequency for this measured text.
+    private final @Layout.HyphenationFrequency int mHyphenationFrequency;
 
     /**
-     * Build MeasuredText from the specific range of the text..
-     *
-     * @param text The text to be measured.
-     * @param paint The paint to be used for drawing.
-     * @param textDir The text direction.
-     * @param start The inclusive start offset of the text.
-     * @param end The exclusive start offset of the text.
-     * @return The measured text.
+     * A Builder for MeasuredText
      */
-    public static @NonNull MeasuredText build(@NonNull CharSequence text,
-                                              @NonNull TextPaint paint,
-                                              @NonNull TextDirectionHeuristic textDir,
-                                              @IntRange(from = 0) int start,
-                                              @IntRange(from = 0) int end) {
-        Preconditions.checkNotNull(text);
-        Preconditions.checkNotNull(paint);
-        Preconditions.checkNotNull(textDir);
-        Preconditions.checkArgumentInRange(start, 0, text.length(), "start");
-        Preconditions.checkArgumentInRange(end, 0, text.length(), "end");
+    public static final class Builder {
+        // Mandatory parameters.
+        private final @NonNull CharSequence mText;
+        private final @NonNull TextPaint mPaint;
 
-        final IntArray paragraphEnds = new IntArray();
-        final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>();
+        // Members to be updated by setters.
+        private @IntRange(from = 0) int mStart;
+        private @IntRange(from = 0) int mEnd;
+        private TextDirectionHeuristic mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
+        private @Layout.BreakStrategy int mBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
+        private @Layout.HyphenationFrequency int mHyphenationFrequency =
+                Layout.HYPHENATION_FREQUENCY_NORMAL;
 
-        int paraEnd = 0;
-        for (int paraStart = start; paraStart < end; paraStart = paraEnd) {
-            paraEnd = TextUtils.indexOf(text, LINE_FEED, paraStart, end);
-            if (paraEnd < 0) {
-                // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph end.
-                paraEnd = end;
-            } else {
-                paraEnd++;  // Includes LINE_FEED(U+000A) to the prev paragraph.
-            }
 
-            paragraphEnds.add(paraEnd);
-            measuredTexts.add(MeasuredParagraph.buildForStaticLayout(
-                    paint, text, paraStart, paraEnd, textDir, null /* no recycle */));
+        /**
+         * Builder constructor
+         *
+         * @param text The text to be measured.
+         * @param paint The paint to be used for drawing.
+         */
+        public Builder(@NonNull CharSequence text, @NonNull TextPaint paint) {
+            Preconditions.checkNotNull(text);
+            Preconditions.checkNotNull(paint);
+
+            mText = text;
+            mPaint = paint;
+            mStart = 0;
+            mEnd = text.length();
         }
 
-        return new MeasuredText(text, start, end, paint, textDir,
-                                measuredTexts.toArray(new MeasuredParagraph[measuredTexts.size()]),
-                                paragraphEnds.toArray());
-    }
+        /**
+         * Set the range of measuring target.
+         *
+         * @param start The measuring target start offset in the text.
+         * @param end The measuring target end offset in the text.
+         */
+        public @NonNull Builder setRange(@IntRange(from = 0) int start,
+                                         @IntRange(from = 0) int end) {
+            Preconditions.checkArgumentInRange(start, 0, mText.length(), "start");
+            Preconditions.checkArgumentInRange(end, 0, mText.length(), "end");
+            Preconditions.checkArgument(start <= end, "The range is reversed.");
 
-    // Use MeasuredText.build instead.
+            mStart = start;
+            mEnd = end;
+            return this;
+        }
+
+        /**
+         * Set the text direction heuristic
+         *
+         * The default value is {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}.
+         *
+         * @param textDir The text direction heuristic for resolving bidi behavior.
+         * @return this builder, useful for chaining.
+         */
+        public @NonNull Builder setTextDirection(@NonNull TextDirectionHeuristic textDir) {
+            Preconditions.checkNotNull(textDir);
+            mTextDir = textDir;
+            return this;
+        }
+
+        /**
+         * Set the break strategy
+         *
+         * The default value is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}.
+         *
+         * @param breakStrategy The break strategy.
+         * @return this builder, useful for chaining.
+         */
+        public @NonNull Builder setBreakStrategy(@Layout.BreakStrategy int breakStrategy) {
+            mBreakStrategy = breakStrategy;
+            return this;
+        }
+
+        /**
+         * Set the hyphenation frequency
+         *
+         * The default value is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}.
+         *
+         * @param hyphenationFrequency The hyphenation frequency.
+         * @return this builder, useful for chaining.
+         */
+        public @NonNull Builder setHyphenationFrequency(
+                @Layout.HyphenationFrequency int hyphenationFrequency) {
+            mHyphenationFrequency = hyphenationFrequency;
+            return this;
+        }
+
+        /**
+         * Build the measured text
+         *
+         * @return the measured text.
+         */
+        public @NonNull MeasuredText build() {
+            final boolean needHyphenation = mBreakStrategy != Layout.BREAK_STRATEGY_SIMPLE
+                    && mHyphenationFrequency != Layout.HYPHENATION_FREQUENCY_NONE;
+
+            final IntArray paragraphEnds = new IntArray();
+            final ArrayList<MeasuredParagraph> measuredTexts = new ArrayList<>();
+
+            int paraEnd = 0;
+            for (int paraStart = mStart; paraStart < mEnd; paraStart = paraEnd) {
+                paraEnd = TextUtils.indexOf(mText, LINE_FEED, paraStart, mEnd);
+                if (paraEnd < 0) {
+                    // No LINE_FEED(U+000A) character found. Use end of the text as the paragraph
+                    // end.
+                    paraEnd = mEnd;
+                } else {
+                    paraEnd++;  // Includes LINE_FEED(U+000A) to the prev paragraph.
+                }
+
+                paragraphEnds.add(paraEnd);
+                measuredTexts.add(MeasuredParagraph.buildForStaticLayout(
+                        mPaint, mText, paraStart, paraEnd, mTextDir, needHyphenation,
+                        null /* no recycle */));
+            }
+
+            return new MeasuredText(mText, mStart, mEnd, mPaint, mTextDir, mBreakStrategy,
+                                    mHyphenationFrequency, measuredTexts.toArray(
+                                            new MeasuredParagraph[measuredTexts.size()]),
+                                    paragraphEnds.toArray());
+        }
+    };
+
+    // Use MeasuredText.Builder instead.
     private MeasuredText(@NonNull CharSequence text,
                          @IntRange(from = 0) int start,
                          @IntRange(from = 0) int end,
                          @NonNull TextPaint paint,
                          @NonNull TextDirectionHeuristic textDir,
+                         @Layout.BreakStrategy int breakStrategy,
+                         @Layout.HyphenationFrequency int frequency,
                          @NonNull MeasuredParagraph[] measuredTexts,
                          @NonNull int[] paragraphBreakPoints) {
         mText = text;
@@ -125,6 +202,8 @@
         mMeasuredParagraphs = measuredTexts;
         mParagraphBreakPoints = paragraphBreakPoints;
         mTextDir = textDir;
+        mBreakStrategy = breakStrategy;
+        mHyphenationFrequency = frequency;
     }
 
     /**
@@ -190,6 +269,20 @@
         return mMeasuredParagraphs[paraIndex];
     }
 
+    /**
+     * Returns the break strategy for this text.
+     */
+    public @Layout.BreakStrategy int getBreakStrategy() {
+        return mBreakStrategy;
+    }
+
+    /**
+     * Returns the hyphenation frequency for this text.
+     */
+    public @Layout.HyphenationFrequency int getHyphenationFrequency() {
+        return mHyphenationFrequency;
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Spanned overrides
     //
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 36bec86..70d6486 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -653,26 +653,40 @@
 
         MeasuredText measured = null;
         final Spanned spanned;
+        final boolean canUseMeasuredText;
         if (source instanceof MeasuredText) {
             measured = (MeasuredText) source;
 
-            final CharSequence original = measured.getText();
-            spanned = (original instanceof Spanned) ? (Spanned) original : null;
-
             if (bufStart != measured.getStart() || bufEnd != measured.getEnd()) {
                 // The buffer position has changed. Re-measure here.
-                measured = MeasuredText.build(original, paint, textDir, bufStart, bufEnd);
+                canUseMeasuredText = false;
+            } else if (b.mBreakStrategy != measured.getBreakStrategy()
+                    || b.mHyphenationFrequency != measured.getHyphenationFrequency()) {
+                // The computed hyphenation pieces may not be able to used. Re-measure it.
+                canUseMeasuredText = false;
             } else {
                 // We can use measured information.
-
-                // Overwrite with the one when emeasured.
-                // TODO: Give an option for developer not to overwrite and measure again here?
-                textDir = measured.getTextDir();
-                paint = measured.getPaint();
+                canUseMeasuredText = true;
             }
         } else {
-            measured = MeasuredText.build(source, paint, textDir, bufStart, bufEnd);
+            canUseMeasuredText = false;
+        }
+
+        if (!canUseMeasuredText) {
+            measured = new MeasuredText.Builder(source, paint)
+                    .setRange(bufStart, bufEnd)
+                    .setTextDirection(textDir)
+                    .setBreakStrategy(b.mBreakStrategy)
+                    .setHyphenationFrequency(b.mHyphenationFrequency)
+                    .build();
             spanned = (source instanceof Spanned) ? (Spanned) source : null;
+        } else {
+            final CharSequence original = measured.getText();
+            spanned = (original instanceof Spanned) ? (Spanned) original : null;
+            // Overwrite with the one when measured.
+            // TODO: Give an option for developer not to overwrite and measure again here?
+            textDir = measured.getTextDir();
+            paint = measured.getPaint();
         }
 
         try {
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index e765ab1..8a456d1 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.dex.DexMetadataHelper;
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -415,6 +416,9 @@
             sizeBytes += codeFile.length();
         }
 
+        // Include raw dex metadata files
+        sizeBytes += DexMetadataHelper.getPackageDexMetadataSize(pkg);
+
         // Include all relevant native code
         sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);
 
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 6ed8973..e3f1f47 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -60,7 +60,7 @@
             in byte[] token, int requestedQuality, int userId);
     void unlockUserWithToken(long tokenHandle, in byte[] token, int userId);
 
-    // Keystore RecoveryManager methods.
+    // Keystore RecoveryController methods.
     // {@code ServiceSpecificException} may be thrown to signal an error, which caller can
     // convert to  {@code RecoveryManagerException}.
     void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
@@ -81,4 +81,5 @@
             in List<KeychainProtectionParams> secrets);
     Map/*<String, byte[]>*/ recoverKeys(in String sessionId, in byte[] recoveryKeyBlob,
             in List<WrappedApplicationKey> applicationKeys);
+    void closeSession(in String sessionId);
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 77d0617..543acc7 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -119,6 +119,7 @@
         "android_util_jar_StrictJarFile.cpp",
         "android_graphics_Canvas.cpp",
         "android_graphics_Picture.cpp",
+        "android/graphics/AnimatedImageDrawable.cpp",
         "android/graphics/Bitmap.cpp",
         "android/graphics/BitmapFactory.cpp",
         "android/graphics/ByteBufferStreamAdaptor.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 068197a..aa9a824 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -63,6 +63,7 @@
 extern int register_android_graphics_GraphicBuffer(JNIEnv* env);
 extern int register_android_graphics_Graphics(JNIEnv* env);
 extern int register_android_graphics_ImageDecoder(JNIEnv*);
+extern int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv*);
 extern int register_android_graphics_Interpolator(JNIEnv* env);
 extern int register_android_graphics_MaskFilter(JNIEnv* env);
 extern int register_android_graphics_Movie(JNIEnv* env);
@@ -1396,6 +1397,7 @@
     REG_JNI(register_android_graphics_FontFamily),
     REG_JNI(register_android_graphics_GraphicBuffer),
     REG_JNI(register_android_graphics_ImageDecoder),
+    REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
     REG_JNI(register_android_graphics_Interpolator),
     REG_JNI(register_android_graphics_MaskFilter),
     REG_JNI(register_android_graphics_Matrix),
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
new file mode 100644
index 0000000..12feaab
--- /dev/null
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include "GraphicsJNI.h"
+#include "ImageDecoder.h"
+#include "core_jni_helpers.h"
+
+#include <hwui/Canvas.h>
+#include <SkAndroidCodec.h>
+#include <SkAnimatedImage.h>
+#include <SkColorFilter.h>
+#include <SkPicture.h>
+#include <SkPictureRecorder.h>
+
+using namespace android;
+
+struct AnimatedImageDrawable {
+    sk_sp<SkAnimatedImage> mDrawable;
+    SkPaint                mPaint;
+};
+
+// Note: jpostProcess holds a handle to the ImageDecoder.
+static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
+                                           jlong nativeImageDecoder, jobject jpostProcess,
+                                           jint width, jint height, jobject jsubset) {
+    if (nativeImageDecoder == 0) {
+        doThrowIOE(env, "Cannot create AnimatedImageDrawable from null!");
+        return 0;
+    }
+
+    auto* imageDecoder = reinterpret_cast<ImageDecoder*>(nativeImageDecoder);
+    auto info = imageDecoder->mCodec->getInfo();
+    const SkISize scaledSize = SkISize::Make(width, height);
+    SkIRect subset;
+    if (jsubset) {
+        GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
+    } else {
+        subset = SkIRect::MakeWH(width, height);
+    }
+
+    sk_sp<SkPicture> picture;
+    if (jpostProcess) {
+        SkRect bounds = SkRect::MakeWH(subset.width(), subset.height());
+
+        SkPictureRecorder recorder;
+        SkCanvas* skcanvas = recorder.beginRecording(bounds);
+        std::unique_ptr<Canvas> canvas(Canvas::create_canvas(skcanvas));
+        postProcessAndRelease(env, jpostProcess, std::move(canvas), bounds.width(),
+                              bounds.height());
+        if (env->ExceptionCheck()) {
+            return 0;
+        }
+        picture = recorder.finishRecordingAsPicture();
+    }
+
+    std::unique_ptr<AnimatedImageDrawable> drawable(new AnimatedImageDrawable);
+    drawable->mDrawable = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
+                scaledSize, subset, std::move(picture));
+    if (!drawable->mDrawable) {
+        doThrowIOE(env, "Failed to create drawable");
+        return 0;
+    }
+    drawable->mDrawable->start();
+
+    return reinterpret_cast<jlong>(drawable.release());
+}
+
+static void AnimatedImageDrawable_destruct(AnimatedImageDrawable* drawable) {
+    delete drawable;
+}
+
+static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&AnimatedImageDrawable_destruct));
+}
+
+static jlong AnimatedImageDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
+                                         jlong canvasPtr, jlong msecs) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    double timeToNextUpdate = drawable->mDrawable->update(msecs);
+    auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+    canvas->drawAnimatedImage(drawable->mDrawable.get(), 0, 0, &drawable->mPaint);
+    return (jlong) timeToNextUpdate;
+}
+
+static void AnimatedImageDrawable_nSetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
+                                            jint alpha) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    drawable->mPaint.setAlpha(alpha);
+}
+
+static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    return drawable->mPaint.getAlpha();
+}
+
+static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
+                                                  jlong nativeFilter) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter);
+    drawable->mPaint.setColorFilter(sk_ref_sp(filter));
+}
+
+static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    return drawable->mDrawable->isRunning();
+}
+
+static void AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    drawable->mDrawable->start();
+}
+
+static void AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    drawable->mDrawable->stop();
+}
+
+static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    // FIXME: Report the size of the internal SkBitmap etc.
+    return sizeof(drawable);
+}
+
+static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
+    { "nCreate",             "(JLandroid/graphics/ImageDecoder;IILandroid/graphics/Rect;)J", (void*) AnimatedImageDrawable_nCreate },
+    { "nGetNativeFinalizer", "()J",                                                          (void*) AnimatedImageDrawable_nGetNativeFinalizer },
+    { "nDraw",               "(JJJ)J",                                                       (void*) AnimatedImageDrawable_nDraw },
+    { "nSetAlpha",           "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetAlpha },
+    { "nGetAlpha",           "(J)I",                                                         (void*) AnimatedImageDrawable_nGetAlpha },
+    { "nSetColorFilter",     "(JJ)V",                                                        (void*) AnimatedImageDrawable_nSetColorFilter },
+    { "nIsRunning",          "(J)Z",                                                         (void*) AnimatedImageDrawable_nIsRunning },
+    { "nStart",              "(J)V",                                                         (void*) AnimatedImageDrawable_nStart },
+    { "nStop",               "(J)V",                                                         (void*) AnimatedImageDrawable_nStop },
+    { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
+};
+
+int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
+    return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
+            gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
+}
+
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 249202a..ed9d0e9 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -19,12 +19,11 @@
 #include "ByteBufferStreamAdaptor.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include "GraphicsJNI.h"
-#include "NinePatchPeeker.h"
+#include "ImageDecoder.h"
 #include "Utils.h"
 #include "core_jni_helpers.h"
 
 #include <hwui/Bitmap.h>
-#include <hwui/Canvas.h>
 
 #include <SkAndroidCodec.h>
 #include <SkEncodedImageFormat.h>
@@ -43,34 +42,14 @@
 static jclass    gCorrupt_class;
 static jclass    gCanvas_class;
 static jmethodID gImageDecoder_constructorMethodID;
+static jmethodID gImageDecoder_postProcessMethodID;
 static jmethodID gPoint_constructorMethodID;
 static jmethodID gIncomplete_constructorMethodID;
 static jmethodID gCorrupt_constructorMethodID;
 static jmethodID gCallback_onPartialImageMethodID;
-static jmethodID gPostProcess_postProcessMethodID;
 static jmethodID gCanvas_constructorMethodID;
 static jmethodID gCanvas_releaseMethodID;
 
-struct ImageDecoder {
-    // These need to stay in sync with ImageDecoder.java's Allocator constants.
-    enum Allocator {
-        kDefault_Allocator      = 0,
-        kSoftware_Allocator     = 1,
-        kSharedMemory_Allocator = 2,
-        kHardware_Allocator     = 3,
-    };
-
-    // These need to stay in sync with PixelFormat.java's Format constants.
-    enum PixelFormat {
-        kUnknown     =  0,
-        kTranslucent = -3,
-        kOpaque      = -1,
-    };
-
-    NinePatchPeeker mPeeker;
-    std::unique_ptr<SkAndroidCodec> mCodec;
-};
-
 static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream) {
     if (!stream.get()) {
         doThrowIOE(env, "Failed to create a stream");
@@ -78,7 +57,7 @@
     }
     std::unique_ptr<ImageDecoder> decoder(new ImageDecoder);
     SkCodec::Result result;
-    auto codec = SkCodec::MakeFromStream(std::move(stream), &result, &decoder->mPeeker);
+    auto codec = SkCodec::MakeFromStream(std::move(stream), &result, decoder->mPeeker.get());
     if (!codec) {
         switch (result) {
             case SkCodec::kIncompleteInput:
@@ -90,22 +69,24 @@
                            SkCodec::ResultToString(result));
                 doThrowIOE(env, msg.c_str());
                 break;
-        }
 
+        }
         return nullptr;
     }
 
+    // FIXME: Avoid parsing the whole image?
+    const bool animated = codec->getFrameCount() > 1;
     decoder->mCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
     if (!decoder->mCodec.get()) {
         doThrowIOE(env, "Could not create AndroidCodec");
         return nullptr;
     }
-
     const auto& info = decoder->mCodec->getInfo();
     const int width = info.width();
     const int height = info.height();
     return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
-                          reinterpret_cast<jlong>(decoder.release()), width, height);
+                          reinterpret_cast<jlong>(decoder.release()), width, height,
+                          animated);
 }
 
 static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
@@ -176,6 +157,24 @@
     return native_create(env, std::move(stream));
 }
 
+jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas,
+                           int width, int height) {
+    jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
+                                     reinterpret_cast<jlong>(canvas.get()));
+    if (!jcanvas) {
+        doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
+        return ImageDecoder::kUnknown;
+    }
+
+    // jcanvas now owns canvas.
+    canvas.release();
+
+    return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID,
+                              jcanvas, width, height);
+}
+
+// Note: jpostProcess points to an ImageDecoder object if it has a PostProcess object, and nullptr
+// otherwise.
 static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                           jobject jcallback, jobject jpostProcess,
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
@@ -322,23 +321,23 @@
     // Ignore ninepatch when post-processing.
     if (!jpostProcess) {
         // FIXME: Share more code with BitmapFactory.cpp.
-        if (decoder->mPeeker.mPatch != nullptr) {
+        if (decoder->mPeeker->mPatch != nullptr) {
             if (scale) {
-                decoder->mPeeker.scale(scaleX, scaleY, desiredWidth, desiredHeight);
+                decoder->mPeeker->scale(scaleX, scaleY, desiredWidth, desiredHeight);
             }
-            size_t ninePatchArraySize = decoder->mPeeker.mPatch->serializedSize();
+            size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize();
             ninePatchChunk = env->NewByteArray(ninePatchArraySize);
             if (ninePatchChunk == nullptr) {
                 doThrowOOME(env, "Failed to allocate nine patch chunk.");
                 return nullptr;
             }
 
-            env->SetByteArrayRegion(ninePatchChunk, 0, decoder->mPeeker.mPatchSize,
-                                    reinterpret_cast<jbyte*>(decoder->mPeeker.mPatch));
+            env->SetByteArrayRegion(ninePatchChunk, 0, decoder->mPeeker->mPatchSize,
+                                    reinterpret_cast<jbyte*>(decoder->mPeeker->mPatch));
         }
 
-        if (decoder->mPeeker.mHasInsets) {
-            ninePatchInsets = decoder->mPeeker.createNinePatchInsets(env, 1.0f);
+        if (decoder->mPeeker->mHasInsets) {
+            ninePatchInsets = decoder->mPeeker->createNinePatchInsets(env, 1.0f);
             if (ninePatchInsets == nullptr) {
                 doThrowOOME(env, "Failed to allocate nine patch insets.");
                 return nullptr;
@@ -399,23 +398,9 @@
 
     if (jpostProcess) {
         std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
-        jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
-                                         reinterpret_cast<jlong>(canvas.get()));
-        if (!jcanvas) {
-            doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
-            return nullptr;
-        }
-        // jcanvas will now own canvas.
-        canvas.release();
 
-        jint pixelFormat = env->CallIntMethod(jpostProcess, gPostProcess_postProcessMethodID,
-                                              jcanvas, bm.width(), bm.height());
-        if (env->ExceptionCheck()) {
-            return nullptr;
-        }
-
-        // The Canvas objects are no longer needed, and will not remain valid.
-        env->CallVoidMethod(jcanvas, gCanvas_releaseMethodID);
+        jint pixelFormat = postProcessAndRelease(env, jpostProcess, std::move(canvas),
+                                                 bm.width(), bm.height());
         if (env->ExceptionCheck()) {
             return nullptr;
         }
@@ -493,7 +478,7 @@
 static void ImageDecoder_nGetPadding(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
                                      jobject outPadding) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
-    decoder->mPeeker.getPadding(env, outPadding);
+    decoder->mPeeker->getPadding(env, outPadding);
 }
 
 static void ImageDecoder_nClose(JNIEnv* /*env*/, jobject /*clazz*/, jlong nativePtr) {
@@ -511,7 +496,7 @@
     { "nCreate",        "([BII)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[B)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
     { "nCreate",        "(Ljava/io/FileDescriptor;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder$OnPartialImageListener;Landroid/graphics/PostProcess;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder$OnPartialImageListener;Landroid/graphics/ImageDecoder;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/graphics/Point;",          (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
@@ -521,7 +506,8 @@
 
 int register_android_graphics_ImageDecoder(JNIEnv* env) {
     gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
-    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JII)V");
+    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZ)V");
+    gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;II)I");
 
     gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point"));
     gPoint_constructorMethodID = GetMethodIDOrDie(env, gPoint_class, "<init>", "(II)V");
@@ -535,9 +521,6 @@
     jclass callback_class = FindClassOrDie(env, "android/graphics/ImageDecoder$OnPartialImageListener");
     gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, callback_class, "onPartialImage", "(Ljava/io/IOException;)Z");
 
-    jclass postProcess_class = FindClassOrDie(env, "android/graphics/PostProcess");
-    gPostProcess_postProcessMethodID = GetMethodIDOrDie(env, postProcess_class, "postProcess", "(Landroid/graphics/Canvas;II)I");
-
     gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
     gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
     gCanvas_releaseMethodID = GetMethodIDOrDie(env, gCanvas_class, "release", "()V");
diff --git a/core/jni/android/graphics/ImageDecoder.h b/core/jni/android/graphics/ImageDecoder.h
new file mode 100644
index 0000000..2df71eb
--- /dev/null
+++ b/core/jni/android/graphics/ImageDecoder.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include "NinePatchPeeker.h"
+
+#include <hwui/Canvas.h>
+
+#include <jni.h>
+
+class SkAndroidCodec;
+
+using namespace android;
+
+struct ImageDecoder {
+    // These need to stay in sync with ImageDecoder.java's Allocator constants.
+    enum Allocator {
+        kDefault_Allocator      = 0,
+        kSoftware_Allocator     = 1,
+        kSharedMemory_Allocator = 2,
+        kHardware_Allocator     = 3,
+    };
+
+    // These need to stay in sync with PixelFormat.java's Format constants.
+    enum PixelFormat {
+        kUnknown     =  0,
+        kTranslucent = -3,
+        kOpaque      = -1,
+    };
+
+    std::unique_ptr<SkAndroidCodec> mCodec;
+    sk_sp<NinePatchPeeker> mPeeker;
+
+    ImageDecoder()
+        :mPeeker(new NinePatchPeeker)
+    {}
+};
+
+// Creates a Java Canvas object from canvas, calls jimageDecoder's PostProcess on it, and then
+// releases the Canvas.
+// Caller needs to check for exceptions.
+jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas,
+                           int width, int height);
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 1676d4b..f3aeb32 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -27,6 +27,7 @@
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
 #include <ETC1/etc1.h>
 
 #include <SkBitmap.h>
@@ -641,7 +642,7 @@
             }
             break;
         case kRGBA_F16_SkColorType:
-            if (type == GL_HALF_FLOAT_OES && format == PIXEL_FORMAT_RGBA_FP16)
+            if (type == GL_HALF_FLOAT && format == GL_RGBA16F)
                 return 0;
             break;
         default:
@@ -662,7 +663,7 @@
         case kRGB_565_SkColorType:
             return GL_RGB;
         case kRGBA_F16_SkColorType:
-            return PIXEL_FORMAT_RGBA_FP16;
+            return GL_RGBA16F;
         default:
             return -1;
     }
@@ -680,7 +681,7 @@
         case kRGB_565_SkColorType:
             return GL_UNSIGNED_SHORT_5_6_5;
         case kRGBA_F16_SkColorType:
-            return GL_HALF_FLOAT_OES;
+            return GL_HALF_FLOAT;
         default:
             return -1;
     }
diff --git a/core/jni/android_text_MeasuredParagraph.cpp b/core/jni/android_text_MeasuredParagraph.cpp
index bdae0b2..58c05b4 100644
--- a/core/jni/android_text_MeasuredParagraph.cpp
+++ b/core/jni/android_text_MeasuredParagraph.cpp
@@ -85,12 +85,12 @@
 
 // Regular JNI
 static jlong nBuildNativeMeasuredParagraph(JNIEnv* env, jclass /* unused */, jlong builderPtr,
-                                      jcharArray javaText) {
+                                      jcharArray javaText, jboolean computeHyphenation) {
     ScopedCharArrayRO text(env, javaText);
     const minikin::U16StringPiece textBuffer(text.get(), text.size());
 
     // Pass the ownership to Java.
-    return toJLong(toBuilder(builderPtr)->build(textBuffer).release());
+    return toJLong(toBuilder(builderPtr)->build(textBuffer, computeHyphenation).release());
 }
 
 // Regular JNI
@@ -108,7 +108,7 @@
     {"nInitBuilder", "()J", (void*) nInitBuilder},
     {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
     {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
-    {"nBuildNativeMeasuredParagraph", "(J[C)J", (void*) nBuildNativeMeasuredParagraph},
+    {"nBuildNativeMeasuredParagraph", "(J[CZ)J", (void*) nBuildNativeMeasuredParagraph},
     {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
 
     // MeasuredParagraph native functions.
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 3ffb254..8d6df12 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -390,8 +390,9 @@
     optional SettingProto enable_gnss_raw_meas_full_tracking = 346;
     optional SettingProto zram_enabled = 347;
     optional SettingProto enable_smart_replies_in_notifications = 348;
+    optional SettingProto show_first_crash_dialog = 349;
 
-    // Next tag = 349;
+    // Next tag = 350;
 }
 
 message SecureSettingsProto {
@@ -593,8 +594,9 @@
     optional SettingProto qs_auto_added_tiles = 193;
     optional SettingProto lockdown_in_power_menu = 194;
     optional SettingProto backup_manager_constants = 169;
+    optional SettingProto show_first_crash_dialog_dev_option = 195;
 
-    // Next tag = 195
+    // Next tag = 196
 }
 
 message SystemSettingsProto {
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index f6752c2..a7736e7c 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -10,7 +10,7 @@
      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
+     See the License for the specific language gning permissions and
      limitations under the License.
 -->
 
@@ -147,6 +147,7 @@
     an activity that looks like a Dialog.-->
     <style name="Theme.DeviceDefault.Dialog" parent="Theme.Material.Dialog" >
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
         <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
 
@@ -183,6 +184,7 @@
 
     <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <!-- Color palette Dark -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -200,6 +202,7 @@
 
     <style name="Theme.DeviceDefault.Settings.CompactMenu" parent="Theme.Material.CompactMenu">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <!-- Color palette Dark -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -219,6 +222,7 @@
     regular dialog. -->
     <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <!-- Color palette Dark -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -237,6 +241,7 @@
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
     <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <!-- Color palette Dark -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -256,6 +261,7 @@
     for a regular dialog. -->
     <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <!-- Color palette Dark -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -434,6 +440,7 @@
 
     <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
         <!-- Color palette Dialog -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
diff --git a/core/res/res/values-watch/themes_material.xml b/core/res/res/values-watch/themes_material.xml
index 0cf398b..40a249a 100644
--- a/core/res/res/values-watch/themes_material.xml
+++ b/core/res/res/values-watch/themes_material.xml
@@ -43,6 +43,7 @@
     <!-- Override behaviour to set the theme colours for dialogs, keep them the same. -->
     <style name="ThemeOverlay.Material.Dialog" parent="ThemeOverlay.Material.BaseDialog">
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
     </style>
 
     <!-- Force the background and floating colours to be the default colours. -->
@@ -51,6 +52,7 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
     </style>
 
     <!-- Force the background and floating colours to be the default colours. -->
@@ -59,6 +61,7 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
         <item name="windowIsFloating">false</item>
+        <item name="windowElevation">0dp</item>
     </style>
 
     <!-- Force all settings themes to use normal Material theme. -->
diff --git a/core/tests/coretests/apks/install-split-base/Android.mk b/core/tests/coretests/apks/install-split-base/Android.mk
new file mode 100644
index 0000000..5b60e31
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-base/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install_split_base
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/install-split-base/AndroidManifest.xml b/core/tests/coretests/apks/install-split-base/AndroidManifest.xml
new file mode 100644
index 0000000..c2bfedd
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-base/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.coretests.install_split"
+        android:isolatedSplits="true">
+
+    <application android:label="ClassloaderSplitApp">
+        <activity android:name=".BaseActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java b/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java
new file mode 100644
index 0000000..cb5760ce
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-base/src/com/google/android/dexapis/splitapp/BaseActivity.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright 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.google.android.dexapis.splitapp;
+
+import android.app.Activity;
+
+/** Main activity */
+public class BaseActivity extends Activity {
+}
diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.mk b/core/tests/coretests/apks/install-split-feature-a/Android.mk
new file mode 100644
index 0000000..0f37d16
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-feature-a/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install_split_feature_a
+
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS += --custom-package com.google.android.dexapis.splitapp.feature_a
+LOCAL_AAPT_FLAGS += --package-id 0x80
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml b/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml
new file mode 100644
index 0000000..3221c75
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-feature-a/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.coretests.install_split"
+        featureSplit="feature_a">
+
+    <application>
+        <activity android:name=".feature_a.FeatureAActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java b/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java
new file mode 100644
index 0000000..0af5f89
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-feature-a/src/com/google/android/dexapis/splitapp/feature_a/FeatureAActivity.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright 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.google.android.dexapis.splitapp.feature_a;
+
+import android.app.Activity;
+
+/** Main activity */
+public class FeatureAActivity extends Activity {
+}
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
new file mode 100644
index 0000000..4b84429
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -0,0 +1,208 @@
+/**
+ * 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 android.content.pm.dex;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.Package;
+import android.content.pm.PackageParser.PackageParserException;
+import android.os.FileUtils;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.frameworks.coretests.R;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import libcore.io.IoUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DexMetadataHelperTest {
+    private static final String APK_FILE_EXTENSION = ".apk";
+    private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
+
+    private File mTmpDir = null;
+
+    @Before
+    public void setUp() {
+        mTmpDir = IoUtils.createTemporaryDirectory("DexMetadataHelperTest");
+    }
+
+    @After
+    public void tearDown() {
+        if (mTmpDir != null) {
+            File[] files = mTmpDir.listFiles();
+            for (File f : files) {
+                f.delete();
+            }
+        }
+    }
+
+    private File createDexMetadataFile(String apkFileName) throws IOException {
+        File dmFile = new File(mTmpDir, apkFileName.replace(APK_FILE_EXTENSION,
+                DEX_METADATA_FILE_EXTENSION));
+        try (FileOutputStream fos = new FileOutputStream(dmFile)) {
+            try (ZipOutputStream zipOs = new ZipOutputStream(fos)) {
+                zipOs.putNextEntry(new ZipEntry("primary.prof"));
+                zipOs.closeEntry();
+            }
+        }
+        return dmFile;
+    }
+
+    private File copyApkToToTmpDir(String apkFileName, int apkResourceId) throws IOException {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        File outFile = new File(mTmpDir, apkFileName);
+        try (InputStream is = context.getResources().openRawResource(apkResourceId)) {
+            FileUtils.copyToFileOrThrow(is, outFile);
+        }
+        return outFile;
+    }
+
+    @Test
+    public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("install_split_base.apk");
+        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+
+        Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
+        assertEquals(1, packageDexMetadata.size());
+        String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+        assertNotNull(baseDexMetadata);
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+    }
+
+    @Test
+    public void testParsePackageSplitsWithDmFileValid()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
+        createDexMetadataFile("install_split_base.apk");
+        createDexMetadataFile("install_split_feature_a.apk");
+        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+
+        Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
+        assertEquals(2, packageDexMetadata.size());
+        String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+        assertNotNull(baseDexMetadata);
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+
+        String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+        assertNotNull(splitDexMetadata);
+        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+    }
+
+    @Test
+    public void testParsePackageSplitsNoBaseWithDmFileValid()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
+        createDexMetadataFile("install_split_feature_a.apk");
+        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+
+        Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
+        assertEquals(1, packageDexMetadata.size());
+
+        String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+        assertNotNull(splitDexMetadata);
+        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+    }
+
+    @Test
+    public void testParsePackageWithDmFileInvalid() throws IOException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
+        Files.createFile(invalidDmFile.toPath());
+        try {
+            PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+            DexMetadataHelper.validatePackageDexMetadata(pkg);
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testParsePackageSplitsWithDmFileInvalid()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
+        createDexMetadataFile("install_split_base.apk");
+        File invalidDmFile = new File(mTmpDir, "install_split_feature_a.dm");
+        Files.createFile(invalidDmFile.toPath());
+
+        try {
+            PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+            DexMetadataHelper.validatePackageDexMetadata(pkg);
+        } catch (PackageParserException e) {
+            assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
+        }
+    }
+
+    @Test
+    public void testPackageWithDmFileNoMatch() throws IOException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        createDexMetadataFile("non_existent.apk");
+
+        try {
+            DexMetadataHelper.validateDexPaths(mTmpDir.list());
+            fail("Should fail validation");
+        } catch (IllegalStateException e) {
+            // expected.
+        }
+    }
+
+    @Test
+    public void testPackageSplitsWithDmFileNoMatch()
+            throws IOException, PackageParserException {
+        copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
+        copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
+        createDexMetadataFile("install_split_base.apk");
+        createDexMetadataFile("install_split_feature_a.mistake.apk");
+
+        try {
+            DexMetadataHelper.validateDexPaths(mTmpDir.list());
+            fail("Should fail validation");
+        } catch (IllegalStateException e) {
+            // expected.
+        }
+    }
+
+    private static boolean isDexMetadataForApk(String dmaPath, String apkPath) {
+        return apkPath.substring(0, apkPath.length() - APK_FILE_EXTENSION.length()).equals(
+                dmaPath.substring(0, dmaPath.length() - DEX_METADATA_FILE_EXTENSION.length()));
+    }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d5689c7..c2ae776 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -331,6 +331,7 @@
                     Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
                     Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
                     Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+                    Settings.Global.SHOW_FIRST_CRASH_DIALOG,
                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index 5d33397..f6300ee 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -132,7 +132,7 @@
     public void buildForStaticLayout() {
         MeasuredParagraph mt = null;
 
-        mt = MeasuredParagraph.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, null);
+        mt = MeasuredParagraph.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, false, null);
         assertNotNull(mt);
         assertNotNull(mt.getChars());
         assertEquals("XXX", charsToString(mt.getChars()));
@@ -147,7 +147,7 @@
 
         // Recycle it
         MeasuredParagraph mt2 =
-                MeasuredParagraph.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, mt);
+                MeasuredParagraph.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, false, mt);
         assertEquals(mt2, mt);
         assertNotNull(mt2.getChars());
         assertEquals("VVV", charsToString(mt.getChars()));
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index f169f22..993bae1 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -194,6 +194,10 @@
     <allow-in-power-save package="com.android.cellbroadcastreceiver" />
     <allow-in-power-save package="com.android.shell" />
 
+    <!-- Whitelist system providers -->
+    <allow-in-power-save-except-idle package="com.android.providers.calendar" />
+    <allow-in-power-save-except-idle package="com.android.providers.contacts" />
+
     <!-- These are the packages that are white-listed to be able to run as system user -->
     <system-user-whitelisted-app package="com.android.settings" />
 
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index d13e05c..05dadc9 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -26,6 +26,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
+import android.graphics.drawable.AnimatedImageDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.NinePatchDrawable;
@@ -294,9 +295,10 @@
     };
 
     // Fields
-    private long      mNativePtr;
-    private final int mWidth;
-    private final int mHeight;
+    private long          mNativePtr;
+    private final int     mWidth;
+    private final int     mHeight;
+    private final boolean mAnimated;
 
     private int     mDesiredWidth;
     private int     mDesiredHeight;
@@ -322,12 +324,14 @@
      * called after decoding to delete native resources.
      */
     @SuppressWarnings("unused")
-    private ImageDecoder(long nativePtr, int width, int height) {
+    private ImageDecoder(long nativePtr, int width, int height,
+            boolean animated) {
         mNativePtr = nativePtr;
         mWidth = width;
         mHeight = height;
         mDesiredWidth = width;
         mDesiredHeight = height;
+        mAnimated = animated;
         mCloseGuard.open("close");
     }
 
@@ -677,6 +681,18 @@
         }
     }
 
+    private Bitmap decodeBitmap() throws IOException {
+        checkState();
+        // nDecodeBitmap calls postProcessAndRelease only if mPostProcess
+        // exists.
+        ImageDecoder postProcessPtr = mPostProcess == null ? null : this;
+        return nDecodeBitmap(mNativePtr, mOnPartialImageListener,
+                postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
+                mMutable, mAllocator, mRequireUnpremultiplied,
+                mPreferRamOverQuality, mAsAlphaMask);
+
+    }
+
     /**
      *  Create a {@link Drawable} from a {@code Source}.
      *
@@ -702,8 +718,6 @@
                 }
             }
 
-            decoder.checkState();
-
             if (decoder.mRequireUnpremultiplied) {
                 // Though this could be supported (ignored) for opaque images,
                 // it seems better to always report this error.
@@ -716,17 +730,22 @@
                                                 "Drawable!");
             }
 
-            Bitmap bm = nDecodeBitmap(decoder.mNativePtr,
-                                      decoder.mOnPartialImageListener,
-                                      decoder.mPostProcess,
-                                      decoder.mDesiredWidth,
-                                      decoder.mDesiredHeight,
-                                      decoder.mCropRect,
-                                      false,    // mMutable
-                                      decoder.mAllocator,
-                                      false,    // mRequireUnpremultiplied
-                                      decoder.mPreferRamOverQuality,
-                                      decoder.mAsAlphaMask);
+            if (decoder.mAnimated) {
+                // AnimatedImageDrawable calls postProcessAndRelease only if
+                // mPostProcess exists.
+                ImageDecoder postProcessPtr = decoder.mPostProcess == null ?
+                        null : decoder;
+                Drawable d = new AnimatedImageDrawable(decoder.mNativePtr,
+                        postProcessPtr, decoder.mDesiredWidth,
+                        decoder.mDesiredHeight, decoder.mCropRect,
+                        decoder.mInputStream, decoder.mAssetFd);
+                // d has taken ownership of these objects.
+                decoder.mInputStream = null;
+                decoder.mAssetFd = null;
+                return d;
+            }
+
+            Bitmap bm = decoder.decodeBitmap();
             Resources res = src.getResources();
             if (res == null) {
                 bm.setDensity(Bitmap.DENSITY_NONE);
@@ -742,7 +761,6 @@
                         opticalInsets, null);
             }
 
-            // TODO: Handle animation.
             return new BitmapDrawable(res, bm);
         }
     }
@@ -781,19 +799,7 @@
                 }
             }
 
-            decoder.checkState();
-
-            return nDecodeBitmap(decoder.mNativePtr,
-                                 decoder.mOnPartialImageListener,
-                                 decoder.mPostProcess,
-                                 decoder.mDesiredWidth,
-                                 decoder.mDesiredHeight,
-                                 decoder.mCropRect,
-                                 decoder.mMutable,
-                                 decoder.mAllocator,
-                                 decoder.mRequireUnpremultiplied,
-                                 decoder.mPreferRamOverQuality,
-                                 decoder.mAsAlphaMask);
+            return decoder.decodeBitmap();
         }
     }
 
@@ -809,6 +815,18 @@
         return decodeBitmap(src, null);
     }
 
+    /**
+     * Private method called by JNI.
+     */
+    @SuppressWarnings("unused")
+    private int postProcessAndRelease(@NonNull Canvas canvas, int width, int height) {
+        try {
+            return mPostProcess.postProcess(canvas, width, height);
+        } finally {
+            canvas.release();
+        }
+    }
+
     private static native ImageDecoder nCreate(long asset) throws IOException;
     private static native ImageDecoder nCreate(ByteBuffer buffer,
                                                int position,
@@ -820,7 +838,7 @@
     @NonNull
     private static native Bitmap nDecodeBitmap(long nativePtr,
             OnPartialImageListener listener,
-            PostProcess postProcess,
+            @Nullable ImageDecoder decoder,     // Only used if mPostProcess != null
             int width, int height,
             Rect cropRect, boolean mutable,
             int allocator, boolean requireUnpremul,
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
new file mode 100644
index 0000000..ce3bd9a
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -0,0 +1,173 @@
+/*
+ * 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 android.graphics.drawable;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.AssetFileDescriptor;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.SystemClock;
+
+import libcore.io.IoUtils;
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Runnable;
+
+/**
+ * @hide
+ */
+public class AnimatedImageDrawable extends Drawable implements Animatable {
+    private final long                mNativePtr;
+    private final InputStream         mInputStream;
+    private final AssetFileDescriptor mAssetFd;
+
+    private final int                 mIntrinsicWidth;
+    private final int                 mIntrinsicHeight;
+
+    private Runnable mRunnable = new Runnable() {
+        @Override
+        public void run() {
+            invalidateSelf();
+        }
+    };
+
+    /**
+     * @hide
+     * This should only be called by ImageDecoder.
+     *
+     * decoder is only non-null if it has a PostProcess
+     */
+    public AnimatedImageDrawable(long nativeImageDecoder,
+            @Nullable ImageDecoder decoder, int width, int height, Rect cropRect,
+            InputStream inputStream, AssetFileDescriptor afd)
+            throws IOException {
+        mNativePtr = nCreate(nativeImageDecoder, decoder, width, height, cropRect);
+        mInputStream = inputStream;
+        mAssetFd = afd;
+
+        if (cropRect == null) {
+            mIntrinsicWidth  = width;
+            mIntrinsicHeight = height;
+        } else {
+            mIntrinsicWidth  = cropRect.width();
+            mIntrinsicHeight = cropRect.height();
+        }
+
+        long nativeSize = nNativeByteSize(mNativePtr);
+        NativeAllocationRegistry registry = new NativeAllocationRegistry(
+                AnimatedImageDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
+        registry.registerNativeAllocation(this, mNativePtr);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        // FIXME: It's a shame that we have *both* a native finalizer and a Java
+        // one. The native one is necessary to report how much memory is being
+        // used natively, and this one is necessary to close the input. An
+        // alternative might be to read the entire stream ahead of time, so we
+        // can eliminate the Java finalizer.
+        try {
+            IoUtils.closeQuietly(mInputStream);
+            IoUtils.closeQuietly(mAssetFd);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mIntrinsicWidth;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mIntrinsicHeight;
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper(),
+                SystemClock.uptimeMillis());
+        scheduleSelf(mRunnable, nextUpdate);
+    }
+
+    @Override
+    public void setAlpha(@IntRange(from=0,to=255) int alpha) {
+        if (alpha < 0 || alpha > 255) {
+            throw new IllegalArgumentException("Alpha must be between 0 and"
+                   + " 255! provided " + alpha);
+        }
+        nSetAlpha(mNativePtr, alpha);
+    }
+
+    @Override
+    public int getAlpha() {
+        return nGetAlpha(mNativePtr);
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+        long nativeFilter = colorFilter == null ? 0 : colorFilter.getNativeInstance();
+        nSetColorFilter(mNativePtr, nativeFilter);
+    }
+
+    @Override
+    public @PixelFormat.Opacity int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    // TODO: Add a Constant State?
+    // @Override
+    // public @Nullable ConstantState getConstantState() {}
+
+
+    // Animatable overrides
+    @Override
+    public boolean isRunning() {
+        return nIsRunning(mNativePtr);
+    }
+
+    @Override
+    public void start() {
+        nStart(mNativePtr);
+    }
+
+    @Override
+    public void stop() {
+        nStop(mNativePtr);
+    }
+
+    private static native long nCreate(long nativeImageDecoder,
+            @Nullable ImageDecoder decoder, int width, int height, Rect cropRect)
+        throws IOException;
+    private static native long nGetNativeFinalizer();
+    private static native long nDraw(long nativePtr, long canvasNativePtr, long msecs);
+    private static native void nSetAlpha(long nativePtr, int alpha);
+    private static native int nGetAlpha(long nativePtr);
+    private static native void nSetColorFilter(long nativePtr, long nativeFilter);
+    private static native boolean nIsRunning(long nativePtr);
+    private static native void nStart(long nativePtr);
+    private static native void nStop(long nativePtr);
+    private static native long nNativeByteSize(long nativePtr);
+}
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3fb1c0d..fb7b246 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -495,6 +495,11 @@
                                           refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
 }
 
+void RecordingCanvas::drawAnimatedImage(SkAnimatedImage*, float left, float top,
+                                        const SkPaint*) {
+    // Unimplemented
+}
+
 // Text
 void RecordingCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int glyphCount, const SkPaint& paint,
                                  float x, float y, float boundsLeft, float boundsTop,
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 3087db0..dd06ada 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -183,6 +183,8 @@
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) override;
+    virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
+                                   const SkPaint* paint) override;
 
     // Text
     virtual bool drawTextAbsolutePos() const override { return false; }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 2e08670..dc274cf 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -23,6 +23,7 @@
 #include "hwui/MinikinUtils.h"
 #include "pipeline/skia/AnimatedDrawables.h"
 
+#include <SkAnimatedImage.h>
 #include <SkCanvasStateUtils.h>
 #include <SkColorFilter.h>
 #include <SkColorSpaceXformCanvas.h>
@@ -32,6 +33,7 @@
 #include <SkGraphics.h>
 #include <SkImage.h>
 #include <SkImagePriv.h>
+#include <SkPicture.h>
 #include <SkRSXform.h>
 #include <SkShader.h>
 #include <SkTemplates.h>
@@ -723,6 +725,20 @@
     mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter));
 }
 
+void SkiaCanvas::drawAnimatedImage(SkAnimatedImage* image, float left, float top,
+                                   const SkPaint* paint) {
+    sk_sp<SkPicture> pic(image->newPictureSnapshot());
+    SkMatrix matrixStorage;
+    SkMatrix* matrix;
+    if (left == 0.0f && top == 0.0f) {
+        matrix = nullptr;
+    } else {
+        matrixStorage = SkMatrix::MakeTrans(left, top);
+        matrix = &matrixStorage;
+    }
+    mCanvas->drawPicture(pic.get(), matrix, paint);
+}
+
 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
     vectorDrawable->drawStaging(this);
 }
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 99e676a..7137210 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -124,6 +124,8 @@
     virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
                                float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) override;
+    virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
+                                   const SkPaint* paint) override;
 
     virtual bool drawTextAbsolutePos() const override { return true; }
     virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index e682a2e..5efd357 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -28,6 +28,7 @@
 #include <SkCanvas.h>
 #include <SkMatrix.h>
 
+class SkAnimatedImage;
 class SkCanvasState;
 class SkVertices;
 
@@ -237,6 +238,9 @@
                                float dstTop, float dstRight, float dstBottom,
                                const SkPaint* paint) = 0;
 
+    virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
+                                   const SkPaint* paint) = 0;
+
     /**
      * Specifies if the positions passed to ::drawText are absolute or relative
      * to the (x,y) value provided.
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index e0289f0..d7861e3 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -180,6 +180,7 @@
     /**
      * IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
      *            if applicable, as well as audioattributes.proto.
+     *            Also consider adding them to <aaudio/AAudio.h> for the NDK.
      */
 
     /**
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d33e084..87ed7eb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1125,6 +1125,9 @@
         dumpSetting(s, p,
                 Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS,
                 GlobalSettingsProto.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_FIRST_CRASH_DIALOG,
+                GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
     }
 
     /** Dump a single {@link SettingsState.Setting} to a proto buf */
@@ -1516,6 +1519,9 @@
                 Settings.Secure.ANR_SHOW_BACKGROUND,
                 SecureSettingsProto.ANR_SHOW_BACKGROUND);
         dumpSetting(s, p,
+                Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+                SecureSettingsProto.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION);
+        dumpSetting(s, p,
                 Settings.Secure.VOICE_RECOGNITION_SERVICE,
                 SecureSettingsProto.VOICE_RECOGNITION_SERVICE);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
deleted file mode 100644
index 00bcaf6..0000000
--- a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/ic_landscape_from_auto_rotate" >
-    <target
-        android:name="landscape"
-        android:animation="@anim/ic_rotate_to_landscape_landscape_animation" />
-    <target
-        android:name="arrows"
-        android:animation="@anim/ic_rotate_to_landscape_arrows_animation" />
-    <target
-        android:name="arrows_0"
-        android:animation="@anim/ic_rotate_to_landscape_arrows_0_animation" />
-    <target
-        android:name="bottom_merged"
-        android:animation="@anim/ic_rotate_to_landscape_bottom_merged_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
deleted file mode 100644
index cde6797..0000000
--- a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_landscape_to_rotate"
-    android:height="48dp"
-    android:width="48dp"
-    android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
-    <group
-        android:name="device"
-        android:translateX="24"
-        android:translateY="24" >
-        <group
-            android:name="device_pivot"
-            android:translateX="-24.15"
-            android:translateY="-24.25" >
-            <group
-                android:name="landscape"
-                android:translateX="24"
-                android:translateY="24" >
-                <path
-                    android:name="device_merged"
-                    android:pathData="M -21.9799957275,-10.0 c 0.0,0.0 -0.0200042724609,20.0 -0.0200042724609,20.0 c 0.0,2.19999694824 1.80000305176,4.0 4.0,4.0 c 0.0,0.0 36.0,0.0 36.0,0.0 c 2.19999694824,0.0 4.0,-1.80000305176 4.0,-4.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,-2.19999694824 -1.80000305176,-4.0 -4.0,-4.0 c 0.0,0.0 -36.0,0.0 -36.0,0.0 c -2.19999694824,0.0 -3.97999572754,1.80000305176 -3.97999572754,4.0 Z M 14.0,10.0 c 0.0,0.0 -28.0,0.0 -28.0,0.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,0.0 28.0,0.0 28.0,0.0 c 0.0,0.0 0.0,20.0 0.0,20.0 Z"
-                    android:fillColor="#FFFFFFFF" />
-            </group>
-        </group>
-    </group>
-    <group
-        android:name="arrows"
-        android:translateX="24"
-        android:translateY="24"
-        android:rotation="-90" >
-        <group
-            android:name="arrows_pivot"
-            android:translateX="-24.0798"
-            android:translateY="-24.23" >
-            <group
-                android:name="arrows_0"
-                android:translateX="12.2505"
-                android:translateY="37.2145" >
-                <path
-                    android:name="bottom_merged"
-                    android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
-                    android:fillColor="#FFFFFFFF"
-                    android:fillAlpha="0" />
-            </group>
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
deleted file mode 100644
index 86dc6ce..0000000
--- a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/ic_landscape_to_auto_rotate" >
-    <target
-        android:name="landscape"
-        android:animation="@anim/ic_landscape_to_rotate_landscape_animation" />
-    <target
-        android:name="arrows"
-        android:animation="@anim/ic_landscape_to_rotate_arrows_animation" />
-    <target
-        android:name="bottom_merged"
-        android:animation="@anim/ic_landscape_to_rotate_bottom_merged_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
deleted file mode 100644
index b8465f4..0000000
--- a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/ic_portrait_to_auto_rotate" >
-    <target
-        android:name="device_0"
-        android:animation="@anim/ic_portrait_to_rotate_device_0_animation" />
-    <target
-        android:name="device_merged"
-        android:animation="@anim/ic_portrait_to_rotate_device_merged_animation" />
-    <target
-        android:name="arrows"
-        android:animation="@anim/ic_portrait_to_rotate_arrows_animation" />
-    <target
-        android:name="arrows_0"
-        android:animation="@anim/ic_portrait_to_rotate_arrows_0_animation" />
-    <target
-        android:name="bottom_merged"
-        android:animation="@anim/ic_portrait_to_rotate_bottom_merged_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
deleted file mode 100644
index 0ef15f0..0000000
--- a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_rotate_to_portrait"
-    android:height="48dp"
-    android:width="48dp"
-    android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
-    <group
-        android:name="device"
-        android:translateX="24"
-        android:translateY="24" >
-        <group
-            android:name="device_pivot"
-            android:translateX="-24.15"
-            android:translateY="-24.25" >
-            <group
-                android:name="device_0"
-                android:translateX="24.14999"
-                android:translateY="24.25"
-                android:rotation="-135" >
-                <path
-                    android:name="device_merged"
-                    android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
-                    android:fillColor="#FFFFFFFF" />
-            </group>
-        </group>
-    </group>
-    <group
-        android:name="arrows"
-        android:translateX="24"
-        android:translateY="24"
-        android:rotation="-221" >
-        <group
-            android:name="arrows_pivot"
-            android:translateX="-24.0798"
-            android:translateY="-24.23" >
-            <group
-                android:name="arrows_0"
-                android:translateX="12.2505"
-                android:translateY="37.2145"
-                android:scaleX="0.9"
-                android:scaleY="0.9" >
-                <path
-                    android:name="bottom_merged"
-                    android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
-                    android:fillColor="#FFFFFFFF"
-                    android:fillAlpha="0" />
-            </group>
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
deleted file mode 100644
index 6d3fd37..0000000
--- a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/ic_portrait_from_auto_rotate" >
-    <target
-        android:name="device_0"
-        android:animation="@anim/ic_rotate_to_portrait_device_0_animation" />
-    <target
-        android:name="device_merged"
-        android:animation="@anim/ic_rotate_to_portrait_device_merged_animation" />
-    <target
-        android:name="arrows"
-        android:animation="@anim/ic_rotate_to_portrait_arrows_animation" />
-    <target
-        android:name="arrows_0"
-        android:animation="@anim/ic_rotate_to_portrait_arrows_0_animation" />
-    <target
-        android:name="bottom_merged"
-        android:animation="@anim/ic_rotate_to_portrait_bottom_merged_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
similarity index 95%
rename from packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
rename to packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
index bce494c..fba45d1 100644
--- a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2017 The Android Open Source Project
+     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.
@@ -16,12 +16,10 @@
 -->
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_portrait_to_rotate"
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48">
     <group
         android:name="device"
         android:translateX="24"
@@ -61,4 +59,3 @@
         </group>
     </group>
 </vector>
-
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
index 5e7cd97..56223db 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
@@ -18,7 +18,7 @@
         android:height="32dp"
         android:viewportWidth="6.0"
         android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorSecondary">
+        android:tint="?android:attr/colorAccent">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M6.000000,15.700000l-3.000000,5.599999 -3.000000,-5.599999z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
index 0dca1db..12c1a7a 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
@@ -18,7 +18,7 @@
         android:height="32dp"
         android:viewportWidth="6.0"
         android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorSecondary">
+        android:tint="?android:attr/colorAccent">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M0.000000,13.700000l3.000000,-5.700000 3.000000,5.700000z"/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7a670fd..0134086 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -618,6 +618,8 @@
          type icon is wide for the tile in quick settings. -->
     <dimen name="wide_type_icon_start_padding_qs">3dp</dimen>
 
+    <dimen name="signal_indicator_to_icon_frame_spacing">3dp</dimen>
+
     <!-- The maximum width of the navigation bar ripples. -->
     <dimen name="key_button_ripple_max_width">95dp</dimen>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 90c5977..4837fef 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -476,7 +476,6 @@
     <style name="TextAppearance.NotificationInfo.Button">
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textSize">14sp</item>
-        <item name="android:textAllCaps">true</item>
         <item name="android:textColor">?android:attr/colorAccent</item>
         <item name="android:background">@drawable/btn_borderless_rect</item>
         <item name="android:gravity">center</item>
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index a7d1f0d..0be522b 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -51,7 +51,8 @@
  */
 public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
 
-    private static final String TAG = "OverviewProxyService";
+    public static final String TAG_OPS = "OverviewProxyService";
+    public static final boolean DEBUG_OVERVIEW_PROXY = false;
     private static final long BACKOFF_MILLIS = 5000;
 
     private final Context mContext;
@@ -96,12 +97,12 @@
                 try {
                     service.linkToDeath(mOverviewServiceDeathRcpt, 0);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Lost connection to launcher service", e);
+                    Log.e(TAG_OPS, "Lost connection to launcher service", e);
                 }
                 try {
                     mOverviewProxy.onBind(mSysUiProxy);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to call onBind()", e);
+                    Log.e(TAG_OPS, "Failed to call onBind()", e);
                 }
                 notifyConnectionChanged();
             }
@@ -211,7 +212,7 @@
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println(TAG + " state:");
+        pw.println(TAG_OPS + " state:");
         pw.print("  mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
         pw.print("  isCurrentUserSetup="); pw.println(mDeviceProvisionedController
                 .isCurrentUserSetup());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index 9ee40cc..d9583af 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -41,6 +41,7 @@
     private ImageView mOut;
 
     private int mWideOverlayIconStartPadding;
+    private int mSignalIndicatorToIconFrameSpacing;
 
     public SignalTileView(Context context) {
         super(context);
@@ -48,8 +49,13 @@
         mIn = addTrafficView(R.drawable.ic_qs_signal_in);
         mOut = addTrafficView(R.drawable.ic_qs_signal_out);
 
+        setClipChildren(false);
+        setClipToPadding(false);
+
         mWideOverlayIconStartPadding = context.getResources().getDimensionPixelSize(
                 R.dimen.wide_type_icon_start_padding_qs);
+        mSignalIndicatorToIconFrameSpacing = context.getResources().getDimensionPixelSize(
+                R.dimen.signal_indicator_to_icon_frame_spacing);
     }
 
     private ImageView addTrafficView(int icon) {
@@ -99,10 +105,10 @@
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         int left, right;
         if (isRtl) {
-            right = mIconFrame.getLeft();
+            right = getLeft() - mSignalIndicatorToIconFrameSpacing;
             left = right - indicator.getMeasuredWidth();
         } else {
-            left = mIconFrame.getRight();
+            left = getRight() + mSignalIndicatorToIconFrameSpacing;
             right = left + indicator.getMeasuredWidth();
         }
         indicator.layout(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index acd327b..b4cfda6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -85,6 +85,8 @@
                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
         params.setMargins(0, padding, 0, padding);
         mIconFrame.addView(mIcon, params);
+        mIconFrame.setClipChildren(false);
+        mIconFrame.setClipToPadding(false);
 
         mTileBackground = newTileBackground();
         if (mTileBackground instanceof RippleDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 1e00894..60422ee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -36,20 +36,8 @@
 
 /** Quick settings tile: Rotation **/
 public class RotationLockTile extends QSTileImpl<BooleanState> {
-    private final AnimationIcon mPortraitToAuto
-            = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation,
-            R.drawable.ic_portrait_from_auto_rotate);
-    private final AnimationIcon mAutoToPortrait
-            = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation,
-            R.drawable.ic_portrait_to_auto_rotate);
 
-    private final AnimationIcon mLandscapeToAuto
-            = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation,
-            R.drawable.ic_landscape_from_auto_rotate);
-    private final AnimationIcon mAutoToLandscape
-            = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation,
-            R.drawable.ic_landscape_to_auto_rotate);
-
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_auto_rotate);
     private final RotationLockController mController;
 
     public RotationLockTile(QSHost host) {
@@ -93,19 +81,10 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         if (mController == null) return;
         final boolean rotationLocked = mController.isRotationLocked();
-        // TODO: Handle accessibility rotation lock and whatnot.
 
         state.value = !rotationLocked;
-        final boolean portrait = isCurrentOrientationLockPortrait(mController, mContext);
-        if (rotationLocked) {
-            final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
-                    : R.string.quick_settings_rotation_locked_landscape_label;
-            state.label = mContext.getString(label);
-            state.icon = portrait ? mAutoToPortrait : mAutoToLandscape;
-        } else {
-            state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-            state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
-        }
+        state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
+        state.icon = mIcon;
         state.contentDescription = getAccessibilityString(rotationLocked);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
@@ -134,18 +113,7 @@
      * @param locked Whether or not rotation is locked.
      */
     private String getAccessibilityString(boolean locked) {
-        if (locked) {
-            return mContext.getString(R.string.accessibility_quick_settings_rotation_value,
-                    isCurrentOrientationLockPortrait(mController, mContext)
-                            ? mContext.getString(
-                                    R.string.quick_settings_rotation_locked_portrait_label)
-                            : mContext.getString(
-                                    R.string.quick_settings_rotation_locked_landscape_label))
-                    + "," + mContext.getString(R.string.accessibility_quick_settings_rotation);
-
-        } else {
-            return mContext.getString(R.string.accessibility_quick_settings_rotation);
-        }
+        return mContext.getString(R.string.accessibility_quick_settings_rotation);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 4faa84a..ff923e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -43,6 +43,8 @@
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.OverviewProxyService.TAG_OPS;
 
 /**
  * Class to detect gestures on the navigation bar.
@@ -118,6 +120,9 @@
             event.transform(mTransformGlobalMatrix);
             try {
                 overviewProxy.onMotionEvent(event);
+                if (DEBUG_OVERVIEW_PROXY) {
+                    Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
+                }
                 return true;
             } catch (RemoteException e) {
                 Log.e(TAG, "Callback failed", e);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index f41cb29..6857337 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -39,7 +39,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.graphics.drawable.Icon;
 import android.media.AudioManager;
 import android.net.Uri;
@@ -66,7 +65,6 @@
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -146,7 +144,6 @@
     private boolean mDockedStackExists;
 
     private boolean mManagedProfileIconVisible = false;
-    private boolean mManagedProfileInQuietMode = false;
 
     private BluetoothController mBluetooth;
 
@@ -474,17 +471,6 @@
         }
     }
 
-    private void updateQuietState() {
-        mManagedProfileInQuietMode = false;
-        int currentUserId = ActivityManager.getCurrentUser();
-        for (UserInfo ui : mUserManager.getEnabledProfiles(currentUserId)) {
-            if (ui.isManagedProfile() && ui.isQuietModeEnabled()) {
-                mManagedProfileInQuietMode = true;
-                return;
-            }
-        }
-    }
-
     private void updateManagedProfile() {
         // getLastResumedActivityUserId needds to acquire the AM lock, which may be contended in
         // some cases. Since it doesn't really matter here whether it's updated in this frame
@@ -502,11 +488,6 @@
                         mIconController.setIcon(mSlotManagedProfile,
                                 R.drawable.stat_sys_managed_profile_status,
                                 mContext.getString(R.string.accessibility_managed_profile));
-                    } else if (mManagedProfileInQuietMode) {
-                        showIcon = true;
-                        mIconController.setIcon(mSlotManagedProfile,
-                                R.drawable.stat_sys_managed_profile_status_off,
-                                mContext.getString(R.string.accessibility_managed_profile));
                     } else {
                         showIcon = false;
                     }
@@ -676,7 +657,6 @@
                 public void onUserSwitchComplete(int newUserId) throws RemoteException {
                     mHandler.post(() -> {
                         updateAlarm();
-                        updateQuietState();
                         updateManagedProfile();
                         updateForegroundInstantApps();
                     });
@@ -724,7 +704,6 @@
         if (mCurrentUserSetup == userSetup) return;
         mCurrentUserSetup = userSetup;
         updateAlarm();
-        updateQuietState();
     }
 
     @Override
@@ -793,7 +772,6 @@
             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) ||
                     action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) ||
                     action.equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) {
-                updateQuietState();
                 updateManagedProfile();
             } else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
                 updateHeadsetPlug(intent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index afd2236..6fc5bbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -49,6 +49,8 @@
 
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.OverviewProxyService.TAG_OPS;
 
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub and switch.
@@ -144,6 +146,9 @@
                     try {
                         final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
                         overviewProxy.onQuickSwitch();
+                        if (DEBUG_OVERVIEW_PROXY) {
+                            Log.d(TAG_OPS, "Quick Switch");
+                        }
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to send start of quick switch.", e);
                     }
@@ -256,6 +261,9 @@
                         if (mQuickScrubActive) {
                             try {
                                 overviewProxy.onQuickScrubProgress(scrubFraction);
+                                if (DEBUG_OVERVIEW_PROXY) {
+                                    Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
+                                }
                             } catch (RemoteException e) {
                                 Log.e(TAG, "Failed to send progress of quick scrub.", e);
                             }
@@ -355,6 +363,9 @@
             mTrackAnimator.start();
             try {
                 mOverviewEventSender.getProxy().onQuickScrubStart();
+                if (DEBUG_OVERVIEW_PROXY) {
+                    Log.d(TAG_OPS, "Quick Scrub Start");
+                }
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to send start of quick scrub.", e);
             }
@@ -369,6 +380,9 @@
             mQuickScrubEndAnimator.start();
             try {
                 mOverviewEventSender.getProxy().onQuickScrubEnd();
+                if (DEBUG_OVERVIEW_PROXY) {
+                    Log.d(TAG_OPS, "Quick Scrub End");
+                }
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to send end of quick scrub.", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 5a19a76..9041d5a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -368,16 +368,16 @@
                 mController.setActiveStream(row.stream);
                 if (row.stream == AudioManager.STREAM_RING) {
                     final boolean hasVibrator = mController.hasVibrator();
-                    if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+                    if (mState.ringerModeExternal == AudioManager.RINGER_MODE_NORMAL) {
                         if (hasVibrator) {
-                            mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+                            mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, true);
                         } else {
                             final boolean wasZero = row.ss.level == 0;
                             mController.setStreamVolume(stream,
                                     wasZero ? row.lastAudibleLevel : 0);
                         }
                     } else {
-                        mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+                        mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, true);
                         if (row.ss.level == 0) {
                             mController.setStreamVolume(stream, 1);
                         }
@@ -403,15 +403,15 @@
                 return;
             }
             final boolean hasVibrator = mController.hasVibrator();
-            if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+            if (mState.ringerModeExternal == AudioManager.RINGER_MODE_NORMAL) {
                 if (hasVibrator) {
-                    mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+                    mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, true);
                 } else {
                     final boolean wasZero = ss.level == 0;
                     mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
                 }
             } else {
-                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, true);
                 if (ss.level == 0) {
                     mController.setStreamVolume(AudioManager.STREAM_RING, 1);
                 }
@@ -552,7 +552,7 @@
             if (ss == null) {
                 return;
             }
-            switch (mState.ringerModeInternal) {
+            switch (mState.ringerModeExternal) {
                 case AudioManager.RINGER_MODE_VIBRATE:
                     mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
                     mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
@@ -653,9 +653,9 @@
         final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
         final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
         final boolean isRingVibrate = isRingStream
-                && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
+                && mState.ringerModeExternal == AudioManager.RINGER_MODE_VIBRATE;
         final boolean isRingSilent = isRingStream
-                && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT;
+                && mState.ringerModeExternal == AudioManager.RINGER_MODE_SILENT;
         final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS;
         final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
         final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 48c678e..29d33ce 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -294,6 +294,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManagerInternal;
 import android.location.LocationManager;
 import android.media.audiofx.AudioEffect;
 import android.metrics.LogMaker;
@@ -474,6 +475,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -25142,6 +25144,11 @@
         public void setSwitchingToSystemUserMessage(String switchingToSystemUserMessage) {
             mUserController.setSwitchingToSystemUserMessage(switchingToSystemUserMessage);
         }
+
+        @Override
+        public int getMaxRunningUsers() {
+            return mUserController.mMaxRunningUsers;
+        }
     }
 
     /**
@@ -25352,9 +25359,18 @@
                 }
             }
         }
-        if (updateFrameworkRes && mWindowManager != null) {
-            ActivityThread.currentActivityThread().getExecutor().execute(
-                    mWindowManager::onOverlayChanged);
+        if (updateFrameworkRes) {
+            // Update system server components that need to know about changed overlays. Because the
+            // overlay is applied in ActivityThread, we need to serialize through its thread too.
+            final Executor executor = ActivityThread.currentActivityThread().getExecutor();
+            final DisplayManagerInternal display =
+                    LocalServices.getService(DisplayManagerInternal.class);
+            if (display != null) {
+                executor.execute(display::onOverlayChanged);
+            }
+            if (mWindowManager != null) {
+                executor.execute(mWindowManager::onOverlayChanged);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0904c8e..f496a67 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1817,7 +1817,8 @@
             boolean behindFullscreenActivity = !stackShouldBeVisible;
             boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
                     && (isInStackLocked(starting) == null);
-            final boolean isTopNotPinnedStack = getDisplay().isTopNotPinnedStack(this);
+            final boolean isTopNotPinnedStack =
+                    isAttached() && getDisplay().isTopNotPinnedStack(this);
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                 final TaskRecord task = mTaskHistory.get(taskNdx);
                 final ArrayList<ActivityRecord> activities = task.mActivities;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 35465a7..8910274 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -738,9 +738,18 @@
                 }
                 return;
             }
+            final boolean showFirstCrash = Settings.Global.getInt(
+                    mContext.getContentResolver(),
+                    Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0;
+            final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+                    0,
+                    UserHandle.USER_CURRENT) != 0;
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
-            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced) {
+            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
+                    && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
                 proc.crashDialog = new AppErrorDialog(mContext, mService, data);
             } else {
                 // The device is asleep, so just pretend that the user
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c7210a8..65bebc6 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -796,7 +796,7 @@
     private void stopGuestOrEphemeralUserIfBackground(int oldUserId) {
         if (DEBUG_MU) Slog.i(TAG, "Stop guest or ephemeral user if background: " + oldUserId);
         UserState oldUss = mStartedUsers.get(oldUserId);
-        if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
+        if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss == null
                 || oldUss.state == UserState.STATE_STOPPING
                 || oldUss.state == UserState.STATE_SHUTDOWN) {
             return;
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 1e94e00..bcf8bfe 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -521,6 +521,7 @@
     public void dump(PrintWriter pw) {
         pw.println("BrightnessTracker state:");
         synchronized (mDataCollectionLock) {
+            pw.println("  mStarted=" + mStarted);
             pw.println("  mLastSensorReadings.size=" + mLastSensorReadings.size());
             if (!mLastSensorReadings.isEmpty()) {
                 pw.println("  mLastSensorReadings time span "
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 839ab4d..3a8e291 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -143,6 +143,9 @@
     public void requestDisplayModesInTransactionLocked(int colorMode, int modeId) {
     }
 
+    public void onOverlayChangedLocked() {
+    }
+
     /**
      * Sets the display layer stack while in a transaction.
      */
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a55fec5..b97de65 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -29,6 +29,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -1005,11 +1006,13 @@
     }
 
     private void setBrightnessConfigurationForUserInternal(
-            @NonNull BrightnessConfiguration c, @UserIdInt int userId) {
+            @NonNull BrightnessConfiguration c, @UserIdInt int userId,
+            @Nullable String packageName) {
         final int userSerial = getUserManager().getUserSerialNumber(userId);
         synchronized (mSyncRoot) {
             try {
-                mPersistentDataStore.setBrightnessConfigurationForUser(c, userSerial);
+                mPersistentDataStore.setBrightnessConfigurationForUser(c, userSerial,
+                        packageName);
             } finally {
                 mPersistentDataStore.saveIfNeeded();
             }
@@ -1833,7 +1836,7 @@
 
         @Override // Binder call
         public void setBrightnessConfigurationForUser(
-                BrightnessConfiguration c, @UserIdInt int userId) {
+                BrightnessConfiguration c, @UserIdInt int userId, String packageName) {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
                     "Permission required to change the display's brightness configuration");
@@ -1843,10 +1846,13 @@
                         "Permission required to change the display brightness"
                         + " configuration of another user");
             }
+            if (packageName != null && !validatePackageName(getCallingUid(), packageName)) {
+                packageName = null;
+            }
             Preconditions.checkNotNull(c);
             final long token = Binder.clearCallingIdentity();
             try {
-                setBrightnessConfigurationForUserInternal(c, userId);
+                setBrightnessConfigurationForUserInternal(c, userId, packageName);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -2013,8 +2019,8 @@
         @Override
         public void onOverlayChanged() {
             synchronized (mSyncRoot) {
-                if (updateLogicalDisplaysLocked()) {
-                    scheduleTraversalLocked(false);
+                for (int i = 0; i < mDisplayDevices.size(); i++) {
+                    mDisplayDevices.get(i).onOverlayChangedLocked();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 23e4c9b..fc3c1f7 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -600,6 +600,11 @@
             }
         }
 
+        @Override
+        public void onOverlayChangedLocked() {
+            updateDeviceInfoLocked();
+        }
+
         public boolean requestModeInTransactionLocked(int modeId) {
             if (modeId == 0) {
                 modeId = mDefaultModeId;
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 49b4465..f1ce5c5 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -23,6 +23,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.Nullable;
 import android.graphics.Point;
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.WifiDisplay;
@@ -30,6 +31,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Pair;
+import android.util.SparseLongArray;
+import android.util.TimeUtils;
 import android.util.Xml;
 import android.view.Display;
 
@@ -73,8 +76,8 @@
  *      &lt;stable-display-width>1080&lt;/stable-display-width>
  *  &lt;/stable-device-values>
  *  &lt;brightness-configurations>
- *      &lt;brightness-configuration user-id="0">
- *          &lt;brightness-curve>
+ *      &lt;brightness-configuration user-serial="0" package-name="com.example" timestamp="1234">
+ *          &lt;brightness-curve description="some text">
  *              &lt;brightness-point lux="0" nits="13.25"/>
  *              &lt;brightness-point lux="20" nits="35.94"/>
  *          &lt;/brightness-curve>
@@ -110,8 +113,11 @@
     private static final String TAG_BRIGHTNESS_CURVE = "brightness-curve";
     private static final String TAG_BRIGHTNESS_POINT = "brightness-point";
     private static final String ATTR_USER_SERIAL = "user-serial";
+    private static final String ATTR_PACKAGE_NAME = "package-name";
+    private static final String ATTR_TIME_STAMP = "timestamp";
     private static final String ATTR_LUX = "lux";
     private static final String ATTR_NITS = "nits";
+    private static final String ATTR_DESCRIPTION = "description";
 
     // Remembered Wifi display devices.
     private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
@@ -273,9 +279,11 @@
 		}
 	}
 
-    public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userSerial) {
+    public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userSerial,
+            @Nullable String packageName) {
         loadIfNeeded();
-        if (mBrightnessConfigurations.setBrightnessConfigurationForUser(c, userSerial)) {
+        if (mBrightnessConfigurations.setBrightnessConfigurationForUser(c, userSerial,
+                packageName)) {
             setDirty();
         }
     }
@@ -576,15 +584,27 @@
     private static final class BrightnessConfigurations {
         // Maps from a user ID to the users' given brightness configuration
         private SparseArray<BrightnessConfiguration> mConfigurations;
+        // Timestamp of time the configuration was set.
+        private SparseLongArray mTimeStamps;
+        // Package that set the configuration.
+        private SparseArray<String> mPackageNames;
 
         public BrightnessConfigurations() {
             mConfigurations = new SparseArray<>();
+            mTimeStamps = new SparseLongArray();
+            mPackageNames = new SparseArray<>();
         }
 
         private boolean setBrightnessConfigurationForUser(BrightnessConfiguration c,
-                int userSerial) {
+                int userSerial, String packageName) {
             BrightnessConfiguration currentConfig = mConfigurations.get(userSerial);
             if (currentConfig == null || !currentConfig.equals(c)) {
+                if (packageName == null) {
+                    mPackageNames.remove(userSerial);
+                } else {
+                    mPackageNames.put(userSerial, packageName);
+                }
+                mTimeStamps.put(userSerial, System.currentTimeMillis());
                 mConfigurations.put(userSerial, c);
                 return true;
             }
@@ -604,14 +624,31 @@
                         userSerial = Integer.parseInt(
                                 parser.getAttributeValue(null, ATTR_USER_SERIAL));
                     } catch (NumberFormatException nfe) {
-                        userSerial= -1;
+                        userSerial = -1;
                         Slog.e(TAG, "Failed to read in brightness configuration", nfe);
                     }
 
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                    String timeStampString = parser.getAttributeValue(null, ATTR_TIME_STAMP);
+                    long timeStamp = -1;
+                    if (timeStampString != null) {
+                        try {
+                            timeStamp = Long.parseLong(timeStampString);
+                        } catch (NumberFormatException nfe) {
+                            // Ignore we will just not restore the timestamp.
+                        }
+                    }
+
                     try {
                         BrightnessConfiguration config = loadConfigurationFromXml(parser);
-                        if (userSerial>= 0 && config != null) {
+                        if (userSerial >= 0 && config != null) {
                             mConfigurations.put(userSerial, config);
+                            if (timeStamp != -1) {
+                                mTimeStamps.put(userSerial, timeStamp);
+                            }
+                            if (packageName != null) {
+                                mPackageNames.put(userSerial, packageName);
+                            }
                         }
                     } catch (IllegalArgumentException iae) {
                         Slog.e(TAG, "Failed to load brightness configuration!", iae);
@@ -623,18 +660,24 @@
         private static BrightnessConfiguration loadConfigurationFromXml(XmlPullParser parser)
                 throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
-            final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
+            String description = null;
+            Pair<float[], float[]> curve = null;
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                 if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) {
-                    Pair<float[], float[]> curve = loadCurveFromXml(parser, builder);
-                    builder.setCurve(curve.first /*lux*/, curve.second /*nits*/);
+                    description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
+                    curve = loadCurveFromXml(parser);
                 }
             }
+            if (curve == null) {
+                return null;
+            }
+            final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
+                    curve.first, curve.second);
+            builder.setDescription(description);
             return builder.build();
         }
 
-        private static Pair<float[], float[]> loadCurveFromXml(XmlPullParser parser,
-                BrightnessConfiguration.Builder builder)
+        private static Pair<float[], float[]> loadCurveFromXml(XmlPullParser parser)
                 throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
             List<Float> luxLevels = new ArrayList<>();
@@ -666,11 +709,19 @@
 
         public void saveToXml(XmlSerializer serializer) throws IOException {
             for (int i = 0; i < mConfigurations.size(); i++) {
-                final int userSerial= mConfigurations.keyAt(i);
+                final int userSerial = mConfigurations.keyAt(i);
                 final BrightnessConfiguration config = mConfigurations.valueAt(i);
 
                 serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATION);
                 serializer.attribute(null, ATTR_USER_SERIAL, Integer.toString(userSerial));
+                String packageName = mPackageNames.get(userSerial);
+                if (packageName != null) {
+                    serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
+                }
+                long timestamp = mTimeStamps.get(userSerial, -1);
+                if (timestamp != -1) {
+                    serializer.attribute(null, ATTR_TIME_STAMP, Long.toString(timestamp));
+                }
                 saveConfigurationToXml(serializer, config);
                 serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATION);
             }
@@ -679,6 +730,9 @@
         private static void saveConfigurationToXml(XmlSerializer serializer,
                 BrightnessConfiguration config) throws IOException {
             serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
+            if (config.getDescription() != null) {
+                serializer.attribute(null, ATTR_DESCRIPTION, config.getDescription());
+            }
             final Pair<float[], float[]> curve = config.getCurve();
             for (int i = 0; i < curve.first.length; i++) {
                 serializer.startTag(null, TAG_BRIGHTNESS_POINT);
@@ -691,8 +745,16 @@
 
         public void dump(final PrintWriter pw, final String prefix) {
             for (int i = 0; i < mConfigurations.size(); i++) {
-                final int userSerial= mConfigurations.keyAt(i);
+                final int userSerial = mConfigurations.keyAt(i);
+                long time = mTimeStamps.get(userSerial, -1);
+                String packageName = mPackageNames.get(userSerial);
                 pw.println(prefix + "User " + userSerial + ":");
+                if (time != -1) {
+                    pw.println(prefix + "  set at: " + TimeUtils.formatForLogging(time));
+                }
+                if (packageName != null) {
+                    pw.println(prefix + "  set by: " + packageName);
+                }
                 pw.println(prefix + "  " + mConfigurations.valueAt(i));
             }
         }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e158819..6dc5403 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2628,6 +2628,10 @@
         s.append("  mStarted=").append(mStarted).append('\n');
         s.append("  mFixInterval=").append(mFixInterval).append('\n');
         s.append("  mLowPowerMode=").append(mLowPowerMode).append('\n');
+        s.append("  mGnssMeasurementsProvider.isRegistered()=")
+                .append(mGnssMeasurementsProvider.isRegistered()).append('\n');
+        s.append("  mGnssNavigationMessageProvider.isRegistered()=")
+                .append(mGnssNavigationMessageProvider.isRegistered()).append('\n');
         s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
         s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
         s.append(" ( ");
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 58a9516..fcdb9d1 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -46,7 +46,8 @@
 
     private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
 
-    private boolean mIsRegistered;  // must access only on handler thread
+    private volatile boolean mIsRegistered;  // must access only on handler thread, or read-only
+
     private boolean mHasIsSupported;
     private boolean mIsSupported;
 
@@ -58,6 +59,11 @@
         mTag = name;
     }
 
+    // read-only access for a dump() thread assured via volatile
+    public boolean isRegistered() {
+        return mIsRegistered;
+    }
+
     public boolean addListener(@NonNull TListener listener) {
         Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
         IBinder binder = listener.asBinder();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7bd1ae9..07ea51b 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2028,6 +2028,10 @@
                 vaultParams, vaultChallenge, secrets);
     }
 
+    public void closeSession(@NonNull String sessionId) throws RemoteException {
+        mRecoverableKeyStoreManager.closeSession(sessionId);
+    }
+
     @Override
     public Map<String, byte[]> recoverKeys(@NonNull String sessionId,
             @NonNull byte[] recoveryKeyBlob, @NonNull List<WrappedApplicationKey> applicationKeys)
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 801dc54..76508d5 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -16,12 +16,12 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import static android.security.keystore.RecoveryManager.ERROR_BAD_CERTIFICATE_FORMAT;
-import static android.security.keystore.RecoveryManager.ERROR_DECRYPTION_FAILED;
-import static android.security.keystore.RecoveryManager.ERROR_INSECURE_USER;
-import static android.security.keystore.RecoveryManager.ERROR_NO_SNAPSHOT_PENDING;
-import static android.security.keystore.RecoveryManager.ERROR_SERVICE_INTERNAL_ERROR;
-import static android.security.keystore.RecoveryManager.ERROR_SESSION_EXPIRED;
+import static android.security.keystore.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT;
+import static android.security.keystore.RecoveryController.ERROR_DECRYPTION_FAILED;
+import static android.security.keystore.RecoveryController.ERROR_INSECURE_USER;
+import static android.security.keystore.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
+import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
+import static android.security.keystore.RecoveryController.ERROR_SESSION_EXPIRED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,8 +35,8 @@
 
 import android.security.keystore.KeychainProtectionParams;
 import android.security.keystore.KeychainSnapshot;
+import android.security.keystore.RecoveryController;
 import android.security.keystore.WrappedApplicationKey;
-import android.security.keystore.RecoveryManager;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -63,7 +63,7 @@
 import javax.crypto.AEADBadTagException;
 
 /**
- * Class with {@link RecoveryManager} API implementation and internal methods to interact
+ * Class with {@link RecoveryController} API implementation and internal methods to interact
  * with {@code LockSettingsService}.
  *
  * @hide
@@ -435,6 +435,13 @@
         }
     }
 
+    /**
+     * Destroys the session with the given {@code sessionId}.
+     */
+    public void closeSession(@NonNull String sessionId) throws RemoteException {
+        mRecoverySessionStorage.remove(Binder.getCallingUid(), sessionId);
+    }
+
     public void removeKey(@NonNull String alias) throws RemoteException {
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
index 0042e10..c33c9de 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
@@ -16,8 +16,8 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
+import android.security.keystore.RecoveryController;
 import android.util.Log;
-import android.security.keystore.RecoveryManager;
 
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -97,7 +97,7 @@
                 /*nonce=*/ cipher.getIV(),
                 /*keyMaterial=*/ encryptedKeyMaterial,
                 /*platformKeyGenerationId=*/ wrappingKey.getGenerationId(),
-                RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+                RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
     }
 
     /**
@@ -107,14 +107,14 @@
      * @param keyMaterial The encrypted bytes of the key material.
      * @param platformKeyGenerationId The generation ID of the key used to wrap this key.
      *
-     * @see RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS
+     * @see RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS
      * @hide
      */
     public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) {
         mNonce = nonce;
         mKeyMaterial = keyMaterial;
         mPlatformKeyGenerationId = platformKeyGenerationId;
-        mRecoveryStatus = RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS;
+        mRecoveryStatus = RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS;
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java
index f7633e4..0e66746 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java
@@ -73,6 +73,16 @@
     }
 
     /**
+     * Deletes the session with {@code sessionId} created by app with {@code uid}.
+     */
+    public void remove(int uid, String sessionId) {
+        if (mSessionsByUid.get(uid) == null) {
+            return;
+        }
+        mSessionsByUid.get(uid).removeIf(session -> session.mSessionId.equals(sessionId));
+    }
+
+    /**
      * Removes all sessions associated with the given recovery agent uid.
      *
      * @param uid The uid of the recovery agent whose sessions to remove.
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 4c00921..2584187 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -160,7 +160,7 @@
     }
 
     private boolean isCall(NotificationRecord record) {
-        return record.getNotification().category == Notification.CATEGORY_CALL
+        return record.isCategory(Notification.CATEGORY_CALL)
                 && isDefaultPhoneApp(record.sbn.getPackageName());
     }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b5d2844..8f672b5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1002,7 +1002,7 @@
                     if (isChange && policy.doNotDisturbWhenSilent) {
                         if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
                                 && mZenMode != Global.ZEN_MODE_ALARMS) {
-                            newZen = Global.ZEN_MODE_ALARMS;
+                            newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
                         }
                         setPreviousRingerModeSetting(ringerModeOld);
                     }
@@ -1042,7 +1042,7 @@
                 case AudioManager.RINGER_MODE_SILENT:
                     if (isChange) {
                         if (mZenMode == Global.ZEN_MODE_OFF) {
-                            newZen = Global.ZEN_MODE_ALARMS;
+                            newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
                         }
                         ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
                                 : AudioManager.RINGER_MODE_SILENT;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a43818a..cc448da 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -17,10 +17,12 @@
 package com.android.server.pm;
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA;
 import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
@@ -96,6 +98,7 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 
+import android.content.pm.dex.DexMetadataHelper;
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -259,6 +262,7 @@
             // entries like "lost+found".
             if (file.isDirectory()) return false;
             if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+            if (DexMetadataHelper.isDexMetadataFile(file)) return false;
             return true;
         }
     };
@@ -939,6 +943,15 @@
                 mInstallerPackageName, mInstallerUid, user, mSigningDetails);
     }
 
+    private static void maybeRenameFile(File from, File to) throws PackageManagerException {
+        if (!from.equals(to)) {
+            if (!from.renameTo(to)) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Could not rename file " + from + " to " + to);
+            }
+        }
+    }
+
     /**
      * Validate install by confirming that all application packages are have
      * consistent package name, version code, and signing certificates.
@@ -983,6 +996,7 @@
         if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
         }
+
         // Verify that all staged packages are internally consistent
         final ArraySet<String> stagedSplits = new ArraySet<>();
         for (File addedFile : addedFiles) {
@@ -1013,9 +1027,9 @@
             // Take this opportunity to enforce uniform naming
             final String targetName;
             if (apk.splitName == null) {
-                targetName = "base.apk";
+                targetName = "base" + APK_FILE_EXTENSION;
             } else {
-                targetName = "split_" + apk.splitName + ".apk";
+                targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
             }
             if (!FileUtils.isValidExtFilename(targetName)) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -1023,9 +1037,7 @@
             }
 
             final File targetFile = new File(mResolvedStageDir, targetName);
-            if (!addedFile.equals(targetFile)) {
-                addedFile.renameTo(targetFile);
-            }
+            maybeRenameFile(addedFile, targetFile);
 
             // Base is coming from session
             if (apk.splitName == null) {
@@ -1033,6 +1045,18 @@
             }
 
             mResolvedStagedFiles.add(targetFile);
+
+            final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
+            if (dexMetadataFile != null) {
+                if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
+                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                            "Invalid filename: " + dexMetadataFile);
+                }
+                final File targetDexMetadataFile = new File(mResolvedStageDir,
+                        DexMetadataHelper.buildDexMetadataPathForApk(targetName));
+                mResolvedStagedFiles.add(targetDexMetadataFile);
+                maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
+            }
         }
 
         if (removeSplitList.size() > 0) {
@@ -1097,6 +1121,12 @@
             if (mResolvedBaseFile == null) {
                 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 mResolvedInheritedFiles.add(mResolvedBaseFile);
+                // Inherit the dex metadata if present.
+                final File baseDexMetadataFile =
+                        DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
+                if (baseDexMetadataFile != null) {
+                    mResolvedInheritedFiles.add(baseDexMetadataFile);
+                }
             }
 
             // Inherit splits if not overridden
@@ -1107,6 +1137,12 @@
                     final boolean splitRemoved = removeSplitList.contains(splitName);
                     if (!stagedSplits.contains(splitName) && !splitRemoved) {
                         mResolvedInheritedFiles.add(splitFile);
+                        // Inherit the dex metadata if present.
+                        final File splitDexMetadataFile =
+                                DexMetadataHelper.findDexMetadataForFile(splitFile);
+                        if (splitDexMetadataFile != null) {
+                            mResolvedInheritedFiles.add(splitDexMetadataFile);
+                        }
                     }
                 }
             }
@@ -1163,43 +1199,6 @@
     }
 
     /**
-     * Calculate the final install footprint size, combining both staged and
-     * existing APKs together and including unpacked native code from both.
-     */
-    private long calculateInstalledSize() throws PackageManagerException {
-        Preconditions.checkNotNull(mResolvedBaseFile);
-
-        final ApkLite baseApk;
-        try {
-            baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
-        } catch (PackageParserException e) {
-            throw PackageManagerException.from(e);
-        }
-
-        final List<String> splitPaths = new ArrayList<>();
-        for (File file : mResolvedStagedFiles) {
-            if (mResolvedBaseFile.equals(file)) continue;
-            splitPaths.add(file.getAbsolutePath());
-        }
-        for (File file : mResolvedInheritedFiles) {
-            if (mResolvedBaseFile.equals(file)) continue;
-            splitPaths.add(file.getAbsolutePath());
-        }
-
-        // This is kind of hacky; we're creating a half-parsed package that is
-        // straddled between the inherited and staged APKs.
-        final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
-                splitPaths.toArray(new String[splitPaths.size()]), null);
-
-        try {
-            return PackageHelper.calculateInstalledSize(pkg, params.abiOverride);
-        } catch (IOException e) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                    "Failed to calculate install size", e);
-        }
-    }
-
-    /**
      * Determine if creating hard links between source and destination is
      * possible. That is, do they all live on the same underlying device.
      */
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 711ea13..dd374fe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -191,6 +191,7 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.pm.VersionedPackage;
+import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -16486,6 +16487,7 @@
         final PackageParser.Package pkg;
         try {
             pkg = pp.parsePackage(tmpPackageFile, parseFlags);
+            DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             res.setError("Failed parse during installPackageLI", e);
             return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index bd1cd33..a33f071 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -18,6 +18,7 @@
 
 import android.accounts.IAccountManager;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -46,6 +47,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
+import android.content.pm.dex.DexMetadataHelper;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
@@ -72,13 +74,13 @@
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.SizedInputStream;
+import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 
 import dalvik.system.DexFile;
 
 import libcore.io.IoUtils;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -222,6 +224,8 @@
                     return runSetUserRestriction();
                 case "get-max-users":
                     return runGetMaxUsers();
+                case "get-max-running-users":
+                    return runGetMaxRunningUsers();
                 case "set-home-activity":
                     return runSetHomeActivity();
                 case "set-installer":
@@ -1883,6 +1887,14 @@
         return 0;
     }
 
+    public int runGetMaxRunningUsers() {
+        ActivityManagerInternal activityManagerInternal =
+                LocalServices.getService(ActivityManagerInternal.class);
+        getOutPrintWriter().println("Maximum supported running users: "
+                + activityManagerInternal.getMaxRunningUsers());
+        return 0;
+    }
+
     private static class InstallParams {
         SessionParams sessionParams;
         String installerPackageName;
@@ -2246,6 +2258,14 @@
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
 
+            // Sanity check that all .dm files match an apk.
+            // (The installer does not support standalone .dm files and will not process them.)
+            try {
+                DexMetadataHelper.validateDexPaths(session.getNames());
+            } catch (IllegalStateException | IOException e) {
+                pw.println("Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+            }
+
             final LocalIntentReceiver receiver = new LocalIntentReceiver();
             session.commit(receiver.getIntentSender());
 
@@ -2607,6 +2627,8 @@
         pw.println("");
         pw.println("  get-max-users");
         pw.println("");
+        pw.println("  get-max-running-users");
+        pw.println("");
         pw.println("  compile [-m MODE | -r REASON] [-f] [-c] [--split SPLIT_NAME]");
         pw.println("          [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)");
         pw.println("    Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".  Options are:");
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 261065f..b474c62 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -517,15 +517,25 @@
     }
 
     WindowState findMainWindow() {
+        return findMainWindow(true);
+    }
+
+    /**
+     * Finds the main window that either has type base application or application starting if
+     * requested.
+     *
+     * @param includeStartingApp Allow to search application-starting windows to also be returned.
+     * @return The main window of type base application or application starting if requested.
+     */
+    WindowState findMainWindow(boolean includeStartingApp) {
         WindowState candidate = null;
-        int j = mChildren.size();
-        while (j > 0) {
-            j--;
+        for (int j = mChildren.size() - 1; j >= 0; --j) {
             final WindowState win = mChildren.get(j);
             final int type = win.mAttrs.type;
             // No need to loop through child window as base application and starting types can't be
             // child windows.
-            if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) {
+            if (type == TYPE_BASE_APPLICATION
+                    || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) {
                 // In cases where there are multiple windows, we prefer the non-exiting window. This
                 // happens for example when replacing windows during an activity relaunch. When
                 // constructing the animation, we want the new window, not the exiting one.
@@ -1373,8 +1383,11 @@
 
         if (mLastTransactionSequence != mService.mTransactionSequence) {
             mLastTransactionSequence = mService.mTransactionSequence;
-            mNumInterestingWindows = mNumDrawnWindows = 0;
+            mNumDrawnWindows = 0;
             startingDisplayed = false;
+
+            // There is the main base application window, even if it is exiting, wait for it
+            mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
         }
 
         final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -1396,7 +1409,10 @@
 
             if (w != startingWindow) {
                 if (w.isInteresting()) {
-                    mNumInterestingWindows++;
+                    // Add non-main window as interesting since the main app has already been added
+                    if (findMainWindow(false /* includeStartingApp */) != w) {
+                        mNumInterestingWindows++;
+                    }
                     if (w.isDrawnLw()) {
                         mNumDrawnWindows++;
 
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 0cf8d2f..36e5d10 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -454,8 +454,11 @@
                 inputMethodManagerInternal.hideCurrentInputMethod();
                 mImeHideRequested = true;
             }
+
+            // If a primary stack was just created, it will not have access to display content at
+            // this point so pass it from here to get a valid dock side.
             final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
-            mOriginalDockedSide = stack.getDockSide();
+            mOriginalDockedSide = stack.getDockSideForDisplay(mDisplayContent);
             return;
         }
         mOriginalDockedSide = DOCKED_INVALID;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 8a36226..bc0f9ad 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1397,15 +1397,23 @@
         return getDockSide(getRawBounds());
     }
 
+    int getDockSideForDisplay(DisplayContent dc) {
+        return getDockSide(dc, getRawBounds());
+    }
+
     private int getDockSide(Rect bounds) {
-        if (!inSplitScreenWindowingMode()) {
-            return DOCKED_INVALID;
-        }
         if (mDisplayContent == null) {
             return DOCKED_INVALID;
         }
-        mDisplayContent.getBounds(mTmpRect);
-        final int orientation = mDisplayContent.getConfiguration().orientation;
+        return getDockSide(mDisplayContent, bounds);
+    }
+
+    private int getDockSide(DisplayContent dc, Rect bounds) {
+        if (!inSplitScreenWindowingMode()) {
+            return DOCKED_INVALID;
+        }
+        dc.getBounds(mTmpRect);
+        final int orientation = dc.getConfiguration().orientation;
         return getDockSideUnchecked(bounds, mTmpRect, orientation);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0fedc79..10e7893 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6613,7 +6613,7 @@
     public void onOverlayChanged() {
         synchronized (mWindowMap) {
             mPolicy.onOverlayChangedLw();
-            mDisplayManagerInternal.onOverlayChanged();
+            getDefaultDisplayContentLocked().updateDisplayInfo();
             requestTraversal();
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
index 0cc37b4..c5f8c90 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -58,8 +58,11 @@
         String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                 + "<display-manager-state>\n"
                 + "  <brightness-configurations>\n"
-                + "    <brightness-configuration user-serial=\"1\">\n"
-                + "      <brightness-curve>\n"
+                + "    <brightness-configuration"
+                + "         user-serial=\"1\""
+                + "         package-name=\"example.com\""
+                + "         timestamp=\"123456\">\n"
+                + "      <brightness-curve description=\"something\">\n"
                 + "        <brightness-point lux=\"0\" nits=\"13.25\"/>\n"
                 + "        <brightness-point lux=\"25\" nits=\"35.94\"/>\n"
                 + "      </brightness-curve>\n"
@@ -81,6 +84,7 @@
         float[] expectedNits = { 13.25f, 35.94f };
         assertArrayEquals(expectedLux, curve.first, "lux");
         assertArrayEquals(expectedNits, curve.second, "nits");
+        assertEquals("something", config.getDescription());
 
         config = mDataStore.getBrightnessConfiguration(3 /*userSerial*/);
         curve = config.getCurve();
@@ -88,6 +92,7 @@
         expectedNits = new float[] { 13.25f, 15f };
         assertArrayEquals(expectedLux, curve.first, "lux");
         assertArrayEquals(expectedNits, curve.second, "nits");
+        assertNull(config.getDescription());
     }
 
     @Test
@@ -144,12 +149,12 @@
     public void testStoreAndReloadOfBrightnessConfigurations() {
         final float[] lux = { 0f, 10f };
         final float[] nits = {1f, 100f };
-        final BrightnessConfiguration config = new BrightnessConfiguration.Builder()
-                .setCurve(lux, nits)
+        final BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
+                .setDescription("a description")
                 .build();
         mDataStore.loadIfNeeded();
         assertNull(mDataStore.getBrightnessConfiguration(0 /*userSerial*/));
-        mDataStore.setBrightnessConfigurationForUser(config, 0);
+        mDataStore.setBrightnessConfigurationForUser(config, 0, "packagename");
 
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         mInjector.setWriteStream(baos);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 767472a..402a37c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -283,6 +283,44 @@
     }
 
     @Test
+    public void closeSession_closesASession() throws Exception {
+        mRecoverableKeyStoreManager.startRecoverySession(
+                TEST_SESSION_ID,
+                TEST_PUBLIC_KEY,
+                TEST_VAULT_PARAMS,
+                TEST_VAULT_CHALLENGE,
+                ImmutableList.of(
+                        new KeychainProtectionParams(
+                                TYPE_LOCKSCREEN,
+                                TYPE_PASSWORD,
+                                KeyDerivationParams.createSha256Params(TEST_SALT),
+                                TEST_SECRET)));
+
+        mRecoverableKeyStoreManager.closeSession(TEST_SESSION_ID);
+
+        assertEquals(0, mRecoverySessionStorage.size());
+    }
+
+    @Test
+    public void closeSession_doesNotCloseUnrelatedSessions() throws Exception {
+        mRecoverableKeyStoreManager.startRecoverySession(
+                TEST_SESSION_ID,
+                TEST_PUBLIC_KEY,
+                TEST_VAULT_PARAMS,
+                TEST_VAULT_CHALLENGE,
+                ImmutableList.of(
+                        new KeychainProtectionParams(
+                                TYPE_LOCKSCREEN,
+                                TYPE_PASSWORD,
+                                KeyDerivationParams.createSha256Params(TEST_SALT),
+                                TEST_SECRET)));
+
+        mRecoverableKeyStoreManager.closeSession("some random session");
+
+        assertEquals(1, mRecoverySessionStorage.size());
+    }
+
+    @Test
     public void startRecoverySession_throwsIfBadNumberOfSecrets() throws Exception {
         try {
             mRecoverableKeyStoreManager.startRecoverySession(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 5cb7b67..f0254c6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -28,8 +28,7 @@
 import org.junit.runner.RunWith;
 
 import android.content.Context;
-import android.content.SharedPreferences;
-import android.security.keystore.RecoveryManager;
+import android.security.keystore.RecoveryController;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -283,7 +282,7 @@
 
         Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
         assertThat(statuses).hasSize(3);
-        assertThat(statuses).containsEntry(alias, RecoveryManager.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+        assertThat(statuses).containsEntry(alias, RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
         assertThat(statuses).containsEntry(alias2, status);
         assertThat(statuses).containsEntry(alias3, status);
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java
index 6f93fe4..0f95748 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorageTest.java
@@ -19,6 +19,8 @@
 import static junit.framework.Assert.fail;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -88,6 +90,45 @@
     }
 
     @Test
+    public void remove_deletesSpecificSession() {
+        RecoverySessionStorage storage = new RecoverySessionStorage();
+        storage.add(TEST_USER_ID, new RecoverySessionStorage.Entry(
+                TEST_SESSION_ID,
+                lskfHashFixture(),
+                keyClaimantFixture(),
+                vaultParamsFixture()));
+        storage.add(TEST_USER_ID, new RecoverySessionStorage.Entry(
+                "some other session",
+                lskfHashFixture(),
+                keyClaimantFixture(),
+                vaultParamsFixture()));
+
+        storage.remove(TEST_USER_ID, TEST_SESSION_ID);
+
+        assertNull(storage.get(TEST_USER_ID, TEST_SESSION_ID));
+    }
+
+    @Test
+    public void remove_doesNotDeleteOtherSessions() {
+        String otherSessionId = "some other session";
+        RecoverySessionStorage storage = new RecoverySessionStorage();
+        storage.add(TEST_USER_ID, new RecoverySessionStorage.Entry(
+                TEST_SESSION_ID,
+                lskfHashFixture(),
+                keyClaimantFixture(),
+                vaultParamsFixture()));
+        storage.add(TEST_USER_ID, new RecoverySessionStorage.Entry(
+                otherSessionId,
+                lskfHashFixture(),
+                keyClaimantFixture(),
+                vaultParamsFixture()));
+
+        storage.remove(TEST_USER_ID, TEST_SESSION_ID);
+
+        assertNotNull(storage.get(TEST_USER_ID, TEST_SESSION_ID));
+    }
+
+    @Test
     public void destroy_overwritesLskfHashMemory() {
         RecoverySessionStorage storage = new RecoverySessionStorage();
         RecoverySessionStorage.Entry entry = new RecoverySessionStorage.Entry(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index 3dcd5b9..30fae01 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -78,6 +78,8 @@
     private NotificationRecord mRecordCheater;
     private NotificationRecord mRecordCheaterColorized;
     private NotificationRecord mNoMediaSessionMedia;
+    private NotificationRecord mRecordColorized;
+    private NotificationRecord mRecordColorizedCall;
 
     @Before
     public void setUp() {
@@ -113,7 +115,6 @@
         Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setCategory(Notification.CATEGORY_CALL)
                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
-                .setColorized(true /* colorized */)
                 .build();
         mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "highcall", callUid, callUid, n2,
@@ -200,13 +201,34 @@
                 pkg2, pkg2, 1, "cheater", uid2, uid2, n12, new UserHandle(userId),
                 "", 9258), getDefaultChannel());
         mNoMediaSessionMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
+
+        Notification n13 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .setColorized(true /* colorized */)
+                .build();
+        mRecordColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
+                pkg2, 1, "colorized", uid2, uid2, n13,
+                new UserHandle(userId), "", 1999), getDefaultChannel());
+        mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
+
+        Notification n14 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setCategory(Notification.CATEGORY_CALL)
+                .setColorized(true)
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        mRecordColorizedCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
+                callPkg, 1, "colorizedCall", callUid, callUid, n14,
+                new UserHandle(userId), "", 1999), getDefaultChannel());
+        mRecordColorizedCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
     }
 
     @Test
     public void testOrdering() throws Exception {
         final List<NotificationRecord> expected = new ArrayList<>();
-        expected.add(mRecordHighCall);
+        expected.add(mRecordColorizedCall);
         expected.add(mRecordDefaultMedia);
+        expected.add(mRecordColorized);
+        expected.add(mRecordHighCall);
         expected.add(mRecordInlineReply);
         expected.add(mRecordSms);
         expected.add(mRecordStarredContact);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2fafdf5..423dc80 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -499,7 +499,7 @@
     public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
 
     private final Context mContext;
-    private final INetworkPolicyManager mNetworkPolicy;
+    private INetworkPolicyManager mNetworkPolicy;
 
     /**
      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
@@ -572,11 +572,9 @@
     }
 
     /** @hide */
-    public SubscriptionManager(Context context) throws ServiceNotFoundException {
+    public SubscriptionManager(Context context) {
         if (DBG) logd("SubscriptionManager created");
         mContext = context;
-        mNetworkPolicy = INetworkPolicyManager.Stub
-                .asInterface(ServiceManager.getServiceOrThrow(Context.NETWORK_POLICY_SERVICE));
     }
 
     /**
@@ -589,6 +587,14 @@
                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
     }
 
+    private final INetworkPolicyManager getNetworkPolicy() {
+        if (mNetworkPolicy == null) {
+            mNetworkPolicy = INetworkPolicyManager.Stub
+                    .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+        }
+        return mNetworkPolicy;
+    }
+
     /**
      * Register for changes to the list of active {@link SubscriptionInfo} records or to the
      * individual records themselves. When a change occurs the onSubscriptionsChanged method of
@@ -1686,7 +1692,7 @@
     public @NonNull List<SubscriptionPlan> getSubscriptionPlans(int subId) {
         try {
             SubscriptionPlan[] subscriptionPlans =
-                    mNetworkPolicy.getSubscriptionPlans(subId, mContext.getOpPackageName());
+                    getNetworkPolicy().getSubscriptionPlans(subId, mContext.getOpPackageName());
             return subscriptionPlans == null
                     ? Collections.emptyList() : Arrays.asList(subscriptionPlans);
         } catch (RemoteException e) {
@@ -1715,7 +1721,7 @@
     @SystemApi
     public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) {
         try {
-            mNetworkPolicy.setSubscriptionPlans(subId,
+            getNetworkPolicy().setSubscriptionPlans(subId,
                     plans.toArray(new SubscriptionPlan[plans.size()]), mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1725,7 +1731,7 @@
     /** @hide */
     private String getSubscriptionPlansOwner(int subId) {
         try {
-            return mNetworkPolicy.getSubscriptionPlansOwner(subId);
+            return getNetworkPolicy().getSubscriptionPlansOwner(subId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }