Merge "Fixed issue where XmlPullParserExceptions are thrown with Theme defined GradientDrawable attributes"
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 8cd409e..017cb6d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -81,7 +81,7 @@
         "src/external/StatsPullerManager.cpp",
         "src/external/puller_util.cpp",
         "src/logd/LogEvent.cpp",
-        "src/logd/LogListener.cpp",
+        "src/logd/LogEventQueue.cpp",
         "src/matchers/CombinationLogMatchingTracker.cpp",
         "src/matchers/EventMatcherWizard.cpp",
         "src/matchers/matcher_util.cpp",
@@ -226,6 +226,7 @@
         "tests/indexed_priority_queue_test.cpp",
         "tests/LogEntryMatcher_test.cpp",
         "tests/LogEvent_test.cpp",
+        "tests/log_event/LogEventQueue_test.cpp",
         "tests/MetricsManager_test.cpp",
         "tests/StatsLogProcessor_test.cpp",
         "tests/StatsService_test.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 0aacdf2..3bcebd9 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -130,34 +130,36 @@
     }                                                             \
 }
 
-StatsService::StatsService(const sp<Looper>& handlerLooper)
-    : mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
-       [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
-           if (sc != nullptr) {
-               sc->setAnomalyAlarm(timeMillis);
-               StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
-           }
-       },
-       [](const sp<IStatsCompanionService>& sc) {
-           if (sc != nullptr) {
-               sc->cancelAnomalyAlarm();
-               StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
-           }
-       })),
-   mPeriodicAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
-      [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
-           if (sc != nullptr) {
-               sc->setAlarmForSubscriberTriggering(timeMillis);
-               StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
-           }
-      },
-      [](const sp<IStatsCompanionService>& sc) {
-           if (sc != nullptr) {
-               sc->cancelAlarmForSubscriberTriggering();
-               StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
-           }
-
-      }))  {
+StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
+    : mAnomalyAlarmMonitor(new AlarmMonitor(
+              MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+              [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+                  if (sc != nullptr) {
+                      sc->setAnomalyAlarm(timeMillis);
+                      StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+                  }
+              },
+              [](const sp<IStatsCompanionService>& sc) {
+                  if (sc != nullptr) {
+                      sc->cancelAnomalyAlarm();
+                      StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+                  }
+              })),
+      mPeriodicAlarmMonitor(new AlarmMonitor(
+              MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+              [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+                  if (sc != nullptr) {
+                      sc->setAlarmForSubscriberTriggering(timeMillis);
+                      StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+                  }
+              },
+              [](const sp<IStatsCompanionService>& sc) {
+                  if (sc != nullptr) {
+                      sc->cancelAlarmForSubscriberTriggering();
+                      StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+                  }
+              })),
+      mEventQueue(queue) {
     mUidMap = UidMap::getInstance();
     mPullerManager = new StatsPullerManager();
     StatsPuller::SetUidMap(mUidMap);
@@ -199,11 +201,33 @@
     mConfigManager->AddListener(mProcessor);
 
     init_system_properties();
+
+    if (mEventQueue != nullptr) {
+        std::thread pushedEventThread([this] { readLogs(); });
+        pushedEventThread.detach();
+    }
 }
 
 StatsService::~StatsService() {
 }
 
+/* Runs on a dedicated thread to process pushed events. */
+void StatsService::readLogs() {
+    // Read forever..... long live statsd
+    while (1) {
+        // Block until an event is available.
+        auto event = mEventQueue->waitPop();
+        // Pass it to StatsLogProcess to all configs/metrics
+        // At this point, the LogEventQueue is not blocked, so that the socketListener
+        // can read events from the socket and write to buffer to avoid data drop.
+        mProcessor->OnLogEvent(event.get());
+        // The ShellSubscriber is only used by shell for local debugging.
+        if (mShellSubscriber != nullptr) {
+            mShellSubscriber->onLogEvent(*event);
+        }
+    }
+}
+
 void StatsService::init_system_properties() {
     mEngBuild = false;
     const prop_info* buildType = __system_property_find("ro.build.type");
@@ -1007,6 +1031,7 @@
     }
 }
 
+// Test only interface!!!
 void StatsService::OnLogEvent(LogEvent* event) {
     mProcessor->OnLogEvent(event);
     if (mShellSubscriber != nullptr) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 38efa89..929d260 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -22,7 +22,7 @@
 #include "anomaly/AlarmMonitor.h"
 #include "config/ConfigManager.h"
 #include "external/StatsPullerManager.h"
-#include "logd/LogListener.h"
+#include "logd/LogEventQueue.h"
 #include "packages/UidMap.h"
 #include "shell/ShellSubscriber.h"
 #include "statscompanion_util.h"
@@ -52,11 +52,10 @@
 using android::hardware::Return;
 
 class StatsService : public BnStatsManager,
-                     public LogListener,
                      public IStats,
                      public IBinder::DeathRecipient {
 public:
-    StatsService(const sp<Looper>& handlerLooper);
+    StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
     virtual ~StatsService();
 
     /** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
@@ -92,7 +91,7 @@
     void Terminate();
 
     /**
-     * Called by LogReader when there's a log event to process.
+     * Test ONLY interface. In real world, StatsService reads from LogEventQueue.
      */
     virtual void OnLogEvent(LogEvent* event);
 
@@ -283,6 +282,9 @@
      */
     void print_cmd_help(int out);
 
+    /* Runs on its dedicated thread to process pushed stats event from socket. */
+    void readLogs();
+
     /**
      * Trigger a broadcast.
      */
@@ -415,6 +417,8 @@
 
     sp<ShellSubscriber> mShellSubscriber;
 
+    std::shared_ptr<LogEventQueue> mEventQueue;
+
     FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 29100aa..74a4c87 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -50,6 +50,7 @@
 const int FIELD_ID_PERIODIC_ALARM_STATS = 12;
 const int FIELD_ID_SYSTEM_SERVER_RESTART = 15;
 const int FIELD_ID_LOGGER_ERROR_STATS = 16;
+const int FIELD_ID_OVERFLOW = 18;
 
 const int FIELD_ID_ATOM_STATS_TAG = 1;
 const int FIELD_ID_ATOM_STATS_COUNT = 2;
@@ -64,6 +65,10 @@
 const int FIELD_ID_LOG_LOSS_STATS_UID = 5;
 const int FIELD_ID_LOG_LOSS_STATS_PID = 6;
 
+const int FIELD_ID_OVERFLOW_COUNT = 1;
+const int FIELD_ID_OVERFLOW_MAX_HISTORY = 2;
+const int FIELD_ID_OVERFLOW_MIN_HISTORY = 3;
+
 const int FIELD_ID_CONFIG_STATS_UID = 1;
 const int FIELD_ID_CONFIG_STATS_ID = 2;
 const int FIELD_ID_CONFIG_STATS_CREATION = 3;
@@ -235,6 +240,22 @@
     noteDataDropped(key, totalBytes, getWallClockSec());
 }
 
+void StatsdStats::noteEventQueueOverflow(int64_t oldestEventTimestampNs) {
+    lock_guard<std::mutex> lock(mLock);
+
+    mOverflowCount++;
+
+    int64_t history = getElapsedRealtimeNs() - oldestEventTimestampNs;
+
+    if (history > mMaxQueueHistoryNs) {
+        mMaxQueueHistoryNs = history;
+    }
+
+    if (history < mMinQueueHistoryNs) {
+        mMinQueueHistoryNs = history;
+    }
+}
+
 void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes, int32_t timeSec) {
     lock_guard<std::mutex> lock(mLock);
     auto it = mConfigStats.find(key);
@@ -534,6 +555,9 @@
     mPeriodicAlarmRegisteredStats = 0;
     mSystemServerRestartSec.clear();
     mLogLossStats.clear();
+    mOverflowCount = 0;
+    mMinQueueHistoryNs = kInt64Max;
+    mMaxQueueHistoryNs = 0;
     for (auto& config : mConfigStats) {
         config.second->broadcast_sent_time_sec.clear();
         config.second->activation_time_sec.clear();
@@ -726,6 +750,9 @@
                 (long long)loss.mWallClockSec, loss.mCount, loss.mLastError, loss.mLastTag,
                 loss.mUid, loss.mPid);
     }
+
+    dprintf(out, "Event queue overflow: %d; MaxHistoryNs: %lld; MinHistoryNs: %lld\n",
+            mOverflowCount, (long long)mMaxQueueHistoryNs, (long long)mMinQueueHistoryNs);
 }
 
 void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* proto) {
@@ -904,6 +931,16 @@
         proto.end(token);
     }
 
+    if (mOverflowCount > 0) {
+        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_OVERFLOW);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_OVERFLOW_COUNT, (int32_t)mOverflowCount);
+        proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MAX_HISTORY,
+                    (long long)mMaxQueueHistoryNs);
+        proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MIN_HISTORY,
+                    (long long)mMinQueueHistoryNs);
+        proto.end(token);
+    }
+
     for (const auto& restart : mSystemServerRestartSec) {
         proto.write(FIELD_TYPE_INT32 | FIELD_ID_SYSTEM_SERVER_RESTART | FIELD_COUNT_REPEATED,
                     restart);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 434920e..88ecccc 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -160,6 +160,8 @@
     // Max platform atom tag number.
     static const int32_t kMaxPlatformAtomTag = 100000;
 
+    static const int64_t kInt64Max = 0x7fffffffffffffffLL;
+
     /**
      * Report a new config has been received and report the static stats about the config.
      *
@@ -419,6 +421,10 @@
      */
     void noteBucketUnknownCondition(int64_t metricId);
 
+    /* Reports one event has been dropped due to queue overflow, and the oldest event timestamp in
+     * the queue */
+    void noteEventQueueOverflow(int64_t oldestEventTimestampNs);
+
     /**
      * 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
@@ -522,6 +528,17 @@
         int32_t mPid;
     };
 
+    // Max of {(now - oldestEventTimestamp) when overflow happens}.
+    // This number is helpful to understand how SLOW statsd can be.
+    int64_t mMaxQueueHistoryNs = 0;
+
+    // Min of {(now - oldestEventTimestamp) when overflow happens}.
+    // This number is helpful to understand how FAST the events floods to statsd.
+    int64_t mMinQueueHistoryNs = kInt64Max;
+
+    // Total number of events that are lost due to queue overflow.
+    int32_t mOverflowCount = 0;
+
     // Timestamps when we detect log loss, and the number of logs lost.
     std::list<LogLossStats> mLogLossStats;
 
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 2b7dc8d..ca874b5 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -121,6 +121,7 @@
 
 LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
     mLogdTimestampNs = wallClockTimestampNs;
+    mElapsedTimestampNs = elapsedTimestampNs;
     mTagId = tagId;
     mLogUid = 0;
     mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
@@ -251,7 +252,8 @@
     mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
 }
 
-LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, 0) {}
+LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, timestampNs) {
+}
 
 LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) {
     mLogdTimestampNs = timestampNs;
diff --git a/cmds/statsd/src/logd/LogEventQueue.cpp b/cmds/statsd/src/logd/LogEventQueue.cpp
new file mode 100644
index 0000000..146464b
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEventQueue.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false  // STOPSHIP if true
+#include "Log.h"
+
+#include "LogEventQueue.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::unique_lock;
+using std::unique_ptr;
+
+unique_ptr<LogEvent> LogEventQueue::waitPop() {
+    std::unique_lock<std::mutex> lock(mMutex);
+
+    if (mQueue.empty()) {
+        mCondition.wait(lock, [this] { return !this->mQueue.empty(); });
+    }
+
+    unique_ptr<LogEvent> item = std::move(mQueue.front());
+    mQueue.pop();
+
+    return item;
+}
+
+bool LogEventQueue::push(unique_ptr<LogEvent> item, int64_t* oldestTimestampNs) {
+    bool success;
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (mQueue.size() < mQueueLimit) {
+            mQueue.push(std::move(item));
+            success = true;
+        } else {
+            // safe operation as queue must not be empty.
+            *oldestTimestampNs = mQueue.front()->GetElapsedTimestampNs();
+            success = false;
+        }
+    }
+
+    mCondition.notify_one();
+    return success;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEventQueue.h b/cmds/statsd/src/logd/LogEventQueue.h
new file mode 100644
index 0000000..b4fd63f
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEventQueue.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "LogEvent.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * A zero copy thread safe queue buffer for producing and consuming LogEvent.
+ */
+class LogEventQueue {
+public:
+    explicit LogEventQueue(size_t maxSize) : mQueueLimit(maxSize){};
+
+    /**
+     * Blocking read one event from the queue.
+     */
+    std::unique_ptr<LogEvent> waitPop();
+
+    /**
+     * Puts a LogEvent ptr to the end of the queue.
+     * Returns false on failure when the queue is full, and output the oldest event timestamp
+     * in the queue.
+     */
+    bool push(std::unique_ptr<LogEvent> event, int64_t* oldestTimestampNs);
+
+private:
+    const size_t mQueueLimit;
+    std::condition_variable mCondition;
+    std::mutex mMutex;
+    std::queue<std::unique_ptr<LogEvent>> mQueue;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogListener.h b/cmds/statsd/src/logd/LogListener.h
deleted file mode 100644
index d8b06e9..0000000
--- a/cmds/statsd/src/logd/LogListener.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include "logd/LogEvent.h"
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Callback for LogReader
- */
-class LogListener : public virtual android::RefBase {
-public:
-    LogListener();
-    virtual ~LogListener();
-
-    virtual void OnLogEvent(LogEvent* msg) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index eddc86e..68082c2 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -80,8 +80,11 @@
 
     ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
 
+    std::shared_ptr<LogEventQueue> eventQueue =
+            std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
+
     // Create the service
-    gStatsService = new StatsService(looper);
+    gStatsService = new StatsService(looper, eventQueue);
     if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
                 IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
             != 0) {
@@ -101,13 +104,13 @@
 
     gStatsService->Startup();
 
-    sp<StatsSocketListener> socketListener = new StatsSocketListener(gStatsService);
+    sp<StatsSocketListener> socketListener = new StatsSocketListener(eventQueue);
 
-        ALOGI("using statsd socket");
-        // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
-        if (socketListener->startListener(600)) {
-            exit(1);
-        }
+    ALOGI("Statsd starts to listen to socket.");
+    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
+    if (socketListener->startListener(600)) {
+        exit(1);
+    }
 
     // Loop forever -- the reports run on this thread in a handler, and the
     // binder calls remain responsive in their pool of one thread.
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
index aed926d..92200f9 100755
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ b/cmds/statsd/src/socket/StatsSocketListener.cpp
@@ -41,8 +41,8 @@
 
 static const int kLogMsgHeaderSize = 28;
 
-StatsSocketListener::StatsSocketListener(const sp<LogListener>& listener)
-    : SocketListener(getLogSocket(), false /*start listen*/), mListener(listener) {
+StatsSocketListener::StatsSocketListener(std::shared_ptr<LogEventQueue> queue)
+    : SocketListener(getLogSocket(), false /*start listen*/), mQueue(queue) {
 }
 
 StatsSocketListener::~StatsSocketListener() {
@@ -134,10 +134,11 @@
     msg.entry.uid = cred->uid;
 
     memcpy(msg.buf + kLogMsgHeaderSize, ptr, n + 1);
-    LogEvent event(msg);
 
-    // Call the listener
-    mListener->OnLogEvent(&event);
+    int64_t oldestTimestamp;
+    if (!mQueue->push(std::make_unique<LogEvent>(msg), &oldestTimestamp)) {
+        StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
+    }
 
     return true;
 }
diff --git a/cmds/statsd/src/socket/StatsSocketListener.h b/cmds/statsd/src/socket/StatsSocketListener.h
index b8185d2..2167a56 100644
--- a/cmds/statsd/src/socket/StatsSocketListener.h
+++ b/cmds/statsd/src/socket/StatsSocketListener.h
@@ -17,7 +17,7 @@
 
 #include <sysutils/SocketListener.h>
 #include <utils/RefBase.h>
-#include "logd/LogListener.h"
+#include "logd/LogEventQueue.h"
 
 // DEFAULT_OVERFLOWUID is defined in linux/highuid.h, which is not part of
 // the uapi headers for userspace to use.  This value is filled in on the
@@ -35,7 +35,7 @@
 
 class StatsSocketListener : public SocketListener, public virtual android::RefBase {
 public:
-    explicit StatsSocketListener(const sp<LogListener>& listener);
+    explicit StatsSocketListener(std::shared_ptr<LogEventQueue> queue);
 
     virtual ~StatsSocketListener();
 
@@ -47,7 +47,7 @@
     /**
      * Who is going to get the events when they're read.
      */
-    sp<LogListener> mListener;
+    std::shared_ptr<LogEventQueue> mQueue;
 };
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 967c3525..1dfc433 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -460,6 +460,14 @@
         optional int32 pid = 6;
     }
     repeated LogLossStats detected_log_loss = 16;
+
+    message EventQueueOverflow {
+        optional int32 count = 1;
+        optional int64 max_queue_history_ns = 2;
+        optional int64 min_queue_history_ns = 3;
+    }
+
+    optional EventQueueOverflow queue_overflow = 18;
 }
 
 message AlertTriggerDetails {
diff --git a/cmds/statsd/tests/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp
index 560fb9f..7c00531 100644
--- a/cmds/statsd/tests/StatsService_test.cpp
+++ b/cmds/statsd/tests/StatsService_test.cpp
@@ -33,7 +33,7 @@
 #ifdef __ANDROID__
 
 TEST(StatsServiceTest, TestAddConfig_simple) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     StatsdConfig config;
     config.set_id(12345);
     string serialized = config.SerializeAsString();
@@ -43,7 +43,7 @@
 }
 
 TEST(StatsServiceTest, TestAddConfig_empty) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     string serialized = "";
 
     EXPECT_TRUE(
@@ -51,7 +51,7 @@
 }
 
 TEST(StatsServiceTest, TestAddConfig_invalid) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     string serialized = "Invalid config!";
 
     EXPECT_FALSE(
@@ -69,7 +69,7 @@
 
     int32_t uid;
 
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     service.mEngBuild = true;
 
     // "-1"
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 3dff7f5..309d251 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -111,7 +111,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -126,7 +126,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -146,7 +146,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -171,7 +171,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -195,7 +195,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeValueMetricConfig(0));
@@ -213,7 +213,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
@@ -237,7 +237,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeGaugeMetricConfig(0));
@@ -255,7 +255,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
new file mode 100644
index 0000000..f27d129
--- /dev/null
+++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "logd/LogEventQueue.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace android;
+using namespace testing;
+
+using std::unique_ptr;
+
+#ifdef __ANDROID__
+TEST(LogEventQueue_test, TestGoodConsumer) {
+    LogEventQueue queue(50);
+    int64_t timeBaseNs = 100;
+    std::thread writer([&queue, timeBaseNs] {
+        for (int i = 0; i < 100; i++) {
+            int64_t oldestEventNs;
+            bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000),
+                                      &oldestEventNs);
+            EXPECT_TRUE(success);
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+    });
+
+    std::thread reader([&queue, timeBaseNs] {
+        for (int i = 0; i < 100; i++) {
+            auto event = queue.waitPop();
+            EXPECT_TRUE(event != nullptr);
+            // All events are in right order.
+            EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
+        }
+    });
+
+    reader.join();
+    writer.join();
+}
+
+TEST(LogEventQueue_test, TestSlowConsumer) {
+    LogEventQueue queue(50);
+    int64_t timeBaseNs = 100;
+    std::thread writer([&queue, timeBaseNs] {
+        int failure_count = 0;
+        int64_t oldestEventNs;
+        for (int i = 0; i < 100; i++) {
+            bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000),
+                                      &oldestEventNs);
+            if (!success) failure_count++;
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+
+        // There is some remote chance that reader thread not get chance to run before writer thread
+        // ends. That's why the following comparison is not "==".
+        // There will be at least 45 events lost due to overflow.
+        EXPECT_TRUE(failure_count >= 45);
+        // The oldest event must be at least the 6th event.
+        EXPECT_TRUE(oldestEventNs <= (100 + 5 * 1000));
+    });
+
+    std::thread reader([&queue, timeBaseNs] {
+        // The consumer quickly processed 5 events, then it got stuck (not reading anymore).
+        for (int i = 0; i < 5; i++) {
+            auto event = queue.waitPop();
+            EXPECT_TRUE(event != nullptr);
+            // All events are in right order.
+            EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
+        }
+    });
+
+    reader.join();
+    writer.join();
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 2ef0856..8ec5e3a 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Insets;
+import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
@@ -46,6 +47,7 @@
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -81,6 +83,9 @@
     // Temp container to store view coordinates in window.
     private final int[] mLocationInWindow = new int[2];
 
+    // The latest tap exclude region that we've sent to WM.
+    private final Region mTapExcludeRegion = new Region();
+
     private TaskStackListener mTaskStackListener;
 
     private final CloseGuard mGuard = CloseGuard.get();
@@ -279,11 +284,11 @@
     }
 
     /**
-     * Triggers an update of {@link ActivityView}'s location in window to properly set touch exclude
+     * Triggers an update of {@link ActivityView}'s location in window to properly set tap exclude
      * regions and avoid focus switches by touches on this view.
      */
     public void onLocationChanged() {
-        updateLocation();
+        updateTapExcludeRegion();
     }
 
     @Override
@@ -291,15 +296,38 @@
         mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
     }
 
-    /** Send current location and size to the WM to set tap exclude region for this view. */
-    private void updateLocation() {
+    @Override
+    public boolean gatherTransparentRegion(Region region) {
+        // The tap exclude region may be affected by any view on top of it, so we detect the
+        // possible change by monitoring this function.
+        updateTapExcludeRegion();
+        return super.gatherTransparentRegion(region);
+    }
+
+    /** Compute and send current tap exclude region to WM for this view. */
+    private void updateTapExcludeRegion() {
         if (!isAttachedToWindow()) {
             return;
         }
+        if (!canReceivePointerEvents()) {
+            cleanTapExcludeRegion();
+            return;
+        }
         try {
             getLocationInWindow(mLocationInWindow);
+            final int x = mLocationInWindow[0];
+            final int y = mLocationInWindow[1];
+            mTapExcludeRegion.set(x, y, x + getWidth(), y + getHeight());
+
+            // There might be views on top of us. We need to subtract those areas from the tap
+            // exclude region.
+            final ViewParent parent = getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).subtractObscuredTouchableRegion(mTapExcludeRegion, this);
+            }
+
             WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
-                    mLocationInWindow[0], mLocationInWindow[1], getWidth(), getHeight());
+                    mTapExcludeRegion);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -322,7 +350,7 @@
                 mVirtualDisplay.setDisplayState(true);
             }
 
-            updateLocation();
+            updateTapExcludeRegion();
         }
 
         @Override
@@ -330,7 +358,7 @@
             if (mVirtualDisplay != null) {
                 mVirtualDisplay.resize(width, height, getBaseDisplayDensity());
             }
-            updateLocation();
+            updateTapExcludeRegion();
         }
 
         @Override
@@ -460,13 +488,14 @@
 
     /** Report to server that tap exclude region on hosting display should be cleared. */
     private void cleanTapExcludeRegion() {
-        if (!isAttachedToWindow()) {
+        if (!isAttachedToWindow() || mTapExcludeRegion.isEmpty()) {
             return;
         }
-        // Update tap exclude region with an empty rect to clean the state on server.
+        // Update tap exclude region with a null region to clean the state on server.
         try {
             WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
-                    0 /* left */, 0 /* top */, 0 /* width */, 0 /* height */);
+                    null /* region */);
+            mTapExcludeRegion.setEmpty();
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 1727d34..76c4fb8 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -136,13 +136,18 @@
     @Override
     public String toString() {
         if (lite) {
-            return "ContentCaptureOptions [(lite) loggingLevel=" + loggingLevel + "]";
+            return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
         }
-        return "ContentCaptureOptions [loggingLevel=" + loggingLevel + ", maxBufferSize="
-                + maxBufferSize + ", idleFlushingFrequencyMs=" + idleFlushingFrequencyMs
-                + ", textChangeFlushingFrequencyMs=" + textChangeFlushingFrequencyMs
-                + ", logHistorySize=" + logHistorySize + ", whitelistedComponents="
-                + whitelistedComponents + "]";
+        final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
+        string.append("loggingLevel=").append(loggingLevel)
+            .append(", maxBufferSize=").append(maxBufferSize)
+            .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
+            .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
+            .append(", logHistorySize=").append(logHistorySize);
+        if (whitelistedComponents != null) {
+            string.append(", whitelisted=").append(whitelistedComponents);
+        }
+        return string.append(']').toString();
     }
 
     /** @hide */
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 5980251..f9e0af2 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -205,6 +205,7 @@
         if (cancellationSignal != null && cancellationSignal.isCanceled()) {
             return;
         }
+        final Object lock = new Object();
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkSend((network != null
@@ -214,8 +215,8 @@
             return;
         }
 
-        maybeAddCancellationSignal(cancellationSignal, queryfd);
-        registerFDListener(executor, queryfd, callback);
+        maybeAddCancellationSignal(cancellationSignal, queryfd, lock);
+        registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
     }
 
     /**
@@ -242,6 +243,7 @@
         if (cancellationSignal != null && cancellationSignal.isCanceled()) {
             return;
         }
+        final Object lock = new Object();
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
@@ -251,31 +253,37 @@
             return;
         }
 
-        maybeAddCancellationSignal(cancellationSignal, queryfd);
-        registerFDListener(executor, queryfd, callback);
+        maybeAddCancellationSignal(cancellationSignal, queryfd, lock);
+        registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
     }
 
     private <T> void registerFDListener(@NonNull Executor executor,
-            @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+            @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback,
+            @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
         Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
                 queryfd,
                 FD_EVENTS,
                 (fd, events) -> {
                     executor.execute(() -> {
-                        byte[] answerbuf = null;
-                        try {
-                            answerbuf = resNetworkResult(fd);
-                        } catch (ErrnoException e) {
-                            Log.e(TAG, "resNetworkResult:" + e.toString());
-                            answerCallback.onQueryException(e);
-                            return;
-                        }
+                        synchronized (lock) {
+                            if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+                                return;
+                            }
+                            byte[] answerbuf = null;
+                            try {
+                                answerbuf = resNetworkResult(fd);
+                            } catch (ErrnoException e) {
+                                Log.e(TAG, "resNetworkResult:" + e.toString());
+                                answerCallback.onQueryException(e);
+                                return;
+                            }
 
-                        try {
-                            answerCallback.onAnswer(
-                                    answerCallback.parser.parse(answerbuf));
-                        } catch (ParseException e) {
-                            answerCallback.onParseException(e);
+                            try {
+                                answerCallback.onAnswer(
+                                        answerCallback.parser.parse(answerbuf));
+                            } catch (ParseException e) {
+                                answerCallback.onParseException(e);
+                            }
                         }
                     });
                     // Unregister this fd listener
@@ -284,14 +292,16 @@
     }
 
     private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal,
-            @NonNull FileDescriptor queryfd) {
+            @NonNull FileDescriptor queryfd, @NonNull Object lock) {
         if (cancellationSignal == null) return;
-        cancellationSignal.setOnCancelListener(
-                () -> {
-                    Looper.getMainLooper().getQueue()
-                            .removeOnFileDescriptorEventListener(queryfd);
-                    resNetworkCancel(queryfd);
-            });
+        cancellationSignal.setOnCancelListener(() -> {
+            synchronized (lock)  {
+                if (!queryfd.valid()) return;
+                Looper.getMainLooper().getQueue()
+                        .removeOnFileDescriptorEventListener(queryfd);
+                resNetworkCancel(queryfd);
+            }
+        });
     }
 
     private static class DnsAddressAnswer extends DnsPacket {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 6536fc9..03e8c15 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -330,12 +330,6 @@
      */
     void removeIdleTimer(String iface);
 
-    /**
-     * Configure name servers, search paths, and resolver parameters for the given network.
-     */
-    void setDnsConfigurationForNetwork(int netId, in String[] servers, in String[] domains,
-            in int[] params, String tlsHostname, in String[] tlsServers);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
@@ -381,11 +375,6 @@
     void createVirtualNetwork(int netId, boolean secure);
 
     /**
-     * Remove a network.
-     */
-    void removeNetwork(int netId);
-
-    /**
      * Add an interface to a network.
      */
     void addInterfaceToNetwork(String iface, int netId);
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 6629233..af5bf74 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.uicc.IccUtils;
@@ -223,7 +224,7 @@
               + "mcc=" + mMcc
               + ",mnc=" + mMnc
               + ",spn=" + mSpn
-              + ",imsi=" + mImsi
+              + ",imsi=" + Rlog.pii(false, mImsi)
               + ",gid1=" + mGid1
               + ",gid2=" + mGid2
               + ",carrierid=" + mCarrierId
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 7a35b9e..dc57a15 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -17,6 +17,8 @@
 
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+import static android.view.contentcapture.ContentCaptureHelper.toList;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -36,9 +38,9 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.service.autofill.AutofillService;
-import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureEvent;
@@ -53,7 +55,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -117,7 +118,7 @@
         }
 
         @Override
