Merge "Modify statsd dogfood app to use toString() of enum"
diff --git a/api/current.txt b/api/current.txt
index 2f3fc26..ed14b0e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22033,6 +22033,7 @@
     method public android.media.Image acquireLatestImage();
     method public android.media.Image acquireNextImage();
     method public void close();
+    method public void discardFreeBuffers();
     method public int getHeight();
     method public int getImageFormat();
     method public int getMaxImages();
@@ -49092,15 +49093,19 @@
 
   public abstract interface TextClassifier {
     method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
+    method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int);
     method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
     method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
+    method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
+    method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
     field public static final android.view.textclassifier.TextClassifier NO_OP;
     field public static final java.lang.String TYPE_ADDRESS = "address";
     field public static final java.lang.String TYPE_EMAIL = "email";
     field public static final java.lang.String TYPE_OTHER = "other";
     field public static final java.lang.String TYPE_PHONE = "phone";
+    field public static final java.lang.String TYPE_UNKNOWN = "";
     field public static final java.lang.String TYPE_URL = "url";
   }
 
@@ -49116,13 +49121,9 @@
   }
 
   public static final class TextLinks.Options {
+    ctor public TextLinks.Options();
     method public android.os.LocaleList getDefaultLocales();
-  }
-
-  public static final class TextLinks.Options.Builder {
-    ctor public TextLinks.Options.Builder();
-    method public android.view.textclassifier.TextLinks.Options build();
-    method public android.view.textclassifier.TextLinks.Options.Builder setLocaleList(android.os.LocaleList);
+    method public android.view.textclassifier.TextLinks.Options setDefaultLocales(android.os.LocaleList);
   }
 
   public static final class TextLinks.TextLink {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 57b4fc1..2fd7947 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -220,7 +220,7 @@
                                          const unique_ptr<MetricsManager>& metricsManager) {
     std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
 
-    size_t totalBytes = metricsManager->byteSize();
+    size_t totalBytes = metricsManager->byteSize() + mUidMap->getBytesUsed();
     if (totalBytes > .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
         auto lastFlushNs = mLastBroadcastTimes.find(key);
         if (lastFlushNs != mLastBroadcastTimes.end()) {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c019d5d..7eca5aa 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -480,7 +480,7 @@
         fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
                 mProcessor->GetMetricsSize(key));
     }
-    fprintf(out, "Detailed statsd stats in logcat...");
+    fprintf(out, "Detailed statsd stats in logcat...\n");
     StatsdStats& statsdStats = StatsdStats::getInstance();
     bool reset = false;
     if (args.size() > 1) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 2bd3612..2957457 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -45,6 +45,7 @@
 const int FIELD_ID_CONDITION_STATS = 5;
 const int FIELD_ID_METRIC_STATS = 6;
 const int FIELD_ID_ATOM_STATS = 7;
+const int FIELD_ID_UIDMAP_STATS = 8;
 
 const int FIELD_ID_MATCHER_STATS_NAME = 1;
 const int FIELD_ID_MATCHER_STATS_COUNT = 2;
@@ -173,6 +174,27 @@
     it->second.add_dump_report_time_sec(timeSec);
 }
 
+void StatsdStats::noteUidMapDropped(int snapshots, int deltas) {
+    lock_guard<std::mutex> lock(mLock);
+    mUidMapStats.set_dropped_snapshots(mUidMapStats.dropped_snapshots() + snapshots);
+    mUidMapStats.set_dropped_changes(mUidMapStats.dropped_changes() + deltas);
+}
+
+void StatsdStats::setUidMapSnapshots(int snapshots) {
+    lock_guard<std::mutex> lock(mLock);
+    mUidMapStats.set_snapshots(snapshots);
+}
+
+void StatsdStats::setUidMapChanges(int changes) {
+    lock_guard<std::mutex> lock(mLock);
+    mUidMapStats.set_changes(changes);
+}
+
+void StatsdStats::setCurrentUidMapMemory(int bytes) {
+    lock_guard<std::mutex> lock(mLock);
+    mUidMapStats.set_bytes_used(bytes);
+}
+
 void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) {
     lock_guard<std::mutex> lock(mLock);
     // if name doesn't exist before, it will create the key with count 0.
@@ -364,6 +386,15 @@
         }
     }
 
+    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();
     output->resize(bufferSize);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 451144f..d6f6566 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -45,6 +45,10 @@
 
     const static int kMaxTimestampCount = 20;
 
+    // Cap the UID map's memory usage to this. This should be fairly high since the UID information
+    // is critical for understanding the metrics.
+    const static size_t kMaxBytesUsedUidMap = 50 * 1024;
+
     /**
      * Report a new config has been received and report the static stats about the config.
      *
@@ -113,6 +117,18 @@
     void noteAtomLogged(int atomId, int32_t timeSec);
 
     /**
+     * Records the number of snapshot and delta entries that are being dropped from the uid map.
+     */
+    void noteUidMapDropped(int snapshots, int deltas);
+
+    /**
+     * Updates the number of snapshots currently stored in the uid map.
+     */
+    void setUidMapSnapshots(int snapshots);
+    void setUidMapChanges(int changes);
+    void setCurrentUidMapMemory(int bytes);
+
+    /**
      * Reset the historical stats. Including all stats in icebox, and the tracked stats about
      * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
      * to collect stats after reset() has been called.
@@ -133,6 +149,9 @@
 
     int32_t mStartTimeSec;
 
+    // Track the number of dropped entries used by the uid map.
+    StatsdStatsReport_UidMapStats mUidMapStats;
+
     // The stats about the configs that are still in use.
     std::map<const ConfigKey, StatsdStatsReport_ConfigStats> mConfigStats;
 
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 6c32d3e..db592e2 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+#define DEBUG true  // STOPSHIP if true
 #include "Log.h"
 
+#include "guardrail/StatsdStats.h"
 #include "packages/UidMap.h"
 
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IServiceManager.h>
 #include <utils/Errors.h>
 
 using namespace android;
@@ -26,6 +29,11 @@
 namespace os {
 namespace statsd {
 
+UidMap::UidMap() : mBytesUsed(0) {
+}
+UidMap::~UidMap() {
+}
+
 bool UidMap::hasApp(int uid, const string& packageName) const {
     lock_guard<mutex> lock(mMutex);
 
@@ -73,6 +81,10 @@
         t->set_version(int(versionCode[j]));
         t->set_uid(uid[j]);
     }
+    mBytesUsed += snapshot->ByteSize();
+    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+    StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
+    ensureBytesUsedBelowLimit();
 }
 
 void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
@@ -96,6 +108,10 @@
     log->set_app(app);
     log->set_uid(uid);
     log->set_version(versionCode);
+    mBytesUsed += log->ByteSize();
+    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+    StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+    ensureBytesUsedBelowLimit();
 
     auto range = mMap.equal_range(int(uid));
     for (auto it = range.first; it != range.second; ++it) {
@@ -103,7 +119,7 @@
             it->second.versionCode = int(versionCode);
             return;
         }
-        ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
+        VLOG("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
         return;
     }
 
@@ -111,6 +127,28 @@
     mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
 }
 
+void UidMap::ensureBytesUsedBelowLimit() {
+    size_t limit;
+    if (maxBytesOverride <= 0) {
+        limit = StatsdStats::kMaxBytesUsedUidMap;
+    } else {
+        limit = maxBytesOverride;
+    }
+    while (mBytesUsed > limit) {
+        VLOG("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
+        if (mOutput.snapshots_size() > 0) {
+            auto snapshots = mOutput.mutable_snapshots();
+            snapshots->erase(snapshots->begin());  // Remove first snapshot.
+            StatsdStats::getInstance().noteUidMapDropped(1, 0);
+        } else if (mOutput.changes_size() > 0) {
+            auto changes = mOutput.mutable_changes();
+            changes->DeleteSubrange(0, 1);
+            StatsdStats::getInstance().noteUidMapDropped(0, 1);
+        }
+        mBytesUsed = mOutput.ByteSize();
+    }
+}
+
 void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
     removeApp(time(nullptr) * NS_PER_SEC, app_16, uid);
 }
@@ -128,6 +166,10 @@
     log->set_timestamp_nanos(timestamp);
     log->set_app(app);
     log->set_uid(uid);
+    mBytesUsed += log->ByteSize();
+    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+    StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+    ensureBytesUsedBelowLimit();
 
     auto range = mMap.equal_range(int(uid));
     for (auto it = range.first; it != range.second; ++it) {
@@ -136,7 +178,7 @@
             return;
         }
     }
-    ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
+    VLOG("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
     return;
 }
 
@@ -177,7 +219,6 @@
 
 void UidMap::clearOutput() {
     mOutput.Clear();
-
     // Re-initialize the initial state for the outputs. This results in extra data being uploaded
     // but helps ensure we can re-construct the UID->app name, versionCode mapping in server.
     auto snapshot = mOutput.add_snapshots();
@@ -187,6 +228,12 @@
         t->set_version(it.second.versionCode);
         t->set_uid(it.first);
     }
+
+    // Also update the guardrail trackers.
+    StatsdStats::getInstance().setUidMapChanges(0);
+    StatsdStats::getInstance().setUidMapSnapshots(1);
+    mBytesUsed = snapshot->ByteSize();
+    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
 }
 
 int64_t UidMap::getMinimumTimestampNs() {
@@ -201,6 +248,10 @@
     return m;
 }
 
+size_t UidMap::getBytesUsed() {
+    return mBytesUsed;
+}
+
 UidMapping UidMap::getOutput(const ConfigKey& key) {
     return getOutput(time(nullptr) * NS_PER_SEC, key);
 }
@@ -236,6 +287,10 @@
             }
         }
     }
+    mBytesUsed = mOutput.ByteSize();  // Compute actual size after potential deletions.
+    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+    StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+    StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
     return ret;
 }
 
@@ -250,6 +305,23 @@
 
 void UidMap::OnConfigUpdated(const ConfigKey& key) {
     mLastUpdatePerConfigKey[key] = -1;
+
+    // Ensure there is at least one snapshot available since this configuration also needs to know
+    // what all the uid's represent.
+    if (mOutput.snapshots_size() == 0) {
+        sp<IStatsCompanionService> statsCompanion = nullptr;
+        // Get statscompanion service from service manager
+        const sp<IServiceManager> sm(defaultServiceManager());
+        if (sm != nullptr) {
+            const String16 name("statscompanion");
+            statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
+            if (statsCompanion == nullptr) {
+                ALOGW("statscompanion service unavailable!");
+                return;
+            }
+            statsCompanion->triggerUidSnapshot();
+        }
+    }
 }
 
 void UidMap::OnConfigRemoved(const ConfigKey& key) {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 24eb966..d2971c9 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -50,15 +50,16 @@
 // at any given moment. This map must be updated by StatsCompanionService.
 class UidMap : public virtual android::RefBase {
 public:
+    UidMap();
+    ~UidMap();
+
     /*
      * All three inputs must be the same size, and the jth element in each array refers to the same
      * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
      */