-        public void onSessionStarted(ContentCaptureContext context, String sessionId, int uid,
+        public void onSessionStarted(ContentCaptureContext context, int sessionId, int uid,
                 IResultReceiver clientReceiver, int initialState) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnCreateSession,
                     ContentCaptureService.this, context, sessionId, uid, clientReceiver,
@@ -125,14 +126,14 @@
         }
 
         @Override
-        public void onActivitySnapshot(String sessionId, SnapshotData snapshotData) {
+        public void onActivitySnapshot(int sessionId, SnapshotData snapshotData) {
             mHandler.sendMessage(
                     obtainMessage(ContentCaptureService::handleOnActivitySnapshot,
                             ContentCaptureService.this, sessionId, snapshotData));
         }
 
         @Override
-        public void onSessionFinished(String sessionId) {
+        public void onSessionFinished(int sessionId) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleFinishSession,
                     ContentCaptureService.this, sessionId));
         }
@@ -171,7 +172,7 @@
      * <p>This map is populated when an session is started, which is called by the system server
      * and can be trusted. Then subsequent calls made by the app are verified against this map.
      */
-    private final ArrayMap<String, Integer> mSessionUids = new ArrayMap<>();
+    private final SparseIntArray mSessionUids = new SparseIntArray();
 
     @CallSuper
     @Override
@@ -240,11 +241,17 @@
      */
     public final void setContentCaptureConditions(@NonNull String packageName,
             @Nullable Set<ContentCaptureCondition> conditions) {
-        // TODO(b/129267994): implement
-    }
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setContentCaptureConditions(): no server callback");
+            return;
+        }
 