-    // TODO: Add safeguards to call clearOutput if there's too much data already stored.
     void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
                    const vector<String16>& packageName);
 
-    // TODO: Add safeguards to call clearOutput if there's too much data already stored.
     void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
     void removeApp(const String16& packageName, const int32_t& uid);
 
@@ -98,11 +99,13 @@
     // in case we lose a previous upload.
     void clearOutput();
 
+    // Get currently cached value of memory used by UID map.
+    size_t getBytesUsed();
+
 private:
     void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
                    const vector<int32_t>& versionCode, const vector<String16>& packageName);
 
-    // TODO: Add safeguards to call clearOutput if there's too much data already stored.
     void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
                    const int32_t& versionCode);
     void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
@@ -135,8 +138,22 @@
     // Returns the minimum value from mConfigKeys.
     int64_t getMinimumTimestampNs();
 
+    // If our current used bytes is above the limit, then we clear out the earliest snapshot. If
+    // there are no more snapshots, then we clear out the earliest delta. We repeat the deletions
+    // until the memory consumed by mOutput is below the specified limit.
+    void ensureBytesUsedBelowLimit();
+
+    // Override used for testing the max memory allowed by uid map. -1 means we use the value
+    // specified in StatsdStats.h with the rest of the guardrails.
+    size_t maxBytesOverride = -1;
+
+    // Cache the size of mOutput;
+    size_t mBytesUsed;
+
     // Allows unit-test to access private methods.
     FRIEND_TEST(UidMapTest, TestClearingOutput);
+    FRIEND_TEST(UidMapTest, TestMemoryComputed);
+    FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index e7e1d43..cc8a26d 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -220,4 +220,13 @@
     }
 
     repeated AtomStats atom_stats = 7;
+
+    message UidMapStats {
+        optional int32 snapshots = 1;
+        optional int32 changes = 2;
+        optional int32 bytes_used = 3;
+        optional int32 dropped_snapshots = 4;
+        optional int32 dropped_changes = 5;
+    }
+    optional UidMapStats uidmap_stats = 8;
 }
\ No newline at end of file
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 0c19468..aa194e6 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -15,6 +15,7 @@
 #include "packages/UidMap.h"
 #include "StatsLogProcessor.h"
 #include "config/ConfigKey.h"
+#include "guardrail/StatsdStats.h"
 #include "logd/LogEvent.h"
 #include "statslog.h"
 
@@ -35,7 +36,8 @@
 TEST(UidMapTest, TestIsolatedUID) {
     sp<UidMap> m = new UidMap();
     sp<AnomalyMonitor> anomalyMonitor;
-    StatsLogProcessor p(m, anomalyMonitor, nullptr);
+    // Construct the processor with a dummy sendBroadcast function that does nothing.
+    StatsLogProcessor p(m, anomalyMonitor, [](const ConfigKey& key) {});
     LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
     addEvent.write(100);  // parent UID
     addEvent.write(101);  // isolated UID
@@ -114,26 +116,34 @@
     versions.push_back(4);
     versions.push_back(5);
     m.updateMap(1, uids, versions, apps);
+    EXPECT_EQ(1, m.mOutput.snapshots_size());
 
     UidMapping results = m.getOutput(2, config1);
     EXPECT_EQ(1, results.snapshots_size());
 
     // It should be cleared now
+    EXPECT_EQ(0, m.mOutput.snapshots_size());
     results = m.getOutput(3, config1);
     EXPECT_EQ(0, results.snapshots_size());
 
     // Now add another configuration.
     m.OnConfigUpdated(config2);
     m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
+    EXPECT_EQ(1, m.mOutput.changes_size());
     results = m.getOutput(6, config1);
     EXPECT_EQ(0, results.snapshots_size());
     EXPECT_EQ(1, results.changes_size());
+    EXPECT_EQ(1, m.mOutput.changes_size());
 
-    // Now we still haven't been able to delete anything
+    // Add another delta update.
     m.updateApp(7, String16(kApp2.c_str()), 1001, 41);
+    EXPECT_EQ(2, m.mOutput.changes_size());
+
+    // We still can't remove anything.
     results = m.getOutput(8, config1);
     EXPECT_EQ(0, results.snapshots_size());
     EXPECT_EQ(2, results.changes_size());
+    EXPECT_EQ(2, m.mOutput.changes_size());
 
     results = m.getOutput(9, config2);
     EXPECT_EQ(0, results.snapshots_size());
@@ -142,6 +152,66 @@
     EXPECT_EQ(0, m.mOutput.snapshots_size());
     EXPECT_EQ(0, m.mOutput.changes_size());
 }