-    private <T> ArrayList<T> toList(@Nullable Set<T> set) {
-        return set == null ? null : new ArrayList<T>(set);
+        try {
+            callback.setContentCaptureConditions(packageName, toList(conditions));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -378,7 +385,7 @@
     // so we don't need to create a temporary InteractionSessionId for each event.
 
     private void handleOnCreateSession(@NonNull ContentCaptureContext context,
-            @NonNull String sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
+            int sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
         mSessionUids.put(sessionId, uid);
         onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
 
@@ -403,27 +410,27 @@
 
         // Most events belong to the same session, so we can keep a reference to the last one
         // to avoid creating too many ContentCaptureSessionId objects
-        String lastSessionId = null;
+        int lastSessionId = NO_SESSION_ID;
         ContentCaptureSessionId sessionId = null;
 
         final List<ContentCaptureEvent> events = parceledEvents.getList();
         for (int i = 0; i < events.size(); i++) {
             final ContentCaptureEvent event = events.get(i);
             if (!handleIsRightCallerFor(event, uid)) continue;
-            String sessionIdString = event.getSessionId();
-            if (!sessionIdString.equals(lastSessionId)) {
-                sessionId = new ContentCaptureSessionId(sessionIdString);
-                lastSessionId = sessionIdString;
+            int sessionIdInt = event.getSessionId();
+            if (sessionIdInt != lastSessionId) {
+                sessionId = new ContentCaptureSessionId(sessionIdInt);
+                lastSessionId = sessionIdInt;
             }
             switch (event.getType()) {
                 case ContentCaptureEvent.TYPE_SESSION_STARTED:
                     final ContentCaptureContext clientContext = event.getContentCaptureContext();
                     clientContext.setParentSessionId(event.getParentSessionId());
-                    mSessionUids.put(sessionIdString, uid);
+                    mSessionUids.put(sessionIdInt, uid);
                     onCreateContentCaptureSession(clientContext, sessionId);
                     break;
                 case ContentCaptureEvent.TYPE_SESSION_FINISHED:
-                    mSessionUids.remove(sessionIdString);
+                    mSessionUids.delete(sessionIdInt);
                     onDestroyContentCaptureSession(sessionId);
                     break;
                 default:
@@ -432,13 +439,12 @@
         }
     }
 
-    private void handleOnActivitySnapshot(@NonNull String sessionId,
-            @NonNull SnapshotData snapshotData) {
+    private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
         onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
     }
 
-    private void handleFinishSession(@NonNull String sessionId) {
-        mSessionUids.remove(sessionId);
+    private void handleFinishSession(int sessionId) {
+        mSessionUids.delete(sessionId);
         onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
     }
 
@@ -454,7 +460,7 @@
      * Checks if the given {@code uid} owns the session associated with the event.
      */
     private boolean handleIsRightCallerFor(@NonNull ContentCaptureEvent event, int uid) {
-        final String sessionId;
+        final int sessionId;
         switch (event.getType()) {
             case ContentCaptureEvent.TYPE_SESSION_STARTED:
             case ContentCaptureEvent.TYPE_SESSION_FINISHED:
@@ -463,8 +469,7 @@
             default:
                 sessionId = event.getSessionId();
         }
-        final Integer rightUid = mSessionUids.get(sessionId);
-        if (rightUid == null) {
+        if (mSessionUids.indexOfKey(sessionId) < 0) {
             if (sVerbose) {
                 Log.v(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
                         + ": " + mSessionUids);
@@ -472,6 +477,7 @@
             // Just ignore, as the session could have been finished already
             return false;
         }
+        final int rightUid = mSessionUids.get(sessionId);
         if (rightUid != uid) {
             Log.e(TAG, "invalid call from UID " + uid + ": session " + sessionId + " belongs to "
                     + rightUid);
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 6be7a80..03e1b78 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -35,10 +35,10 @@
 oneway interface IContentCaptureService {
     void onConnected(IBinder callback, boolean verbose, boolean debug);
     void onDisconnected();
-    void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
+    void onSessionStarted(in ContentCaptureContext context, int sessionId, int uid,
                           in IResultReceiver clientReceiver, int initialState);
-    void onSessionFinished(String sessionId);
-    void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
+    void onSessionFinished(int sessionId);
+    void onActivitySnapshot(int sessionId, in SnapshotData snapshotData);
     void onUserDataRemovalRequest(in UserDataRemovalRequest request);
     void onActivityEvent(in ActivityEvent event);
 }
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
index 8bc8def..0550ad3 100644
--- a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -17,6 +17,7 @@
 package android.service.contentcapture;
 
 import android.content.ComponentName;
+import android.view.contentcapture.ContentCaptureCondition;
 
 import java.util.List;
 
@@ -27,5 +28,6 @@
  */
 oneway interface IContentCaptureServiceCallback {
     void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
+    void setContentCaptureConditions(String packageName, in List<ContentCaptureCondition> conditions);
     void disableSelf();
  }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 87efb3f..d317df0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -255,12 +255,11 @@
     void updatePointerIcon(IWindow window);
 
     /**
-     * Update a tap exclude region with a rectangular area identified by provided id in the window.
-     * Touches on this region will not switch focus to this window. Passing an empty rect will
-     * remove the area from the exclude region of this window.
+     * Update a tap exclude region identified by provided id in the window. Touches on this region
+     * will neither be dispatched to this window nor change the focus to this window. Passing an
+     * invalid region will remove the area from the exclude region of this window.
      */
-    void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
-            int height);
+    void updateTapExcludeRegion(IWindow window, int regionId, in Region region);
 
     /**
      * Called when the client has changed the local insets state, and now the server should reflect
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1e23832..5df990c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -86,7 +86,6 @@
 import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.LayoutDirection;
@@ -13912,6 +13911,16 @@
     }
 
     /**
+     * Returns whether this view can receive pointer events.
+     *
+     * @return {@code true} if this view can receive pointer events.
+     * @hide
+     */
+    protected boolean canReceivePointerEvents() {
+        return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null;
+    }
+
+    /**
      * Filter the touch event to apply security policies.
      *
      * @param event The motion event to be filtered.
@@ -28590,8 +28599,7 @@
          * hierarchy is traversed: value is either the view itself for appearead events, or its
          * autofill id for disappeared.
          */
-        // TODO(b/121197119): use SparseArray once session id becomes integer
-        ArrayMap<String, ArrayList<Object>> mContentCaptureEvents;
+        SparseArray<ArrayList<Object>> mContentCaptureEvents;
 
         /**
          * Cached reference to the {@link ContentCaptureManager}.
@@ -28621,9 +28629,9 @@
                 @NonNull View view, boolean appeared) {
             if (mContentCaptureEvents == null) {
                 // Most of the time there will be just one session, so intial capacity is 1
-                mContentCaptureEvents = new ArrayMap<>(1);
+                mContentCaptureEvents = new SparseArray<>(1);
             }
-            String sessionId = session.getId();
+            int sessionId = session.getId();
             // TODO: life would be much easier if we provided a MultiMap implementation somwhere...
             ArrayList<Object> events = mContentCaptureEvents.get(sessionId);
             if (events == null) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4851476..937bd1b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2011,7 +2011,7 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                if (!canViewReceivePointerEvents(child)
+                if (!child.canReceivePointerEvents()
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
                 }
@@ -2094,7 +2094,7 @@
                             childrenCount, i, customOrder);
                     final View child = getAndVerifyPreorderedView(
                             preorderedList, children, childIndex);
-                    if (!canViewReceivePointerEvents(child)
+                    if (!child.canReceivePointerEvents()
                             || !isTransformedTouchPointInView(x, y, child, null)) {
                         continue;
                     }
@@ -2314,7 +2314,7 @@
                                 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                         final View child =
                                 getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                        if (!canViewReceivePointerEvents(child)
+                        if (!child.canReceivePointerEvents()
                                 || !isTransformedTouchPointInView(x, y, child, null)) {
                             continue;
                         }
@@ -2500,7 +2500,7 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                if (!canViewReceivePointerEvents(child)
+                if (!child.canReceivePointerEvents()
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
                 }
@@ -2680,7 +2680,7 @@
                                 i = childrenCount - 1;
                             }
 
-                            if (!canViewReceivePointerEvents(child)
+                            if (!child.canReceivePointerEvents()
                                     || !isTransformedTouchPointInView(x, y, child, null)) {
                                 ev.setTargetAccessibilityFocus(false);
                                 continue;
@@ -2970,15 +2970,6 @@
         }
     }
 
-    /**
-     * Returns true if a child view can receive pointer events.
-     * @hide
-     */
-    private static boolean canViewReceivePointerEvents(@NonNull View child) {
-        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                || child.getAnimation() != null;
-    }
-
     private float[] getTempPoint() {
         if (mTempPoint == null) {
             mTempPoint = new float[2];
@@ -7199,6 +7190,46 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
+        final int childrenCount = mChildrenCount;
+        final ArrayList<View> preorderedList = buildTouchDispatchChildList();
+        final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
+        final View[] children = mChildren;
+        for (int i = childrenCount - 1; i >= 0; i--) {
+            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+            if (child == view) {
+                // We've reached the target view.
+                break;
+            }
+            if (!child.canReceivePointerEvents()) {
+                // This child cannot be touched. Skip it.
+                continue;
+            }
+            applyOpToRegionByBounds(touchableRegion, child, Region.Op.DIFFERENCE);
+        }
+
+        // The touchable region should not exceed the bounds of its container.
+        applyOpToRegionByBounds(touchableRegion, this, Region.Op.INTERSECT);
+
+        final ViewParent parent = getParent();
+        if (parent != null) {
+            parent.subtractObscuredTouchableRegion(touchableRegion, this);
+        }
+    }
+
+    private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
+        final int[] locationInWindow = new int[2];
+        view.getLocationInWindow(locationInWindow);
+        final int x = locationInWindow[0];
+        final int y = locationInWindow[1];
+        region.op(x, y, x + view.getWidth(), y + view.getHeight(), op);
+    }
+
     @Override
     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
         insets = super.dispatchApplyWindowInsets(insets);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 572e69b..feba7bb 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Bundle;
 import android.view.accessibility.AccessibilityEvent;
 
@@ -660,4 +661,17 @@
      * @return true if the action was consumed by this ViewParent
      */
     public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
+
+    /**
+     * Given a touchable region of a child, this method reduces region by the bounds of all views on
+     * top of the child for which {@link View#canReceivePointerEvents} returns {@code true}. This
+     * applies recursively for all views in the view hierarchy on top of this one.
+     *
+     * @param touchableRegion The touchable region we want to modify.
+     * @param view A child view of this ViewGroup which indicates the z-order of the touchable
+     *             region.
+     * @hide
+     */
+    default void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
+    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2880e7f..5f60333 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2811,8 +2811,7 @@
             MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
                     .getMainContentCaptureSession();
             for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
-                String sessionId = mAttachInfo.mContentCaptureEvents
-                        .keyAt(i);
+                int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i);
                 mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
                 ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
                         .valueAt(i);
@@ -2827,8 +2826,8 @@
                             Log.w(mTag, "no content capture session on view: " + view);
                             continue for_each_event;
                         }
-                        String actualId = session.getId().toString();
-                        if (!actualId.equals(sessionId)) {
+                        int actualId = session.getId();
+                        if (actualId != sessionId) {
                             Log.w(mTag, "content capture session mismatch for view (" + view
                                     + "): was " + sessionId + " before, it's " + actualId + " now");
                             continue for_each_event;
diff --git a/cmds/statsd/src/logd/LogListener.cpp b/core/java/android/view/contentcapture/ContentCaptureCondition.aidl
similarity index 60%
rename from cmds/statsd/src/logd/LogListener.cpp
rename to core/java/android/view/contentcapture/ContentCaptureCondition.aidl
index ddb26f9..99f8894 100644
--- a/cmds/statsd/src/logd/LogListener.cpp
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
+/**
+ * Copyright (c) 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     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,
@@ -14,18 +14,6 @@
  * limitations under the License.
  */
 
-#include "logd/LogListener.h"
+package android.view.contentcapture;
 
-namespace android {
-namespace os {
-namespace statsd {
-
-LogListener::LogListener() {
-}
-
-LogListener::~LogListener() {
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
+parcelable ContentCaptureCondition;
diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index ed87257..cf171d7 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -20,6 +20,7 @@
 import android.content.LocusId;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.DebugUtils;
 
 import com.android.internal.util.Preconditions;
 
@@ -58,7 +59,6 @@
     public ContentCaptureCondition(@NonNull LocusId locusId, @Flags int flags) {
         this.mLocusId = Preconditions.checkNotNull(locusId);
         this.mFlags = flags;
-        // TODO(b/129267994): check flags, add test case for null and invalid flags
     }
 
     /**
@@ -79,6 +79,42 @@
     }
 
     @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mFlags;
+        result = prime * result + ((mLocusId == null) ? 0 : mLocusId.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final ContentCaptureCondition other = (ContentCaptureCondition) obj;
+        if (mFlags != other.mFlags) return false;
+        if (mLocusId == null) {
+            if (other.mLocusId != null) return false;
+        } else {
+            if (!mLocusId.equals(other.mLocusId)) return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder string = new StringBuilder(mLocusId.toString()); // LocusID is PII safe
+        if (mFlags != 0) {
+            string
+                .append(" (")
+                .append(DebugUtils.flagsToString(ContentCaptureCondition.class, "FLAG_", mFlags))
+                .append(')');
+        }
+        return string.toString();
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 0e9b16d..94e548f 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -15,6 +15,8 @@
  */
 package android.view.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,7 +37,6 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-
 /**
  * Context associated with a {@link ContentCaptureSession} - see {@link ContentCaptureManager} for
  * more info.
@@ -107,7 +108,7 @@
     private final int mDisplayId;
 
     // Fields below are set by the service upon "delivery" and are not marshalled in the parcel
-    private @Nullable String mParentSessionId;
+    private int mParentSessionId = NO_SESSION_ID;
 
     /** @hide */
     public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
@@ -198,11 +199,12 @@
     @SystemApi
     @TestApi
     public @Nullable ContentCaptureSessionId getParentSessionId() {
-        return mParentSessionId == null ?  null : new ContentCaptureSessionId(mParentSessionId);
+        return mParentSessionId == NO_SESSION_ID ? null
+                : new ContentCaptureSessionId(mParentSessionId);
     }
 
     /** @hide */
-    public void setParentSessionId(@NonNull String parentSessionId) {
+    public void setParentSessionId(int parentSessionId) {
         mParentSessionId = parentSessionId;
     }
 
@@ -317,7 +319,7 @@
         }
         pw.print(", taskId="); pw.print(mTaskId);
         pw.print(", displayId="); pw.print(mDisplayId);
-        if (mParentSessionId != null) {
+        if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentId="); pw.print(mParentSessionId);
         }
         if (mFlags > 0) {
@@ -349,7 +351,7 @@
                 builder.append(", hasExtras");
             }
         }
-        if (mParentSessionId != null) {
+        if (mParentSessionId != NO_SESSION_ID) {
             builder.append(", parentId=").append(mParentSessionId);
         }
         return builder.append(']').toString();
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 8188e05..bd38629 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -16,6 +16,7 @@
 package android.view.contentcapture;
 
 import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -126,25 +127,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType{}
 
-    private final @NonNull String mSessionId;
+    private final int mSessionId;
     private final int mType;
     private final long mEventTime;
     private @Nullable AutofillId mId;
     private @Nullable ArrayList<AutofillId> mIds;
     private @Nullable ViewNode mNode;
     private @Nullable CharSequence mText;
-    private @Nullable String mParentSessionId;
+    private int mParentSessionId = NO_SESSION_ID;
     private @Nullable ContentCaptureContext mClientContext;
 
     /** @hide */
-    public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime) {
+    public ContentCaptureEvent(int sessionId, int type, long eventTime) {
         mSessionId = sessionId;
         mType = type;
         mEventTime = eventTime;
     }
 
     /** @hide */
-    public ContentCaptureEvent(@NonNull String sessionId, int type) {
+    public ContentCaptureEvent(int sessionId, int type) {
         this(sessionId, type, System.currentTimeMillis());
     }
 
@@ -185,7 +186,7 @@
      *
      * @hide
      */
-    public ContentCaptureEvent setParentSessionId(@NonNull String parentSessionId) {
+    public ContentCaptureEvent setParentSessionId(int parentSessionId) {
         mParentSessionId = parentSessionId;
         return this;
     }
@@ -202,7 +203,7 @@
 
     /** @hide */
     @NonNull
-    public String getSessionId() {
+    public int getSessionId() {
         return mSessionId;
     }
 
@@ -212,7 +213,7 @@
      * @hide
      */
     @Nullable
-    public String getParentSessionId() {
+    public int getParentSessionId() {
         return mParentSessionId;
     }
 
@@ -357,10 +358,10 @@
         if (mNode != null) {
             pw.print(", mNode.id="); pw.print(mNode.getAutofillId());
         }
-        if (mSessionId != null) {
+        if (mSessionId != NO_SESSION_ID) {
             pw.print(", sessionId="); pw.print(mSessionId);
         }
-        if (mParentSessionId != null) {
+        if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentSessionId="); pw.print(mParentSessionId);
         }
         if (mText != null) {
@@ -377,7 +378,7 @@
         final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
                 .append(getTypeAsString(mType));
         string.append(", session=").append(mSessionId);
-        if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) {
+        if (mType == TYPE_SESSION_STARTED && mParentSessionId != NO_SESSION_ID) {
             string.append(", parent=").append(mParentSessionId);
         }
         if (mId != null) {
@@ -409,7 +410,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeString(mSessionId);
+        parcel.writeInt(mSessionId);
         parcel.writeInt(mType);
         parcel.writeLong(mEventTime);
         parcel.writeParcelable(mId, flags);
@@ -417,7 +418,7 @@
         ViewNode.writeToParcel(parcel, mNode, flags);
         parcel.writeCharSequence(mText);
         if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) {
-            parcel.writeString(mParentSessionId);
+            parcel.writeInt(mParentSessionId);
         }
         if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) {
             parcel.writeParcelable(mClientContext, flags);
@@ -430,7 +431,7 @@
         @Override
         @NonNull
         public ContentCaptureEvent createFromParcel(Parcel parcel) {
-            final String sessionId = parcel.readString();
+            final int sessionId = parcel.readInt();
             final int type = parcel.readInt();
             final long eventTime  = parcel.readLong();
             final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime);
@@ -448,7 +449,7 @@
             }
             event.setText(parcel.readCharSequence());
             if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) {
-                event.setParentSessionId(parcel.readString());
+                event.setParentSessionId(parcel.readInt());
             }
             if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) {
                 event.setClientContext(parcel.readParcelable(null));
diff --git a/core/java/android/view/contentcapture/ContentCaptureHelper.java b/core/java/android/view/contentcapture/ContentCaptureHelper.java
index 6bc3829..c7ca220 100644
--- a/core/java/android/view/contentcapture/ContentCaptureHelper.java
+++ b/core/java/android/view/contentcapture/ContentCaptureHelper.java
@@ -23,9 +23,14 @@
 import android.annotation.Nullable;
 import android.os.Build;
 import android.provider.DeviceConfig;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.contentcapture.ContentCaptureManager.LoggingLevel;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
 /**
  * Helper class for this package and server's.
  *
@@ -101,6 +106,22 @@
         }
     }
 
+    /**
+     * Converts a set to a list.
+     */
+    @Nullable
+    public static <T> ArrayList<T> toList(@Nullable Set<T> set) {
+        return set == null ? null : new ArrayList<T>(set);
+    }
+
+    /**
+     * Converts a list to a set.
+     */
+    @Nullable
+    public static <T> ArraySet<T> toSet(@Nullable List<T> list) {
+        return list == null ? null : new ArraySet<T>(list);
+    }
+
     private ContentCaptureHelper() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 4f3325c..35f8023 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -17,6 +17,7 @@
 
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+import static android.view.contentcapture.ContentCaptureHelper.toSet;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -46,6 +47,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Set;
 
 /**
@@ -518,7 +520,20 @@
      */
     @Nullable
     public Set<ContentCaptureCondition> getContentCaptureConditions() {
-        return null; // TODO(b/129267994): implement
+        // NOTE: we could cache the conditions on ContentCaptureOptions, but then it would be stick
+        // to the lifetime of the app. OTOH, by dynamically calling the server every time, we allow
+        // the service to fine tune how long-lived apps (like browsers) are whitelisted.
+        if (!isContentCaptureEnabled() && !mOptions.lite) return null;
+
+        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        try {
+            mService.getContentCaptureConditions(mContext.getPackageName(), resultReceiver);
+            final ArrayList<ContentCaptureCondition> result = resultReceiver
+                    .getParcelableListResult();
+            return toSet(result);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index ed1ca2a..7761038 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -38,7 +38,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.UUID;
+import java.util.Random;
 
 /**
  * Session used to notify a system-provided Content Capture service about events associated with
@@ -48,6 +48,11 @@
 
     private static final String TAG = ContentCaptureSession.class.getSimpleName();
 
+    private static final Random sIdGenerator = new Random();
+
+    /** @hide */
+    public static final int NO_SESSION_ID = 0;
+
     /**
      * Initial state, when there is no session.
      *
@@ -186,7 +191,7 @@
 
     /** @hide */
     @Nullable
-    protected final String mId;
+    protected final int mId;
 
     private int mState = UNKNOWN_STATE;
 
@@ -210,13 +215,14 @@
 
     /** @hide */
     protected ContentCaptureSession() {
-        this(UUID.randomUUID().toString());
+        this(getRandomSessionId());
     }
 
     /** @hide */
     @VisibleForTesting
-    public ContentCaptureSession(@NonNull String id) {
-        mId = Preconditions.checkNotNull(id);
+    public ContentCaptureSession(int id) {
+        Preconditions.checkArgument(id != NO_SESSION_ID);
+        mId = id;
     }
 
     // Used by ChildCOntentCaptureSession
@@ -241,15 +247,8 @@
     }
 
     /** @hide */
-    @VisibleForTesting
-    public int getIdAsInt() {
-        // TODO(b/121197119): use sessionId instead of hashcode once it's changed to int
-        return mId.hashCode();
-    }
-
-    /** @hide */
     @NonNull
-    public String getId() {
+    public int getId() {
         return mId;
     }
 
@@ -415,7 +414,7 @@
         // TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is
         // parcelized
         for (long id : virtualIds) {
-            internalNotifyViewDisappeared(new AutofillId(hostId, id, getIdAsInt()));
+            internalNotifyViewDisappeared(new AutofillId(hostId, id, mId));
         }
     }
 
@@ -464,7 +463,7 @@
     public @NonNull AutofillId newAutofillId(@NonNull AutofillId hostId, long virtualChildId) {
         Preconditions.checkNotNull(hostId);
         Preconditions.checkArgument(hostId.isNonVirtual(), "hostId cannot be virtual: %s", hostId);
-        return new AutofillId(hostId, virtualChildId, getIdAsInt());
+        return new AutofillId(hostId, virtualChildId, mId);
     }
 
     /**
@@ -480,7 +479,7 @@
     @NonNull
     public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
             long virtualId) {
-        return new ViewNode.ViewStructureImpl(parentId, virtualId, getIdAsInt());
+        return new ViewNode.ViewStructureImpl(parentId, virtualId, mId);
     }
 
     boolean isContentCaptureEnabled() {
@@ -511,7 +510,7 @@
 
     @Override
     public String toString() {
-        return mId;
+        return Integer.toString(mId);
     }
 
     /** @hide */
@@ -541,4 +540,12 @@
                 return "UNKOWN-" + reason;
         }
     }
+
+    private static int getRandomSessionId() {
+        int id;
+        do {
+            id = sIdGenerator.nextInt();
+        } while (id == NO_SESSION_ID);
+        return id;
+    }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSessionId.java b/core/java/android/view/contentcapture/ContentCaptureSessionId.java
index e7c350a..2d350b2 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSessionId.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSessionId.java
@@ -27,7 +27,7 @@
  */
 public final class ContentCaptureSessionId implements Parcelable {
 
-    private final @NonNull String mValue;
+    private final @NonNull int mValue;
 
     /**
      * Creates a new instance.
@@ -36,14 +36,14 @@
      *
      * @hide
      */
-    public ContentCaptureSessionId(@NonNull String value) {
+    public ContentCaptureSessionId(@NonNull int value) {
         mValue = value;
     }
 
     /**
      * @hide
      */
-    public String getValue() {
+    public int getValue() {
         return mValue;
     }
 
@@ -51,7 +51,7 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((mValue == null) ? 0 : mValue.hashCode());
+        result = prime * result + mValue;
         return result;
     }
 
@@ -61,11 +61,7 @@
         if (obj == null) return false;
         if (getClass() != obj.getClass()) return false;
         final ContentCaptureSessionId other = (ContentCaptureSessionId) obj;
-        if (mValue == null) {
-            if (other.mValue != null) return false;
-        } else if (!mValue.equals(other.mValue)) {
-            return false;
-        }
+        if (mValue != other.mValue) return false;
         return true;
     }
 
@@ -77,9 +73,10 @@
      */
     @Override
     public String toString() {
-        return mValue;
+        return Integer.toString(mValue);
     }
 
+
     /** @hide */
     // TODO(b/111276913): dump to proto as well
     public void dump(PrintWriter pw) {
@@ -93,16 +90,16 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeString(mValue);
+        parcel.writeInt(mValue);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureSessionId> CREATOR =
+    public static final @NonNull Parcelable.Creator<ContentCaptureSessionId> CREATOR =
             new Parcelable.Creator<ContentCaptureSessionId>() {
 
         @Override
         @NonNull
         public ContentCaptureSessionId createFromParcel(Parcel parcel) {
-            return new ContentCaptureSessionId(parcel.readString());
+            return new ContentCaptureSessionId(parcel.readInt());
         }
 
         @Override
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 15fbaa2..7335073 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -42,13 +42,13 @@
      *     {@link IContentCaptureContext#flags}).
      */
     void startSession(IBinder activityToken, in ComponentName componentName,
-                      String sessionId, int flags, in IResultReceiver result);
+                      int sessionId, int flags, in IResultReceiver result);
 
     /**
      * Marks the end of a session for the calling user identified by
      * the corresponding {@code startSession}'s {@code sessionId}.
      */
-    void finishSession(String sessionId);
+    void finishSession(int sessionId);
 
     /**
      * Returns the content capture service's component name (if enabled and
@@ -72,4 +72,9 @@
      * Returns a ComponentName with the name of custom service activity, if defined.
      */
     void getServiceSettingsActivity(in IResultReceiver result);
+
+    /**
+     * Returns a list with the ContentCaptureConditions for the package (or null if not defined).
+     */
+    void getContentCaptureConditions(String packageName, in IResultReceiver result);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 790b8f9..784cf9c 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -318,7 +318,7 @@
         if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) {
             final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
             if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED
-                    && event.getSessionId().equals(lastEvent.getSessionId())) {
+                    && event.getSessionId() == lastEvent.getSessionId()) {
                 if (sVerbose) {
                     Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
                             + lastEvent.getSessionId());
@@ -581,37 +581,35 @@
     // TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is
     // shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such
     // change should also get get rid of the "internalNotifyXXXX" methods above
-    void notifyChildSessionStarted(@NonNull String parentSessionId,
-            @NonNull String childSessionId, @NonNull ContentCaptureContext clientContext) {
+    void notifyChildSessionStarted(int parentSessionId, int childSessionId,
+            @NonNull ContentCaptureContext clientContext) {
         sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
                 .setParentSessionId(parentSessionId).setClientContext(clientContext),
                 FORCE_FLUSH);
     }
 
-    void notifyChildSessionFinished(@NonNull String parentSessionId,
-            @NonNull String childSessionId) {
+    void notifyChildSessionFinished(int parentSessionId, int childSessionId) {
         sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
                 .setParentSessionId(parentSessionId), FORCE_FLUSH);
     }
 
-    void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) {
+    void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
                 .setViewNode(node.mNode));
     }
 
     /** Public because is also used by ViewRootImpl */
-    public void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) {
+    public void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
     }
 
-    void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
-            @Nullable CharSequence text) {
+    void notifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
                 .setText(text));
     }
 
     /** Public because is also used by ViewRootImpl */
-    public void notifyViewTreeEvent(@NonNull String sessionId, boolean started) {
+    public void notifyViewTreeEvent(int sessionId, boolean started) {
         final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
         sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
     }
@@ -622,8 +620,7 @@
         sendEvent(new ContentCaptureEvent(mId, type), FORCE_FLUSH);
     }
 
-    void notifyContextUpdated(@NonNull String sessionId,
-            @Nullable ContentCaptureContext context) {
+    void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
                 .setClientContext(context));
     }
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 60af511..6fad84b 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -23,6 +23,7 @@
 
 import com.android.internal.os.IResultReceiver;
 
+import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -97,6 +98,15 @@
     }
 
     /**
+     * Gets the result from an operation that returns a {@code Parcelable} list.
+     */
+    @Nullable
+    public <P extends Parcelable> ArrayList<P> getParcelableListResult() throws TimeoutException {
+        waitResult();
+        return mBundle == null ? null : mBundle.getParcelableArrayList(EXTRA);
+    }
+
+    /**
      * Gets the optional result from an operation that returns an extra {@code int} (besides the
      * result code).
      *
@@ -150,6 +160,17 @@
     }
 
     /**
+     * Creates a bundle for a {@code Parcelable} list so it can be retrieved by
+     * {@link #getParcelableResult()}.
+     */
+    @NonNull
+    public static Bundle bundleFor(@Nullable ArrayList<? extends Parcelable> value) {
+        final Bundle bundle = new Bundle();
+        bundle.putParcelableArrayList(EXTRA, value);
+        return bundle;
+    }
+
+    /**
      * Creates a bundle for an {@code int} value so it can be retrieved by
      * {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st
      * is returned as the result code).
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index d7a981e..82acf6f 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -470,6 +470,7 @@
     std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
 
     int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
+    jniSetFileDescriptorOfFD(env, javaFd, -1);
     if (res < 0) {
         throwErrnoException(env, "resNetworkResult", -res);
         return nullptr;
@@ -490,6 +491,7 @@
 static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     resNetworkCancel(fd);
+    jniSetFileDescriptorOfFD(env, javaFd, -1);
 }
 
 static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java
new file mode 100644
index 0000000..979a839
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Region;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+
+/**
+ * Test basic functions of ViewGroup.
+ *
+ * Build/Install/Run:
+ *     atest FrameworksCoreTests:ViewGroupTest
+ */
+@Presubmit
+@SmallTest
+public class ViewGroupTest {
+
+    /**
+     * Test if {@link ViewGroup#subtractObscuredTouchableRegion} works as expected.
+     *
+     * The view hierarchy:
+     *   A---B---C
+     *    \   \
+     *     \   --D
+     *      \
+     *       E---F
+     *
+     * The layer and bounds of each view:
+     *   F -- (invisible)
+     *   E --
+     *   D ----
+     *   C ----------
+     *   B ------
+     *   A --------
+     */
+    @Test
+    public void testSubtractObscuredTouchableRegion() {
+        final Context context = getContext();
+        final TestView viewA = new TestView(context, 8 /* right */);
+        final TestView viewB = new TestView(context, 6 /* right */);
+        final TestView viewC = new TestView(context, 10 /* right */);
+        final TestView viewD = new TestView(context, 4 /* right */);
+        final TestView viewE = new TestView(context, 2 /* right */);
+        final TestView viewF = new TestView(context, 2 /* right */);
+
+        viewA.addView(viewB);
+        viewA.addView(viewE);
+        viewB.addView(viewC);
+        viewB.addView(viewD);
+        viewE.addView(viewF);
+
+        viewF.setVisibility(View.INVISIBLE);
+
+        final Region r = new Region();
+
+        getUnobscuredTouchableRegion(r, viewA);
+        assertRegionContainPoint(1 /* x */, r, true /* contain */);
+        assertRegionContainPoint(3 /* x */, r, true /* contain */);
+        assertRegionContainPoint(5 /* x */, r, true /* contain */);
+        assertRegionContainPoint(7 /* x */, r, true /* contain */);
+        assertRegionContainPoint(9 /* x */, r, false /* contain */); // Outside of bounds
+
+        getUnobscuredTouchableRegion(r, viewB);
+        assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by E
+        assertRegionContainPoint(3 /* x */, r, true /* contain */);
+        assertRegionContainPoint(5 /* x */, r, true /* contain */);
+        assertRegionContainPoint(7 /* x */, r, false /* contain */); // Outside of bounds
+
+        getUnobscuredTouchableRegion(r, viewC);
+        assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by D and E
+        assertRegionContainPoint(3 /* x */, r, false /* contain */); // Obscured by D
+        assertRegionContainPoint(5 /* x */, r, true /* contain */);
+        assertRegionContainPoint(7 /* x */, r, false /* contain */); // Outside of parent bounds
+
+        getUnobscuredTouchableRegion(r, viewD);
+        assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by E
+        assertRegionContainPoint(3 /* x */, r, true /* contain */);
+        assertRegionContainPoint(5 /* x */, r, false /* contain */); // Outside of bounds
+
+        getUnobscuredTouchableRegion(r, viewE);
+        assertRegionContainPoint(1 /* x */, r, true /* contain */);
+        assertRegionContainPoint(3 /* x */, r, false /* contain */); // Outside of bounds
+    }
+
+    private static void getUnobscuredTouchableRegion(Region outRegion, View view) {
+        outRegion.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+        final ViewParent parent = view.getParent();
+        if (parent != null) {
+            parent.subtractObscuredTouchableRegion(outRegion, view);
+        }
+    }
+
+    private static void assertRegionContainPoint(int x, Region region, boolean contain) {
+        assertEquals(String.format("Touchable region must%s contain (%s, 0).",
+                (contain ? "" : " not"), x), contain, region.contains(x, 0 /* y */));
+    }
+
+    private static class TestView extends ViewGroup {
+        TestView(Context context, int right) {
+            super(context);
+            setFrame(0 /* left */, 0 /* top */, right, 1 /* bottom */);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            // We don't layout this view.
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index 2416de1..2008537 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -49,13 +49,15 @@
 
     private static final LocusId ID = new LocusId("WHATEVER");
 
+    private static final int NO_SESSION_ID = 0;
+
     // Not using @Mock because it's final - no need to be fancy here....
     private final ContentCaptureContext mClientContext =
             new ContentCaptureContext.Builder(ID).build();
 
     @Test
     public void testSetAutofillId_null() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(NullPointerException.class, () -> event.setAutofillId(null));
         assertThat(event.getId()).isNull();
@@ -64,7 +66,7 @@
 
     @Test
     public void testSetAutofillIds_null() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(NullPointerException.class, () -> event.setAutofillIds(null));
         assertThat(event.getId()).isNull();
@@ -73,7 +75,7 @@
 
     @Test
     public void testAddAutofillId_null() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(NullPointerException.class, () -> event.addAutofillId(null));
         assertThat(event.getId()).isNull();
@@ -82,7 +84,7 @@
 
     @Test
     public void testSetAutofillId() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id = new AutofillId(108);
         event.setAutofillId(id);
@@ -92,7 +94,7 @@
 
     @Test
     public void testSetAutofillIds() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id = new AutofillId(108);
         final ArrayList<AutofillId> ids = new ArrayList<>(1);
@@ -104,7 +106,7 @@
 
     @Test
     public void testAddAutofillId() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id1 = new AutofillId(108);
         event.addAutofillId(id1);
@@ -119,7 +121,7 @@
 
     @Test
     public void testAddAutofillId_afterSetId() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id1 = new AutofillId(108);
         event.setAutofillId(id1);
@@ -134,7 +136,7 @@
 
     @Test
     public void testAddAutofillId_afterSetIds() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id1 = new AutofillId(108);
         final ArrayList<AutofillId> ids = new ArrayList<>(1);
@@ -163,9 +165,9 @@
     }
 
     private ContentCaptureEvent newEventForSessionStarted() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_STARTED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_STARTED)
                 .setClientContext(mClientContext)
-                .setParentSessionId("108");
+                .setParentSessionId(108);
         assertThat(event).isNotNull();
         return event;
     }
@@ -173,8 +175,8 @@
     private void assertSessionStartedEvent(ContentCaptureEvent event) {
         assertThat(event.getType()).isEqualTo(TYPE_SESSION_STARTED);
         assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
-        assertThat(event.getSessionId()).isEqualTo("42");
-        assertThat(event.getParentSessionId()).isEqualTo("108");
+        assertThat(event.getSessionId()).isEqualTo(42);
+        assertThat(event.getParentSessionId()).isEqualTo(108);
         assertThat(event.getId()).isNull();
         assertThat(event.getIds()).isNull();
         assertThat(event.getText()).isNull();
@@ -186,17 +188,17 @@
 
     @Test
     public void testSessionFinished_directly() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
-                .setParentSessionId("108");
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_FINISHED)
+                .setParentSessionId(108);
         assertThat(event).isNotNull();
         assertSessionFinishedEvent(event);
     }
 
     @Test
     public void testSessionFinished_throughParcel() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_FINISHED)
                 .setClientContext(mClientContext) // should not be writting to parcel
-                .setParentSessionId("108");
+                .setParentSessionId(108);
         assertThat(event).isNotNull();
         final ContentCaptureEvent clone = cloneThroughParcel(event);
         assertSessionFinishedEvent(clone);
@@ -205,8 +207,8 @@
     private void assertSessionFinishedEvent(ContentCaptureEvent event) {
         assertThat(event.getType()).isEqualTo(TYPE_SESSION_FINISHED);
         assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
-        assertThat(event.getSessionId()).isEqualTo("42");
-        assertThat(event.getParentSessionId()).isEqualTo("108");
+        assertThat(event.getSessionId()).isEqualTo(42);
+        assertThat(event.getParentSessionId()).isEqualTo(108);
         assertThat(event.getId()).isNull();
         assertThat(event.getIds()).isNull();
         assertThat(event.getText()).isNull();
@@ -216,7 +218,7 @@
 
     @Test
     public void testContextUpdated_directly() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_CONTEXT_UPDATED)
                 .setClientContext(mClientContext);
         assertThat(event).isNotNull();
         assertContextUpdatedEvent(event);
@@ -224,7 +226,7 @@
 
     @Test
     public void testContextUpdated_throughParcel() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_CONTEXT_UPDATED)
                 .setClientContext(mClientContext);
         assertThat(event).isNotNull();
         final ContentCaptureEvent clone = cloneThroughParcel(event);
@@ -233,9 +235,9 @@
 
     @Test
     public void testMergeEvent_typeViewTextChanged() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_TEXT_CHANGED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_TEXT_CHANGED)
                 .setText("test");
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_TEXT_CHANGED)
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_TEXT_CHANGED)
                 .setText("empty");
 
         event.mergeEvent(event2);
@@ -244,14 +246,14 @@
 
     @Test
     public void testMergeEvent_typeViewDisappeared() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
                 .setAutofillId(new AutofillId(1));
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_DISAPPEARED)
                 .setAutofillId(new AutofillId(2));
         final ArrayList<AutofillId> autofillIds = new ArrayList<>();
         autofillIds.add(new AutofillId(3));
         autofillIds.add(new AutofillId(4));
-        final ContentCaptureEvent event3 = new ContentCaptureEvent("17", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event3 = new ContentCaptureEvent(17, TYPE_VIEW_DISAPPEARED)
                 .setAutofillIds(autofillIds);
 
         event.mergeEvent(event2);
@@ -264,24 +266,24 @@
 
     @Test
     public void testMergeEvent_typeViewDisappeared_noIds() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
                 .setAutofillId(new AutofillId(1));
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(IllegalArgumentException.class, () -> event.mergeEvent(event2));
     }
 
     @Test
     public void testMergeEvent_nullArgument() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
         assertThrows(NullPointerException.class, () -> event.mergeEvent(null));
     }
 
     @Test
     public void testMergeEvent_differentEventTypes() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
                 .setText("test").setAutofillId(new AutofillId(1));
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("17", TYPE_VIEW_TEXT_CHANGED)
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(17, TYPE_VIEW_TEXT_CHANGED)
                 .setText("empty").setAutofillId(new AutofillId(2));
 
         event.mergeEvent(event2);
@@ -296,8 +298,8 @@
     private void assertContextUpdatedEvent(ContentCaptureEvent event) {
         assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_UPDATED);
         assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
-        assertThat(event.getSessionId()).isEqualTo("42");
-        assertThat(event.getParentSessionId()).isNull();
+        assertThat(event.getSessionId()).isEqualTo(42);
+        assertThat(event.getParentSessionId()).isEqualTo(NO_SESSION_ID);
         assertThat(event.getId()).isNull();
         assertThat(event.getIds()).isNull();
         assertThat(event.getText()).isNull();
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 013408e..81ce15a 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -39,9 +39,9 @@
 @RunWith(MockitoJUnitRunner.class)
 public class ContentCaptureSessionTest {
 
-    private ContentCaptureSession mSession1 = new MyContentCaptureSession("111");
+    private ContentCaptureSession mSession1 = new MyContentCaptureSession(111);
 
-    private ContentCaptureSession mSession2 = new MyContentCaptureSession("2222");
+    private ContentCaptureSession mSession2 = new MyContentCaptureSession(2222);
 
     @Mock
     private View mMockView;
@@ -60,12 +60,12 @@
         assertThat(childId.getViewId()).isEqualTo(42);
         assertThat(childId.getVirtualChildLongId()).isEqualTo(108L);
         assertThat(childId.getVirtualChildIntId()).isEqualTo(View.NO_ID);
-        assertThat(childId.getSessionId()).isEqualTo(mSession1.getIdAsInt());
+        assertThat(childId.getSessionId()).isEqualTo(mSession1.getId());
     }
 
     @Test
     public void testNewAutofillId_differentSessions() {
-        assertThat(mSession1.getIdAsInt()).isNotSameAs(mSession2.getIdAsInt()); //sanity check
+        assertThat(mSession1.getId()).isNotEqualTo(mSession2.getId()); //sanity check
         final AutofillId parentId = new AutofillId(42);
         final AutofillId childId1 = mSession1.newAutofillId(parentId, 108L);
         final AutofillId childId2 = mSession2.newAutofillId(parentId, 108L);
@@ -117,7 +117,7 @@
     // Cannot use @Spy because we need to pass the session id on constructor
     private class MyContentCaptureSession extends ContentCaptureSession {
 
-        private MyContentCaptureSession(String id) {
+        private MyContentCaptureSession(int id) {
             super(id);
         }
 
diff --git a/core/xsd/Android.bp b/core/xsd/Android.bp
index 81669eb..738f330 100644
--- a/core/xsd/Android.bp
+++ b/core/xsd/Android.bp
@@ -2,5 +2,5 @@
     name: "permission",
     srcs: ["permission.xsd"],
     api_dir: "schema",
-    package_name: "com.android.xml.permission",
+    package_name: "com.android.xml.permission.configfile",
 }
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 1228124..2ef2d04 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -78,6 +78,7 @@
     <xs:complexType name="feature">
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="notLowRam" type="xs:string"/>
+        <xs:attribute name="version" type="xs:int"/>
     </xs:complexType>
     <xs:complexType name="unavailable-feature">
         <xs:attribute name="name" type="xs:string"/>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index 82bb0fea..c25bc14 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -1,5 +1,5 @@
 // Signature format: 2.0
-package com.android.xml.permission {
+package com.android.xml.permission.configfile {
 
   public class AllowAssociation {
     ctor public AllowAssociation();
@@ -97,8 +97,10 @@
     ctor public Feature();
     method public String getName();
     method public String getNotLowRam();
+    method public int getVersion();
     method public void setName(String);
     method public void setNotLowRam(String);
+    method public void setVersion(int);
   }
 
   public class Group {
@@ -125,8 +127,8 @@
 
   public class OemPermissions {
     ctor public OemPermissions();
-    method public java.util.List<com.android.xml.permission.OemPermissions.DenyPermission> getDenyPermission();
-    method public java.util.List<com.android.xml.permission.OemPermissions.Permission> getPermission();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions.DenyPermission> getDenyPermission();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions.Permission> getPermission();
     method public String get_package();
     method public void set_package(String);
   }
@@ -151,37 +153,37 @@
 
   public class Permissions {
     ctor public Permissions();
-    method public java.util.List<com.android.xml.permission.AllowAssociation> getAllowAssociation();
-    method public java.util.List<com.android.xml.permission.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
-    method public java.util.List<com.android.xml.permission.AllowImplicitBroadcast> getAllowImplicitBroadcast();
-    method public java.util.List<com.android.xml.permission.AllowInDataUsageSave> getAllowInDataUsageSave();
-    method public java.util.List<com.android.xml.permission.AllowInPowerSave> getAllowInPowerSave();
-    method public java.util.List<com.android.xml.permission.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
-    method public java.util.List<com.android.xml.permission.AllowUnthrottledLocation> getAllowUnthrottledLocation();
-    method public java.util.List<com.android.xml.permission.AppLink> getAppLink();
-    method public java.util.List<com.android.xml.permission.AssignPermission> getAssignPermission();
-    method public java.util.List<com.android.xml.permission.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
-    method public java.util.List<com.android.xml.permission.BugreportWhitelisted> getBugreportWhitelisted();
-    method public java.util.List<com.android.xml.permission.DefaultEnabledVrApp> getDefaultEnabledVrApp();
-    method public java.util.List<com.android.xml.permission.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
-    method public java.util.List<com.android.xml.permission.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
-    method public java.util.List<com.android.xml.permission.Feature> getFeature();
-    method public java.util.List<com.android.xml.permission.Group> getGroup();
-    method public java.util.List<com.android.xml.permission.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
-    method public java.util.List<com.android.xml.permission.Library> getLibrary();
-    method public java.util.List<com.android.xml.permission.OemPermissions> getOemPermissions();
-    method public java.util.List<com.android.xml.permission.Permission> getPermission();
-    method public java.util.List<com.android.xml.permission.PrivappPermissions> getPrivappPermissions();
-    method public java.util.List<com.android.xml.permission.SplitPermission> getSplitPermission();
-    method public java.util.List<com.android.xml.permission.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
-    method public java.util.List<com.android.xml.permission.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
-    method public java.util.List<com.android.xml.permission.UnavailableFeature> getUnavailableFeature();
+    method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation();
+    method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
+    method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
+    method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation();
+    method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink();
+    method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission();
+    method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
+    method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted();
+    method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp();
+    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
+    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
+    method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature();
+    method public java.util.List<com.android.xml.permission.configfile.Group> getGroup();
+    method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
+    method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions();
+    method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions();
+    method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission();
+    method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
+    method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
+    method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature();
   }
 
   public class PrivappPermissions {
     ctor public PrivappPermissions();
-    method public java.util.List<com.android.xml.permission.PrivappPermissions.DenyPermission> getDenyPermission();
-    method public java.util.List<com.android.xml.permission.PrivappPermissions.Permission> getPermission();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions.DenyPermission> getDenyPermission();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions.Permission> getPermission();
     method public String get_package();
     method public void set_package(String);
   }
@@ -200,7 +202,7 @@
 
   public class SplitPermission {
     ctor public SplitPermission();
-    method public java.util.List<com.android.xml.permission.SplitPermission.Library> getLibrary();
+    method public java.util.List<com.android.xml.permission.configfile.SplitPermission.Library> getLibrary();
     method public String getName();
     method public int getTargetSdk();
     method public void setName(String);
@@ -233,7 +235,7 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static com.android.xml.permission.Permissions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static com.android.xml.permission.configfile.Permissions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 347edc5..3c8794f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -271,7 +271,10 @@
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
         <permission name="android.permission.OBSERVE_APP_USAGE"/>
+        <permission name="android.permission.NETWORK_SCAN"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
+        <!-- Needed for test only -->
+        <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
         <permission name="android.permission.POWER_SAVER" />
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b0a7923..9b60dc3 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,17 @@
           package="com.android.networkstack"
           android:sharedUserId="android.uid.networkstack">
     <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <!-- Send latency broadcast as current user -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+
     <!-- Signature permission defined in NetworkStackStub -->
     <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
     <application>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
index f69e4b2..69a4da4 100644
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -20,15 +20,6 @@
           package="com.android.networkstack"
           android:versionCode="11"
           android:versionName="Q-initial">
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
-    <!-- Send latency broadcast as current user -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <application
         android:label="NetworkStack"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 3dd90ee..d2f3259 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -74,6 +74,7 @@
 import java.net.UnknownHostException;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -282,6 +283,7 @@
     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
+    private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
     // Endianness is not an issue for this constant because the APF interpreter always operates in
     // network byte order.
@@ -881,10 +883,23 @@
 
         protected final TcpKeepaliveAckData mPacket;
         protected final byte[] mSrcDstAddr;
+        protected final byte[] mPortSeqAckFingerprint;
 
         TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
             mPacket = packet;
             mSrcDstAddr = srcDstAddr;
+            mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
+                    mPacket.dstPort, mPacket.seq, mPacket.ack);
+        }
+
+        static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
+            final ByteBuffer fp = ByteBuffer.allocate(12);
+            fp.order(ByteOrder.BIG_ENDIAN);
+            fp.putShort((short) srcPort);
+            fp.putShort((short) dstPort);
+            fp.putInt(seq);
+            fp.putInt(ack);
+            return fp.array();
         }
 
         static byte[] concatArrays(final byte[]... arr) {
@@ -919,10 +934,6 @@
 
     private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
         private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
-        private static final int IPV4_TCP_SRC_PORT_OFFSET = 0;
-        private static final int IPV4_TCP_DST_PORT_OFFSET = 2;
-        private static final int IPV4_TCP_SEQ_OFFSET = 4;
-        private static final int IPV4_TCP_ACK_OFFSET = 8;
 
         TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
             this(new TcpKeepaliveAckData(sentKeepalivePacket));
@@ -934,12 +945,12 @@
         @Override
         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
             final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
-            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
-            gen.addJumpIfR0NotEquals(IPPROTO_TCP, nextFilterLabel);
+
             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
             gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
 
-            // Pass the packet if it's not zero-sized :
+            // Skip to the next filter if it's not zero-sized :
+            // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
             // Load the IP header size into R1
             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
             // Load the TCP header size into R0 (it's indexed by R1)
@@ -947,27 +958,18 @@
             // Size offset is in the top nibble, but it must be multiplied by 4, and the two
             // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
             gen.addRightShift(2);
-            // R0 += R1 -> R0 contains TCP + IP headers lenght
+            // R0 += R1 -> R0 contains TCP + IP headers length
             gen.addAddR1();
-            // Add the Ethernet header length to R0.
-            gen.addLoadImmediate(Register.R1, ETH_HEADER_LEN);
-            gen.addAddR1();
-            // Compare total length of headers to the size of the packet.
-            gen.addLoadFromMemory(Register.R1, gen.PACKET_SIZE_MEMORY_SLOT);
+            // Load IPv4 total length
+            gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
             gen.addNeg(Register.R0);
             gen.addAddR1();
             gen.addJumpIfR0NotEquals(0, nextFilterLabel);
-
             // Add IPv4 header length
             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addLoad16Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_SRC_PORT_OFFSET);
-            gen.addJumpIfR0NotEquals(mPacket.srcPort, nextFilterLabel);
-            gen.addLoad16Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_DST_PORT_OFFSET);
-            gen.addJumpIfR0NotEquals(mPacket.dstPort, nextFilterLabel);
-            gen.addLoad32Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_SEQ_OFFSET);
-            gen.addJumpIfR0NotEquals(mPacket.seq, nextFilterLabel);
-            gen.addLoad32Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_ACK_OFFSET);
-            gen.addJumpIfR0NotEquals(mPacket.ack, nextFilterLabel);
+            gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
+            gen.addAddR1();
+            gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
 
             maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
             gen.addJump(mCountAndDropLabel);
@@ -1169,9 +1171,10 @@
                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
             }
 
-            // If any keepalive filters,
-            generateKeepaliveFilter(gen);
+            // If any keepalive filter matches, drop
+            generateV4KeepaliveFilters(gen);
 
+            // Otherwise, this is an IPv4 unicast, pass
             // If L2 broadcast packet, drop.
             // TODO: can we invert this condition to fall through to the common pass case below?
             maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
@@ -1180,7 +1183,7 @@
             maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
             gen.addJump(mCountAndDropLabel);
         } else {
-            generateKeepaliveFilter(gen);
+            generateV4KeepaliveFilters(gen);
         }
 
         // Otherwise, pass
@@ -1188,12 +1191,25 @@
         gen.addJump(mCountAndPassLabel);
     }
 
-    private void generateKeepaliveFilter(ApfGenerator gen) throws IllegalInstructionException {
+    private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+        final String skipV4KeepaliveFilter = "skip_v4_keepalive_filter";
+        final boolean haveV4KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
+                ack -> ack instanceof TcpKeepaliveAckV4);
+
+        // If no keepalive acks
+        if (!haveV4KeepaliveAcks) return;
+
+        // If not tcp, skip keepalive filters
+        gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+        gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV4KeepaliveFilter);
+
         // Drop IPv4 Keepalive acks
         for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
             final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
             if (ack instanceof TcpKeepaliveAckV4) ack.generateFilterLocked(gen);
         }