+
+TEST(UidMapTest, TestMemoryComputed) {
+    UidMap m;
+
+    ConfigKey config1(1, "config1");
+    m.OnConfigUpdated(config1);
+
+    size_t startBytes = m.mBytesUsed;
+    vector<int32_t> uids;
+    vector<int32_t> versions;
+    vector<String16> apps;
+    uids.push_back(1000);
+    apps.push_back(String16(kApp1.c_str()));
+    versions.push_back(1);
+    m.updateMap(1, uids, versions, apps);
+    size_t snapshot_bytes = m.mBytesUsed;
+    EXPECT_TRUE(snapshot_bytes > startBytes);
+
+    m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
+    EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
+    size_t bytesWithSnapshotChange = m.mBytesUsed;
+
+    m.getOutput(2, config1);
+    EXPECT_TRUE(m.mBytesUsed < bytesWithSnapshotChange);
+    size_t prevBytes = m.mBytesUsed;
+
+    m.getOutput(4, config1);
+    EXPECT_TRUE(m.mBytesUsed < prevBytes);
+}
+
+TEST(UidMapTest, TestMemoryGuardrail) {
+    UidMap m;
+    string buf;
+
+    ConfigKey config1(1, "config1");
+    m.OnConfigUpdated(config1);
+
+    size_t startBytes = m.mBytesUsed;
+    vector<int32_t> uids;
+    vector<int32_t> versions;
+    vector<String16> apps;
+    for (int i = 0; i < 100; i++) {
+        uids.push_back(1);
+        buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i);
+        apps.push_back(String16(buf.c_str()));
+        versions.push_back(1);
+    }
+    m.updateMap(1, uids, versions, apps);
+    EXPECT_EQ(1, m.mOutput.snapshots_size());
+
+    m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2);
+    EXPECT_EQ(1, m.mOutput.snapshots_size());
+    EXPECT_EQ(1, m.mOutput.changes_size());
+
+    // Now force deletion by limiting the memory to hold one delta change.
+    m.maxBytesOverride = 80; // Since the app string alone requires >45 characters.
+    m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4);
+    EXPECT_EQ(0, m.mOutput.snapshots_size());
+    EXPECT_EQ(1, m.mOutput.changes_size());
+}
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/core/java/Android.bp b/core/java/Android.bp
index d8c7929..b43cf27 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -4,16 +4,16 @@
 }
 
 // only used by key_store_service
-cc_library_static {
+cc_library_shared {
     name: "libkeystore_aidl",
     srcs: ["android/security/IKeystoreService.aidl"],
     aidl: {
         export_aidl_headers: true,
-        include_dirs: ["frameworks/base/core/java/"],
+        include_dirs: [
+            "frameworks/base/core/java/",
+            "system/security/keystore/",
+        ],
     },
-    header_libs: [
-        "libkeystore_headers",
-    ],
     shared_libs: [
         "libbinder",
         "libcutils",
@@ -22,7 +22,12 @@
         "libhidltransport",
         "libhwbinder",
         "liblog",
+        "libkeystore_parcelables",
         "libselinux",
         "libutils",
     ],
+    export_shared_lib_headers: [
+        "libbinder",
+        "libkeystore_parcelables",
+    ],
 }
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 3314f60..1d2a408 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -56,4 +56,7 @@
 
     /** Send a broadcast to the specified pkg and class that it should getData now. */
     oneway void sendBroadcast(String pkg, String cls);
+
+    /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
+    oneway void triggerUidSnapshot();
 }
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index cd233b8..df0842f 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -105,6 +105,13 @@
     public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
             "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
 
+    /**
+     * Intent extra set for resolution requests containing a boolean indicating whether to ask the
+     * user to retry another confirmation code.
+     */
+    public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED =
+            "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
+
     /** Result code for a successful operation. */
     public static final int RESULT_OK = 0;
     /** Result code indicating that an active SIM must be deactivated to perform the operation. */
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 2779aa2..f675c35 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -31,6 +31,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Information for generating a widget to handle classified text.
@@ -42,7 +43,7 @@
  *
  * <pre>{@code
  *   // Called preferably outside the UiThread.
- *   TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ *   TextClassification classification = textClassifier.classifyText(allText, 10, 25);
  *
  *   // Called on the UiThread.
  *   Button button = new Button(context);
@@ -55,7 +56,7 @@
  *
  * <pre>{@code
  *   // Called preferably outside the UiThread.
- *   final TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ *   final TextClassification classification = textClassifier.classifyText(allText, 10, 25);
  *
  *   // Called on the UiThread.
  *   view.startActionMode(new ActionMode.Callback() {
@@ -281,8 +282,8 @@
 
     @Override
     public String toString() {
-        return String.format("TextClassification {"
-                        + "text=%s, entities=%s, labels=%s, intents=%s}",
+        return String.format(Locale.US,
+                "TextClassification {text=%s, entities=%s, labels=%s, intents=%s}",
                 mText, mEntityConfidence, mLabels, mIntents);
     }
 
@@ -421,7 +422,7 @@
         }
 
         /**
-         * Ensures that we have at we have storage for the default action.
+         * Ensures that we have storage for the default action.
          */
         private void ensureDefaultActionAvailable() {
             if (mIntents.isEmpty()) mIntents.add(null);
@@ -441,7 +442,7 @@
     }
 
     /**
-     * TextClassification optional input parameters.
+     * Optional input parameters for generating TextClassification.
      */
     public static final class Options {
 
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index aeb8489..5aaa5ad 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -23,6 +23,8 @@
 import android.annotation.WorkerThread;
 import android.os.LocaleList;
 
+import com.android.internal.util.Preconditions;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -37,8 +39,7 @@
     /** @hide */
     String DEFAULT_LOG_TAG = "TextClassifierImpl";
 
-    /** @hide */
-    String TYPE_UNKNOWN = "";  // TODO: Make this public API.
+    String TYPE_UNKNOWN = "";
     String TYPE_OTHER = "other";
     String TYPE_EMAIL = "email";
     String TYPE_PHONE = "phone";
@@ -70,6 +71,8 @@
      *
      * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
      *      selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
+     *
+     * @see #suggestSelection(CharSequence, int, int)
      */
     @WorkerThread
     @NonNull
@@ -78,13 +81,46 @@
             @IntRange(from = 0) int selectionStartIndex,
             @IntRange(from = 0) int selectionEndIndex,
             @Nullable TextSelection.Options options) {
+        Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
         return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
     }
 
     /**
+     * Returns suggested text selection start and end indices, recognized entity types, and their
+     * associated confidence scores. The entity types are ordered from highest to lowest scoring.
+     *
+     * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+     * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
+     * calls this method, a stack overflow error will happen.
+     *
+     * @param text text providing context for the selected text (which is specified
+     *      by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
+     * @param selectionStartIndex start index of the selected part of text
+     * @param selectionEndIndex end index of the selected part of text
+     *
+     * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
+     *      selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
+     *
      * @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
      */
-    // TODO: Consider deprecating (b/68846316)
+    @WorkerThread
+    @NonNull
+    default TextSelection suggestSelection(
+            @NonNull CharSequence text,
+            @IntRange(from = 0) int selectionStartIndex,
+            @IntRange(from = 0) int selectionEndIndex) {
+        return suggestSelection(text, selectionStartIndex, selectionEndIndex,
+                (TextSelection.Options) null);
+    }
+
+    /**
+     * See {@link #suggestSelection(CharSequence, int, int)} or
+     * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}.
+     *
+     * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+     * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
+     * calls this method, a stack overflow error will happen.
+     */
     @WorkerThread
     @NonNull
     default TextSelection suggestSelection(
@@ -92,7 +128,10 @@
             @IntRange(from = 0) int selectionStartIndex,
             @IntRange(from = 0) int selectionEndIndex,
             @Nullable LocaleList defaultLocales) {
-        return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+        final TextSelection.Options options = (defaultLocales != null)
+                ? new TextSelection.Options().setDefaultLocales(defaultLocales)
+                : null;
+        return suggestSelection(text, selectionStartIndex, selectionEndIndex, options);
     }
 
     /**
@@ -107,6 +146,8 @@
      *
      * @throws IllegalArgumentException if text is null; startIndex is negative;
      *      endIndex is greater than text.length() or not greater than startIndex
+     *
+     * @see #classifyText(CharSequence, int, int)
      */
     @WorkerThread
     @NonNull
@@ -115,13 +156,45 @@
             @IntRange(from = 0) int startIndex,
             @IntRange(from = 0) int endIndex,
             @Nullable TextClassification.Options options) {
+        Utils.validateInput(text, startIndex, endIndex);
         return TextClassification.EMPTY;
     }
 
     /**
+     * Classifies the specified text and returns a {@link TextClassification} object that can be
+     * used to generate a widget for handling the classified text.
+     *
+     * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+     * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
+     * calls this method, a stack overflow error will happen.
+     *
+     * @param text text providing context for the text to classify (which is specified
+     *      by the sub sequence starting at startIndex and ending at endIndex)
+     * @param startIndex start index of the text to classify
+     * @param endIndex end index of the text to classify
+     *
+     * @throws IllegalArgumentException if text is null; startIndex is negative;
+     *      endIndex is greater than text.length() or not greater than startIndex
+     *
      * @see #classifyText(CharSequence, int, int, TextClassification.Options)
      */
-    // TODO: Consider deprecating (b/68846316)
+    @WorkerThread
+    @NonNull
+    default TextClassification classifyText(
+            @NonNull CharSequence text,
+            @IntRange(from = 0) int startIndex,
+            @IntRange(from = 0) int endIndex) {
+        return classifyText(text, startIndex, endIndex, (TextClassification.Options) null);
+    }
+
+    /**
+     * See {@link #classifyText(CharSequence, int, int, TextClassification.Options)} or
+     * {@link #classifyText(CharSequence, int, int)}.
+     *
+     * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+     * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
+     * calls this method, a stack overflow error will happen.
+     */
     @WorkerThread
     @NonNull
     default TextClassification classifyText(
@@ -129,7 +202,10 @@
             @IntRange(from = 0) int startIndex,
             @IntRange(from = 0) int endIndex,
             @Nullable LocaleList defaultLocales) {
-        return TextClassification.EMPTY;
+        final TextClassification.Options options = (defaultLocales != null)
+                ? new TextClassification.Options().setDefaultLocales(defaultLocales)
+                : null;
+        return classifyText(text, startIndex, endIndex, options);
     }
 
     /**
@@ -137,17 +213,39 @@
      * information.
      *
      * @param text the text to generate annotations for
-     * @param options configuration for link generation. If null, defaults will be used.
+     * @param options configuration for link generation
      *
      * @throws IllegalArgumentException if text is null
+     *
+     * @see #generateLinks(CharSequence)
      */
     @WorkerThread
     default TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+        Utils.validateInput(text);
         return new TextLinks.Builder(text.toString()).build();
     }
 
     /**
+     * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
+     * information.
+     *
+     * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+     * {@link #generateLinks(CharSequence, TextLinks.Options)}. If that method calls this method,
+     * a stack overflow error will happen.
+     *
+     * @param text the text to generate annotations for
+     *
+     * @throws IllegalArgumentException if text is null
+     *
+     * @see #generateLinks(CharSequence, TextLinks.Options)
+     */
+    @WorkerThread
+    default TextLinks generateLinks(@NonNull CharSequence text) {
+        return generateLinks(text, null);
+    }
+
+    /**
      * Logs a TextClassifier event.
      *
      * @param source the text classifier used to generate this event
@@ -164,4 +262,38 @@
     default TextClassifierConstants getSettings() {
         return TextClassifierConstants.DEFAULT;
     }
+
+
+    /**
+     * Utility functions for TextClassifier methods.
+     *
+     * <ul>
+     *  <li>Provides validation of input parameters to TextClassifier methods
+     * </ul>
+     *
+     * Intended to be used only in this package.
+     * @hide
+     */
+    final class Utils {
+
+        /**
+         * @throws IllegalArgumentException if text is null; startIndex is negative;
+         *      endIndex is greater than text.length() or is not greater than startIndex;
+         *      options is null
+         */
+        static void validateInput(
+                @NonNull CharSequence text, int startIndex, int endIndex) {
+            Preconditions.checkArgument(text != null);
+            Preconditions.checkArgument(startIndex >= 0);
+            Preconditions.checkArgument(endIndex <= text.length());
+            Preconditions.checkArgument(endIndex > startIndex);
+        }
+
+        /**
+         * @throws IllegalArgumentException if text is null or options is null
+         */
+        static void validateInput(@NonNull CharSequence text) {
+            Preconditions.checkArgument(text != null);
+        }
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 2ad6e02..df5e35f 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -90,8 +90,8 @@
     @Override
     public TextSelection suggestSelection(
             @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
-            @Nullable TextSelection.Options options) {
-        validateInput(text, selectionStartIndex, selectionEndIndex);
+            @NonNull TextSelection.Options options) {
+        Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
         try {
             if (text.length() > 0) {
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
@@ -141,18 +141,10 @@
     }
 
     @Override
-    public TextSelection suggestSelection(
-            @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
-            @Nullable LocaleList defaultLocales) {
-        return suggestSelection(text, selectionStartIndex, selectionEndIndex,
-                new TextSelection.Options().setDefaultLocales(defaultLocales));
-    }
-
-    @Override
     public TextClassification classifyText(
             @NonNull CharSequence text, int startIndex, int endIndex,
-            @Nullable TextClassification.Options options) {
-        validateInput(text, startIndex, endIndex);
+            @NonNull TextClassification.Options options) {
+        Utils.validateInput(text, startIndex, endIndex);
         try {
             if (text.length() > 0) {
                 final String string = text.toString();
@@ -176,17 +168,9 @@
     }
 
     @Override
-    public TextClassification classifyText(
-            @NonNull CharSequence text, int startIndex, int endIndex,
-            @Nullable LocaleList defaultLocales) {
-        return classifyText(text, startIndex, endIndex,
-                new TextClassification.Options().setDefaultLocales(defaultLocales));
-    }
-
-    @Override
     public TextLinks generateLinks(
-            @NonNull CharSequence text, @Nullable TextLinks.Options options) {
-        Preconditions.checkNotNull(text);
+            @NonNull CharSequence text, @NonNull TextLinks.Options options) {
+        Utils.validateInput(text);
         final String textString = text.toString();
         final TextLinks.Builder builder = new TextLinks.Builder(textString);
         try {
@@ -486,17 +470,6 @@
     }
 
     /**
-     * @throws IllegalArgumentException if text is null; startIndex is negative;
-     *      endIndex is greater than text.length() or is not greater than startIndex
-     */
-    private static void validateInput(@NonNull CharSequence text, int startIndex, int endIndex) {
-        Preconditions.checkArgument(text != null);
-        Preconditions.checkArgument(startIndex >= 0);
-        Preconditions.checkArgument(endIndex <= text.length());
-        Preconditions.checkArgument(endIndex > startIndex);
-    }
-
-    /**
      * Creates intents based on the classification type.
      */
     private static final class IntentFactory {
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index f3cc827..76748d2 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -161,39 +161,28 @@
      * Optional input parameters for generating TextLinks.
      */
     public static final class Options {
-        private final LocaleList mLocaleList;
 
-        private Options(LocaleList localeList) {
-            this.mLocaleList = localeList;
+        private LocaleList mDefaultLocales;
+
+        /**
+         * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+         *      the provided text. If no locale preferences exist, set this to null or an empty
+         *      locale list.
+         */
+        public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+            mDefaultLocales = defaultLocales;
+            return this;
         }
 
         /**
-         * Builder to construct Options.
+         * @return ordered list of locale preferences that can be used to disambiguate
+         *      the provided text.
          */
-        public static final class Builder {
-            private LocaleList mLocaleList;
-
-            /**
-             * Sets the LocaleList to use.
-             *
-             * @return this Builder.
-             */
-            public Builder setLocaleList(@Nullable LocaleList localeList) {
-                this.mLocaleList = localeList;
-                return this;
-            }
-
-            /**
-             * Builds the Options object.
-             */
-            public Options build() {
-                return new Options(mLocaleList);
-            }
+        @Nullable
+        public LocaleList getDefaultLocales() {
+            return mDefaultLocales;
         }
-        public @Nullable LocaleList getDefaultLocales() {
-            return mLocaleList;
-        }
-    };
+    }
 
     /**
      * A function to create spans from TextLinks.
@@ -204,13 +193,10 @@
      * @hide
      */
     public static final Function<TextLink, ClickableSpan> DEFAULT_SPAN_FACTORY =
-            new Function<TextLink, ClickableSpan>() {
-        @Override
-        public ClickableSpan apply(TextLink textLink) {
-            // TODO: Implement.
-            throw new UnsupportedOperationException("Not yet implemented");
-        }
-    };
+            textLink -> {
+                // TODO: Implement.
+                throw new UnsupportedOperationException("Not yet implemented");
+            };
 
     /**
      * A builder to construct a TextLinks instance.
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 0a67954..480b27a 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -26,6 +26,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Information about where text selection should be.
@@ -114,8 +115,8 @@
 
     @Override
     public String toString() {
-        return String.format("TextSelection {%d, %d, %s}",
-                mStartIndex, mEndIndex, mEntityConfidence);
+        return String.format(Locale.US,
+                "TextSelection {%d, %d, %s}", mStartIndex, mEndIndex, mEntityConfidence);
     }
 
     /**
@@ -185,7 +186,7 @@
     }
 
     /**
-     * TextSelection optional input parameters.
+     * Optional input parameters for generating TextSelection.
      */
     public static final class Options {
 
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index d38ea2c..24f0b0c 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -142,7 +142,7 @@
         mTmpAnchorPos[1] -= mTmpAppPos[1];
         // mTmpAnchorPos is now relative to the main app window.
 
-        outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2;
+        outParams.x = mTmpAnchorPos[0] + offsetX - appView.getWidth() / 2;
 
         final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
         mContentView.measure(spec, spec);
@@ -157,6 +157,9 @@
                 outParams.y = yBelow;
             }
         } else {
+            // Use mTmpDisplayFrame.height() as the lower boundary instead of appView.getHeight(),
+            // as the latter includes the navigation bar, and tooltips do not look good over
+            // the navigation bar.
             if (yBelow + tooltipHeight <= mTmpDisplayFrame.height()) {
                 outParams.y = yBelow;
             } else {
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index d7300c4..601bd98 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -25,6 +25,7 @@
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/JNIHelp.h>
 #include "core_jni_helpers.h"
+#include "scoped_nullable_primitive_array.h"
 #include <cstdint>
 #include <vector>
 #include <list>
@@ -87,9 +88,8 @@
 static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
                         jfloatArray recycleWidths, jfloatArray recycleAscents,
                         jfloatArray recycleDescents, jintArray recycleFlags,
-                        jint recycleLength, size_t nBreaks, const jint* breaks,
-                        const jfloat* widths, const jfloat* ascents, const jfloat* descents,
-                        const jint* flags) {
+                        jint recycleLength, const minikin::LineBreakResult& result) {
+    const size_t nBreaks = result.breakPoints.size();
     if ((size_t)recycleLength < nBreaks) {
         // have to reallocate buffers
         recycleBreaks = env->NewIntArray(nBreaks);
@@ -105,11 +105,11 @@
         env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
     }
     // copy data
-    env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
-    env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
-    env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, ascents);
-    env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, descents);
-    env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags);
+    env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data());
+    env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data());
+    env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data());
+    env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data());
+    env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data());
 }
 
 static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
@@ -136,34 +136,22 @@
     minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
 
     ScopedCharArrayRO text(env, javaText);
+    ScopedNullableIntArrayRO tabStops(env, variableTabStops);
 
-    // TODO: Reorganize minikin APIs.
-    minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length));
-    if (variableTabStops == nullptr) {
-        b.setTabStops(nullptr, 0, defaultTabStop);
-    } else {
-        ScopedIntArrayRO stops(env, variableTabStops);
-        b.setTabStops(stops.get(), stops.size(), defaultTabStop);
-    }
-    b.setStrategy(builder->getStrategy());
-    b.setHyphenationFrequency(builder->getFrequency());
-    b.setJustified(builder->isJustified());
-    b.setLineWidthDelegate(builder->buildLineWidthDelegate(
-            firstWidth, firstWidthLineCount, restWidth, indentsOffset));
-
-    builder->addRuns(&b);
-
-    size_t nBreaks = b.computeBreaks();
+    minikin::U16StringPiece u16Text(text.get(), length);
+    minikin::MeasuredText measuredText = builder->measureText(u16Text);
+    minikin::LineBreakResult result = builder->computeBreaks(
+            u16Text, measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
+            tabStops.get(), tabStops.size(), defaultTabStop);
 
     recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents,