+
+        gen.defineLabel(skipV4KeepaliveFilter);
     }
 
     /**
@@ -1244,11 +1260,14 @@
             maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
             gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
+            // If any keepalive filter matches, drop
+            generateV6KeepaliveFilters(gen);
             // Not multicast. Pass.
             maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
             gen.addJump(mCountAndPassLabel);
             gen.defineLabel(skipIPv6MulticastFilterLabel);
         } else {
+            generateV6KeepaliveFilters(gen);
             // If not ICMPv6, pass.
             maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
@@ -1272,12 +1291,27 @@
         maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
         gen.addJump(mCountAndDropLabel);
         gen.defineLabel(skipUnsolicitedMulticastNALabel);
+    }
+
+    private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+        final String skipV6KeepaliveFilter = "skip_v6_keepalive_filter";
+        final boolean haveV6KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
+                ack -> ack instanceof TcpKeepaliveAckV6);
+
+        // If no keepalive acks
+        if (!haveV6KeepaliveAcks) return;
+
+        // If not tcp, skip keepalive filters
+        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
+        gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV6KeepaliveFilter);
 
         // Drop IPv6 Keepalive acks
         for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
             final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
             if (ack instanceof TcpKeepaliveAckV6) ack.generateFilterLocked(gen);
         }
+
+        gen.defineLabel(skipV6KeepaliveFilter);
     }
 
     /**
@@ -1294,6 +1328,8 @@
      * <li>Pass all non-IPv4 and non-IPv6 packets,
      * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
      * <li>Drop IPv6 ICMPv6 RSs.
+     * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
+     * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
      *     insertion of RA filters here, or if there aren't any, just passes the packets.
      * </ul>
@@ -1737,7 +1773,7 @@
         }
         pw.decreaseIndent();
 
-        pw.println("Keepalive filter:");
+        pw.println("Keepalive filters:");
         pw.increaseIndent();
         for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
             final TcpKeepaliveAck keepaliveAck = mKeepaliveAcks.valueAt(i);
diff --git a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
index 809327a..44ce2db 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
@@ -108,7 +108,7 @@
         private String mLabel;
         // When mOpcode == Opcodes.JNEBS:
         private byte[] mCompareBytes;
-        // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}.
+        // Offset in bytes from the beginning of this program. Set by {@link ApfGenerator#generate}.
         int offset;
 
         Instruction(Opcodes opcode, Register register) {
@@ -431,7 +431,7 @@
 
     /**
      * Add an instruction to the end of the program to load the byte at offset {@code offset}
-     * bytes from the begining of the packet into {@code register}.
+     * bytes from the beginning of the packet into {@code register}.
      */
     public ApfGenerator addLoad8(Register register, int offset) {
         Instruction instruction = new Instruction(Opcodes.LDB, register);
@@ -442,7 +442,7 @@
 
     /**
      * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
-     * bytes from the begining of the packet into {@code register}.
+     * bytes from the beginning of the packet into {@code register}.
      */
     public ApfGenerator addLoad16(Register register, int offset) {
         Instruction instruction = new Instruction(Opcodes.LDH, register);
@@ -453,7 +453,7 @@
 
     /**
      * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
-     * bytes from the begining of the packet into {@code register}.
+     * bytes from the beginning of the packet into {@code register}.
      */
     public ApfGenerator addLoad32(Register register, int offset) {
         Instruction instruction = new Instruction(Opcodes.LDW, register);
@@ -464,7 +464,7 @@
 
     /**
      * Add an instruction to the end of the program to load a byte from the packet into
-     * {@code register}. The offset of the loaded byte from the begining of the packet is
+     * {@code register}. The offset of the loaded byte from the beginning of the packet is
      * the sum of {@code offset} and the value in register R1.
      */
     public ApfGenerator addLoad8Indexed(Register register, int offset) {
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 481dbda..fedb8d1 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -17,10 +17,13 @@
 package android.net.util;
 
 import android.annotation.NonNull;
+import android.util.SparseArray;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.List;
+import java.util.function.Predicate;
+
 
 /**
  * Collection of utilities for the network stack.
@@ -65,4 +68,17 @@
         }
         return array;
     }
+
+    /**
+     * @return True if there exists at least one element in the sparse array for which
+     * condition {@code predicate}
+     */
+    public static <T> boolean any(SparseArray<T> array, Predicate<T> predicate) {
+        for (int i = 0; i < array.size(); ++i) {
+            if (predicate.test(array.valueAt(i))) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index aadf99e..0535af3 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -45,6 +45,8 @@
         "libcrypto",
         "libcutils",
         "libdexfile",
+        "ld-android",
+        "libdl_android",
         "libhidl-gen-utils",
         "libhidlbase",
         "libhidltransport",
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index 88a05d5..a0e508f 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -1006,7 +1006,7 @@
 
     private static final int IPV4_HEADER_LEN = 20;
     private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
-    private static final int IPV4_TOTAL_LENGTH_OFFSET  = ETH_HEADER_LEN + 2;
+    private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
     private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
new file mode 100644
index 0000000..9420954
--- /dev/null
+++ b/packages/PackageInstaller/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+
+android_app {
+    name: "PackageInstaller",
+
+    srcs: ["src/**/*.java"],
+
+    certificate: "platform",
+    privileged: true,
+    platform_apis: true,
+
+    static_libs: [
+        "xz-java",
+        "androidx.leanback_leanback",
+    ],
+}
diff --git a/packages/PackageInstaller/Android.mk b/packages/PackageInstaller/Android.mk
deleted file mode 100644
index ab5483c..0000000
--- a/packages/PackageInstaller/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := PackageInstaller
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := xz-java
-LOCAL_STATIC_ANDROID_LIBRARIES := androidx.leanback_leanback
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d6e61eb..d39646b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -125,6 +125,8 @@
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <!-- Shell only holds android.permission.NETWORK_SCAN in order to to enable CTS testing -->
+    <uses-permission android:name="android.permission.NETWORK_SCAN" />
     <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
     <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
     <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
@@ -178,6 +180,8 @@
 
     <!-- Permission needed to run network tests in CTS -->
     <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
+    <!-- Permission needed to test tcp keepalive offload. -->
+    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
 
     <!-- Permission needed to run keyguard manager tests in CTS -->
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane.xml b/packages/SystemUI/res/drawable/ic_airplane.xml
similarity index 76%
rename from packages/SystemUI/res/drawable/ic_signal_airplane.xml
rename to packages/SystemUI/res/drawable/ic_airplane.xml
index f708ed9..166d415 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_airplane.xml
@@ -15,12 +15,11 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
+        android:width="18dp"
+        android:height="18dp"
         android:viewportWidth="24"
         android:viewportHeight="24">
-
-<path
-    android:fillColor="#FFFFFF"
-    android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_alarm.xml b/packages/SystemUI/res/drawable/ic_alarm.xml
new file mode 100644
index 0000000..1c1adcd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_alarm.xml
@@ -0,0 +1,25 @@
+<!--
+     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:height="17dp"
+    android:width="17dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_alarm_dim.xml b/packages/SystemUI/res/drawable/ic_alarm_dim.xml
new file mode 100644
index 0000000..37ab873
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_alarm_dim.xml
@@ -0,0 +1,26 @@
+<!--
+     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:height="17dp"
+    android:width="17dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillAlpha="0.3"
+        android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml
new file mode 100644
index 0000000..125082c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml
@@ -0,0 +1,30 @@
+<!--
+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:width="17dp"
+    android:height="17dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M19,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_cast.xml b/packages/SystemUI/res/drawable/ic_cast.xml
new file mode 100644
index 0000000..a2c2eb2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cast.xml
@@ -0,0 +1,24 @@
+<!--
+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:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_cast_connected.xml b/packages/SystemUI/res/drawable/ic_cast_connected.xml
new file mode 100644
index 0000000..995fd49
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cast_connected.xml
@@ -0,0 +1,26 @@
+<!--
+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:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M1,18v3h3C4,19.34 2.66,18 1,18zM1,14v2c2.76,0 5,2.24 5,5h2C8,17.13 4.87,14 1,14zM19,7H5v1.63c3.96,1.28 7.09,4.41 8.37,8.37H19V7zM1,10v2c4.97,0 9,4.03 9,9h2C12,14.92 7.07,10 1,10zM21,3H3C1.9,3 1,3.9 1,5v3h2V5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2V5C23,3.9 22.1,3 21,3"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
index 0f027ee..cc3f539 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver.xml
@@ -14,15 +14,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="18dp"
+    android:height="18dp"
     android:viewportWidth="24.0"
-    android:viewportHeight="24.0"
-    android:tint="?android:attr/colorControlNormal">
+    android:viewportHeight="24.0">
     <path
-        android:pathData="M16,12c0,0.55 -0.45,1 -1,1h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2L9,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2L11,9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1zM17.69,16.87a7.437,7.437 0,0 1,-5.93 2.63c-3.82,-0.12 -7.03,-3.25 -7.25,-7.07 -0.21,-3.84 2.48,-7.1 6.07,-7.79 0.24,-0.04 0.42,-0.24 0.42,-0.48L11,2.62c0,-0.3 -0.27,-0.55 -0.57,-0.5A10.02,10.02 0,0 0,2.09 13.4c0.59,4.4 4.16,7.94 8.56,8.52a9.99,9.99 0,0 0,9.14 -3.65,0.5 0.5,0 0,0 -0.15,-0.74l-1.32,-0.76a0.469,0.469 0,0 0,-0.63 0.1z"
+        android:pathData="M11,8v3L8,11v2h3v3h2v-3h3v-2h-3L13,8zM13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92L11,2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"
         android:fillColor="#FFFFFFFF"/>
-    <path
-        android:pathData="M13.41,4.64a0.493,0.493 0,0 1,-0.41 -0.48L13,2.62c0,-0.3 0.27,-0.55 0.57,-0.5C18.35,2.88 22,7.01 22,12c0,1.23 -0.23,2.41 -0.64,3.5 -0.11,0.28 -0.45,0.4 -0.72,0.24l-1.33,-0.77a0.484,0.484 0,0 1,-0.21 -0.59c0.25,-0.75 0.39,-1.55 0.39,-2.38 0.01,-3.65 -2.62,-6.69 -6.08,-7.36z"
-        android:fillColor="#54FFFFFF" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
index 29e6c91..d8e9bc4 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
@@ -17,9 +17,8 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M18.32,16.75l1.32,0.76c0.26,0.15 0.34,0.51 0.15,0.74 -2.09,2.6 -5.44,4.14 -9.14,3.65 -4.4,-0.58 -7.96,-4.12 -8.56,-8.52C1.34,7.8 5.21,2.95 10.43,2.12c0.3,-0.05 0.57,0.2 0.57,0.5v1.53c0,0.24 -0.18,0.44 -0.41,0.49 -3.6,0.69 -6.29,3.95 -6.07,7.79 0.21,3.82 3.43,6.95 7.25,7.07 2.37,0.08 4.51,-0.96 5.93,-2.63a0.48,0.48 0,0 1,0.62 -0.12zM19.5,12c0,0.83 -0.14,1.63 -0.39,2.38 -0.08,0.23 0.01,0.47 0.21,0.59l1.33,0.77c0.26,0.15 0.61,0.04 0.72,-0.24 0.4,-1.09 0.63,-2.27 0.63,-3.5 0,-4.99 -3.65,-9.12 -8.43,-9.88 -0.3,-0.04 -0.57,0.2 -0.57,0.5v1.53c0,0.24 0.18,0.44 0.41,0.48 3.46,0.68 6.09,3.72 6.09,7.37z" />
+        android:pathData="M13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92V2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd.xml b/packages/SystemUI/res/drawable/ic_dnd.xml
index 09a6aab..b361169 100644
--- a/packages/SystemUI/res/drawable/ic_dnd.xml
+++ b/packages/SystemUI/res/drawable/ic_dnd.xml
@@ -14,17 +14,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
+    android:height="17dp"
+    android:width="17dp"
     android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:width="24dp"
-    android:tint="?android:attr/colorControlNormal">
+    android:viewportWidth="24.0" >
 
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M7,11h10v2h-10z"/>
-
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM7,11h10v2L7,13z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset.xml b/packages/SystemUI/res/drawable/ic_headset.xml
index 27efe80..797a80a 100644
--- a/packages/SystemUI/res/drawable/ic_headset.xml
+++ b/packages/SystemUI/res/drawable/ic_headset.xml
@@ -13,19 +13,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="17.0dp"
-        android:height="17.0dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
-        <group
-            android:translateY="-1">
-            <path
-                android:fillColor="#FFFFFFFF"
-                android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4H19M7,15v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7M12,2c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7C21,6.03 16.97,2 12,2L12,2z"/>
-        </group>
-    </vector>
-</inset>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17.0dp"
+    android:height="17.0dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4h2M7,15v4H6c-0.55,0 -1,-0.45 -1,-1v-3h2m5,-13c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03,-9 -9,-9z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset_mic.xml b/packages/SystemUI/res/drawable/ic_headset_mic.xml
index 1260e0f..b3f006d 100644
--- a/packages/SystemUI/res/drawable/ic_headset_mic.xml
+++ b/packages/SystemUI/res/drawable/ic_headset_mic.xml
@@ -13,16 +13,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="17.0dp"
-        android:height="17.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-1.71C5,6.45 7.96,3.11 11.79,3C15.76,2.89 19,6.06 19,10v2h-4v8h4v1h-6v2h6c1.1,0 2,-0.9 2,-2V10C21,5.03 16.97,1 12,1zM7,14v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7zM19,18h-2v-4h2V18z"/>
-    </vector>
-</inset>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17.0dp"
+    android:height="17.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-1.71C5,6.45 7.96,3.11 11.79,3C15.76,2.89 19,6.06 19,10v2h-4v8h4v1h-6v2h6c1.1,0 2,-0.9 2,-2V10C21,5.03 16.97,1 12,1zM7,14v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7zM19,18h-2v-4h2V18z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot.xml b/packages/SystemUI/res/drawable/ic_hotspot.xml
index 8450bf6..b6fa798 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot.xml
@@ -15,14 +15,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
+    android:width="18dp"
+    android:height="18dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
-    <group
-        android:translateY="-0.32">
-        <path
-            android:pathData="M12,11c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,13a6,6 0,0 0,-6.75 -5.95c-2.62,0.32 -4.78,2.41 -5.18,5.02 -0.32,2.14 0.49,4.11 1.92,5.39 0.48,0.43 1.24,0.33 1.56,-0.23 0.24,-0.42 0.14,-0.94 -0.22,-1.26a3.99,3.99 0,0 1,-1.22 -3.94,3.954 3.954,0 0,1 2.9,-2.91A4.007,4.007 0,0 1,16 13c0,1.18 -0.51,2.23 -1.33,2.96 -0.36,0.33 -0.47,0.85 -0.23,1.27 0.31,0.54 1.04,0.69 1.5,0.28A5.97,5.97 0,0 0,18 13zM10.83,3.07c-4.62,0.52 -8.35,4.33 -8.78,8.96a9.966,9.966 0,0 0,4.02 9.01c0.48,0.35 1.16,0.2 1.46,-0.31 0.25,-0.43 0.14,-0.99 -0.26,-1.29 -2.28,-1.69 -3.65,-4.55 -3.16,-7.7 0.54,-3.5 3.46,-6.29 6.98,-6.68C15.91,4.51 20,8.28 20,13c0,2.65 -1.29,4.98 -3.27,6.44 -0.4,0.3 -0.51,0.85 -0.26,1.29 0.3,0.52 0.98,0.66 1.46,0.31A9.96,9.96 0,0 0,22 13c0,-5.91 -5.13,-10.62 -11.17,-9.93z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,7c-3.31,0 -6,2.69 -6,6 0,1.66 0.68,3.15 1.76,4.24l1.42,-1.42C8.45,15.1 8,14.11 8,13c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,1.11 -0.45,2.1 -1.18,2.82l1.42,1.42C17.32,16.15 18,14.66 18,13c0,-3.31 -2.69,-6 -6,-6zM12,3C6.48,3 2,7.48 2,13c0,2.76 1.12,5.26 2.93,7.07l1.41,-1.41C4.9,17.21 4,15.21 4,13c0,-4.42 3.58,-8 8,-8s8,3.58 8,8c0,2.21 -0.9,4.2 -2.35,5.65l1.41,1.41C20.88,18.26 22,15.76 22,13c0,-5.52 -4.48,-10 -10,-10zM12,11c-1.1,0 -2,0.9 -2,2 0,0.55 0.23,1.05 0.59,1.41 0.36,0.36 0.86,0.59 1.41,0.59s1.05,-0.23 1.41,-0.59c0.36,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2z" />
+
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml b/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
deleted file mode 100644
index 7641998..0000000
--- a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 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="root"
-    android:height="48dp"
-    android:width="48dp"
-    android:viewportHeight="48"
-    android:viewportWidth="48" >
-    <group
-        android:name="ic_hotspot"
-        android:translateX="23.97354"
-        android:translateY="24.26306" >
-        <group
-            android:name="ic_hotspot_pivot"
-            android:translateX="-23.21545"
-            android:translateY="-18.86649" >
-            <clip-path
-                android:name="mask"
-                android:pathData="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 43.1884765625,43.515335083 43.1884765625,43.515335083 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -42.9885101318,-43.0112609863 -42.9885101318,-43.0112609863 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 13.0984039307,13.025604248 13.0984039307,13.025604248 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 16.571762085,22.0471801758 16.571762085,22.0471801758 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z" />
-            <group
-                android:name="cross" >
-                <path
-                    android:name="cross_1"
-                    android:pathData="M 4.44044494629,2.24310302734 c 0.0,0.0 35.4000396729,35.3999633789 35.4000396729,35.3999633789 "
-                    android:strokeColor="#FFFFFFFF"
-                    android:strokeAlpha="1"
-                    android:strokeWidth="3.5"
-                    android:fillColor="#00000000" />
-            </group>
-            <group
-                android:name="hotspot"
-                android:translateX="23.481"
-                android:translateY="18.71151" >
-                <group
-                    android:name="circles"
-                    android:translateX="-0.23909"
-                    android:translateY="-0.10807" >
-                    <path
-                        android:name="circle_3"
-                        android:pathData="M 0.0843505859375,-2.93901062012 c -2.30102539062,0.0 -4.16702270508,1.86602783203 -4.16702270508,4.16702270508 c 0.0,2.29898071289 1.86599731445,4.16598510742 4.16702270508,4.16598510742 c 2.29998779297,0.0 4.16598510742,-1.86700439453 4.16598510742,-4.16598510742 c 0.0,-2.30099487305 -1.86599731445,-4.16702270508 -4.16598510742,-4.16702270508 Z M 11.1185302734,5.83390808105 c 0.0,0.0 0.0009765625,0.00100708007812 0.0009765625,0.00100708007812 c 0.14501953125,-0.356994628906 0.27099609375,-0.725006103516 0.382995605469,-1.09799194336 c 0.0570068359375,-0.195007324219 0.101013183594,-0.394989013672 0.149017333984,-0.595001220703 c 0.0690002441406,-0.281005859375 0.126983642578,-0.563995361328 0.175994873047,-0.851989746094 c 0.0270080566406,-0.169006347656 0.0559997558594,-0.337005615234 0.0759887695313,-0.509002685547 c 0.0580139160156,-0.468017578125 0.0970153808594,-0.942993164062 0.0970153808593,-1.4280090332 c 0.0,0.0 0.0,-0.00100708007812 0.0,-0.00100708007812 c 0.0,-5.03900146484 -3.11099243164,-9.3450012207 -7.5119934082,-11.1229858398 c -0.00601196289062,-0.00299072265625 -0.0130004882812,-0.0050048828125 -0.0190124511719,-0.00701904296875 c -0.686004638672,-0.275970458984 -1.39999389648,-0.492980957031 -2.14099121094,-0.638977050781 c -0.072998046875,-0.0150146484375 -0.149017333984,-0.02099609375 -0.222991943359,-0.0339965820313 c -0.302001953125,-0.0540161132812 -0.605010986328,-0.106018066406 -0.916015625,-0.136016845703 c -0.389984130859,-0.0390014648438 -0.786987304688,-0.0599975585938 -1.18899536133,-0.0599975585937 c -0.402008056641,0.0 -0.799011230469,0.02099609375 -1.19000244141,0.0599975585937 c -0.304992675781,0.0299987792969 -0.602996826172,0.0809936523438 -0.901000976563,0.132995605469 c -0.0790100097656,0.0150146484375 -0.160003662109,0.02099609375 -0.238006591797,0.0370178222656 c -0.368988037109,0.0719909667969 -0.730987548828,0.164001464844 -1.08700561523,0.269989013672 c -0.00299072265625,0.00100708007812 -0.0059814453125,0.00201416015625 -0.00900268554687,0.0020141601562 c -0.351989746094,0.10498046875 -0.694000244141,0.226989746094 -1.0309753418,0.361999511719 c -0.0110168457031,0.00399780273438 -0.0220031738281,0.00698852539062 -0.0320129394531,0.0119934082031 c -4.40200805664,1.77798461914 -7.51098632812,6.083984375 -7.5119934082,11.1229858398 c 0.0,0.00799560546875 0.00198364257812,0.0160217285156 0.0019836425781,0.0240173339844 c 0.00100708007812,0.475006103516 0.0380249023438,0.940002441406 0.0950012207032,1.39898681641 c 0.02001953125,0.175994873047 0.0490112304688,0.348999023438 0.0780029296875,0.523010253906 c 0.0469970703125,0.281982421875 0.105010986328,0.557983398438 0.171997070312,0.833984375 c 0.0480041503906,0.204010009766 0.093017578125,0.410003662109 0.152008056641,0.610015869141 c 0.110992431641,0.372009277344 0.238006591797,0.736999511719 0.382019042969,1.09298706055 c 0.0,0.0 0.0009765625,0.0 0.0009765625,0.0 c 1.00701904297,2.48400878906 2.81301879883,4.56100463867 5.11001586914,5.89501953125 c 0.0,0.0 2.01599121094,-3.48300170898 2.01599121094,-3.48300170898 c -2.03900146484,-1.18402099609 -3.5119934082,-3.22500610352 -3.89898681641,-5.63900756836 c 0.0,0.0 0.0009765625,-0.00100708007812 0.0009765625,-0.00100708007812 c -0.0220031738281,-0.130981445312 -0.0369873046875,-0.265991210938 -0.052978515625,-0.399993896484 c -0.0290222167969,-0.274993896484 -0.0570068359375,-0.552001953125 -0.0570068359375,-0.834991455078 c 0.0,0.0 0.0,-0.0190124511719 0.0,-0.0190124511719 c 0.0,-3.98999023438 2.92498779297,-7.28900146484 6.74398803711,-7.89199829102 c 0.0,0.0 0.0180053710938,0.0169982910156 0.0180053710938,0.0169982910156 c 0.404998779297,-0.0639953613281 0.81298828125,-0.125 1.23599243164,-0.125 c 0.0,0.0 0.00201416015625,0.0 0.00201416015624,0.0 c 0.0,0.0 0.00299072265625,0.0 0.00299072265626,0.0 c 0.423004150391,0.0 0.830017089844,0.0610046386719 1.23501586914,0.125 c 0.0,0.0 0.0169982910156,-0.0180053710938 0.0169982910156,-0.0180053710938 c 3.81997680664,0.60400390625 6.74499511719,3.90301513672 6.74499511719,7.89199829102 c 0.0,0.292999267578 -0.0280151367188,0.578002929688 -0.0589904785156,0.861999511719 c -0.0150146484375,0.132019042969 -0.0290222167969,0.264007568359 -0.051025390625,0.393005371094 c -0.385986328125,2.41500854492 -1.85897827148,4.45599365234 -3.89797973633,5.64001464844 c 0.0,0.0 2.01599121094,3.48300170898 2.01599121094,3.48300170898 c 2.29699707031,-1.33401489258 4.10299682617,-3.41101074219 5.11001586914,-5.89602661133 Z M 19.9300231934,2.95698547363 c 0.0059814453125,-0.0659790039062 0.0159912109375,-0.130981445312 0.02099609375,-0.196990966797 c 0.031982421875,-0.462005615234 0.0479736328125,-0.928009033203 0.0489807128906,-1.39700317383 c 0,0.0 0,-0.00997924804688 0,-0.00997924804687 c 0,0.0 0,-0.00100708007812 0,-0.00100708007813 c 0,-7.22500610352 -3.84399414062,-13.5360107422 -9.58599853516,-17.0500183105 c -1.06500244141,-0.652984619141 -2.19299316406,-1.20599365234 -3.37799072266,-1.65197753906 c -0.157989501953,-0.0599975585938 -0.317016601562,-0.118011474609 -0.476989746094,-0.174011230469 c -0.317016601562,-0.110992431641 -0.634002685547,-0.218994140625 -0.9580078125,-0.31298828125 c -0.470001220703,-0.139007568359 -0.944000244141,-0.264007568359 -1.4280090332,-0.368011474609 c -0.186004638672,-0.0390014648438 -0.376983642578,-0.0669860839844 -0.565002441406,-0.101013183594 c -0.414001464844,-0.0759887695312 -0.832000732422,-0.140991210938 -1.25500488281,-0.190979003906 c -0.184997558594,-0.0220031738281 -0.369995117188,-0.0429992675781 -0.556976318359,-0.0599975585937 c -0.592010498047,-0.0530090332031 -1.18801879883,-0.0899963378906 -1.79602050781,-0.0899963378907 c -0.605987548828,0.0 -1.20300292969,0.0369873046875 -1.79598999023,0.0899963378907 c -0.186004638672,0.0169982910156 -0.371002197266,0.0379943847656 -0.555999755859,0.0599975585937 c -0.423004150391,0.0499877929688 -0.842010498047,0.114990234375 -1.25601196289,0.190979003906 c -0.18798828125,0.0350036621094 -0.377990722656,0.06201171875 -0.563995361328,0.101013183594 c -0.483001708984,0.10400390625 -0.959991455078,0.22900390625 -1.42999267578,0.368011474609 c -0.321990966797,0.093994140625 -0.638000488281,0.201995849609 -0.953002929688,0.311981201172 c -0.162994384766,0.0570068359375 -0.324005126953,0.115997314453 -0.484985351562,0.177001953125 c -1.18099975586,0.445007324219 -2.30599975586,0.997009277344 -3.36801147461,1.64700317383 c -0.00201416015625,0.00100708007812 -0.00399780273438,0.00201416015625 -0.0060119628907,0.0029907226562 c -5.74099731445,3.51400756836 -9.58499145508,9.82501220703 -9.58599853516,17.0500183105 c 0,0.0 0,0.00100708007812 0,0.00100708007813 c 0,0.0059814453125 0.00100708007812,0.0130004882812 0.0010070800781,0.0199890136719 c 0.0,0.466003417969 0.0169982910156,0.928009033203 0.0490112304688,1.38598632812 c 0.0050048828125,0.0690002441406 0.0159912109375,0.136016845703 0.02099609375,0.206024169922 c 0.031982421875,0.401000976562 0.0719909667969,0.799987792969 0.127990722656,1.19400024414 c 0.00201416015625,0.0189819335938 0.00701904296875,0.0369873046875 0.010009765625,0.0569763183594 c 0.888000488281,6.17202758789 4.59799194336,11.4250183105 9.7799987793,14.4309997559 c 0.0,0.0 2.00198364258,-3.458984375 2.00198364258,-3.458984375 c -2.58599853516,-1.5 -4.708984375,-3.70401000977 -6.11697387695,-6.34399414063 c 0.0,0.0 0.0169982910156,-0.0180053710938 0.0169982910156,-0.0180053710938 c -0.890014648438,-1.67098999023 -1.50601196289,-3.5110168457 -1.76000976562,-5.46499633789 c -0.00698852539062,-0.0500183105469 -0.010009765625,-0.102020263672 -0.0159912109375,-0.152008056641 c -0.0330200195312,-0.273010253906 -0.0610046386719,-0.545989990234 -0.0800170898437,-0.821990966797 c -0.0220031738281,-0.343017578125 -0.0350036621094,-0.68701171875 -0.0350036621094,-1.03500366211 c 0,-6.53701782227 3.92599487305,-12.1480102539 9.54299926758,-14.6310119629 c 0.157012939453,-0.0700073242188 0.313995361328,-0.135986328125 0.472015380859,-0.199981689453 c 0.373992919922,-0.151000976562 0.751983642578,-0.294006347656 1.13900756836,-0.417022705078 c 0.108978271484,-0.0350036621094 0.221984863281,-0.0619812011719 0.332000732422,-0.0950012207031 c 0.349975585938,-0.102996826172 0.705993652344,-0.194976806641 1.06597900391,-0.273986816406 c 0.114013671875,-0.0249938964844 0.227996826172,-0.052001953125 0.342010498047,-0.0750122070313 c 0.440002441406,-0.0869750976562 0.885986328125,-0.154998779297 1.33700561523,-0.203979492188 c 0.10400390625,-0.0120239257812 0.209991455078,-0.02001953125 0.315002441406,-0.0299987792969 c 0.47998046875,-0.0429992675781 0.963989257812,-0.072998046875 1.45397949219,-0.072998046875 c 0.492004394531,0.0 0.975006103516,0.0299987792969 1.45401000977,0.072998046875 c 0.105987548828,0.00997924804688 0.212005615234,0.0179748535156 0.316986083984,0.0299987792969 c 0.450012207031,0.0489807128906 0.89501953125,0.117004394531 1.33502197266,0.203002929688 c 0.115997314453,0.0239868164062 0.22998046875,0.0509948730469 0.345001220703,0.0769958496094 c 0.358001708984,0.0780029296875 0.710998535156,0.169982910156 1.06097412109,0.272003173828 c 0.111022949219,0.0329895019531 0.226013183594,0.0609741210938 0.336029052734,0.0969848632813 c 0.385986328125,0.123016357422 0.761993408203,0.265014648438 1.13497924805,0.415008544922 c 0.160003662109,0.0650024414062 0.319000244141,0.131988525391 0.477020263672,0.201995849609 c 5.61599731445,2.48400878906 9.53997802734,8.09399414062 9.53997802734,14.6310119629 c 0,0.346984863281 -0.0130004882812,0.690979003906 -0.0350036621094,1.03399658203 c -0.0179748535156,0.274993896484 -0.0469970703125,0.548004150391 -0.0789794921875,0.819000244141 c -0.00601196289062,0.052001953125 -0.010009765625,0.10498046875 -0.0160217285156,0.154998779297 c -0.252990722656,1.95498657227 -0.871002197266,3.79400634766 -1.75997924805,5.46499633789 c 0.0,0.0 0.0169982910156,0.0180053710938 0.0169982910156,0.0180053710938 c -1.40802001953,2.63998413086 -3.53100585938,4.84399414062 -6.11700439453,6.34399414063 c 0.0,0.0 2.00198364258,3.458984375 2.00198364258,3.458984375 c 5.18402099609,-3.00698852539 8.89501953125,-8.26300048828 9.78100585938,-14.4379882813 c 0.00201416015625,-0.0169982910156 0.00601196289062,-0.0320129394531 0.0079956054688,-0.0490112304688 c 0.0570068359375,-0.39697265625 0.0970153808594,-0.798980712891 0.129028320312,-1.20300292969 Z"
-                        android:fillColor="#FFFFFFFF"
-                        android:fillAlpha="1" />
-                </group>
-            </group>
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location.xml b/packages/SystemUI/res/drawable/ic_location.xml
new file mode 100644
index 0000000..50ba523
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2014 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:width="17dp"
+    android:height="17dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
deleted file mode 100644
index dd124b7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-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:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24"
-        android:tint="?android:attr/colorControlNormal">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M 5 10.5 C 5.82842712475 10.5 6.5 11.1715728753 6.5 12 C 6.5 12.8284271247 5.82842712475 13.5 5 13.5 C 4.17157287525 13.5 3.5 12.8284271247 3.5 12 C 3.5 11.1715728753 4.17157287525 10.5 5 10.5 Z" />
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M 19 10.5 C 19.8284271247 10.5 20.5 11.1715728753 20.5 12 C 20.5 12.8284271247 19.8284271247 13.5 19 13.5 C 18.1715728753 13.5 17.5 12.8284271247 17.5 12 C 17.5 11.1715728753 18.1715728753 10.5 19 10.5 Z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 220c63c..1c86706 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -14,13 +14,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24"
-        android:tint="?android:attr/colorControlNormal">
-
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-</vector>
+        android:fillColor="@android:color/white"
+        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
deleted file mode 100644
index 9e57577..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-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:width="64dp"
-    android:height="64dp"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:pathData="M1,18v2c0,0.55 0.45,1 1,1h2c0,-1.66 -1.34,-3 -3,-3zM0.97,15.06c-0.01,0.51 0.35,0.93 0.85,1.02 2.08,0.36 3.74,2 4.1,4.08 0.09,0.48 0.5,0.84 0.99,0.84 0.61,0 1.09,-0.54 1,-1.14a6.996,6.996 0,0 0,-5.8 -5.78c-0.59,-0.09 -1.12,0.38 -1.14,0.98zM0.97,11.03c-0.01,0.52 0.37,0.96 0.88,1.01 4.26,0.43 7.68,3.82 8.1,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.52,-5.21 -4.66,-9.34 -9.87,-9.85 -0.57,-0.05 -1.08,0.4 -1.1,0.98zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z"
-        android:fillColor="#FFFFFFFF" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 3dda87c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-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:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M1,18v2c0,0.55 0.45,1 1,1h2c0,-1.66 -1.34,-3 -3,-3zM0.97,15.06c-0.01,0.51 0.35,0.93 0.85,1.02 2.08,0.36 3.74,2 4.1,4.08 0.09,0.48 0.5,0.84 0.99,0.84 0.61,0 1.09,-0.54 1,-1.14a6.996,6.996 0,0 0,-5.8 -5.78c-0.59,-0.09 -1.12,0.38 -1.14,0.98zM19,7L5,7v1.63c3.96,1.28 7.09,4.41 8.37,8.37L19,17L19,7zM0.97,11.03c-0.01,0.52 0.37,0.96 0.88,1.01 4.26,0.43 7.68,3.82 8.1,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.52,-5.21 -4.66,-9.34 -9.87,-9.85 -0.57,-0.05 -1.08,0.4 -1.1,0.98zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm.xml b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
index 996e488..771b466 100644
--- a/packages/SystemUI/res/drawable/ic_volume_alarm.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
@@ -14,14 +14,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24.0dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:width="24.0dp"
-    android:tint="?android:attr/colorControlNormal">
-
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
     <path
         android:fillColor="#FFFFFF"
-        android:pathData="M2.7,6.5c-0.4,-0.4 -0.3,-1 0.1,-1.4l3,-2.6c0.4,-0.4 1,-0.3 1.4,0.1C7.6,3 7.5,3.7 7.1,4l-3,2.6C3.6,7 3,6.9 2.7,6.5zM21.3,5.1l-3.1,-2.6c-0.4,-0.4 -0.99,-0.31 -1.4,0.1c-0.4,0.4 -0.3,1 0.1,1.4L20,6.6c0.41,0.37 1,0.3 1.4,-0.1C21.73,6.12 21.7,5.4 21.3,5.1zM21,13c0,5 -4,9 -9,9s-9,-4 -9,-9s4,-9 9,-9S21,8 21,13zM19.1,13c0,-3.9 -3.2,-7.1 -7.1,-7.1S4.9,9.1 4.9,13s3.2,7.1 7.1,7.1S19.1,16.9 19.1,13zM11.75,8C11.34,8 11,8.34 11,8.75V14l4.14,2.48c0.34,0.21 0.77,0.1 0.98,-0.24s0.09,-0.79 -0.25,-0.99l-3.37,-2v-4.5C12.5,8.34 12.16,8 11.75,8z"/>
+        android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
index 02fb1e7..18e2736 100644
--- a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
@@ -22,6 +22,6 @@
 
     <path
         android:fillColor="#FFFFFF"
-        android:pathData="M21.35,6.49c-0.35,0.42 -0.98,0.47 -1.4,0.12l-3.07,-2.57a1,1 0,1 1,1.29 -1.53l3.07,2.57c0.42,0.35 0.47,0.98 0.11,1.41zM20.72,20.09a0.9,0.9 0,0 1,0 1.27,0.9 0.9,0 0,1 -1.27,0l-1.57,-1.57A8.875,8.875 0,0 1,12 22c-4.98,0 -9,-4.03 -9,-9 0,-2.25 0.83,-4.31 2.2,-5.89l-0.8,-0.8 -0.41,0.35a1,1 0,0 1,-1.35 -0.06,1 1,0 0,1 0.07,-1.47l0.27,-0.23 -0.7,-0.7a0.9,0.9 0,0 1,0 -1.27c0.35,-0.35 0.93,-0.35 1.28,0l17.16,17.16zM16.54,18.45L6.55,8.46A7.041,7.041 0,0 0,4.9 13c0,3.91 3.19,7.1 7.1,7.1 1.73,0 3.31,-0.62 4.54,-1.65zM7.17,3.98A0.997,0.997 0,1 0,5.9 2.44l-0.16,0.13 1.42,1.42 0.01,-0.01zM12,4c-1.41,0 -2.73,0.33 -3.92,0.91l1.45,1.45c0.77,-0.29 1.6,-0.46 2.47,-0.46 3.91,0 7.1,3.18 7.1,7.1 0,0.87 -0.17,1.7 -0.45,2.47l1.44,1.44c0.58,-1.18 0.91,-2.5 0.91,-3.91a9,9 0,0 0,-9 -9z"/>
+        android:pathData="M16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM9.35,6.52C10.17,6.19 11.06,6 12,6c3.86,0 7,3.14 7,7 0,0.94 -0.19,1.83 -0.52,2.65l1.5,1.5C20.63,15.91 21,14.5 21,13c0,-4.97 -4.03,-9 -9,-9 -1.5,0 -2.91,0.37 -4.15,1.02l1.5,1.5zM17.42,17.42L7.58,7.58 6.16,6.16l-0.72,-0.72 -1.42,-1.42 -1.21,-1.21 -1.42,1.41L2.48,5.3l-0.42,0.35 1.28,1.54 0.56,-0.47 0.9,0.9C3.67,9.12 3,10.98 3,13c0,4.97 4.03,9 9,9 2.02,0 3.88,-0.67 5.38,-1.79l2.4,2.4 1.41,-1.41 -2.35,-2.35 -1.42,-1.43zM12,20c-3.86,0 -7,-3.14 -7,-7 0,-1.46 0.46,-2.82 1.23,-3.94l9.71,9.71C14.82,19.54 13.46,20 12,20zM7.94,3.35L6.66,1.81l-1.1,0.92 1.42,1.42z"/>
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
index aa13f1e..314e06c 100644
--- a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
@@ -14,11 +14,10 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
+    android:height="19dp"
+    android:width="19dp"
     android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:width="24dp"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="24.0">
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml b/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
index 2655bcd..9577b0b 100644
--- a/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
@@ -16,16 +16,5 @@
 ** limitations under the License.
 */
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="17.25dp"
-    android:height="18dp"
-    android:viewportWidth="19.65"
-    android:viewportHeight="20.5">
-    <group
-        android:translateX="1.3"
-        android:translateY="1.7">
-        <path
-            android:pathData="M16.01,9.87l-6.24,-3.9v-4.7C9.77,0.57 9.21,0 8.5,0S7.23,0.57 7.23,1.28v4.7L0.99,9.88c-0.37,0.23 -0.6,0.64 -0.6,1.08v0.41c0,0.29 0.29,0.5 0.55,0.41l6.27,-1.97v4.7l-1.37,1.02c-0.21,0.16 -0.34,0.41 -0.34,0.68v0.57c0,0.15 0.12,0.23 0.27,0.2 1.67,-0.47 1.12,-0.31 2.73,-0.78 1.03,0.3 1.7,0.49 2.72,0.78 0.15,0.03 0.27,-0.06 0.27,-0.2v-0.57c0,-0.27 -0.13,-0.52 -0.34,-0.68l-1.37,-1.02v-4.7l6.27,1.97c0.28,0.09 0.55,-0.12 0.55,-0.41v-0.41c0.01,-0.45 -0.23,-0.87 -0.59,-1.09z"
-            android:fillColor="#FFF"/>
-    </group>
-</vector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_airplane" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm.xml b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
index 0e9319c..b9bebec 100644
--- a/packages/SystemUI/res/drawable/stat_sys_alarm.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
@@ -1,35 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 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.
+ *
+ * Copyright 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.
 */
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="19.3"
-        android:viewportHeight="19.3">
-        <group
-            android:translateX="1.2"
-            android:translateY="1.2">
-            <path
-                android:pathData="M0.97,3.97c-0.32,-0.33 -0.24,-0.81 0.08,-1.13L3.47,0.74C3.79,0.42 4.28,0.5 4.6,0.82s0.24,0.89 -0.08,1.13L2.1,4.05c-0.4,0.32 -0.89,0.24 -1.13,-0.08zM15.97,2.84l-2.5,-2.1c-0.32,-0.32 -0.8,-0.25 -1.13,0.08 -0.32,0.32 -0.24,0.81 0.08,1.13l2.5,2.1c0.33,0.3 0.81,0.24 1.13,-0.08 0.27,-0.31 0.25,-0.89 -0.08,-1.13zM15.73,9.21c0,4.03 -3.23,7.26 -7.26,7.26s-7.26,-3.23 -7.26,-7.26 3.23,-7.26 7.26,-7.26 7.26,3.23 7.26,7.26zM14.2,9.21c0,-3.15 -2.58,-5.73 -5.73,-5.73S2.74,6.06 2.74,9.21s2.58,5.73 5.73,5.73 5.73,-2.59 5.73,-5.73zM8.27,5.18c-0.33,0 -0.6,0.27 -0.6,0.6v4.23l3.34,2c0.27,0.17 0.62,0.08 0.79,-0.19s0.07,-0.64 -0.2,-0.8L8.87,9.41L8.87,5.78c0,-0.33 -0.27,-0.6 -0.6,-0.6z"
-                android:fillColor="#FFF"/>
-        </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_alarm" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml b/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
index c8e2ac1..cf1119d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
@@ -15,18 +15,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-
-    <vector
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-        <path
-            android:fillColor="#4dffffff"
-            android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
-
-    </vector>
-
-</inset>
\ No newline at end of file
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_alarm_dim" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_cast.xml b/packages/SystemUI/res/drawable/stat_sys_cast.xml
index 5228085..de7ec9d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_cast.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_cast.xml
@@ -15,14 +15,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector android:width="17dp"
-            android:height="17dp"
-            android:viewportWidth="17.0"
-            android:viewportHeight="17.0">
-
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M0.71,12.75v1.42c0,0.39 0.32,0.71 0.71,0.71h1.42C2.83,13.7 1.88,12.75 0.71,12.75zM0.69,10.67c-0.01,0.36 0.25,0.66 0.6,0.72c1.47,0.26 2.65,1.42 2.9,2.89c0.06,0.34 0.35,0.6 0.7,0.6c0.43,0 0.77,-0.38 0.71,-0.81c-0.34,-2.11 -2,-3.76 -4.11,-4.09C1.08,9.91 0.7,10.24 0.69,10.67zM13.46,4.96H3.54v1.15c2.81,0.91 5.02,3.12 5.93,5.93h3.99V4.96zM0.69,7.81C0.68,8.18 0.95,8.49 1.31,8.53c3.02,0.3 5.44,2.71 5.74,5.72c0.04,0.35 0.34,0.62 0.7,0.62c0.42,0 0.75,-0.36 0.71,-0.78c-0.37,-3.69 -3.3,-6.62 -6.99,-6.98C1.06,7.08 0.7,7.4 0.69,7.81zM14.88,2.12H2.12c-0.78,0 -1.42,0.64 -1.42,1.42v2.12h1.42V3.54h12.75v9.92H9.92v1.42h4.96c0.78,0 1.42,-0.64 1.42,-1.42V3.54C16.29,2.76 15.65,2.12 14.88,2.12z" />
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_cast_connected" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
deleted file mode 100644
index 4dc0e4b..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="17.0"
-        android:viewportHeight="17.0">
-    <group
-        android:translateY="0.5"
-        android:translateX="0.5" >
-        <path
-            android:pathData="M8.84,8l2.62,-2.62c0.29,-0.29 0.29,-0.75 0,-1.04L8.33,1.22L8.31,1.2c-0.3,-0.28 -0.76,-0.26 -1.03,0.04c-0.13,0.13 -0.2,0.31 -0.2,0.5v4.51L4.24,3.4c-0.29,-0.29 -0.74,-0.29 -1.03,0s-0.29,0.74 0,1.03L6.78,8l-3.56,3.56c-0.29,0.29 -0.29,0.74 0,1.03s0.74,0.29 1.03,0l2.83,-2.83v4.51c0,0.4 0.33,0.73 0.73,0.73c0.18,0 0.36,-0.07 0.5,-0.2l0.03,-0.03l3.12,-3.12c0.29,-0.29 0.29,-0.75 0,-1.04L8.84,8zM8.47,6.37V3.36l1.5,1.5L8.47,6.37zM8.47,12.63V9.62l1.5,1.5L8.47,12.63z"
-            android:fillColor="#FFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
index c8a4440..8d9e561 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
@@ -1,31 +1,17 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 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.
-*/
+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:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="18.0"
-        android:viewportHeight="18.0">
-    <group
-        android:translateY="0.5"
-        android:translateX="0.5" >
-        <path
-            android:pathData="M9.57,8.5l2.79,-2.78c0.3,-0.3 0.3,-0.8 0,-1.1L9.04,1.29L9.02,1.27C8.7,0.98 8.21,1 7.91,1.31C7.78,1.45 7.71,1.64 7.71,1.84v4.79L4.69,3.61c-0.3,-0.3 -0.79,-0.3 -1.09,0s-0.3,0.79 0,1.09L7.39,8.5L3.6,12.29c-0.3,0.3 -0.3,0.79 0,1.09s0.79,0.3 1.09,0l3.01,-3.01v4.8c0,0.42 0.35,0.77 0.77,0.77c0.19,0 0.39,-0.07 0.53,-0.21l0.04,-0.04l3.32,-3.32c0.3,-0.3 0.3,-0.8 0,-1.1L9.57,8.5zM9.19,6.77v-3.2l1.6,1.6L9.19,6.77zM9.19,13.42v-3.2l1.6,1.6L9.19,13.42zM4.03,9.29c-0.44,0.44 -1.15,0.44 -1.58,0C2.02,8.86 2.02,8.16 2.45,7.72l0.01,-0.01C2.89,7.27 3.59,7.27 4.02,7.7l0.01,0.01C4.47,8.15 4.47,8.85 4.03,9.29zM14.44,7.71c0.44,0.44 0.44,1.15 0,1.58c-0.44,0.44 -1.15,0.44 -1.58,0c-0.44,-0.43 -0.44,-1.13 -0.01,-1.57l0.01,-0.01C13.3,7.28 14,7.27 14.43,7.7C14.44,7.7 14.44,7.71 14.44,7.71z"
-            android:fillColor="#FFFFFF"/>
-    </group>
-</vector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_bluetooth_connected" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
index fed7cae..0223501 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
@@ -18,26 +18,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp" >
-    <vector
-        android:width="18dp"
-        android:height="18dp"
-        android:viewportWidth="19.0"
-        android:viewportHeight="19.0">
-        <group
-            android:translateX="1.0"
-            android:translateY="1.0">
-            <path
-                android:pathData="M11.5,8.5c0,0.41 -0.34,0.74 -0.74,0.74L9.24,9.24v1.5c0,0.41 -0.34,0.74 -0.74,0.74s-0.74,-0.34 -0.74,-0.74v-1.5h-1.5c-0.41,0 -0.74,-0.34 -0.74,-0.74s0.34,-0.74 0.74,-0.74h1.5v-1.5c0,-0.41 0.34,-0.74 0.74,-0.74s0.74,0.34 0.74,0.74v1.5h1.5c0.42,-0.01 0.76,0.33 0.76,0.74z"
-                android:fillColor="#FFF"/>
-            <path
-                android:pathData="M13.23,12.05l0.99,0.57c0.19,0.12 0.25,0.38 0.12,0.55A7.452,7.452 0,0 1,7.5 15.9c-3.29,-0.44 -5.96,-3.08 -6.41,-6.38 -0.57,-4.17 2.33,-7.8 6.23,-8.42 0.23,-0.04 0.44,0.15 0.44,0.37v1.15c0,0.18 -0.14,0.33 -0.31,0.37 -2.7,0.52 -4.71,2.96 -4.55,5.83 0.16,2.86 2.57,5.21 5.43,5.29 1.77,0.06 3.38,-0.72 4.44,-1.97 0.11,-0.14 0.31,-0.18 0.46,-0.09z"
-                android:fillColor="#FFF" />
-            <path
-                android:pathData="M14.11,8.5c0,0.62 -0.11,1.22 -0.29,1.78 -0.06,0.17 0.01,0.35 0.16,0.45l1,0.57c0.19,0.12 0.46,0.03 0.54,-0.18 0.3,-0.82 0.47,-1.7 0.47,-2.62 0,-3.73 -2.73,-6.82 -6.31,-7.39a0.377,0.377 0,0 0,-0.44 0.37v1.15c0,0.18 0.14,0.33 0.31,0.36 2.59,0.51 4.56,2.78 4.56,5.51z"
-                android:fillAlpha="0.3"
-                android:fillColor="#FFF" />
-
-        </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_data_saver" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
index 68a06d0..a22d236 100644
--- a/packages/SystemUI/res/drawable/stat_sys_dnd.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -18,17 +18,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp" >
-    <vector
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M7,11h10v2h-10z"/>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_dnd" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_headset.xml b/packages/SystemUI/res/drawable/stat_sys_headset.xml
new file mode 100644
index 0000000..361c665
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_headset.xml
@@ -0,0 +1,19 @@
+<!--
+    Copyright (C) 2016 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_headset" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml b/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml
new file mode 100644
index 0000000..b424caa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml
@@ -0,0 +1,19 @@
+<!--
+    Copyright (C) 2016 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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_headset_mic" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
index 4f52777..361b00a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
@@ -15,18 +15,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="18.0dp"
-        android:height="18.0dp"
-        android:viewportWidth="18.0"
-        android:viewportHeight="18.0">
-      <group
-          android:translateX="0.5"
-          android:translateY="0.5" >
-          <path
-              android:pathData="M8.5,7.79c-0.78,0 -1.42,0.64 -1.42,1.42c0,0.78 0.64,1.42 1.42,1.42s1.42,-0.64 1.42,-1.42C9.92,8.43 9.28,7.79 8.5,7.79zM12.75,9.21c0,-2.35 -1.9,-4.25 -4.25,-4.25c-0.18,0 -0.35,0.01 -0.53,0.03C6.11,5.22 4.58,6.7 4.3,8.55c-0.23,1.52 0.35,2.91 1.36,3.82C6,12.67 6.54,12.6 6.76,12.2c0.17,-0.3 0.1,-0.67 -0.16,-0.89c-0.78,-0.7 -1.12,-1.77 -0.86,-2.79C5.99,7.5 6.78,6.71 7.8,6.46C9.32,6.08 10.86,7 11.25,8.52c0.06,0.23 0.09,0.46 0.09,0.69c0,0.84 -0.36,1.58 -0.94,2.1c-0.25,0.23 -0.33,0.6 -0.16,0.9c0.22,0.38 0.74,0.49 1.06,0.2C12.22,11.6 12.75,10.43 12.75,9.21zM7.63,1.85C4.19,2.24 1.42,5.07 1.1,8.52c-0.26,2.61 0.88,5.15 2.99,6.7c0.36,0.26 0.86,0.15 1.09,-0.23c0.19,-0.32 0.1,-0.74 -0.19,-0.96c-1.7,-1.26 -2.71,-3.38 -2.35,-5.73c0.4,-2.6 2.57,-4.68 5.19,-4.97c3.59,-0.41 6.63,2.4 6.63,5.91c0,1.97 -0.96,3.7 -2.43,4.79c-0.3,0.22 -0.38,0.63 -0.19,0.96c0.22,0.39 0.73,0.49 1.09,0.23c1.9,-1.4 3.03,-3.62 3.03,-5.98C15.94,4.84 12.12,1.34 7.63,1.85z"
-              android:fillColor="#FFFFFFFF"/>
-      </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_hotspot" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_location.xml b/packages/SystemUI/res/drawable/stat_sys_location.xml
index bdb0b0c..7a5aeb9 100644
--- a/packages/SystemUI/res/drawable/stat_sys_location.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_location.xml
@@ -14,18 +14,6 @@
   ~ limitations under the License
   -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="1.5dp"
-    android:insetRight="1.5dp">
-        <vector
-            android:width="17dp"
-            android:height="17dp"
-            android:viewportWidth="24.0"
-            android:viewportHeight="24.0">
-                <path
-                    android:fillColor="#FFFFFFFF"
-                    android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
-                <path
-                    android:fillColor="#FFFFFFFF"
-                    android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-        </vector>
-</inset>
\ No newline at end of file
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_location" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index 0b72f75..21a4c17 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -1,36 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 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.
-*/
+     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.
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="19dp"
-        android:height="19dp"
-        android:viewportWidth="23.0"
-        android:viewportHeight="23.0">
-        <group
-            android:translateX="-0.5"
-            android:translateY="-0.5">
-            <path
-                android:fillColor="#F00"
-                android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-
-        </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_volume_ringer_vibrate" />
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index 8731b6b..0f659c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -799,4 +799,9 @@
             }
         }
     }
+
+    @Override
+    protected boolean canReceivePointerEvents() {
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index b03b872..6f50baa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -286,8 +286,9 @@
         RowBuilder dndBuilder = new RowBuilder(mDndUri)
                 .setContentDescription(getContext().getResources()
                         .getString(R.string.accessibility_quick_settings_dnd))
-                .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
-                        ListBuilder.ICON_IMAGE);
+                .addEndItem(
+                    IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
+                    ListBuilder.ICON_IMAGE);
         builder.addRow(dndBuilder);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 387de71..cf04ea6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -43,8 +43,7 @@
 
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
-    private final Icon mIcon =
-            ResourceIcon.get(R.drawable.ic_signal_airplane);
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_airplane);
     private final GlobalSetting mSetting;
     private final ActivityStarter mActivityStarter;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 5b85498..f1a8d37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -288,7 +288,7 @@
             // This method returns Pair<Drawable, String> while first value is the drawable
             return BluetoothDeviceLayerDrawable.createLayerDrawable(
                     context,
-                    R.drawable.ic_qs_bluetooth_connected,
+                    R.drawable.ic_bluetooth_connected,
                     mBatteryLevel,
                     mIconScale);
         }
@@ -309,7 +309,7 @@
         @Override
         public Drawable getDrawable(Context context) {
             // This method returns Pair<Drawable, String> - the first value is the drawable.
-            return context.getDrawable(R.drawable.ic_qs_bluetooth_connected);
+            return context.getDrawable(R.drawable.ic_bluetooth_connected);
         }
     }
 
@@ -388,7 +388,7 @@
                     item.tag = device;
                     int state = device.getMaxConnectionState();
                     if (state == BluetoothProfile.STATE_CONNECTED) {
-                        item.iconResId = R.drawable.ic_qs_bluetooth_connected;
+                        item.iconResId = R.drawable.ic_bluetooth_connected;
                         int batteryLevel = device.getBatteryLevel();
                         if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
                             item.icon = new BluetoothBatteryTileIcon(batteryLevel,1 /* iconScale */);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index bdebf79..415870c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -202,8 +202,8 @@
         if (connecting && !state.value) {
             state.secondaryLabel = mContext.getString(R.string.quick_settings_connecting);
         }
-        state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
-                : R.drawable.ic_qs_cast_off);
+        state.icon = ResourceIcon.get(state.value ? R.drawable.ic_cast_connected
+                : R.drawable.ic_cast);
         if (mWifiConnected || state.value) {
             state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
             if (!state.value) {
@@ -334,7 +334,7 @@
                 for (CastDevice device : devices) {
                     if (device.state == CastDevice.STATE_CONNECTED) {
                         final Item item = new Item();
-                        item.iconResId = R.drawable.ic_qs_cast_on;
+                        item.iconResId = R.drawable.ic_cast_connected;
                         item.line1 = getDeviceName(device);
                         item.line2 = mContext.getString(R.string.quick_settings_connected);
                         item.tag = device;
@@ -354,7 +354,7 @@
                         final CastDevice device = mVisibleOrder.get(id);
                         if (!devices.contains(device)) continue;
                         final Item item = new Item();
-                        item.iconResId = R.drawable.ic_qs_cast_off;
+                        item.iconResId = R.drawable.ic_cast;
                         item.line1 = getDeviceName(device);
                         if (device.state == CastDevice.STATE_CONNECTING) {
                             item.line2 = mContext.getString(R.string.quick_settings_connecting);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index a0f4e24..837ea9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -37,7 +37,7 @@
 /** Quick settings tile: Location **/
 public class LocationTile extends QSTileImpl<BooleanState> {
 
-    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_signal_location);
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_location);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index cb9060b..cf6e64c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -289,4 +289,9 @@
             }
         }
     }
+
+    @Override
+    protected boolean canReceivePointerEvents() {
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 236c72c..a3be3e33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -110,14 +110,13 @@
             if (zen != null) {
                 int iconId = zen.equals("important") ? R.drawable.stat_sys_zen_important
                         : zen.equals("none") ? R.drawable.stat_sys_zen_none
-                        : 0;
+                        : zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0;
                 updateSlot("zen", null, iconId);
             }
             String bt = args.getString("bluetooth");
             if (bt != null) {
-                int iconId = bt.equals("disconnected") ? R.drawable.stat_sys_data_bluetooth
-                        : bt.equals("connected") ? R.drawable.stat_sys_data_bluetooth_connected
-                        : 0;
+                int iconId = bt.equals("connected")
+                        ? R.drawable.stat_sys_data_bluetooth_connected : 0;
                 updateSlot("bluetooth", null, iconId);
             }
             String location = args.getString("location");
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 b7a7873..1eee058 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -388,13 +388,12 @@
     }
 
     private final void updateBluetooth() {
-        int iconId = R.drawable.stat_sys_data_bluetooth;
+        int iconId = R.drawable.stat_sys_data_bluetooth_connected;
         String contentDescription =
                 mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
         boolean bluetoothVisible = false;
         if (mBluetooth != null) {
             if (mBluetooth.isBluetoothConnected()) {
-                iconId = R.drawable.stat_sys_data_bluetooth_connected;
                 contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
                 bluetoothVisible = mBluetooth.isBluetoothEnabled();
             }
@@ -582,8 +581,8 @@
             String contentDescription = mContext.getString(hasMic
                     ? R.string.accessibility_status_bar_headset
                     : R.string.accessibility_status_bar_headphones);
-            mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.ic_headset_mic
-                    : R.drawable.ic_headset, contentDescription);
+            mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic
+                    : R.drawable.stat_sys_headset, contentDescription);
             mIconController.setIconVisibility(mSlotHeadset, true);
         } else {
             mIconController.setIconVisibility(mSlotHeadset, false);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e5f709a..35a2450 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -288,7 +288,7 @@
                 addRow(AudioManager.STREAM_RING,
                         R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false);
                 addRow(STREAM_ALARM,
-                        R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
+                        R.drawable.ic_alarm, R.drawable.ic_volume_alarm_mute, true, false);
                 addRow(AudioManager.STREAM_VOICE_CALL,
                         com.android.internal.R.drawable.ic_phone,
                         com.android.internal.R.drawable.ic_phone, false, false);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 4a230e7..2894662 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.view.contentcapture.ContentCaptureHelper.toList;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -56,6 +57,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.ContentCaptureHelper;
 import android.view.contentcapture.ContentCaptureManager;
 import android.view.contentcapture.IContentCaptureManager;
@@ -127,7 +129,7 @@
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
-                UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate=*/ false);
+                UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate= */ false);
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ActivityThread.currentApplication().getMainExecutor(),
                 (namespace, key, value) -> onDeviceConfigChange(key, value));