-            recycleFlags, recycleLength, nBreaks, b.getBreaks(), b.getWidths(), b.getAscents(),
-            b.getDescents(), b.getFlags());
+            recycleFlags, recycleLength, result);
 
-    env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths());
+    env->SetFloatArrayRegion(charWidths, 0, measuredText.widths.size(), measuredText.widths.data());
 
     builder->clearRuns();
 
-    return static_cast<jint>(nBreaks);
+    return static_cast<jint>(result.breakPoints.size());
 }
 
 // Basically similar to Paint.getTextRunAdvances but with C++ interface
diff --git a/core/jni/scoped_nullable_primitive_array.h b/core/jni/scoped_nullable_primitive_array.h
new file mode 100644
index 0000000..77f4c9d
--- /dev/null
+++ b/core/jni/scoped_nullable_primitive_array.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#ifndef SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+#define SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+
+#include <jni.h>
+
+namespace android {
+
+#define ARRAY_TRAITS(ARRAY_TYPE, POINTER_TYPE, NAME)                                  \
+class NAME ## ArrayTraits {                                                           \
+public:                                                                               \
+    static constexpr void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start, \
+                                         size_t len, POINTER_TYPE out) {              \
+        env->Get ## NAME ## ArrayRegion(array, start, len, out);                      \
+    }                                                                                 \
+                                                                                      \
+    static constexpr POINTER_TYPE getArrayElements(JNIEnv* env, ARRAY_TYPE array) {   \
+        return env->Get ## NAME ## ArrayElements(array, nullptr);                     \
+    }                                                                                 \
+                                                                                      \
+    static constexpr void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array,         \
+                                               POINTER_TYPE buffer, jint mode) {      \
+        env->Release ## NAME ## ArrayElements(array, buffer, mode);                   \
+    }                                                                                 \
+};                                                                                    \
+
+ARRAY_TRAITS(jbooleanArray, jboolean*, Boolean)
+ARRAY_TRAITS(jbyteArray, jbyte*, Byte)
+ARRAY_TRAITS(jcharArray, jchar*, Char)
+ARRAY_TRAITS(jdoubleArray, jdouble*, Double)
+ARRAY_TRAITS(jfloatArray, jfloat*, Float)
+ARRAY_TRAITS(jintArray, jint*, Int)
+ARRAY_TRAITS(jlongArray, jlong*, Long)
+ARRAY_TRAITS(jshortArray, jshort*, Short)
+
+#undef ARRAY_TRAITS
+
+template<typename JavaArrayType, typename PrimitiveType, class Traits, size_t preallocSize = 10>
+class ScopedArrayRO {
+public:
+    ScopedArrayRO(JNIEnv* env, JavaArrayType javaArray) : mEnv(env), mJavaArray(javaArray) {
+        if (mJavaArray == nullptr) {
+            mSize = 0;
+            mRawArray = nullptr;
+        } else {
+            mSize = mEnv->GetArrayLength(mJavaArray);
+            if (mSize <= preallocSize) {
+                Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer);
+                mRawArray = mBuffer;
+            } else {
+                mRawArray = Traits::getArrayElements(mEnv, mJavaArray);
+            }
+        }
+    }
+
+    ~ScopedArrayRO() {
+        if (mRawArray != nullptr && mRawArray != mBuffer) {
+            Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT);
+        }
+    }
+
+    const PrimitiveType* get() const { return mRawArray; }
+    const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; }
+    size_t size() const { return mSize; }
+
+private:
+    JNIEnv* const mEnv;
+    JavaArrayType mJavaArray;
+    PrimitiveType* mRawArray;
+    size_t mSize;
+    PrimitiveType mBuffer[preallocSize];
+    DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO);
+};
+
+// ScopedNullable***ArrayRO provide convenient read-only access to Java array from JNI code.
+// These accept nullptr. In that case, get() returns nullptr and size() returns 0.
+using ScopedNullableBooleanArrayRO = ScopedArrayRO<jbooleanArray, jboolean, BooleanArrayTraits>;
+using ScopedNullableByteArrayRO = ScopedArrayRO<jbyteArray, jbyte, ByteArrayTraits>;
+using ScopedNullableCharArrayRO = ScopedArrayRO<jcharArray, jchar, CharArrayTraits>;
+using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdoubleArray, jdouble, DoubleArrayTraits>;
+using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloatArray, jfloat, FloatArrayTraits>;
+using ScopedNullableIntArrayRO = ScopedArrayRO<jintArray, jint, IntArrayTraits>;
+using ScopedNullableLongArrayRO = ScopedArrayRO<jlongArray, jlong, LongArrayTraits>;
+using ScopedNullableShortArrayRO = ScopedArrayRO<jshortArray, jshort, ShortArrayTraits>;
+
+}  // namespace android
+
+#endif  // SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index 5f6f62a..978ea7a 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -45,8 +45,9 @@
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 abstract class AbstractCrossUserContentResolverTest {
-    private final static int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
-    private final static int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+    private static final int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
+    private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+    private static final int TIMEOUT_USER_UNLOCK_SEC = 4;
 
     private Context mContext;
     protected UserManager mUm;
@@ -61,7 +62,7 @@
         mCrossUserId = userInfo.id;
         final PackageManager pm = mContext.getPackageManager();
         pm.installExistingPackageAsUser(mContext.getPackageName(), mCrossUserId);
-        ActivityManager.getService().startUserInBackground(mCrossUserId);
+        unlockUser();
 
         final CountDownLatch connectionLatch = new CountDownLatch(1);
         mServiceConnection = new CrossUserContentServiceConnection(connectionLatch);
@@ -77,6 +78,30 @@
 
     protected abstract UserInfo createUser() throws RemoteException ;
 
+    private void unlockUser() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)
+                        == mCrossUserId) {
+                    latch.countDown();
+                }
+            }
+        };
+        mContext.registerReceiverAsUser(receiver, UserHandle.of(mCrossUserId),
+                new IntentFilter(Intent.ACTION_USER_UNLOCKED), null, null);
+        ActivityManager.getService().startUserInBackground(mCrossUserId);
+
+        try {
+            if (!latch.await(TIMEOUT_USER_UNLOCK_SEC, TimeUnit.SECONDS)) {
+                fail("Timed out waiting for the u" + mCrossUserId + " to unlock");
+            }
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
     @After
     public void tearDown() throws Exception {
         if (mCrossUserId != -1) {
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 41686fa..9092c85 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -45,6 +45,9 @@
 
     private TextClassificationManager mTcm;
     private TextClassifier mClassifier;
+    private TextSelection.Options mSelectionOptions;
+    private TextClassification.Options mClassificationOptions;
+    private TextLinks.Options mLinksOptions;
 
     @Before
     public void setup() {
@@ -52,6 +55,9 @@
                 .getSystemService(TextClassificationManager.class);
         mTcm.setTextClassifier(null);
         mClassifier = mTcm.getTextClassifier();
+        mSelectionOptions = new TextSelection.Options().setDefaultLocales(LOCALES);
+        mClassificationOptions = new TextClassification.Options().setDefaultLocales(LOCALES);
+        mLinksOptions = new TextLinks.Options().setDefaultLocales(LOCALES);
     }
 
     @Test
@@ -66,24 +72,9 @@
         int smartStartIndex = text.indexOf(suggested);
         int smartEndIndex = smartStartIndex + suggested.length();
 
-        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
-                isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
-    }
-
-    @Test
-    public void testSmartSelection_nullLocaleList() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "Contact me at droid@android.com";
-        String selected = "droid";
-        String suggested = "droid@android.com";
-        int startIndex = text.indexOf(selected);
-        int endIndex = startIndex + selected.length();
-        int smartStartIndex = text.indexOf(suggested);
-        int smartEndIndex = smartStartIndex + suggested.length();
-        LocaleList nullLocales = null;
-
-        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, nullLocales),
+        TextSelection selection = mClassifier.suggestSelection(
+                text, startIndex, endIndex, mSelectionOptions);
+        assertThat(selection,
                 isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
     }
 
@@ -99,7 +90,9 @@
         int smartStartIndex = text.indexOf(suggested);
         int smartEndIndex = smartStartIndex + suggested.length();
 
-        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+        TextSelection selection = mClassifier.suggestSelection(
+                text, startIndex, endIndex, mSelectionOptions);
+        assertThat(selection,
                 isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
     }
 
@@ -112,7 +105,9 @@
         int startIndex = text.indexOf(selected);
         int endIndex = startIndex + selected.length();
 
-        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+        TextSelection selection = mClassifier.suggestSelection(
+                text, startIndex, endIndex, mSelectionOptions);
+        assertThat(selection,
                 isTextSelection(startIndex, endIndex, NO_TYPE));
     }
 