@@ -472,7 +474,7 @@
             return false;
         }
 
-        final ComponentName serviceComponent  = ComponentName.unflattenFromString(serviceName);
+        final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
         if (serviceComponent == null) {
             Slog.w(mTag, methodName + ": invalid service name: " + serviceName);
             return false;
@@ -523,7 +525,7 @@
 
         @Override
         public void startSession(@NonNull IBinder activityToken,
-                @NonNull ComponentName componentName, @NonNull String sessionId, int flags,
+                @NonNull ComponentName componentName, int sessionId, int flags,
                 @NonNull IResultReceiver result) {
             Preconditions.checkNotNull(activityToken);
             Preconditions.checkNotNull(sessionId);
@@ -540,7 +542,7 @@
         }
 
         @Override
-        public void finishSession(@NonNull String sessionId) {
+        public void finishSession(int sessionId) {
             Preconditions.checkNotNull(sessionId);
             final int userId = UserHandle.getCallingUserId();
 
@@ -568,6 +570,8 @@
         @Override
         public void removeUserData(@NonNull UserDataRemovalRequest request) {
             Preconditions.checkNotNull(request);
+            // TODO(b/122959591): check caller uid owns the package name
+
             final int userId = UserHandle.getCallingUserId();
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
@@ -621,13 +625,32 @@
         }
 
         @Override
+        public void getContentCaptureConditions(@NonNull String packageName,
+                @NonNull IResultReceiver result) {
+            // TODO(b/122959591): check caller uid owns the package name
+
+            final int userId = UserHandle.getCallingUserId();
+            final ArrayList<ContentCaptureCondition> conditions;
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                conditions = service == null ? null
+                        : toList(service.getContentCaptureConditionsLocked(packageName));
+            }
+            try {
+                result.send(RESULT_CODE_OK, bundleFor(conditions));
+            } catch (RemoteException e) {
+                Slog.w(mTag, "Unable to send getServiceComponentName(): " + e);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
 
             boolean showHistory = true;
             if (args != null) {
                 for (String arg : args) {
-                    switch(arg) {
+                    switch (arg) {
                         case "--no-history":
                             showHistory = false;
                             break;
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 5934344..5649526 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -17,6 +17,7 @@
 package com.android.server.contentcapture;
 
 import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
 import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
 import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR;
@@ -34,11 +35,13 @@
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.pm.ActivityPresentationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
@@ -50,7 +53,10 @@
 import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
+import android.util.SparseArray;
+import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.annotations.GuardedBy;
@@ -75,8 +81,7 @@
     private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
 
     @GuardedBy("mLock")
-    private final ArrayMap<String, ContentCaptureServerSession> mSessions =
-            new ArrayMap<>();
+    private final SparseArray<ContentCaptureServerSession> mSessions = new SparseArray<>();
 
     /**
      * Reference to the remote service.
@@ -98,6 +103,13 @@
     private final WhitelistHelper mWhitelistHelper = new WhitelistHelper();
 
     /**
+     * List of conditions keyed by package.
+     */
+    @GuardedBy("mLock")
+    private final ArrayMap<String, ArraySet<ContentCaptureCondition>> mConditionsByPkg =
+            new ArrayMap<>();
+
+    /**
      * When {@code true}, remote service died but service state is kept so it's restored after
      * the system re-binds to it.
      */
@@ -223,9 +235,8 @@
     // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
     public void startSessionLocked(@NonNull IBinder activityToken,
-            @NonNull ActivityPresentationInfo activityPresentationInfo,
-            @NonNull String sessionId, int uid, int flags,
-            @NonNull IResultReceiver clientReceiver) {
+            @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
+            int flags, @NonNull IResultReceiver clientReceiver) {
         if (activityPresentationInfo == null) {
             Slog.w(TAG, "basic activity info is null");
             setClientState(clientReceiver, STATE_DISABLED | STATE_INTERNAL_ERROR,
@@ -315,7 +326,7 @@
 
     // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
-    public void finishSessionLocked(@NonNull String sessionId) {
+    public void finishSessionLocked(int sessionId) {
         if (!isEnabledLocked()) {
             return;
         }
@@ -379,8 +390,8 @@
     @GuardedBy("mLock")
     public boolean sendActivityAssistDataLocked(@NonNull IBinder activityToken,
             @NonNull Bundle data) {
-        final String id = getSessionId(activityToken);
-        if (id != null) {
+        final int id = getSessionId(activityToken);
+        if (id != NO_SESSION_ID) {
             final ContentCaptureServerSession session = mSessions.get(id);
             final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
             final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE);
@@ -396,7 +407,7 @@
     }
 
     @GuardedBy("mLock")
-    public void removeSessionLocked(@NonNull String sessionId) {
+    public void removeSessionLocked(int sessionId) {
         mSessions.remove(sessionId);
     }
 
@@ -450,6 +461,47 @@
     }
 
     @GuardedBy("mLock")
+    @Nullable
+    ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
+        if (!mWhitelistHelper.isWhitelisted(packageName)) {
+            if (packageName.equals(getServicePackageName())) {
+                if (mMaster.verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+                return new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel);
+            }
+            if (mMaster.verbose) {
+                Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+            }
+            return null;
+        }
+
+        final ArraySet<ComponentName> whitelistedComponents = mWhitelistHelper
+                .getWhitelistedComponents(packageName);
+        if (Build.IS_USER && isTemporaryServiceSetLocked()) {
+            final String servicePackageName = getServicePackageName();
+            if (!packageName.equals(servicePackageName)) {
+                Slog.w(mTag, "Ignoring package " + packageName
+                        + " while using temporary service " + servicePackageName);
+                return null;
+            }
+        }
+        final ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
+                mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
+                mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
+                whitelistedComponents);
+        if (mMaster.verbose) {
+            Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+        }
+        return options;
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    ArraySet<ContentCaptureCondition> getContentCaptureConditionsLocked(
+            @NonNull String packageName) {
+        return mConditionsByPkg.get(packageName);
+    }
+
+    @GuardedBy("mLock")
     void onActivityEventLocked(@NonNull ComponentName componentName, @ActivityEventType int type) {
         if (mRemoteService == null) {
             if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
@@ -481,7 +533,7 @@
             mRemoteService.dump(prefix2, pw);
         }
 
-        if (mSessions.isEmpty()) {
+        if (mSessions.size() == 0) {
             pw.print(prefix); pw.println("no sessions");
         } else {
             final int sessionsSize = mSessions.size();
@@ -499,14 +551,14 @@
      * Returns the session id associated with the given activity.
      */
     @GuardedBy("mLock")
-    private String getSessionId(@NonNull IBinder activityToken) {
+    private int getSessionId(@NonNull IBinder activityToken) {
         for (int i = 0; i < mSessions.size(); i++) {
             ContentCaptureServerSession session = mSessions.valueAt(i);
             if (session.isActivitySession(activityToken)) {
                 return mSessions.keyAt(i);
             }
         }
-        return null;
+        return NO_SESSION_ID;
     }
 
     /**
@@ -537,6 +589,23 @@
         }
 
         @Override
+        public void setContentCaptureConditions(String packageName,
+                List<ContentCaptureCondition> conditions) {
+            if (mMaster.verbose) {
+                Slog.v(TAG, "setContentCaptureConditions(" + packageName + "): "
+                        + (conditions == null ? "null" : conditions.size() + " conditions"));
+            }
+            synchronized (mLock) {
+                if (conditions == null) {
+                    mConditionsByPkg.remove(packageName);
+                } else {
+                    mConditionsByPkg.put(packageName, new ArraySet<>(conditions));
+                }
+            }
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
         public void disableSelf() {
             if (mMaster.verbose) Slog.v(TAG, "disableSelf()");
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 9b2c05f..1ad66d8 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -16,6 +16,7 @@
 package com.android.server.contentcapture;
 
 import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 import static android.view.contentcapture.ContentCaptureSession.STATE_ACTIVE;
 import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
 import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_RESURRECTED;
@@ -57,7 +58,7 @@
     /**
      * Canonical session id.
      */
-    private final String mId;
+    private final int mId;
 
     /**
      * UID of the app whose contents is being captured.
@@ -66,11 +67,12 @@
 
     ContentCaptureServerSession(@NonNull IBinder activityToken,
             @NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
-            @NonNull IResultReceiver sessionStateReceiver,
-            int taskId, int displayId, @NonNull String sessionId, int uid, int flags) {
+            @NonNull IResultReceiver sessionStateReceiver, int taskId, int displayId, int sessionId,
+            int uid, int flags) {
+        Preconditions.checkArgument(sessionId != NO_SESSION_ID);
         mActivityToken = activityToken;
         mService = service;
-        mId = Preconditions.checkNotNull(sessionId);
+        mId = sessionId;
         mUid = uid;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
                 appComponentName, taskId, displayId, flags);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 0afe252..3fa3fdf 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -98,9 +98,8 @@
      * Called by {@link ContentCaptureServerSession} to generate a call to the
      * {@link RemoteContentCaptureService} to indicate the session was created.
      */
-    public void onSessionStarted(@Nullable ContentCaptureContext context,
-            @NonNull String sessionId, int uid, @NonNull IResultReceiver clientReceiver,
-            int initialState) {
+    public void onSessionStarted(@Nullable ContentCaptureContext context, int sessionId, int uid,
+            @NonNull IResultReceiver clientReceiver, int initialState) {
         scheduleAsyncRequest(
                 (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState));
     }
@@ -109,15 +108,14 @@
      * Called by {@link ContentCaptureServerSession} to generate a call to the
      * {@link RemoteContentCaptureService} to indicate the session was finished.
      */
-    public void onSessionFinished(@NonNull String sessionId) {
+    public void onSessionFinished(int sessionId) {
         scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId));
     }
 
     /**
      * Called by {@link ContentCaptureServerSession} to send snapshot data to the service.
      */
-    public void onActivitySnapshotRequest(@NonNull String sessionId,
-            @NonNull SnapshotData snapshotData) {
+    public void onActivitySnapshotRequest(int sessionId, @NonNull SnapshotData snapshotData) {
         scheduleAsyncRequest((s) -> s.onActivitySnapshot(sessionId, snapshotData));
     }
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c154240..9e1b3b8 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -51,6 +51,7 @@
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
+        "dnsresolver_aidl_interface-java",
         "netd_aidl_interface-java",
         "netd_event_listener_interface-java",
     ],
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2be92cd..1169eeb 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -63,6 +63,7 @@
 import android.net.ConnectivityManager;
 import android.net.ICaptivePortal;
 import android.net.IConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.IIpConnectivityMetrics;
 import android.net.INetd;
 import android.net.INetdEventCallback;
@@ -294,6 +295,8 @@
 
     private INetworkManagementService mNMS;
     @VisibleForTesting
+    protected IDnsResolver mDnsResolver;
+    @VisibleForTesting
     protected INetd mNetd;
     private INetworkStatsService mStatsService;
     private INetworkPolicyManager mPolicyManager;
@@ -525,6 +528,11 @@
         return sMagicDecoderRing.get(what, Integer.toString(what));
     }
 
+    private static IDnsResolver getDnsResolver() {
+        return IDnsResolver.Stub
+                .asInterface(ServiceManager.getService("dnsresolver"));
+    }
+
     /** Handler thread used for both of the handlers below. */
     @VisibleForTesting
     protected final HandlerThread mHandlerThread;
@@ -810,13 +818,14 @@
 
     public ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
-        this(context, netManager, statsService, policyManager, new IpConnectivityLog());
+        this(context, netManager, statsService, policyManager,
+            getDnsResolver(), new IpConnectivityLog());
     }
 
     @VisibleForTesting
     protected ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager,
-            IpConnectivityLog logger) {
+            IDnsResolver dnsresolver, IpConnectivityLog logger) {
         if (DBG) log("ConnectivityService starting up");
 
         mSystemProperties = getSystemProperties();
@@ -853,6 +862,7 @@
         mPolicyManagerInternal = checkNotNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
+        mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
         mProxyTracker = makeProxyTracker();
 
         mNetd = NetdService.getInstance();
@@ -1006,7 +1016,7 @@
 
         mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
 
-        mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);
+        mDnsManager = new DnsManager(mContext, mDnsResolver, mSystemProperties);
         registerPrivateDnsSettingsCallbacks();
     }
 
@@ -3021,9 +3031,9 @@
             // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
             // long time.
             try {
-                mNMS.removeNetwork(nai.network.netId);
-            } catch (Exception e) {
-                loge("Exception removing network: " + e);
+                mNetd.networkDestroy(nai.network.netId);
+            } catch (RemoteException | ServiceSpecificException e) {
+                loge("Exception destroying network: " + e);
             }
             mDnsManager.removeNetwork(nai.network);
         }
@@ -5372,8 +5382,8 @@
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS,
-                factorySerialNumber);
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
+                mNMS, factorySerialNumber);
         // Make sure the network capabilities reflect what the agent info says.
         nai.networkCapabilities = mixInCapabilities(nai, nc);
         final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 61a7182..d1ae284 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1610,20 +1610,6 @@
     }
 
     @Override
-    public void setDnsConfigurationForNetwork(int netId, String[] servers, String[] domains,
-                    int[] params, String tlsHostname, String[] tlsServers) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        final String[] tlsFingerprints = new String[0];
-        try {
-            mNetdService.setResolverConfiguration(
-                    netId, servers, domains, params, tlsHostname, tlsServers, tlsFingerprints);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
     public void addVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
@@ -2082,21 +2068,6 @@
     }
 
     @Override
-    public void removeNetwork(int netId) {
-        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
-
-        try {
-            mNetdService.networkDestroy(netId);
-        } catch (ServiceSpecificException e) {
-            Log.w(TAG, "removeNetwork(" + netId + "): ", e);
-            throw e;
-        } catch (RemoteException e) {
-            Log.w(TAG, "removeNetwork(" + netId + "): ", e);
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    @Override
     public void addInterfaceToNetwork(String iface, int netId) {
         modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
     }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cef245b..261ed4c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1524,8 +1524,9 @@
         boolean anyClientActivities = false;
         for (int i=proc.services.size()-1; i>=0 && !anyClientActivities; i--) {
             ServiceRecord sr = proc.services.valueAt(i);
-            for (int conni=sr.connections.size()-1; conni>=0 && !anyClientActivities; conni--) {
-                ArrayList<ConnectionRecord> clist = sr.connections.valueAt(conni);
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = sr.getConnections();
+            for (int conni = connections.size() - 1; conni >= 0 && !anyClientActivities; conni--) {
+                ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                 for (int cri=clist.size()-1; cri>=0; cri--) {
                     ConnectionRecord cr = clist.get(cri);
                     if (cr.binding.client == null || cr.binding.client == proc) {
@@ -1752,10 +1753,10 @@
                     callerApp.uid, callerApp.processName, callingPackage);
 
             IBinder binder = connection.asBinder();
-            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+            ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
             if (clist == null) {
                 clist = new ArrayList<ConnectionRecord>();
-                s.connections.put(binder, clist);
+                s.putConnection(binder, clist);
             }
             clist.add(c);
             b.connections.add(c);
@@ -1855,8 +1856,9 @@
                     b.binder = service;
                     b.requested = true;
                     b.received = true;
-                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
-                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                    for (int conni = connections.size() - 1; conni >= 0; conni--) {
+                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                         for (int i=0; i<clist.size(); i++) {
                             ConnectionRecord c = clist.get(i);
                             if (!filter.equals(c.binding.intent.intent)) {
@@ -2722,6 +2724,10 @@
 
         updateServiceClientActivitiesLocked(app, null, true);
 
+        if (newService && created) {
+            app.addBoundClientUidsOfNewService(r);
+        }
+
         // If the service is in the started state, and there are no
         // pending arguments, then fake up one so its onStartCommand() will
         // be called.
@@ -2881,8 +2887,9 @@
 
         // Report to all of the connections that the service is no longer
         // available.
-        for (int conni=r.connections.size()-1; conni>=0; conni--) {
-            ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+        for (int conni = connections.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> c = connections.valueAt(conni);
             for (int i=0; i<c.size(); i++) {
                 ConnectionRecord cr = c.get(i);
                 // There is still a connection to the service that is
@@ -3013,6 +3020,7 @@
                 r.stats.stopLaunchedLocked();
             }
             r.app.services.remove(r);
+            r.app.updateBoundClientUids();
             if (r.whitelistManager) {
                 updateWhitelistManagerLocked(r.app);
             }
@@ -3065,11 +3073,11 @@
         IBinder binder = c.conn.asBinder();
         AppBindRecord b = c.binding;
         ServiceRecord s = b.service;
-        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+        ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
         if (clist != null) {
             clist.remove(c);
             if (clist.size() == 0) {
-                s.connections.remove(binder);
+                s.removeConnection(binder);
             }
         }
         b.connections.remove(c);
@@ -3294,6 +3302,7 @@
             if (finishing) {
                 if (r.app != null && !r.app.isPersistent()) {
                     r.app.services.remove(r);
+                    r.app.updateBoundClientUids();
                     if (r.whitelistManager) {
                         updateWhitelistManagerLocked(r.app);
                     }
@@ -3389,6 +3398,7 @@
                 Slog.i(TAG, "  Force stopping service " + service);
                 if (service.app != null && !service.app.isPersistent()) {
                     service.app.services.remove(service);
+                    service.app.updateBoundClientUids();
                     if (service.whitelistManager) {
                         updateWhitelistManagerLocked(service.app);
                     }
@@ -3504,8 +3514,9 @@
                 Iterator<ServiceRecord> it = app.services.iterator();
                 while (it.hasNext()) {
                     ServiceRecord r = it.next();
-                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
-                        ArrayList<ConnectionRecord> cl = r.connections.valueAt(conni);
+                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                    for (int conni=connections.size()-1; conni>=0; conni--) {
+                        ArrayList<ConnectionRecord> cl = connections.valueAt(conni);
                         for (int i=0; i<cl.size(); i++) {
                             ConnectionRecord c = cl.get(i);
                             if (c.binding.client != app) {
@@ -3542,6 +3553,7 @@
             }
             if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
                 sr.app.services.remove(sr);
+                sr.app.updateBoundClientUids();
             }
             sr.setProcess(null);
             sr.isolatedProc = null;
@@ -3605,6 +3617,7 @@
             // so make sure the service is cleaned out of it.
             if (!app.isPersistent()) {
                 app.services.removeAt(i);
+                app.updateBoundClientUids();
             }
 
             // Sanity check: if the service listed for the app is not one
@@ -3655,6 +3668,7 @@
 
         if (!allowRestart) {
             app.services.clear();
+            app.clearBoundClientUids();
 
             // Make sure there are no more restarting services for this process.
             for (int i=mRestartingServices.size()-1; i>=0; i--) {
@@ -3701,7 +3715,7 @@
         info.foreground = r.isForeground;
         info.activeSince = r.createRealTime;
         info.started = r.startRequested;
-        info.clientCount = r.connections.size();
+        info.clientCount = r.getConnections().size();
         info.crashCount = r.crashCount;
         info.lastActivityTime = r.lastActivity;
         if (r.isForeground) {
@@ -3717,8 +3731,9 @@
             info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
         }
 
-        for (int conni=r.connections.size()-1; conni>=0; conni--) {
-            ArrayList<ConnectionRecord> connl = r.connections.valueAt(conni);
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+        for (int conni = connections.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> connl = connections.valueAt(conni);
             for (int i=0; i<connl.size(); i++) {
                 ConnectionRecord conn = connl.get(i);
                 if (conn.clientLabel != 0) {
@@ -3787,9 +3802,10 @@
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
         int userId = UserHandle.getUserId(Binder.getCallingUid());
         ServiceRecord r = getServiceByNameLocked(name, userId);
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
         if (r != null) {
-            for (int conni=r.connections.size()-1; conni>=0; conni--) {
-                ArrayList<ConnectionRecord> conn = r.connections.valueAt(conni);
+            for (int conni = connections.size() - 1; conni >= 0; conni--) {
+                ArrayList<ConnectionRecord> conn = connections.valueAt(conni);
                 for (int i=0; i<conn.size(); i++) {
                     if (conn.get(i).clientIntent != null) {
                         return conn.get(i).clientIntent;
@@ -4080,11 +4096,12 @@
                 pw.print(" started=");
                 pw.print(r.startRequested);
                 pw.print(" connections=");
-                pw.println(r.connections.size());
-                if (r.connections.size() > 0) {
+                ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                pw.println(connections.size());
+                if (connections.size() > 0) {
                     pw.println("    Connections:");
-                    for (int conni=0; conni<r.connections.size(); conni++) {
-                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+                    for (int conni = 0; conni < connections.size(); conni++) {
+                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                         for (int i = 0; i < clist.size(); i++) {
                             ConnectionRecord conn = clist.get(i);
                             pw.print("      ");
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c1b9a20..924e331 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -53,12 +53,14 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Debug;
+import android.os.IBinder;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -1110,12 +1112,13 @@
                 }
             }
 
-            for (int conni = s.connections.size() - 1;
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
+            for (int conni = serviceConnections.size() - 1;
                     conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                             || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     conni--) {
-                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+                ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
                 for (int i = 0;
                         i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
                                 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a90e994..ce13cd8 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -259,6 +259,8 @@
     // A set of tokens that currently contribute to this process being temporarily whitelisted
     // to start activities even if it's not in the foreground
     final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
+    // a set of UIDs of all bound clients
+    private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
 
     String isolatedEntryPoint;  // Class to run on start if this is a special isolated process.
     String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
@@ -1193,6 +1195,53 @@
                 !mAllowBackgroundActivityStartsTokens.isEmpty());
     }
 
+    void addBoundClientUids(ArraySet<Integer> clientUids) {
+        mBoundClientUids.addAll(clientUids);
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void updateBoundClientUids() {
+        if (services.isEmpty()) {
+            clearBoundClientUids();
+            return;
+        }
+        // grab a set of clientUids of all connections of all services
+        ArraySet<Integer> boundClientUids = new ArraySet<>();
+        final int K = services.size();
+        for (int j = 0; j < K; j++) {
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+                    services.valueAt(j).getConnections();
+            final int N = conns.size();
+            for (int conni = 0; conni < N; conni++) {
+                ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+                for (int i = 0; i < c.size(); i++) {
+                    boundClientUids.add(c.get(i).clientUid);
+                }
+            }
+        }
+        mBoundClientUids = boundClientUids;
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void addBoundClientUidsOfNewService(ServiceRecord sr) {
+        if (sr == null) {
+            return;
+        }
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns = sr.getConnections();
+        for (int conni = conns.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+            for (int i = 0; i < c.size(); i++) {
+                mBoundClientUids.add(c.get(i).clientUid);
+            }
+        }
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void clearBoundClientUids() {
+        mBoundClientUids.clear();
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
     void setActiveInstrumentation(ActiveInstrumentation instr) {
         mInstr = instr;
         boolean isInstrumenting = instr != null;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index eeaa7de..217fd6d 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -38,6 +38,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -88,7 +89,7 @@
     final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
             = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
                             // All active bindings to the service.
-    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
+    private final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
             = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
                             // IBinder -> ConnectionRecord of all bound clients
 
@@ -542,6 +543,7 @@
             }
         } else if (app != null) {
             app.removeAllowBackgroundActivityStartsToken(this);
+            app.updateBoundClientUids();
         }
         app = _proc;
         if (pendingConnectionGroup > 0 && _proc != null) {
@@ -563,6 +565,33 @@
                 }
             }
         }
+        if (_proc != null) {
+            _proc.updateBoundClientUids();
+        }
+    }
+
+    ArrayMap<IBinder, ArrayList<ConnectionRecord>> getConnections() {
+        return connections;
+    }
+
+    void putConnection(IBinder binder, ArrayList<ConnectionRecord> clist) {
+        connections.put(binder, clist);
+        // if we have a process attached, add bound client uids of this connection to it
+        if (app != null) {
+            ArraySet<Integer> boundClientUids = new ArraySet<>();
+            for (int i = 0; i < clist.size(); i++) {
+                boundClientUids.add(clist.get(i).clientUid);
+            }
+            app.addBoundClientUids(boundClientUids);
+        }
+    }
+
+    void removeConnection(IBinder binder) {
+        connections.remove(binder);
+        // if we have a process attached, tell it to update the state of bound clients
+        if (app != null) {
+            app.updateBoundClientUids();
+        }
     }
 
     void updateHasBindingWhitelistingBgActivityStarts() {
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index d8bb635..1913635 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -30,13 +30,15 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.IDnsResolver;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.Uri;
 import android.net.shared.PrivateDnsConfig;
 import android.os.Binder;
-import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -229,7 +231,7 @@
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
-    private final INetworkManagementService mNMS;
+    private final IDnsResolver mDnsResolver;
     private final MockableSystemProperties mSystemProperties;
     // TODO: Replace these Maps with SparseArrays.
     private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
@@ -243,10 +245,10 @@
     private String mPrivateDnsMode;
     private String mPrivateDnsSpecifier;
 
-    public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
+    public DnsManager(Context ctx, IDnsResolver dnsResolver, MockableSystemProperties sp) {
         mContext = ctx;
         mContentResolver = mContext.getContentResolver();
-        mNMS = nms;
+        mDnsResolver = dnsResolver;
         mSystemProperties = sp;
         mPrivateDnsMap = new HashMap<>();
         mPrivateDnsValidationMap = new HashMap<>();
@@ -260,6 +262,12 @@
     }
 
     public void removeNetwork(Network network) {
+        try {
+            mDnsResolver.clearResolverConfiguration(network.netId);
+        } catch (RemoteException | ServiceSpecificException e) {
+            Slog.e(TAG, "Error clearing DNS configuration: " + e);
+            return;
+        }
         mPrivateDnsMap.remove(network.netId);
         mPrivateDnsValidationMap.remove(network.netId);
     }
@@ -344,10 +352,12 @@
         Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
                 netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
                 Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
+        final String[] tlsFingerprints = new String[0];
         try {
-            mNMS.setDnsConfigurationForNetwork(
-                    netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
-        } catch (Exception e) {
+            mDnsResolver.setResolverConfiguration(
+                    netId, assignedServers, domainStrs, params,
+                    tlsHostname, tlsServers, tlsFingerprints);
+        } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error setting DNS configuration: " + e);
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 262ba7a..66bd27c 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.InetAddresses;
 import android.net.InterfaceConfiguration;
@@ -65,6 +66,7 @@
         NetworkInfo.State.SUSPENDED,
     };
 
+    private final IDnsResolver mDnsResolver;
     private final INetd mNetd;
     private final INetworkManagementService mNMService;
 
@@ -84,7 +86,9 @@
     private Inet6Address mIPv6Address;
     private State mState = State.IDLE;
 
-    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
+            INetworkManagementService nmService) {
+        mDnsResolver = dnsResolver;
         mNetd = netd;
         mNMService = nmService;
         mNetwork = nai;
@@ -269,7 +273,7 @@
 
     private void startPrefixDiscovery() {
         try {
-            mNetd.resolverStartPrefix64Discovery(getNetId());
+            mDnsResolver.startPrefix64Discovery(getNetId());
             mState = State.DISCOVERING;
         } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
@@ -278,7 +282,7 @@
 
     private void stopPrefixDiscovery() {
         try {
-            mNetd.resolverStopPrefix64Discovery(getNetId());
+            mDnsResolver.stopPrefix64Discovery(getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
         }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8f2825c..e3fdbe8 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import android.content.Context;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.LinkProperties;
@@ -255,7 +256,7 @@
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
             NetworkMisc misc, ConnectivityService connService, INetd netd,
-            INetworkManagementService nms, int factorySerialNumber) {
+            IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = net;
@@ -263,7 +264,7 @@
         linkProperties = lp;
         networkCapabilities = nc;
         currentScore = score;
-        clatd = new Nat464Xlat(this, netd, nms);
+        clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
         mConnService = connService;
         mContext = context;
         mHandler = handler;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0b1a98e..9986809 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -233,6 +233,10 @@
         // permission is changed according to entitlement check result.
         mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
                 TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
+        mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
+            mLog.log("OBSERVED UiEnitlementFailed");
+            stopTethering(downstream);
+        });
 
         mCarrierConfigChange = new VersionedBroadcastListener(
                 "CarrierConfigChangeListener", mContext, mHandler, filter,
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
index 5c45397..764a6eb 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -109,6 +109,7 @@
     private boolean mCellularUpstreamPermitted = true;
     private boolean mUsingCellularAsUpstream = false;
     private boolean mNeedReRunProvisioningUi = false;
+    private OnUiEntitlementFailedListener mListener;
 
     public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
             int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
@@ -129,6 +130,20 @@
                 null, mHandler);
     }
 
+    public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
+        mListener = listener;
+    }
+
+    /** Callback fired when UI entitlement failed. */
+    public interface OnUiEntitlementFailedListener {
+        /**
+         * Ui entitlement check fails in |downstream|.
+         *
+         * @param downstream  tethering type from ConnectivityManager.TETHERING_{@code *}.
+         */
+        void onUiEntitlementFailed(int downstream);
+    }
+
     /**
      * Pass a new TetheringConfiguration instance each time when
      * Tethering#updateConfiguration() is called.
@@ -337,7 +352,9 @@
      */
     protected void runSilentTetherProvisioning(int type) {
         if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
-        ResultReceiver receiver = buildProxyReceiver(type, null);
+        // For silent provisioning, settings would stop tethering when entitlement fail.
+        ResultReceiver receiver = buildProxyReceiver(type,
+                false/* notifyFail */, null);
 
         Intent intent = new Intent();
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@@ -358,7 +375,8 @@
      */
     @VisibleForTesting
     protected void runUiTetherProvisioning(int type) {
-        ResultReceiver receiver = buildProxyReceiver(type, null);
+        ResultReceiver receiver = buildProxyReceiver(type,
+                true/* notifyFail */, null);
         runUiTetherProvisioning(type, receiver);
     }
 
@@ -555,12 +573,16 @@
         }
     }
 
-    private ResultReceiver buildProxyReceiver(int type, final ResultReceiver receiver) {
+    private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
+            final ResultReceiver receiver) {
         ResultReceiver rr = new ResultReceiver(mHandler) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
                 addDownstreamMapping(type, updatedCacheValue);
+                if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
+                    mListener.onUiEntitlementFailed(type);
+                }
                 if (receiver != null) receiver.send(updatedCacheValue, null);
             }
         };
@@ -627,7 +649,7 @@
         if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
             receiver.send(cacheValue, null);
         } else {
-            ResultReceiver proxy = buildProxyReceiver(downstream, receiver);
+            ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
             runUiTetherProvisioning(downstream, proxy);
         }
     }
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 5a0b991..1820acf 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -769,6 +769,91 @@
                 mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs);
     }
 
+    /**
+     * Returns the amount of time, in milliseconds, until the package would have reached its
+     * duration quota, assuming it has a job counting towards its quota the entire time. This takes
+     * into account any {@link TimingSession}s that may roll out of the window as the job is
+     * running.
+     */
+    @VisibleForTesting
+    long getTimeUntilQuotaConsumedLocked(final int userId, @NonNull final String packageName) {
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        final int standbyBucket = JobSchedulerService.standbyBucketForPackage(
+                packageName, userId, nowElapsed);
+        if (standbyBucket == NEVER_INDEX) {
+            return 0;
+        }
+        List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+        if (sessions == null || sessions.size() == 0) {
+            return mAllowedTimePerPeriodMs;
+        }
+
+        final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
+        final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
+        final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
+        final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs;
+        final long maxExecutionTimeRemainingMs =
+                mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs;
+
+        // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can
+        // essentially run until they reach the maximum limit.
+        if (stats.windowSizeMs == mAllowedTimePerPeriodMs) {
+            return calculateTimeUntilQuotaConsumedLocked(
+                    sessions, startMaxElapsed, maxExecutionTimeRemainingMs);
+        }
+
+        // Need to check both max time and period time in case one is less than the other.
+        // For example, max time remaining could be less than bucket time remaining, but sessions
+        // contributing to the max time remaining could phase out enough that we'd want to use the
+        // bucket value.
+        return Math.min(
+                calculateTimeUntilQuotaConsumedLocked(
+                        sessions, startMaxElapsed, maxExecutionTimeRemainingMs),
+                calculateTimeUntilQuotaConsumedLocked(
+                        sessions, startWindowElapsed, allowedTimeRemainingMs));
+    }
+
+    /**
+     * Calculates how much time it will take, in milliseconds, until the quota is fully consumed.
+     *
+     * @param windowStartElapsed The start of the window, in the elapsed realtime timebase.
+     * @param deadSpaceMs        How much time can be allowed to count towards the quota
+     */
+    private long calculateTimeUntilQuotaConsumedLocked(@NonNull List<TimingSession> sessions,
+            final long windowStartElapsed, long deadSpaceMs) {
+        long timeUntilQuotaConsumedMs = 0;
+        long start = windowStartElapsed;
+        for (int i = 0; i < sessions.size(); ++i) {
+            TimingSession session = sessions.get(i);
+
+            if (session.endTimeElapsed < windowStartElapsed) {
+                // Outside of window. Ignore.
+                continue;
+            } else if (session.startTimeElapsed <= windowStartElapsed) {
+                // Overlapping session. Can extend time by portion of session in window.
+                timeUntilQuotaConsumedMs += session.endTimeElapsed - windowStartElapsed;
+                start = session.endTimeElapsed;
+            } else {
+                // Completely within the window. Can only consider if there's enough dead space
+                // to get to the start of the session.
+                long diff = session.startTimeElapsed - start;
+                if (diff > deadSpaceMs) {
+                    break;
+                }
+                timeUntilQuotaConsumedMs += diff
+                        + (session.endTimeElapsed - session.startTimeElapsed);
+                deadSpaceMs -= diff;
+                start = session.endTimeElapsed;
+            }
+        }
+        // Will be non-zero if the loop didn't look at any sessions.
+        timeUntilQuotaConsumedMs += deadSpaceMs;
+        if (timeUntilQuotaConsumedMs > mMaxExecutionTimeMs) {
+            Slog.wtf(TAG, "Calculated quota consumed time too high: " + timeUntilQuotaConsumedMs);
+        }
+        return timeUntilQuotaConsumedMs;
+    }
+
     /** Returns the execution stats of the app in the most recent window. */
     @VisibleForTesting
     @NonNull
@@ -1483,7 +1568,7 @@
                     return;
                 }
                 Message msg = mHandler.obtainMessage(MSG_REACHED_QUOTA, mPkg);
-                final long timeRemainingMs = getRemainingExecutionTimeLocked(mPkg.userId,
+                final long timeRemainingMs = getTimeUntilQuotaConsumedLocked(mPkg.userId,
                         mPkg.packageName);
                 if (DEBUG) {
                     Slog.i(TAG, "Job for " + mPkg + " has " + timeRemainingMs + "ms left.");
@@ -1642,6 +1727,8 @@
                             // job is currently running.
                             // Reschedule message
                             Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg);
+                            timeRemainingMs = getTimeUntilQuotaConsumedLocked(pkg.userId,
+                                    pkg.packageName);
                             if (DEBUG) {
                                 Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left.");
                             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6c1472c..3833afc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2971,7 +2971,7 @@
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
-            updateAllSharedLibrariesLPw(null);
+            updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 // NOTE: We ignore potential failures here during a system scan (like
@@ -10022,11 +10022,11 @@
     }
 
     @GuardedBy("mPackages")
-    private void updateSharedLibrariesLPr(PackageParser.Package pkg,
-            PackageParser.Package changingLib) throws PackageManagerException {
+    private void updateSharedLibrariesLocked(PackageParser.Package pkg,
+            PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+                    throws PackageManagerException {
         final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
-                collectSharedLibraryInfos(pkg, Collections.unmodifiableMap(mPackages),
-                        mSharedLibraries, null);
+                collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
         executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
     }
 
@@ -10118,7 +10118,6 @@
                                     + " library " + libName + " version "
                                     + libraryInfo.getLongVersion() + "; failing!");
                     }
-
                     PackageParser.Package libPkg =
                             availablePackages.get(libraryInfo.getPackageName());
                     if (libPkg == null) {
@@ -10126,12 +10125,8 @@
                                 "Package " + packageName + " requires unavailable static shared"
                                         + " library; failing!");
                     }
-
                     final String[] expectedCertDigests = requiredCertDigests[i];
-
-
                     if (expectedCertDigests.length > 1) {
-
                         // For apps targeting O MR1 we require explicit enumeration of all certs.
                         final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
                                 ? PackageUtils.computeSignaturesSha256Digests(
@@ -10163,7 +10158,6 @@
                             }
                         }
                     } else {
-
                         // lib signing cert could have rotated beyond the one expected, check to see
                         // if the new one has been blessed by the old
                         if (!libPkg.mSigningDetails.hasSha256Certificate(
@@ -10175,7 +10169,6 @@
                         }
                     }
                 }
-
                 if (outUsedLibraries == null) {
                     outUsedLibraries = new ArrayList<>();
                 }
@@ -10186,7 +10179,7 @@
     }
 
     private static boolean hasString(List<String> list, List<String> which) {
-        if (list == null) {
+        if (list == null || which == null) {
             return false;
         }
         for (int i=list.size()-1; i>=0; i--) {
@@ -10200,39 +10193,63 @@
     }
 
     @GuardedBy("mPackages")
-    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
-            PackageParser.Package changingPkg) {
-        ArrayList<PackageParser.Package> res = null;
-        for (PackageParser.Package pkg : mPackages.values()) {
-            if (changingPkg != null
-                    && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
-                    && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
-                    && !ArrayUtils.contains(pkg.usesStaticLibraries,
-                            changingPkg.staticSharedLibName)) {
-                return null;
-            }
-            if (res == null) {
-                res = new ArrayList<>();
-            }
-            res.add(pkg);
-            try {
-                updateSharedLibrariesLPr(pkg, changingPkg);
-            } catch (PackageManagerException e) {
-                // If a system app update or an app and a required lib missing we
-                // delete the package and for updated system apps keep the data as
-                // it is better for the user to reinstall than to be in an limbo
-                // state. Also libs disappearing under an app should never happen
-                // - just in case.
-                if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
-                    final int flags = pkg.isUpdatedSystemApp()
-                            ? PackageManager.DELETE_KEEP_DATA : 0;
-                    deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
-                            flags , null, true, null);
-                }
-                Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
-            }
+    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
+            PackageParser.Package updatedPkg,
+            Map<String, PackageParser.Package> availablePackages) {
+        ArrayList<PackageParser.Package> resultList = null;
+        // Set of all descendants of a library; used to eliminate cycles
+        ArraySet<String> descendants = null;
+        // The current list of packages that need updating
+        ArrayList<PackageParser.Package> needsUpdating = null;
+        if (updatedPkg != null) {
+            needsUpdating = new ArrayList<>(1);
+            needsUpdating.add(updatedPkg);
         }
-        return res;
+        do {
+            final PackageParser.Package changingPkg =
+                    (needsUpdating == null) ? null : needsUpdating.remove(0);
+            for (int i = mPackages.size() - 1; i >= 0; --i) {
+                final PackageParser.Package pkg = mPackages.valueAt(i);
+                if (changingPkg != null
+                        && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
+                        && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
+                        && !ArrayUtils.contains(pkg.usesStaticLibraries,
+                                changingPkg.staticSharedLibName)) {
+                    continue;
+                }
+                if (resultList == null) {
+                    resultList = new ArrayList<>();
+                }
+                resultList.add(pkg);
+                // if we're updating a shared library, all of its descendants must be updated
+                if (changingPkg != null) {
+                    if (descendants == null) {
+                        descendants = new ArraySet<>();
+                    }
+                    if (!descendants.contains(pkg.packageName)) {
+                        descendants.add(pkg.packageName);
+                        needsUpdating.add(pkg);
+                    }
+                }
+                try {
+                    updateSharedLibrariesLocked(pkg, changingPkg, availablePackages);
+                } catch (PackageManagerException e) {
+                    // If a system app update or an app and a required lib missing we
+                    // delete the package and for updated system apps keep the data as
+                    // it is better for the user to reinstall than to be in an limbo
+                    // state. Also libs disappearing under an app should never happen
+                    // - just in case.
+                    if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
+                        final int flags = pkg.isUpdatedSystemApp()
+                                ? PackageManager.DELETE_KEEP_DATA : 0;
+                        deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+                                flags , null, true, null);
+                    }
+                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+                }
+            }
+        } while (needsUpdating != null && needsUpdating.size() > 0);
+        return resultList;
     }
 
     @GuardedBy({"mInstallLock", "mPackages"})
@@ -11654,19 +11671,19 @@
                 for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
                     commitSharedLibraryInfoLocked(info);
                 }
+                final Map<String, PackageParser.Package> combinedPackages =
+                        reconciledPkg.getCombinedPackages();
                 try {
                     // Shared libraries for the package need to be updated.
-                    updateSharedLibrariesLPr(pkg, null);
+                    updateSharedLibrariesLocked(pkg, null, combinedPackages);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
                 }
-            }
-
-            if (reconciledPkg.hasDynamicSharedLibraries() && (scanFlags & SCAN_BOOTING) == 0) {
-                // If we are not booting, we need to update any applications
-                // that are clients of our shared library.  If we are booting,
-                // this will all be done once the scan is complete.
-                clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
+                // Update all applications that use this library. Skip when booting
+                // since this will be done after all packages are scaned.
+                if ((scanFlags & SCAN_BOOTING) == 0) {
+                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
+                }
             }
         }
 
@@ -15755,6 +15772,7 @@
      * TODO: move most of the data contained her into a PackageSetting for commit.
      */
     private static class ReconciledPackage {
+        public final ReconcileRequest request;
         public final PackageSetting pkgSetting;
         public final ScanResult scanResult;
         // TODO: Remove install-specific details from the reconcile result
@@ -15768,14 +15786,18 @@
         public ArrayList<SharedLibraryInfo> collectedSharedLibraryInfos;
         public final boolean removeAppKeySetData;
 
-        private ReconciledPackage(InstallArgs installArgs, PackageSetting pkgSetting,
+        private ReconciledPackage(ReconcileRequest request,
+                InstallArgs installArgs,
+                PackageSetting pkgSetting,
                 PackageInstalledInfo installResult,
-                PrepareResult prepareResult, ScanResult scanResult,
+                PrepareResult prepareResult,
+                ScanResult scanResult,
                 DeletePackageAction deletePackageAction,
                 List<SharedLibraryInfo> allowedSharedLibraryInfos,
                 SigningDetails signingDetails,
                 boolean sharedUserSignaturesChanged,
                 boolean removeAppKeySetData) {
+            this.request = request;
             this.installArgs = installArgs;
             this.pkgSetting = pkgSetting;
             this.installResult = installResult;
@@ -15788,9 +15810,20 @@
             this.removeAppKeySetData = removeAppKeySetData;
         }
 
-        public boolean hasDynamicSharedLibraries() {
-            return !ArrayUtils.isEmpty(allowedSharedLibraryInfos)
-                    && allowedSharedLibraryInfos.get(0).getType() != SharedLibraryInfo.TYPE_STATIC;
+        /**
+         * Returns a combined set of packages containing the packages already installed combined
+         * with the package(s) currently being installed. The to-be installed packages take
+         * precedence and may shadow already installed packages.
+         */
+        private Map<String, PackageParser.Package> getCombinedPackages() {
+            final ArrayMap<String, PackageParser.Package> combinedPackages =
+                    new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
+
+            combinedPackages.putAll(request.allPackages);
+            for (ScanResult scanResult : request.scannedPackages.values()) {
+                combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+            }
+            return combinedPackages;
         }
     }
 
@@ -15980,7 +16013,7 @@
             }
 
             result.put(installPackageName,
-                    new ReconciledPackage(installArgs, scanResult.pkgSetting,
+                    new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
                             res, request.preparedPackages.get(installPackageName), scanResult,
                             deletePackageAction, allowedSharedLibInfos, signingDetails,
                             sharedUserSignaturesChanged, removeAppKeySetData));
@@ -18415,7 +18448,7 @@
 
         try {
             // update shared libraries for the newly re-installed system package
-            updateSharedLibrariesLPr(pkg, null);
+            updateSharedLibrariesLocked(pkg, null, Collections.unmodifiableMap(mPackages));
         } catch (PackageManagerException e) {
             Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
         }
@@ -20489,7 +20522,7 @@
                         prepareAppDataAfterInstallLIF(pkg);
                         synchronized (mPackages) {
                             try {
-                                updateSharedLibrariesLPr(pkg, null);
+                                updateSharedLibrariesLocked(pkg, null, mPackages);
                             } catch (PackageManagerException e) {
                                 Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
                             }
@@ -23333,6 +23366,23 @@
             }
             return results;
         }
+
+        @Override
+        public int getLocationFlags(String packageName) throws RemoteException {
+            int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+            ApplicationInfo appInfo = getApplicationInfo(packageName,
+                    /*flags*/ 0,
+                    /*userId*/ callingUser);
+            if (appInfo == null) {
+                throw new RemoteException(
+                        "Couldn't get ApplicationInfo for package " + packageName);
+            }
+            return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
+                    | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
+                    | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0)
+                    | (appInfo.isProductServices()
+                            ? IPackageManagerNative.LOCATION_PRODUCT_SERVICES : 0));
+        }
     }
 
     private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7c87462..d4d752f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -206,7 +206,6 @@
 import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ScreenshotHelper;
 import com.android.server.ExtconStateObserver;
 import com.android.server.ExtconUEventObserver;
 import com.android.server.GestureLauncherService;
@@ -377,7 +376,6 @@
     BurnInProtectionHelper mBurnInProtectionHelper;
     private DisplayFoldController mDisplayFoldController;
     AppOpsManager mAppOpsManager;
-    private ScreenshotHelper mScreenshotHelper;
     private boolean mHasFeatureWatch;
     private boolean mHasFeatureLeanback;
     private boolean mHasFeatureHdmiCec;
@@ -1923,7 +1921,6 @@
                         mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
                     }
                 });
-        mScreenshotHelper = new ScreenshotHelper(mContext);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 47745d5..20586db 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -114,6 +114,7 @@
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
@@ -1001,6 +1002,10 @@
             if (callerApp.hasActivityInVisibleTask()) {
                 return false;
             }
+            // don't abort if the caller is bound by a UID that's currently foreground
+            if (isBoundByForegroundUid(callerApp)) {
+                return false;
+            }
         }
         // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
         if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
@@ -1050,6 +1055,18 @@
         return true;
     }
 
+    private boolean isBoundByForegroundUid(WindowProcessController callerApp) {
+        final ArraySet<Integer> boundClientUids = callerApp.getBoundClientUids();
+        for (int i = boundClientUids.size() - 1; i >= 0; --i) {
+            final int uid = boundClientUids.valueAt(i);
+            if (mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid)
+                    || mService.getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Creates a launch intent for the given auxiliary resolution data.
      */
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5d38a69..95d8944 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2962,6 +2962,8 @@
         mLastDockedStackSysUiFlags = dockedVisibility;
         mLastFocusNeedsMenu = needsMenu;
         mFocusedApp = win.getAppToken();
+        mLastNonDockedStackBounds.set(mNonDockedStackBounds);
+        mLastDockedStackBounds.set(mDockedStackBounds);
         final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
         final Rect dockedStackBounds = new Rect(mDockedStackBounds);
         mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9b634f9..22b030d 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -426,11 +426,10 @@
     }
 
     @Override
-    public void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
-            int height) {
+    public void updateTapExcludeRegion(IWindow window, int regionId, Region region) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            mService.updateTapExcludeRegion(window, regionId, left, top, width, height);
+            mService.updateTapExcludeRegion(window, regionId, region);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
index 0a4ab67..22f529b 100644
--- a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
+++ b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
@@ -21,38 +21,35 @@
 import android.util.SparseArray;
 
 /**
- * A holder that contains a collection of rectangular areas identified by int id. Each individual
- * region can be updated separately.
+ * A holder that contains a collection of regions identified by int id. Each individual region can
+ * be updated separately.
  */
 class TapExcludeRegionHolder {
-    private SparseArray<Rect> mTapExcludeRects = new SparseArray<>();
+    private SparseArray<Region> mTapExcludeRegions = new SparseArray<>();
 
     /** Update the specified region with provided position and size. */
-    void updateRegion(int regionId, int left, int top, int width, int height) {
-        if (width <= 0 || height <= 0) {
-            // A region became empty - remove it.
-            mTapExcludeRects.remove(regionId);
+    void updateRegion(int regionId, Region region) {
+        // Remove the previous one because there is a new one incoming.
+        mTapExcludeRegions.remove(regionId);
+
+        if (region == null || region.isEmpty()) {
+            // The incoming region is invalid. Don't use it.
             return;
         }
 
-        Rect region = mTapExcludeRects.get(regionId);
-        if (region == null) {
-            region = new Rect();
-        }
-        region.set(left, top, left + width, top + height);
-        mTapExcludeRects.put(regionId, region);
+        mTapExcludeRegions.put(regionId, region);
     }
 
     /**
      * Union the provided region with current region formed by this container.
      */
-    void amendRegion(Region region, Rect boundingRegion) {
-        for (int i = mTapExcludeRects.size() - 1; i>= 0 ; --i) {
-            final Rect rect = mTapExcludeRects.valueAt(i);
-            if (boundingRegion != null) {
-                rect.intersect(boundingRegion);
+    void amendRegion(Region region, Rect bounds) {
+        for (int i = mTapExcludeRegions.size() - 1; i >= 0; --i) {
+            final Region r = mTapExcludeRegions.valueAt(i);
+            if (bounds != null) {
+                r.op(bounds, Region.Op.INTERSECT);
             }
-            region.union(rect);
+            region.op(r, Region.Op.UNION);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4aa844f..9e421c1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6696,24 +6696,23 @@
     }
 
     /**
-     * Update a tap exclude region with a rectangular area in the window identified by the provided
-     * id. Touches down on this region will not:
+     * Update a tap exclude region in the window identified by the provided id. Touches down on this
+     * region will not:
      * <ol>
      * <li>Switch focus to this window.</li>
      * <li>Move the display of this window to top.</li>
      * <li>Send the touch events to this window.</li>
      * </ol>
-     * Passing an empty rect will remove the area from the exclude region of this window.
+     * Passing an invalid region will remove the area from the exclude region of this window.
      */
-    void updateTapExcludeRegion(IWindow client, int regionId, int left, int top, int width,
-            int height) {
+    void updateTapExcludeRegion(IWindow client, int regionId, Region region) {
         synchronized (mGlobalLock) {
             final WindowState callingWin = windowForClientLocked(null, client, false);
             if (callingWin == null) {
                 Slog.w(TAG_WM, "Bad requesting window " + client);
                 return;
             }
-            callingWin.updateTapExcludeRegion(regionId, left, top, width, height);
+            callingWin.updateTapExcludeRegion(regionId, region);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 1b4aa26..4304d2d 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -149,6 +149,8 @@
     // Set to true if this process is currently temporarily whitelisted to start activities even if
     // it's not in the foreground
     private volatile boolean mAllowBackgroundActivityStarts;
+    // Set of UIDs of clients currently bound to this process
+    private volatile ArraySet<Integer> mBoundClientUids = new ArraySet<Integer>();
 
     // Thread currently set for VR scheduling
     int mVrThreadTid;
@@ -368,6 +370,14 @@
         return mAllowBackgroundActivityStarts;
     }
 
+    public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
+        mBoundClientUids = boundClientUids;
+    }
+
+    public ArraySet<Integer> getBoundClientUids() {
+        return mBoundClientUids;
+    }
+
     public void setInstrumenting(boolean instrumenting,
             boolean hasBackgroundActivityStartPrivileges) {
         mInstrumenting = instrumenting;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f143c70..b5f7a85 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4837,10 +4837,10 @@
     }
 
     /**
-     * Update a tap exclude region with a rectangular area identified by provided id. The requested
-     * area will be clipped to the window bounds.
+     * Update a tap exclude region identified by provided id. The requested area will be clipped to
+     * the window bounds.
      */
-    void updateTapExcludeRegion(int regionId, int left, int top, int width, int height) {
+    void updateTapExcludeRegion(int regionId, Region region) {
         final DisplayContent currentDisplay = getDisplayContent();
         if (currentDisplay == null) {
             throw new IllegalStateException("Trying to update window not attached to any display.");
@@ -4854,7 +4854,7 @@
             currentDisplay.mTapExcludeProvidingWindows.add(this);
         }
 
-        mTapExcludeRegionHolder.updateRegion(regionId, left, top, width, height);
+        mTapExcludeRegionHolder.updateRegion(regionId, region);
         // Trigger touch exclude region update on current display.
         currentDisplay.updateTouchExcludeRegion();
         // Trigger touchable region update for this window.
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 5e1ea89..98e4343 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -2,5 +2,5 @@
     name: "default-permissions",
     srcs: ["default-permissions.xsd"],
     api_dir: "schema",
-    package_name: "com.android.server.pm.permission",
+    package_name: "com.android.server.pm.permission.configfile",
 }
diff --git a/services/core/xsd/default-permissions.xsd b/services/core/xsd/default-permissions.xsd
index d800a26..2e32be0 100644
--- a/services/core/xsd/default-permissions.xsd
+++ b/services/core/xsd/default-permissions.xsd
@@ -27,7 +27,7 @@
     </xs:element>
     <xs:complexType name="exception">
         <xs:sequence>
-            <xs:element name="permission" type="permission"/>
+            <xs:element name="permission" type="permission" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute name="package" type="xs:string"/>
         <xs:attribute name="sha256-cert-digest" type="xs:string"/>
diff --git a/services/core/xsd/schema/current.txt b/services/core/xsd/schema/current.txt
index 4e67e5c..a2092e3 100644
--- a/services/core/xsd/schema/current.txt
+++ b/services/core/xsd/schema/current.txt
@@ -1,21 +1,20 @@
 // Signature format: 2.0
-package com.android.server.pm.permission {
+package com.android.server.pm.permission.configfile {
 
   public class Exception {
     ctor public Exception();
     method public String getBrand();
-    method public com.android.server.pm.permission.Permission getPermission();
+    method public java.util.List<com.android.server.pm.permission.configfile.Permission> getPermission();
     method public String getSha256CertDigest();
     method public String get_package();
     method public void setBrand(String);
-    method public void setPermission(com.android.server.pm.permission.Permission);
     method public void setSha256CertDigest(String);
     method public void set_package(String);
   }
 
   public class Exceptions {
     ctor public Exceptions();
-    method public java.util.List<com.android.server.pm.permission.Exception> getException();
+    method public java.util.List<com.android.server.pm.permission.configfile.Exception> getException();
   }
 
   public class Permission {
@@ -28,7 +27,7 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static com.android.server.pm.permission.Exceptions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static com.android.server.pm.permission.configfile.Exceptions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 7ef0ac4..8f48f5b 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -58,6 +58,7 @@
     name: "services.net",
     srcs: ["java/**/*.java"],
     static_libs: [
+        "dnsresolver_aidl_interface-java",
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
     ]
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index cad71a2..08f6a37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -722,6 +722,147 @@
         assertEquals(expectedStats, newStatsRare);
     }
 
+    /**
+     * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
+     * window.
+     */
+    @Test
+    public void testGetTimeUntilQuotaConsumedLocked_BucketWindow() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Close to RARE boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (24 * HOUR_IN_MILLIS - 30 * SECOND_IN_MILLIS),
+                        30 * SECOND_IN_MILLIS, 5));
+        // Far away from FREQUENT boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+        // Overlap WORKING_SET boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS),
+                        3 * MINUTE_IN_MILLIS, 5));
+        // Close to ACTIVE boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+        setStandbyBucket(RARE_INDEX);
+        assertEquals(30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(FREQUENT_INDEX);
+        assertEquals(MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(5 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(7 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the
+        // max execution time.
+        setStandbyBucket(ACTIVE_INDEX);
+        assertEquals(7 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Test getTimeUntilQuotaConsumedLocked when the app is close to the max execution limit.
+     */
+    @Test
+    public void testGetTimeUntilQuotaConsumedLocked_MaxExecution() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Overlap boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (24 * HOUR_IN_MILLIS + 8 * MINUTE_IN_MILLIS), 4 * HOUR_IN_MILLIS, 5));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(8 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        // Max time will phase out, so should use bucket limit.
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+        // Close to boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (24 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS),
+                        4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(5 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+        // Far from boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(3 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(3 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Test getTimeUntilQuotaConsumedLocked when the max execution time and bucket window time
+     * remaining are equal.
+     */
+    @Test
+    public void testGetTimeUntilQuotaConsumedLocked_EqualTimeRemaining() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setStandbyBucket(FREQUENT_INDEX);
+
+        // Overlap boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (24 * HOUR_IN_MILLIS + 11 * MINUTE_IN_MILLIS),
+                        4 * HOUR_IN_MILLIS,
+                        5));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+        // Both max and bucket time have 8 minutes left.
+        assertEquals(8 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        // Max time essentially free. Bucket time has 2 min phase out plus original 8 minute
+        // window time.
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+        // Overlap boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (24 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (20 * HOUR_IN_MILLIS),
+                        3 * HOUR_IN_MILLIS + 48 * MINUTE_IN_MILLIS,
+                        5));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+        // Both max and bucket time have 8 minutes left.
+        assertEquals(8 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        // Max time only has one minute phase out. Bucket time has 2 minute phase out.
+        assertEquals(9 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
     @Test
     public void testIsWithinQuotaLocked_NeverApp() {
         assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX));
@@ -1902,7 +2043,10 @@
         // window, so as the package "reaches its quota" it will have more to keep running.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - 2 * HOUR_IN_MILLIS,
-                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+                        10 * SECOND_IN_MILLIS - remainingTimeMs, 1));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - HOUR_IN_MILLIS,
+                        9 * MINUTE_IN_MILLIS + 50 * SECOND_IN_MILLIS, 1));
 
         assertEquals(remainingTimeMs, mQuotaController.getRemainingExecutionTimeLocked(jobStatus));
         // Start the job.
@@ -1919,6 +2063,18 @@
         // amount of remaining time left its quota.
         assertEquals(remainingTimeMs,
                 mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
-        verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(remainingTimeMs));
+        // Handler is told to check when the quota will be consumed, not when the initial
+        // remaining time is over.
+        verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(10 * SECOND_IN_MILLIS));
+        verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
+
+        // After 10 seconds, the job should finally be out of quota.
+        advanceElapsedClock(10 * SECOND_IN_MILLIS - remainingTimeMs);
+        // Wait for some extra time to allow for job processing.
+        verify(mJobSchedulerService,
+                timeout(12 * SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        verify(handler, never()).sendMessageDelayed(any(), anyInt());
     }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bb2b275..6aca693 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2571,6 +2571,22 @@
             "emergency_number_prefix_string_array";
 
     /**
+     * Smart forwarding config. Smart forwarding is a feature to configure call forwarding to a
+     * different SIM in the device when one SIM is not reachable. The config here specifies a smart
+     * forwarding component that will launch UI for changing the configuration. An empty string
+     * indicates that no smart forwarding component is specified.
+     *
+     * Currently, only one non-empty configuration of smart forwarding component within system will
+     * be used when multiple SIMs are inserted.
+     *
+     * Empty string by default.
+     *
+     * @hide
+     */
+    public static final String KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING =
+            "smart_forwarding_config_component_name_string";
+
+    /**
      * Indicates when a carrier has a primary subscription and an opportunistic subscription active,
      * and when Internet data is switched to opportunistic network, whether to still show
      * signal bar of primary network. By default it will be false, meaning whenever data
@@ -3130,6 +3146,7 @@
         sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true);
         sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
+        sDefaults.putString(KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING, "");
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
                 false);
     }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b35de59..0ead228 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -104,6 +104,7 @@
 import android.net.ConnectivityManager.PacketKeepaliveCallback;
 import android.net.ConnectivityManager.TooManyRequestsException;
 import android.net.ConnectivityThread;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -240,6 +241,7 @@
     private static final String CLAT_PREFIX = "v4-";
     private static final String MOBILE_IFNAME = "test_rmnet_data0";
     private static final String WIFI_IFNAME = "test_wlan0";
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     private MockContext mServiceContext;
     private WrappedConnectivityService mService;
@@ -256,6 +258,7 @@
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
     @Mock INetworkPolicyManager mNpm;
+    @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
     @Mock NetworkStackClient mNetworkStack;
 
@@ -1053,8 +1056,8 @@
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
                 INetworkStatsService statsService, INetworkPolicyManager policyManager,
-                IpConnectivityLog log, INetd netd) {
-            super(context, netManager, statsService, policyManager, log);
+                IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
+            super(context, netManager, statsService, policyManager, dnsResolver, log);
             mNetd = netd;
             mLingerDelayMs = TEST_LINGER_DELAY_MS;
         }
@@ -1218,7 +1221,8 @@
                 mStatsService,
                 mNpm,
                 mock(IpConnectivityLog.class),
-                mMockNetd);
+                mMockNetd,
+                mMockDnsResolver);
 
         final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
                 ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -4777,14 +4781,14 @@
         ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
 
         // Clear any interactions that occur as a result of CS starting up.
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
-        final String[] EMPTY_STRING_ARRAY = new String[0];
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         waitForIdle();
-        verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
-        verifyNoMoreInteractions(mNetworkManagementService);
+        verify(mMockDnsResolver, never()).setResolverConfiguration(
+                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verifyNoMoreInteractions(mMockDnsResolver);
 
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4801,28 +4805,29 @@
         mCellNetworkAgent.connect(false);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
-        reset(mNetworkManagementService);
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
+                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(1, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
         // Opportunistic mode.
         assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1"));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
@@ -4830,7 +4835,7 @@
         assertEquals(2, tlsServers.getValue().length);
         assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
         final String TLS_SPECIFIER = "tls.example.com";
         final String TLS_SERVER6 = "2001:db8:53::53";
@@ -4840,22 +4845,21 @@
                 new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
 
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(TLS_SPECIFIER), eq(TLS_SERVERS));
+                eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
     }
 
     @Test
     public void testPrivateDnsSettingsChange() throws Exception {
-        final String[] EMPTY_STRING_ARRAY = new String[0];
         ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
 
         // Clear any interactions that occur as a result of CS starting up.
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
         // The default on Android is opportunistic mode ("Automatic").
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
@@ -4868,9 +4872,10 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
-        verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
-        verifyNoMoreInteractions(mNetworkManagementService);
+        verify(mMockDnsResolver, never()).setResolverConfiguration(
+                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verifyNoMoreInteractions(mMockDnsResolver);
 
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4889,9 +4894,9 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(false);
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
@@ -4899,7 +4904,7 @@
         assertEquals(2, tlsServers.getValue().length);
         assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
                 mCellNetworkAgent);
@@ -4911,26 +4916,26 @@
         assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
-        verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, times(1)).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), eq(EMPTY_STRING_ARRAY));
+                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         assertEquals(2, tlsServers.getValue().length);
         assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
@@ -5761,6 +5766,7 @@
         cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
         cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
         reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfig(myIpv4));
 
@@ -5768,7 +5774,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
         // Switching default network updates TCP buffer sizes.
         verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
@@ -5778,17 +5784,22 @@
         cellLp.addLinkAddress(myIpv4);
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
+                eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(),
+                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
 
         verifyNoMoreInteractions(mMockNetd);
+        verifyNoMoreInteractions(mMockDnsResolver);
         reset(mMockNetd);
+        reset(mMockDnsResolver);
 
         // Remove IPv4 address. Expect prefix discovery to be started again.
         cellLp.removeLinkAddress(myIpv4);
         cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
         Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
@@ -5818,6 +5829,12 @@
         assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
         assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
 
+        verify(mMockDnsResolver, times(1)).setResolverConfiguration(
+                eq(cellNetId), mStringArrayCaptor.capture(), any(), any(),
+                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        assertEquals(1, mStringArrayCaptor.getValue().length);
+        assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8"));
+
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
         cellLp.addLinkAddress(myIpv4);
@@ -5825,7 +5842,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
-        verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
 
         // As soon as stop is called, the linkproperties lose the stacked interface.
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
@@ -5840,7 +5857,9 @@
         networkCallback.assertNoCallback();
 
         verifyNoMoreInteractions(mMockNetd);
+        verifyNoMoreInteractions(mMockDnsResolver);
         reset(mMockNetd);
+        reset(mMockDnsResolver);
 
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -5854,7 +5873,7 @@
         cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
                 kNat64PrefixString, 96);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
@@ -5937,6 +5956,7 @@
 
         // Disconnect cell
         reset(mNetworkManagementService);
+        reset(mMockNetd);
         mCellNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
@@ -5944,8 +5964,9 @@
         // unexpectedly before network being removed.
         waitForIdle();
         verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
-        verify(mNetworkManagementService, times(1)).removeNetwork(
-                eq(mCellNetworkAgent.getNetwork().netId));
+        verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
+        verify(mMockDnsResolver, times(1))
+                .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 15ba43d..8fa0ab9 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -29,13 +29,13 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.net.IDnsResolver;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.RouteInfo;
 import android.net.shared.PrivateDnsConfig;
-import android.os.INetworkManagementService;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 
@@ -73,7 +73,7 @@
     MockContentResolver mContentResolver;
 
     @Mock Context mCtx;
-    @Mock INetworkManagementService mNMService;
+    @Mock IDnsResolver mMockDnsResolver;
     @Mock MockableSystemProperties mSystemProperties;
 
     @Before
@@ -83,7 +83,7 @@
         mContentResolver.addProvider(Settings.AUTHORITY,
                 new FakeSettingsProvider());
         when(mCtx.getContentResolver()).thenReturn(mContentResolver);
-        mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties);
+        mDnsManager = new DnsManager(mCtx, mMockDnsResolver, mSystemProperties);
 
         // Clear the private DNS settings
         Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 6de4aa1..142769f 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -69,6 +70,7 @@
     LingerMonitor mMonitor;
 
     @Mock ConnectivityService mConnService;
+    @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
     @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
@@ -353,7 +355,7 @@
         caps.addCapability(0);
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS,
+                caps, 50, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS,
                 NetworkFactory.SerialNumber.NONE);
         nai.everValidated = true;
         return nai;
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index cc09fb7..b709af1 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
@@ -63,6 +64,7 @@
 
     @Mock ConnectivityService mConnectivity;
     @Mock NetworkMisc mMisc;
+    @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
     @Mock INetworkManagementService mNms;
     @Mock InterfaceConfiguration mConfig;
@@ -72,7 +74,7 @@
     Handler mHandler;
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNai, mNetd, mNms) {
+        return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
             @Override protected int getNetId() {
                 return NETID;
             }
@@ -205,7 +207,7 @@
         verify(mNms).unregisterObserver(eq(nat));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
         // Stacked interface removed notification arrives and is ignored.
@@ -331,7 +333,7 @@
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         assertIdle(nat);
@@ -358,7 +360,7 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
         // In-flight interface up notification arrives: no-op
@@ -390,7 +392,7 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
         verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 9eab4be..d28ab70 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -31,6 +31,8 @@
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -80,6 +82,7 @@
     @Mock private MockableSystemProperties mSystemProperties;
     @Mock private Resources mResources;
     @Mock private SharedLog mLog;
+    @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
 
     // Like so many Android system APIs, these cannot be mocked because it is marked final.
     // We have to use the real versions.
@@ -109,7 +112,6 @@
 
     public class WrappedEntitlementManager extends EntitlementManager {
         public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
-        public boolean everRunUiEntitlement = false;
         public int uiProvisionCount = 0;
         public int silentProvisionCount = 0;
 
@@ -118,20 +120,22 @@
             super(ctx, target, log, what, systemProperties);
         }
 
-        @Override
-        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
-            everRunUiEntitlement = true;
-            receiver.send(fakeEntitlementResult, null);
+        public void reset() {
+            fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+            uiProvisionCount = 0;
+            silentProvisionCount = 0;
         }
 
         @Override
-        protected void runUiTetherProvisioning(int type) {
+        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
             uiProvisionCount++;
+            receiver.send(fakeEntitlementResult, null);
         }
 
         @Override
         protected void runSilentTetherProvisioning(int type) {
             silentProvisionCount++;
+            addDownstreamMapping(type, fakeEntitlementResult);
         }
     }
 
@@ -157,6 +161,7 @@
         mSM = new TestStateMachine();
         mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
                 mSystemProperties);
+        mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
         mEnMgr.updateConfiguration(
                 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
     }
@@ -246,7 +251,6 @@
         final CountDownLatch mCallbacklatch = new CountDownLatch(1);
         // 1. Entitlement check is not required.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         ResultReceiver receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -257,13 +261,13 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
 
         setupForRequiredProvisioning();
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
         // 2. No cache value and don't need to run entitlement check.
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -274,10 +278,10 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 3. No cache value and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -288,10 +292,10 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertTrue(mEnMgr.everRunUiEntitlement);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -302,10 +306,10 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -316,10 +320,10 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertTrue(mEnMgr.everRunUiEntitlement);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 6. Cache value is TETHER_ERROR_NO_ERROR.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -330,9 +334,9 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 7. Test get value for other downstream type.
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -343,7 +347,8 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
     }
 
     void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
@@ -358,15 +363,15 @@
         mEnMgr.notifyUpstream(true);
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
         mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
         mLooper.dispatchAll();
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
     }
 
@@ -376,17 +381,17 @@
         mEnMgr.notifyUpstream(true);
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
     }
 
@@ -396,14 +401,14 @@
         mEnMgr.notifyUpstream(true);
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
         mLooper.dispatchAll();
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
         mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
         mLooper.dispatchAll();
@@ -417,48 +422,71 @@
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                 INVALID_SUBSCRIPTION_ID));
         // 1. start ui provisioning, upstream is mobile
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 1);
-        assertTrue(mEnMgr.silentProvisionCount == 0);
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
         // 2. start no-ui provisioning
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.silentProvisionCount == 1);
-        assertTrue(mEnMgr.uiProvisionCount == 1);
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(1, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
         // 3. tear down mobile, then start ui provisioning
         mEnMgr.notifyUpstream(false);
         mLooper.dispatchAll();
         mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 1);
-        assertTrue(mEnMgr.silentProvisionCount == 1);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
         // 4. switch upstream back to mobile
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 2);
-        assertTrue(mEnMgr.silentProvisionCount == 1);
-        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
         // 5. tear down mobile, then switch SIM
         mEnMgr.notifyUpstream(false);
         mLooper.dispatchAll();
         mEnMgr.reevaluateSimCardProvisioning();
-        assertTrue(mEnMgr.uiProvisionCount == 2);
-        assertTrue(mEnMgr.silentProvisionCount == 1);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
         // 6. switch upstream back to mobile again
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 2);
-        assertTrue(mEnMgr.silentProvisionCount == 4);
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
-        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(3, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
     }
 
+    @Test
+    public void testCallStopTetheringWhenUiProvisioningFail() {
+        setupForRequiredProvisioning();
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                INVALID_SUBSCRIPTION_ID));
+        verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.notifyUpstream(true);
+        mLooper.dispatchAll();
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
+    }
+
+
     public class TestStateMachine extends StateMachine {
         public final ArrayList<Message> messages = new ArrayList<>();
         private final State