@@ -124,7 +119,10 @@
         String classifiedText = "droid@android.com";
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
-        assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+        TextClassification classification = mClassifier.classifyText(
+                text, startIndex, endIndex, mClassificationOptions);
+        assertThat(classification,
                 isTextClassification(
                         classifiedText,
                         TextClassifier.TYPE_EMAIL,
@@ -139,7 +137,10 @@
         String classifiedText = "www.android.com";
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
-        assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+        TextClassification classification = mClassifier.classifyText(
+                text, startIndex, endIndex, mClassificationOptions);
+        assertThat(classification,
                 isTextClassification(
                         classifiedText,
                         TextClassifier.TYPE_URL,
@@ -154,7 +155,10 @@
         String classifiedText = "HTTP://ANDROID.COM";
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
-        assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+        TextClassification classification = mClassifier.classifyText(
+                text, startIndex, endIndex, mClassificationOptions);
+        assertThat(classification,
                 isTextClassification(
                         classifiedText,
                         TextClassifier.TYPE_URL,
@@ -162,22 +166,6 @@
     }
 
     @Test
-    public void testTextClassifyText_nullLocaleList() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "Contact me at droid@android.com";
-        String classifiedText = "droid@android.com";
-        int startIndex = text.indexOf(classifiedText);
-        int endIndex = startIndex + classifiedText.length();
-        LocaleList nullLocales = null;
-        assertThat(mClassifier.classifyText(text, startIndex, endIndex, nullLocales),
-                isTextClassification(
-                        classifiedText,
-                        TextClassifier.TYPE_EMAIL,
-                        "mailto:" + classifiedText));
-    }
-
-    @Test
     public void testGenerateLinks() {
         if (isTextClassifierDisabled()) return;
 
@@ -210,13 +198,14 @@
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
 
-        Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, null).getLinks();
+        Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, mLinksOptions)
+                .getLinks();
         for (TextLinks.TextLink link : links) {
             if (text.subSequence(link.getStart(), link.getEnd()).equals(classifiedText)) {
                 assertEquals(type, link.getEntity(0));
                 assertEquals(startIndex, link.getStart());
                 assertEquals(endIndex, link.getEnd());
-                assertTrue(link.getConfidenceScore(type) > .9);
+                assertTrue(link.getConfidenceScore(type) > 0);
                 return;
             }
         }
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 682a002..4b197e4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -104,7 +104,9 @@
 
     @Test
     public void testCpuFreqTimes() throws Exception {
-        assumeTrue(sCpuFreqTimesAvailable);
+        if (!sCpuFreqTimesAvailable) {
+            return;
+        }
 
         batteryOnScreenOn();
         forceStop();
@@ -126,7 +128,9 @@
 
     @Test
     public void testCpuFreqTimes_screenOff() throws Exception {
-        assumeTrue(sCpuFreqTimesAvailable);
+        if (!sCpuFreqTimesAvailable) {
+            return;
+        }
 
         batteryOnScreenOff();
         forceStop();
@@ -154,7 +158,9 @@
 
     @Test
     public void testCpuFreqTimes_isolatedProcess() throws Exception {
-        assumeTrue(sCpuFreqTimesAvailable);
+        if (!sCpuFreqTimesAvailable) {
+            return;
+        }
 
         batteryOnScreenOn();
         forceStop();
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index c78c99f..1019580 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -640,7 +640,6 @@
      * The ImageReader continues to be usable after this call, but may need to reallocate buffers
      * when more buffers are needed for rendering.
      * </p>
-     * @hide
      */
     public void discardFreeBuffers() {
         synchronized (mCloseLock) {
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 334f4e2..37f1e13 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -26,6 +26,8 @@
 
 LOCAL_MODULE := libfilterfw
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libfilterfw_jni \
diff --git a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
index af2c83f..a017f41 100644
--- a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
+++ b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
@@ -16,7 +16,7 @@
 
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape android:shape="rectangle">
-        <corners android:radius="2dp" />
+        <corners android:radius="?android:attr/dialogCornerRadius" />
         <solid android:color="?android:attr/colorBackground" />
     </shape>
 </inset>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 9400fd8..663f206 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -23,14 +23,12 @@
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
 
 import android.app.ActivityManager;
-import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -89,7 +87,6 @@
 import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.util.ArrayList;
@@ -657,13 +654,6 @@
         // the resize mode already.
         if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) {
             EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
-            showRecents(
-                    false /* triggeredFromAltTab */,
-                    dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
-                    false /* animate */,
-                    true /* launchedWhileDockingTask*/,
-                    false /* fromHome */,
-                    DividerView.INVALID_RECENTS_GROW_TARGET);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index f5c77f2..64c52ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -369,7 +369,7 @@
     private void onFacetClicked(Intent intent, int index) {
         String packageName = intent.getPackage();
 
-        if (packageName == null) {
+        if (packageName == null && !intent.getCategories().contains(Intent.CATEGORY_HOME)) {
             return;
         }
 
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 32af29d..bd6af01 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5013,6 +5013,11 @@
     // OS: P
     FIELD_SELECTION_WIDGET_VERSION = 1262;
 
+    // OPEN: Settings > Battery(version 2)
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263;
+
     // ---- End P Constants, all P constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ced8621..bdfd82f 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -501,9 +501,11 @@
             windowingMode = WINDOWING_MODE_FULLSCREEN;
         }
 
+        final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryStack();
+
         // Take any required action due to us not supporting the preferred windowing mode.
         if (windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
-            if (display.hasSplitScreenPrimaryStack()
+            if (alreadyInSplitScreenMode
                     && (preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                     || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
                 // Looks like we can't launch in split screen mode, go ahead an dismiss split-screen
@@ -577,7 +579,7 @@
                 resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
             }
         } finally {
-            if (mDisplayId == DEFAULT_DISPLAY
+            if (!alreadyInSplitScreenMode && mDisplayId == DEFAULT_DISPLAY
                     && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 // Make sure recents stack exist when creating a dock stack as it normally needs to
                 // be on the other side of the docked stack and we make visibility decisions based
@@ -1678,12 +1680,6 @@
         return true;
     }
 
-    /** Returns true if the stack is currently considered visible. */
-    boolean isVisible() {
-        return mWindowContainerController != null && mWindowContainerController.isVisible()
-                && !mForceHidden;
-    }
-
     boolean isTopStackOnDisplay() {
         return getDisplay().isTopStack(this);
     }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 27eb985..2fc5dda 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -606,21 +606,9 @@
             return;
         }
 
-        if (startedActivityStack.inSplitScreenPrimaryWindowingMode()) {
-            final ActivityStack homeStack = mSupervisor.mHomeStack;
-            final boolean homeStackVisible = homeStack != null && homeStack.isVisible();
-            if (homeStackVisible) {
-                // We launch an activity while being in home stack, which means either launcher or
-                // recents into docked stack. We don't want the launched activity to be alone in a
-                // docked stack, so we want to immediately launch recents too.
-                if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
-                mService.mWindowManager.showRecentApps(true /* fromHome */);
-            }
-            return;
-        }
-
-        boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null);
+        final int clearTaskFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK;
+        boolean clearedTask = (mLaunchFlags & clearTaskFlags) == clearTaskFlags
+                && mReuseTask != null;
         if (startedActivityStack.inPinnedWindowingMode()
                 && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP
                 || clearedTask)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index fb6278a..20ec9b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -571,7 +571,7 @@
             if (!match) {
                 throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                         "Package " + packageName +
-                        " signatures don't match previously installed version; ignoring!");
+                        " signatures do not match previously installed version; ignoring!");
             }
         }
         // Check for shared user signatures
@@ -579,16 +579,16 @@
             // Already existing package. Make sure signatures match
             boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
                     parsedSignatures) == PackageManager.SIGNATURE_MATCH;
-            if (!match) {
+            if (!match && compareCompat) {
                 match = matchSignaturesCompat(
                         packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
             }
-            if (!match && compareCompat) {
+            if (!match && compareRecover) {
                 match = matchSignaturesRecover(
                         packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
                 compatMatch |= match;
             }
-            if (!match && compareRecover) {
+            if (!match) {
                 throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                         "Package " + packageName
                         + " has no signatures that match those in shared user "
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index b4300a9..d118c4e 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,3 +1,4 @@
 michaelwr@google.com
 
 per-file BatterySaverPolicy.java=omakoto@google.com
+per-file ShutdownThread.java=fkupolov@google.com
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 6bf725e..6fb345b 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -20,10 +20,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.IActivityManager;
-import android.app.KeyguardManager;
 import android.app.ProgressDialog;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.IBluetoothManager;
 import android.content.BroadcastReceiver;
@@ -31,8 +28,6 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.media.AudioAttributes;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -47,8 +42,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
-import android.os.storage.IStorageManager;
-import android.os.storage.IStorageShutdownObserver;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.TimingsTraceLog;
@@ -123,7 +116,6 @@
     private static String METRIC_RADIOS = "shutdown_radios";
     private static String METRIC_BT = "shutdown_bt";
     private static String METRIC_RADIO = "shutdown_radio";
-    private static String METRIC_SM = "shutdown_storage_manager";
 
     private final Object mActionDoneSync = new Object();
     private boolean mActionDone;
@@ -526,54 +518,6 @@
         shutdownTimingLog.traceEnd(); // ShutdownRadios
         metricEnded(METRIC_RADIOS);
 
-        // Shutdown StorageManagerService to ensure media is in a safe state
-        IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
-            public void onShutDownComplete(int statusCode) throws RemoteException {
-                Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
-                actionDone();
-            }
-        };
-
-        Log.i(TAG, "Shutting down StorageManagerService");
-        shutdownTimingLog.traceBegin("ShutdownStorageManager");
-        metricStarted(METRIC_SM);
-
-        // Set initial variables and time out time.
-        mActionDone = false;
-        final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
-        synchronized (mActionDoneSync) {
-            try {
-                final IStorageManager storageManager = IStorageManager.Stub.asInterface(
-                        ServiceManager.checkService("mount"));
-                if (storageManager != null) {
-                    storageManager.shutdown(observer);
-                } else {
-                    Log.w(TAG, "StorageManagerService unavailable for shutdown");
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Exception during StorageManagerService shutdown", e);
-            }
-            while (!mActionDone) {
-                long delay = endShutTime - SystemClock.elapsedRealtime();
-                if (delay <= 0) {
-                    Log.w(TAG, "StorageManager shutdown wait timed out");
-                    break;
-                } else if (mRebootHasProgressBar) {
-                    int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
-                            (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
-                            MAX_SHUTDOWN_WAIT_TIME);
-                    status += RADIO_STOP_PERCENT;
-                    sInstance.setRebootProgress(status, null);
-                }
-                try {
-                    mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
-                } catch (InterruptedException e) {
-                }
-            }
-        }
-        shutdownTimingLog.traceEnd(); // ShutdownStorageManager
-        metricEnded(METRIC_SM);
-
         if (mRebootHasProgressBar) {
             sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
 
@@ -585,6 +529,7 @@
         shutdownTimingLog.traceEnd(); // SystemServerShutdown
         metricEnded(METRIC_SYSTEM_SERVER);
         saveMetrics(mReboot);
+        // Remaining work will be done by init, including vold shutdown
         rebootOrShutdown(mContext, mReboot, mReason);
     }
 
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 3772371..e240ec5 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -523,6 +523,18 @@
         sayHiToStatsd(); // tell statsd that we're ready too and link to it
     }
 
+    @Override
+    public void triggerUidSnapshot() {
+      enforceCallingPermission();
+      synchronized (sStatsdLock) {
+        try {
+          informAllUidsLocked(mContext);
+        } catch (RemoteException e) {
+          Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+        }
+      }
+    }
+
     private void enforceCallingPermission() {
         if (Binder.getCallingPid() == Process.myPid()) {
             return;
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index c2a4be5..e7547bf 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -87,12 +87,6 @@
         }
     }
 
-    public boolean isVisible() {
-        synchronized (mWindowMap) {
-            return mContainer != null && mContainer.isVisible();
-        }
-    }
-
     public void reparent(int displayId, Rect outStackBounds, boolean onTop) {
         synchronized (mWindowMap) {
             if (mContainer == null) {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index f093d57..fbcccf0 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -126,6 +126,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.MethodRule;
@@ -176,6 +177,7 @@
     "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
  * </code></pre>
  */
+@Ignore
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class NetworkPolicyManagerServiceTest {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
index 5f2e561..d27a758 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
@@ -18,6 +18,7 @@
 
 import android.util.SparseBooleanArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.SmsAddress;
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.util.HexDump;
@@ -113,8 +114,8 @@
      * share code and logic with GSM.  Also, gather all DTMF/BCD
      * processing code in one place.
      */
-
-    private static byte[] parseToDtmf(String address) {
+    @VisibleForTesting
+    public static byte[] parseToDtmf(String address) {
         int digits = address.length();
         byte[] result = new byte[digits];
         for (int i = 0; i < digits; i++) {
@@ -196,33 +197,46 @@
     public static CdmaSmsAddress parse(String address) {
         CdmaSmsAddress addr = new CdmaSmsAddress();
         addr.address = address;
-        addr.ton = CdmaSmsAddress.TON_UNKNOWN;
-        byte[] origBytes = null;
+        addr.ton = TON_UNKNOWN;
+        addr.digitMode = DIGIT_MODE_4BIT_DTMF;
+        addr.numberPlan = NUMBERING_PLAN_UNKNOWN;
+        addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+
+        byte[] origBytes;
         String filteredAddr = filterNumericSugar(address);
-        if (filteredAddr != null) {
-            origBytes = parseToDtmf(filteredAddr);
-        }
-        if (origBytes != null) {
-            addr.digitMode = DIGIT_MODE_4BIT_DTMF;
-            addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
-            if (address.indexOf('+') != -1) {
-                addr.ton = TON_INTERNATIONAL_OR_IP;
-            }
-        } else {
-            filteredAddr = filterWhitespace(address);
-            origBytes = UserData.stringToAscii(filteredAddr);
-            if (origBytes == null) {
-                return null;
-            }
+        if (address.contains("+") || filteredAddr == null) {
+            // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+            // NUMBER_MODE should set to 1 for network address and email address.
             addr.digitMode = DIGIT_MODE_8BIT_CHAR;
             addr.numberMode = NUMBER_MODE_DATA_NETWORK;
-            if (address.indexOf('@') != -1) {
+            filteredAddr = filterWhitespace(address);
+
+            if (address.contains("@")) {
+                // This is an email address
                 addr.ton = TON_NATIONAL_OR_EMAIL;
+            } else if (address.contains("+") && filterNumericSugar(address) != null) {
+                // This is an international number
+                // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+                // digit mode is set to 1 and number mode is set to 0, type of number should set
+                // to the value correspond to the value in 3GPP2 C.S005-D, table2.7.1.3.2.4-2
+                addr.ton = TON_INTERNATIONAL_OR_IP;
+                addr.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY;
+                addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+                filteredAddr = filterNumericSugar(address);
             }
+
+            origBytes = UserData.stringToAscii(filteredAddr);
+        } else {
+            // The address is not an international number and it only contains digit and *#
+            origBytes = parseToDtmf(filteredAddr);
         }
+
+        if (origBytes == null) {
+            return null;
+        }
+
         addr.origBytes = origBytes;
         addr.numberOfDigits = origBytes.length;
         return addr;
     }
-
 }
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index de4fb73..eaaefd5 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -346,30 +346,15 @@
   return true;
 }
 
-class FullyQualifiedClassNameVisitor : public xml::Visitor {
- public:
-  using xml::Visitor::Visit;
-
-  explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : package_(package) {}
-
-  void Visit(xml::Element* el) override {
-    for (xml::Attribute& attr : el->attributes) {
-      if (attr.namespace_uri == xml::kSchemaAndroid &&
-          class_attributes_.find(attr.name) != class_attributes_.end()) {
-        if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package_, attr.value)) {
-          attr.value = std::move(new_value.value());
-        }
-      }
+static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
+                                  const StringPiece& attr_name, xml::Element* el) {
+  xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
+  if (attr != nullptr) {
+    if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) {
+      attr->value = std::move(new_value.value());
     }
-
-    // Super implementation to iterate over the children.
-    xml::Visitor::Visit(el);
   }
-
- private:
-  StringPiece package_;
-  std::unordered_set<StringPiece> class_attributes_ = {"name"};
-};
+}
 
 static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
@@ -381,8 +366,25 @@
   std::string original_package = std::move(attr->value);
   attr->value = package_override.to_string();
 
-  FullyQualifiedClassNameVisitor visitor(original_package);
-  manifest_el->Accept(&visitor);
+  xml::Element* application_el = manifest_el->FindChild({}, "application");
+  if (application_el != nullptr) {
+    FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
+    FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
+
+    for (xml::Element* child_el : application_el->GetChildElements()) {
+      if (child_el->namespace_uri.empty()) {
+        if (child_el->name == "activity" || child_el->name == "activity-alias" ||
+            child_el->name == "provider" || child_el->name == "receiver" ||
+            child_el->name == "service") {
+          FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
+        }
+
+        if (child_el->name == "activity-alias") {
+          FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
+        }
+      }
+    }
+  }
   return true;
 }
 
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index da7f410..40085ea 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -240,6 +240,7 @@
   std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
       <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                 package="android">
+        <uses-split android:name="feature_a" />
         <application android:name=".MainApplication" text="hello">
           <activity android:name=".activity.Start" />
           <receiver android:name="com.google.android.Receiver" />
@@ -248,35 +249,41 @@
                                                             options);
   ASSERT_NE(nullptr, doc);
 
-  xml::Element* manifestEl = doc->root.get();
-  ASSERT_NE(nullptr, manifestEl);
+  xml::Element* manifest_el = doc->root.get();
+  ASSERT_NE(nullptr, manifest_el);
 
   xml::Attribute* attr = nullptr;
 
-  attr = manifestEl->FindAttribute({}, "package");
+  attr = manifest_el->FindAttribute({}, "package");
   ASSERT_NE(nullptr, attr);
   EXPECT_EQ(std::string("com.android"), attr->value);
 
-  xml::Element* applicationEl = manifestEl->FindChild({}, "application");
-  ASSERT_NE(nullptr, applicationEl);
+  xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split");
+  ASSERT_NE(nullptr, uses_split_el);
+  attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name");
+  ASSERT_NE(nullptr, attr);
+  EXPECT_EQ(std::string("feature_a"), attr->value);
 
-  attr = applicationEl->FindAttribute(xml::kSchemaAndroid, "name");
+  xml::Element* application_el = manifest_el->FindChild({}, "application");
+  ASSERT_NE(nullptr, application_el);
+
+  attr = application_el->FindAttribute(xml::kSchemaAndroid, "name");
   ASSERT_NE(nullptr, attr);
   EXPECT_EQ(std::string("android.MainApplication"), attr->value);
 
-  attr = applicationEl->FindAttribute({}, "text");
+  attr = application_el->FindAttribute({}, "text");
   ASSERT_NE(nullptr, attr);
   EXPECT_EQ(std::string("hello"), attr->value);
 
   xml::Element* el;
-  el = applicationEl->FindChild({}, "activity");
+  el = application_el->FindChild({}, "activity");
   ASSERT_NE(nullptr, el);
 
   attr = el->FindAttribute(xml::kSchemaAndroid, "name");
   ASSERT_NE(nullptr, el);
   EXPECT_EQ(std::string("android.activity.Start"), attr->value);
 
-  el = applicationEl->FindChild({}, "receiver");
+  el = application_el->FindChild({}, "receiver");
   ASSERT_NE(nullptr, el);
 
   attr = el->FindAttribute(xml::kSchemaAndroid, "name");