Merge "Throw clear error if a row doesn't fit into CursorWindow"
diff --git a/Android.mk b/Android.mk
index 6470e34..c87aec4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -425,7 +425,6 @@
 	core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl \
 	core/java/com/android/internal/widget/ILockSettings.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
-	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
 	keystore/java/android/security/IKeyChainAliasCallback.aidl \
 	keystore/java/android/security/IKeyChainService.aidl \
 	location/java/android/location/IBatchedLocationCallback.aidl \
@@ -579,6 +578,8 @@
 
 LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
 
+LOCAL_AIDL_INCLUDES += core/java/android/os/StatsLogEventWrapper.aidl
+
 LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java
 LOCAL_SRC_FILES += \
 	lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index df8b7ef..8b3c740 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6451,6 +6451,8 @@
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
+    method public boolean setTime(android.content.ComponentName, long);
+    method public boolean setTimeZone(android.content.ComponentName, java.lang.String);
     method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
diff --git a/api/system-current.txt b/api/system-current.txt
index 007316f..ee23b6d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6686,6 +6686,8 @@
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
+    method public boolean setTime(android.content.ComponentName, long);
+    method public boolean setTimeZone(android.content.ComponentName, java.lang.String);
     method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
diff --git a/api/test-current.txt b/api/test-current.txt
index faccb6b..9a241ad 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6519,6 +6519,8 @@
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
+    method public boolean setTime(android.content.ComponentName, long);
+    method public boolean setTimeZone(android.content.ComponentName, java.lang.String);
     method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 3c2f2d5..8946aed 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -37,6 +37,7 @@
     src/matchers/matcher_util.cpp \
     src/matchers/SimpleLogMatchingTracker.cpp \
     src/metrics/CountAnomalyTracker.cpp \
+    src/metrics/MetricProducer.cpp \
     src/metrics/CountMetricProducer.cpp \
     src/metrics/DurationMetricProducer.cpp \
     src/metrics/MetricsManager.cpp \
@@ -49,7 +50,8 @@
     src/stats_util.cpp
 
 statsd_common_c_includes := \
-    $(LOCAL_PATH)/src
+    $(LOCAL_PATH)/src \
+    $(LOCAL_PATH)/../../libs/services/include
 
 statsd_common_aidl_includes := \
     $(LOCAL_PATH)/../../core/java
@@ -95,7 +97,7 @@
 endif
 LOCAL_PROTOC_OPTIMIZE_TYPE := lite-static
 
-LOCAL_AIDL_INCLUDES := $(statsd_common_c_includes)
+LOCAL_AIDL_INCLUDES := $(statsd_common_aidl_includes)
 LOCAL_C_INCLUDES += $(statsd_common_c_includes)
 
 LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries)
@@ -117,7 +119,7 @@
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_AIDL_INCLUDES := $(statsd_common_c_includes)
+LOCAL_AIDL_INCLUDES := $(statsd_common_aidl_includes)
 LOCAL_C_INCLUDES += $(statsd_common_c_includes)
 
 LOCAL_CFLAGS += \
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 87616d3..1faeee0 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -63,9 +63,9 @@
 
 // ======================================================================
 StatsService::StatsService(const sp<Looper>& handlerLooper)
-    : mStatsPullerManager(),
-      mAnomalyMonitor(new AnomalyMonitor(2))  // TODO: Put this comment somewhere better
+    : mAnomalyMonitor(new AnomalyMonitor(2))  // TODO: Put this comment somewhere better
 {
+    mStatsPullerManager = new StatsPullerManager();
     mUidMap = new UidMap();
     mConfigManager = new ConfigManager();
     mProcessor = new StatsLogProcessor(mUidMap);
@@ -193,6 +193,10 @@
         if (!args[0].compare(String8("dump-report"))) {
             return cmd_dump_report(out, err, args);
         }
+
+        if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
+            return cmd_print_pulled_metrics(out, args);
+        }
     }
 
     print_cmd_help(out);
@@ -210,6 +214,11 @@
     fprintf(out, "  Prints the UID, app name, version mapping.\n");
     fprintf(out, "\n");
     fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmds stats pull-source [int] \n");
+    fprintf(out, "\n");
+    fprintf(out, "  Prints the output of a pulled metrics source (int indicates source)\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
     fprintf(out, "usage: adb shell cmd stats config remove [UID] NAME\n");
     fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
     fprintf(out, "\n");
@@ -353,6 +362,16 @@
     return NO_ERROR;
 }
 
+status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
+    int s = atoi(args[1].c_str());
+    auto stats = mStatsPullerManager->Pull(s);
+    for (const auto& it : stats) {
+        fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+    }
+    fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+    return NO_ERROR;
+}
+
 Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
                                       const vector<String16>& app) {
     if (DEBUG) ALOGD("StatsService::informAllUidData was called");
@@ -414,10 +433,6 @@
 
     if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
     // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
-    String16 output = mStatsPullerManager.pull(StatsPullerManager::KERNEL_WAKELOCKS);
-    // TODO: do something useful with the output instead of writing a string to screen.
-    ALOGD("%s", String8(output).string());
-    ALOGD("%d", int(output.size()));
 
     return Status::ok();
 }
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 294aec8..449a2b8 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -121,6 +121,11 @@
     status_t cmd_print_uid_map(FILE* out);
 
     /**
+     * Print contents of a pulled metrics source.
+     */
+    status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
+
+    /**
      * Update a configuration.
      */
     void set_config(int uid, const string& name, const StatsdConfig& config);
@@ -132,9 +137,8 @@
 
     /**
      * Fetches external metrics.
-     * TODO: This should be an sp<>
      */
-    StatsPullerManager mStatsPullerManager;
+    sp<StatsPullerManager> mStatsPullerManager;
 
     /**
      * Tracks the configurations that have been passed to statsd.
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp
index b9abee0..ee072f8 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp
@@ -37,9 +37,9 @@
 
 // The reading and parsing are implemented in Java. It is not difficult to port over. But for now
 // let StatsCompanionService handle that and send the data back.
-String16 KernelWakelockPuller::pull() {
+vector<StatsLogEventWrapper> KernelWakelockPuller::pull() {
     sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
-    String16 returned_value("");
+    vector<StatsLogEventWrapper> returned_value;
     if (statsCompanion != NULL) {
         Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
                                                  &returned_value);
@@ -47,12 +47,10 @@
             ALOGW("error pulling kernel wakelock");
         }
         ALOGD("KernelWakelockPuller::pull succeeded!");
-        // TODO: remove this when we integrate into aggregation chain.
-        ALOGD("%s", String8(returned_value).string());
         return returned_value;
     } else {
         ALOGW("statsCompanion not found!");
-        return String16();
+        return returned_value;
     }
 }
 
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h
index 1ec3376..c12806c 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/KernelWakelockPuller.h
@@ -29,7 +29,7 @@
     // a number of stats need to be pulled from StatsCompanionService
     //
     const static int PULL_CODE_KERNEL_WAKELOCKS;
-    String16 pull() override;
+    vector<StatsLogEventWrapper> pull() override;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 5e556b8..6655629 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -17,7 +17,12 @@
 #ifndef STATSD_STATSPULLER_H
 #define STATSD_STATSPULLER_H
 
+#include <android/os/StatsLogEventWrapper.h>
 #include <utils/String16.h>
+#include <vector>
+
+using android::os::StatsLogEventWrapper;
+using std::vector;
 
 namespace android {
 namespace os {
@@ -26,8 +31,8 @@
 class StatsPuller {
 public:
     virtual ~StatsPuller(){};
-    // use string for now, until we figure out how to integrate into the aggregation path
-    virtual String16 pull() = 0;
+
+    virtual vector<StatsLogEventWrapper> pull() = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 6e8d58bc..7f554d3 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -21,6 +21,11 @@
 #include "KernelWakelockPuller.h"
 #include "StatsService.h"
 #include "external/StatsPullerManager.h"
+#include "logd/LogEvent.h"
+#include <cutils/log.h>
+#include <algorithm>
+
+#include <iostream>
 
 using namespace android;
 
@@ -35,13 +40,27 @@
             {static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()});
 }
 
-String16 StatsPullerManager::pull(int pullCode) {
+vector<std::shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode) {
     if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
+
+    vector<std::shared_ptr<LogEvent>> ret;
     if (mStatsPullers.find(pullCode) != mStatsPullers.end()) {
-        return (mStatsPullers.find(pullCode)->second)->pull();
+        vector<StatsLogEventWrapper> outputs = (mStatsPullers.find(pullCode)->second)->pull();
+        for (const StatsLogEventWrapper& it : outputs) {
+            log_msg tmp;
+            tmp.entry_v1.len = it.bytes.size();
+            // Manually set the header size to 28 bytes to match the pushed log events.
+            tmp.entry.hdr_size = 28;
+            // And set the received bytes starting after the 28 bytes reserved for header.
+            std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + 28);
+            std::shared_ptr<LogEvent> evt = std::make_shared<LogEvent>(tmp);
+            ret.push_back(evt);
+            // ret.emplace_back(tmp);
+        }
+        return ret;
     } else {
         ALOGD("Unknown pull code %d", pullCode);
-        return String16();
+        return ret;  // Return early since we don't know what to pull.
     }
 }
 
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index f143424..e46aec1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -20,6 +20,8 @@
 #include <utils/String16.h>
 #include <unordered_map>
 #include "external/StatsPuller.h"
+#include "logd/LogEvent.h"
+#include "matchers/matcher_util.h"
 
 namespace android {
 namespace os {
@@ -27,7 +29,7 @@
 
 const static int KERNEL_WAKELOCKS = 1;
 
-class StatsPullerManager {
+class StatsPullerManager : public virtual RefBase {
 public:
     // Enums of pulled data types (pullCodes)
     // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
@@ -35,7 +37,8 @@
     const static int KERNEL_WAKELOCKS;
     StatsPullerManager();
 
-    String16 pull(const int pullCode);
+    // We return a vector of shared_ptr since LogEvent's copy constructor is not available.
+    vector<std::shared_ptr<LogEvent>> Pull(const int pullCode);
 
 private:
     std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 032b4b8..fb992c1 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -23,29 +23,30 @@
 namespace statsd {
 
 using std::ostringstream;
+using std::string;
 
-LogEvent::LogEvent(const log_msg& msg) {
-    init(msg);
+// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
+// for strings is not cleared before we can read them.
+LogEvent::LogEvent(log_msg msg) : mList(msg) {
+    init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
 }
 
-LogEvent::LogEvent(int64_t timestampNs, android_log_event_list* reader) {
-    init(timestampNs, reader);
+LogEvent::LogEvent(int tag) : mList(tag) {
 }
 
 LogEvent::~LogEvent() {
 }
 
+void LogEvent::init() {
+    mList.convert_to_reader();
+    init(mTimestampNs, &mList);
+}
+
 /**
  * The elements of each log event are stored as a vector of android_log_list_elements.
  * The goal is to do as little preprocessing as possible, because we read a tiny fraction
  * of the elements that are written to the log.
  */
-void LogEvent::init(const log_msg& msg) {
-
-    android_log_event_list list(const_cast<log_msg&>(msg));
-    init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &list);
-}
-
 void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
     mTimestampNs = timestampNs;
     mTagId = reader->tag();
@@ -79,6 +80,10 @@
     } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
 }
 
+android_log_event_list* LogEvent::GetAndroidLogEventList() {
+    return &mList;
+}
+
 int64_t LogEvent::GetLong(size_t key, status_t* err) const {
     if (key < 1 || (key - 1)  >= mElements.size()) {
         *err = BAD_INDEX;
@@ -109,7 +114,8 @@
         *err = BAD_TYPE;
         return NULL;
     }
-    return elem.data.string;
+    // Need to add the '/0' at the end by specifying the length of the string.
+    return string(elem.data.string, elem.len).c_str();
 }
 
 bool LogEvent::GetBool(size_t key, status_t* err) const {
@@ -189,7 +195,8 @@
         } else if (elem.type == EVENT_TYPE_FLOAT) {
             result << elem.data.float32;
         } else if (elem.type == EVENT_TYPE_STRING) {
-            result << elem.data.string;
+            // Need to add the '/0' at the end by specifying the length of the string.
+            result << string(elem.data.string, elem.len).c_str();
         }
     }
     result << " }";
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 464afca..4102675 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -22,6 +22,7 @@
 #include <log/log_event_list.h>
 #include <log/log_read.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -40,12 +41,16 @@
     /**
      * Read a LogEvent from a log_msg.
      */
-    explicit LogEvent(const log_msg& msg);
+    explicit LogEvent(log_msg msg);
 
     /**
-     * Read a LogEvent from an android_log_context.
+     * Constructs a LogEvent with the specified tag and creates an android_log_event_list in write
+     * mode. Obtain this list with the getter. Make sure to call init() before attempting to read
+     * any of the values. This constructor is useful for unit-testing since we can't pass in an
+     * android_log_event_list since there is no copy constructor or assignment operator available.
      */
-    explicit LogEvent(int64_t timestampNs, android_log_event_list* reader);
+    explicit LogEvent(int tag);
+
     ~LogEvent();
 
     /**
@@ -85,6 +90,19 @@
      */
     KeyValuePair GetKeyValueProto(size_t key) const;
 
+    /**
+     * A pointer to the contained log_event_list.
+     *
+     * @return The android_log_event_list contained within.
+     */
+    android_log_event_list* GetAndroidLogEventList();
+
+    /**
+     * Used with the constructor where tag is passed in. Converts the log_event_list to read mode
+     * and prepares the list for reading.
+     */
+    void init();
+
 private:
     /**
      * Don't copy, it's slower. If we really need this we can add it but let's try to
@@ -103,6 +121,8 @@
     void init(int64_t timestampNs, android_log_event_list* reader);
 
     vector<android_log_list_element> mElements;
+    // Need a copy of the android_log_event_list so the strings are not cleared.
+    android_log_event_list mList;
     long mTimestampNs;
     int mTagId;
 };
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 1f07914..28cb503 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -124,52 +124,23 @@
     mCondition = conditionMet;
 }
 
-void CountMetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
+void CountMetricProducer::onMatchedLogEventInternal(
+        const size_t matcherIndex, const HashableDimensionKey& eventKey,
+        const map<string, HashableDimensionKey>& conditionKey, bool condition,
+        const LogEvent& event) {
     uint64_t eventTimeNs = event.GetTimestampNs();
-    // this is old event, maybe statsd restarted?
-    if (eventTimeNs < mStartTimeNs) {
-        return;
-    }
 
     flushCounterIfNeeded(eventTimeNs);
 
-    if (mConditionSliced) {
-        map<string, HashableDimensionKey> conditionKeys;
-        for (const auto& link : mConditionLinks) {
-            VLOG("Condition link key_in_main size %d", link.key_in_main_size());
-            HashableDimensionKey conditionKey = getDimensionKeyForCondition(event, link);
-            conditionKeys[link.condition()] = conditionKey;
-        }
-        if (mWizard->query(mConditionTrackerIndex, conditionKeys) != ConditionState::kTrue) {
-            VLOG("metric %lld sliced condition not met", mMetric.metric_id());
-            return;
-        }
-    } else {
-        if (!mCondition) {
-            VLOG("metric %lld condition not met", mMetric.metric_id());
-            return;
-        }
+    if (condition == false) {
+        return;
     }
 
-    HashableDimensionKey hashableKey;
-
-    if (mDimension.size() > 0) {
-        vector<KeyValuePair> key = getDimensionKey(event, mDimension);
-        hashableKey = getHashableKey(key);
-        // Add the HashableDimensionKey->vector<KeyValuePair> to the map, because StatsLogReport
-        // expects vector<KeyValuePair>.
-        if (mDimensionKeyMap.find(hashableKey) == mDimensionKeyMap.end()) {
-            mDimensionKeyMap[hashableKey] = key;
-        }
-    } else {
-        hashableKey = DEFAULT_DIMENSION_KEY;
-    }
-
-    auto it = mCurrentSlicedCounter.find(hashableKey);
+    auto it = mCurrentSlicedCounter.find(eventKey);
 
     if (it == mCurrentSlicedCounter.end()) {
         // create a counter for the new key
-        mCurrentSlicedCounter[hashableKey] = 1;
+        mCurrentSlicedCounter[eventKey] = 1;
 
     } else {
         // increment the existing value
@@ -177,8 +148,8 @@
         count++;
     }
 
-    VLOG("metric %lld %s->%d", mMetric.metric_id(), hashableKey.c_str(),
-         mCurrentSlicedCounter[hashableKey]);
+    VLOG("metric %lld %s->%d", mMetric.metric_id(), eventKey.c_str(),
+         mCurrentSlicedCounter[eventKey]);
 }
 
 // When a new matched event comes in, we check if event falls into the current
@@ -215,4 +186,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index f0d6025..8bbdb01 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -41,8 +41,6 @@
 
     virtual ~CountMetricProducer();
 
-    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) override;
-
     void onConditionChanged(const bool conditionMet) override;
 
     void finish() override;
@@ -54,6 +52,11 @@
     // TODO: Implement this later.
     virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
 
+protected:
+    void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
+                                   const std::map<std::string, HashableDimensionKey>& conditionKey,
+                                   bool condition, const LogEvent& event) override;
+
 private:
     const CountMetric mMetric;
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index aa597f4..38e55fd 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -137,11 +137,10 @@
     return report;
 };
 
-void DurationMetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
-    if (event.GetTimestampNs() < mStartTimeNs) {
-        return;
-    }
-
+void DurationMetricProducer::onMatchedLogEventInternal(
+        const size_t matcherIndex, const HashableDimensionKey& eventKey,
+        const map<string, HashableDimensionKey>& conditionKeys, bool condition,
+        const LogEvent& event) {
     flushDurationIfNeeded(event.GetTimestampNs());
 
     if (matcherIndex == mStopAllIndex) {
@@ -149,49 +148,20 @@
         return;
     }
 
-    HashableDimensionKey hashableKey;
-    if (mDimension.size() > 0) {
-        // hook up sliced counter with AnomalyMonitor.
-        vector<KeyValuePair> key = getDimensionKey(event, mDimension);
-        hashableKey = getHashableKey(key);
-        // Add the HashableDimensionKey->DimensionKey to the map, because StatsLogReport expects
-        // vector<KeyValuePair>.
-        if (mDimensionKeyMap.find(hashableKey) == mDimensionKeyMap.end()) {
-            mDimensionKeyMap[hashableKey] = key;
-        }
-    } else {
-        hashableKey = DEFAULT_DIMENSION_KEY;
-    }
-
-    if (mCurrentSlicedDuration.find(hashableKey) == mCurrentSlicedDuration.end() &&
-        mConditionSliced) {
+    if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end() && mConditionSliced) {
         // add the durationInfo for the current bucket.
-        auto& durationInfo = mCurrentSlicedDuration[hashableKey];
-        auto& conditionKeys = durationInfo.conditionKeys;
-        // get and cache the keys for query condition.
-        for (const auto& link : mConditionLinks) {
-            HashableDimensionKey conditionKey = getDimensionKeyForCondition(event, link);
-            conditionKeys[link.condition()] = conditionKey;
-        }
-    }
-
-    bool conditionMet;
-    if (mConditionSliced) {
-        const auto& conditionKeys = mCurrentSlicedDuration[hashableKey].conditionKeys;
-        conditionMet =
-                mWizard->query(mConditionTrackerIndex, conditionKeys) == ConditionState::kTrue;
-    } else {
-        conditionMet = mCondition;
+        auto& durationInfo = mCurrentSlicedDuration[eventKey];
+        durationInfo.conditionKeys = conditionKeys;
     }
 
     if (matcherIndex == mStartIndex) {
-        VLOG("Metric %lld Key: %s Start, Condition %d", mMetric.metric_id(), hashableKey.c_str(),
-             conditionMet);
-        noteStart(hashableKey, conditionMet, event.GetTimestampNs());
+        VLOG("Metric %lld Key: %s Start, Condition %d", mMetric.metric_id(), eventKey.c_str(),
+             condition);
+        noteStart(eventKey, condition, event.GetTimestampNs());
     } else if (matcherIndex == mStopIndex) {
-        VLOG("Metric %lld Key: %s Stop, Condition %d", mMetric.metric_id(), hashableKey.c_str(),
-             conditionMet);
-        noteStop(hashableKey, event.GetTimestampNs());
+        VLOG("Metric %lld Key: %s Stop, Condition %d", mMetric.metric_id(), eventKey.c_str(),
+             condition);
+        noteStop(eventKey, event.GetTimestampNs());
     }
 }
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 44c3254..19e2437 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -61,8 +61,6 @@
 
     virtual ~DurationMetricProducer();
 
-    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) override;
-
     void onConditionChanged(const bool conditionMet) override;
 
     void finish() override;
@@ -74,6 +72,11 @@
     // TODO: Implement this later.
     virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
 
+protected:
+    void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
+                                   const std::map<std::string, HashableDimensionKey>& conditionKeys,
+                                   bool condition, const LogEvent& event) override;
+
 private:
     const DurationMetric mMetric;
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
new file mode 100644
index 0000000..3c8ce6e
--- /dev/null
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+#include "MetricProducer.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+
+void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
+    uint64_t eventTimeNs = event.GetTimestampNs();
+    // this is old event, maybe statsd restarted?
+    if (eventTimeNs < mStartTimeNs) {
+        return;
+    }
+
+    HashableDimensionKey eventKey;
+
+    if (mDimension.size() > 0) {
+        vector<KeyValuePair> key = getDimensionKey(event, mDimension);
+        eventKey = getHashableKey(key);
+        // Add the HashableDimensionKey->vector<KeyValuePair> to the map, because StatsLogReport
+        // expects vector<KeyValuePair>.
+        if (mDimensionKeyMap.find(eventKey) == mDimensionKeyMap.end()) {
+            mDimensionKeyMap[eventKey] = key;
+        }
+    } else {
+        eventKey = DEFAULT_DIMENSION_KEY;
+    }
+
+    bool condition;
+
+    map<string, HashableDimensionKey> conditionKeys;
+    if (mConditionSliced) {
+        for (const auto& link : mConditionLinks) {
+            HashableDimensionKey conditionKey = getDimensionKeyForCondition(event, link);
+            conditionKeys[link.condition()] = conditionKey;
+        }
+        if (mWizard->query(mConditionTrackerIndex, conditionKeys) != ConditionState::kTrue) {
+            condition = false;
+        } else {
+            condition = true;
+        }
+    } else {
+        condition = mCondition;
+    }
+
+    onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index afaab64..496b145 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -48,7 +48,7 @@
     virtual ~MetricProducer(){};
 
     // Consume the parsed stats log entry that already matched the "what" of the metric.
-    virtual void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) = 0;
+    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event);
 
     virtual void onConditionChanged(const bool condition) = 0;
 
@@ -86,6 +86,26 @@
     std::unordered_map<HashableDimensionKey, std::vector<KeyValuePair>> mDimensionKeyMap;
 
     std::vector<EventConditionLink> mConditionLinks;
+
+    /*
+     * Individual metrics can implement their own business logic here. All pre-processing is done.
+     *
+     * [matcherIndex]: the index of the matcher which matched this event. This is interesting to
+     *                 DurationMetric, because it has start/stop/stop_all 3 matchers.
+     * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
+     *             dimensions, it will be DEFAULT_DIMENSION_KEY
+     * [conditionKey]: the keys of conditions which should be used to query the condition for this
+     *                 target event (from EventConditionLink). This is passed to individual metrics
+     *                 because DurationMetric needs it to be cached.
+     * [condition]: whether condition is met. If condition is sliced, this is the result coming from
+     *              query with ConditionWizard; If condition is not sliced, this is the
+     *              nonSlicedCondition.
+     * [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
+     */
+    virtual void onMatchedLogEventInternal(
+            const size_t matcherIndex, const HashableDimensionKey& eventKey,
+            const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
+            const LogEvent& event) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 19403c0..fdfe8ef 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -42,12 +42,10 @@
     auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
     simpleMatcher->set_tag(TAG_ID);
 
-    // Set up the event
-    android_log_event_list list(TAG_ID);
+    LogEvent event(TAG_ID);
 
     // Convert to a LogEvent
-    list.convert_to_reader();
-    LogEvent event(999, &list);
+    event.init();
 
     // Test
     EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
@@ -64,13 +62,13 @@
     keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
 
     // Set up the event
-    android_log_event_list list(TAG_ID);
-    list << true;
-    list << false;
+    LogEvent event(TAG_ID);
+    auto list = event.GetAndroidLogEventList();
+    *list << true;
+    *list << false;
 
     // Convert to a LogEvent
-    list.convert_to_reader();
-    LogEvent event(999, &list);
+    event.init();
 
     // Test
     keyValue1->set_eq_bool(true);
@@ -100,12 +98,12 @@
     keyValue->set_eq_string("some value");
 
     // Set up the event
-    android_log_event_list list(TAG_ID);
-    list << "some value";
+    LogEvent event(TAG_ID);
+    auto list = event.GetAndroidLogEventList();
+    *list << "some value";
 
     // Convert to a LogEvent
-    list.convert_to_reader();
-    LogEvent event(999, &list);
+    event.init();
 
     // Test
     EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
@@ -121,12 +119,11 @@
     keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
 
     // Set up the event
-    android_log_event_list list(TAG_ID);
-    list << 11;
+    LogEvent event(TAG_ID);
+    auto list = event.GetAndroidLogEventList();
+    *list << 11;
 
-    // Convert to a LogEvent
-    list.convert_to_reader();
-    LogEvent event(999, &list);
+    event.init();
 
     // Test
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3c53063..ab8edee 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6533,6 +6533,52 @@
     }
 
     /**
+     * Called by device owner to set the system wall clock time. This only takes effect if called
+     * when {@link android.provider.Settings.Global#AUTO_TIME} is 0, otherwise {@code false} will be
+     * returned.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+     * @param millis time in milliseconds since the Epoch
+     * @return {@code true} if set time succeeded, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     */
+    public boolean setTime(@NonNull ComponentName admin, long millis) {
+        throwIfParentInstance("setTime");
+        if (mService != null) {
+            try {
+                return mService.setTime(admin, millis);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by device owner to set the system's persistent default time zone. This only takes
+     * effect if called when {@link android.provider.Settings.Global#AUTO_TIME_ZONE} is 0, otherwise
+     * {@code false} will be returned.
+     *
+     * @see android.app.AlarmManager#setTimeZone(String)
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+     * @param timeZone one of the Olson ids from the list returned by
+     *     {@link java.util.TimeZone#getAvailableIDs}
+     * @return {@code true} if set timezone succeeded, {@code false} otherwise.
+     * @throws SecurityException if {@code admin} is not a device owner.
+     */
+    public boolean setTimeZone(@NonNull ComponentName admin, String timeZone) {
+        throwIfParentInstance("setTimeZone");
+        if (mService != null) {
+            try {
+                return mService.setTimeZone(admin, timeZone);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by profile or device owners to update {@link android.provider.Settings.Secure}
      * settings. Validation that the value of the setting is in the correct form for the setting
      * type should be performed by the caller.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8865a05..e77c186 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -229,6 +229,9 @@
     void setGlobalSetting(in ComponentName who, in String setting, in String value);
     void setSecureSetting(in ComponentName who, in String setting, in String value);
 
+    boolean setTime(in ComponentName who, long millis);
+    boolean setTimeZone(in ComponentName who, String timeZone);
+
     void setMasterVolumeMuted(in ComponentName admin, boolean on);
     boolean isMasterVolumeMuted(in ComponentName admin);
 
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 969b19e..37bb6b0 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -20,17 +20,19 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
-import android.annotation.SystemService;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemService;
+import android.app.IServiceConnection;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.ServiceConnection;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
-import android.os.IBinder;
+import android.os.Handler;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -1051,43 +1053,23 @@
      * The appWidgetId specified must already be bound to the calling AppWidgetHost via
      * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
      *
-     * @param packageName   The package from which the binding is requested.
      * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
      * @param intent        The intent of the service which will be providing the data to the
      *                      RemoteViewsAdapter.
      * @param connection    The callback interface to be notified when a connection is made or lost.
+     * @param flags         Flags used for binding to the service
+     *
+     * @see Context#getServiceDispatcher(ServiceConnection, Handler, int)
      * @hide
      */
-    public void bindRemoteViewsService(String packageName, int appWidgetId, Intent intent,
-            IBinder connection) {
+    public boolean bindRemoteViewsService(Context context, int appWidgetId, Intent intent,
+            IServiceConnection connection, @Context.BindServiceFlags int flags) {
         if (mService == null) {
-            return;
+            return false;
         }
         try {
-            mService.bindRemoteViewsService(packageName, appWidgetId, intent, connection);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Unbinds the RemoteViewsService for a given appWidgetId and intent.
-     *
-     * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
-     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
-     *
-     * @param packageName   The package from which the binding is requested.
-     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
-     * @param intent        The intent of the service which will be providing the data to the
-     *                      RemoteViewsAdapter.
-     * @hide
-     */
-    public void unbindRemoteViewsService(String packageName, int appWidgetId, Intent intent) {
-        if (mService == null) {
-            return;
-        }
-        try {
-            mService.unbindRemoteViewsService(packageName, appWidgetId, intent);
+            return mService.bindRemoteViewsService(context.getOpPackageName(), appWidgetId, intent,
+                    context.getIApplicationThread(), context.getActivityToken(), connection, flags);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index d8f9567..20f6c8e 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.os.StatsLogEventWrapper;
+
 /**
   * Binder interface to communicate with the Java-based statistics service helper.
   * {@hide}
@@ -50,5 +52,5 @@
     oneway void cancelPollingAlarms();
 
     /** Pull the specified data. Results will be sent to statsd when complete. */
-    String pullData(int pullCode);
+    StatsLogEventWrapper[] pullData(int pullCode);
 }
diff --git a/core/java/android/service/autofill/SaveInfo.aidl b/core/java/android/os/StatsLogEventWrapper.aidl
similarity index 69%
rename from core/java/android/service/autofill/SaveInfo.aidl
rename to core/java/android/os/StatsLogEventWrapper.aidl
index 8cda608..766343e 100644
--- a/core/java/android/service/autofill/SaveInfo.aidl
+++ b/core/java/android/os/StatsLogEventWrapper.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
+/*
+ * 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
+ *      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,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.service.autofill;
+package android.os;
 
-parcelable SaveInfo;
+/** @hide */
+parcelable StatsLogEventWrapper cpp_header "android/os/StatsLogEventWrapper.h";
\ No newline at end of file
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
new file mode 100644
index 0000000..9491bec
--- /dev/null
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+package android.os;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Wrapper class for sending data from Android OS to StatsD.
+ *
+ * @hide
+ */
+public final class StatsLogEventWrapper implements Parcelable {
+    private ByteArrayOutputStream mStorage = new ByteArrayOutputStream();
+
+    // Below are constants copied from log/log.h
+    private static final int EVENT_TYPE_INT = 0;  /* int32_t */
+    private static final int EVENT_TYPE_LONG = 1; /* int64_t */
+    private static final int EVENT_TYPE_STRING = 2;
+    private static final int EVENT_TYPE_LIST = 3;
+    private static final int EVENT_TYPE_FLOAT = 4;
+
+    /**
+     * Creates a log_event that is binary-encoded as implemented in
+     * system/core/liblog/log_event_list.c; this allows us to use the same parsing logic in statsd
+     * for pushed and pulled data. The write* methods must be called in the same order as their
+     * field number. There is no checking that the correct number of write* methods is called.
+     * We also write an END_LIST character before beginning to write to parcel, but this END_LIST
+     * may be unnecessary.
+     *
+     * @param tag    The integer representing the tag for this event.
+     * @param fields The number of fields specified in this event.
+     */
+    public StatsLogEventWrapper(int tag, int fields) {
+        // Write four bytes from tag, starting with least-significant bit.
+        write4Bytes(tag);
+        mStorage.write(EVENT_TYPE_LIST); // This is required to start the log entry.
+        mStorage.write(fields); // Indicate number of elements in this list.
+    }
+
+    /**
+     * Boilerplate for Parcel.
+     */
+    public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new
+            Parcelable.Creator<StatsLogEventWrapper>() {
+                public StatsLogEventWrapper createFromParcel(Parcel in) {
+                    return new StatsLogEventWrapper(in);
+                }
+
+                public StatsLogEventWrapper[] newArray(int size) {
+                    return new StatsLogEventWrapper[size];
+                }
+            };
+
+    private void write4Bytes(int val) {
+        mStorage.write(val);
+        mStorage.write(val >>> 8);
+        mStorage.write(val >>> 16);
+        mStorage.write(val >>> 24);
+    }
+
+    private void write8Bytes(long val) {
+        write4Bytes((int) (val & 0xFFFFFFFF)); // keep the lowe 32-bits
+        write4Bytes((int) (val >>> 32)); // Write the high 32-bits.
+    }
+
+    /**
+     * Adds 32-bit integer to output.
+     */
+    public void writeInt(int val) {
+        mStorage.write(EVENT_TYPE_INT);
+        write4Bytes(val);
+    }
+
+    /**
+     * Adds 64-bit long to output.
+     */
+    public void writeLong(long val) {
+        mStorage.write(EVENT_TYPE_LONG);
+        write8Bytes(val);
+    }
+
+    /**
+     * Adds a 4-byte floating point value to output.
+     */
+    public void writeFloat(float val) {
+        int v = Float.floatToIntBits(val);
+        mStorage.write(EVENT_TYPE_FLOAT);
+        write4Bytes(v);
+    }
+
+    /**
+     * Adds a string to the output.
+     */
+    public void writeString(String val) {
+        mStorage.write(EVENT_TYPE_STRING);
+        write4Bytes(val.length());
+        byte[] bytes = val.getBytes(StandardCharsets.UTF_8);
+        mStorage.write(bytes, 0, bytes.length);
+    }
+
+    private StatsLogEventWrapper(Parcel in) {
+        readFromParcel(in);
+    }
+
+    /**
+     * Writes the stored fields to a byte array. Will first write a new-line character to denote
+     * END_LIST before writing contents to byte array.
+     */
+    public void writeToParcel(Parcel out, int flags) {
+        mStorage.write(10); // new-line character is same as END_LIST
+        out.writeByteArray(mStorage.toByteArray());
+    }
+
+    /**
+     * Not implemented.
+     */
+    public void readFromParcel(Parcel in) {
+        // Not needed since this java class is for sending to statsd only.
+    }
+
+    /**
+     * Boilerplate for Parcel.
+     */
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/service/autofill/Dataset.aidl b/core/java/android/service/autofill/Dataset.aidl
deleted file mode 100644
index 2342c5f..0000000
--- a/core/java/android/service/autofill/Dataset.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * 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.
- */
-
-package android.service.autofill;
-
-parcelable Dataset;
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index b2cdef2..331130e 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -150,8 +150,16 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        return new StringBuilder("Dataset " + mId + " [")
-                .append("fieldIds=").append(mFieldIds)
+        final StringBuilder builder = new StringBuilder("Dataset[id=");
+        if (mId == null) {
+            builder.append("null");
+        } else {
+            // Cannot disclose id because it could contain PII.
+            builder.append(mId.length()).append("_chars");
+        }
+
+        return builder
+                .append(", fieldIds=").append(mFieldIds)
                 .append(", fieldValues=").append(mFieldValues)
                 .append(", fieldPresentations=")
                 .append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index d6c0dbf..b1857b3 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -129,6 +129,11 @@
     }
 
     @Override
+    public String toString() {
+        return mEvents == null ? "no events" : mEvents.toString();
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index d91cebb..d2033fa 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -71,7 +71,7 @@
     private FillResponse(@NonNull Builder builder) {
         mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
         mSaveInfo = builder.mSaveInfo;
-        mClientState = builder.mCLientState;
+        mClientState = builder.mClientState;
         mPresentation = builder.mPresentation;
         mAuthentication = builder.mAuthentication;
         mAuthenticationIds = builder.mAuthenticationIds;
@@ -145,7 +145,7 @@
     public static final class Builder {
         private ArrayList<Dataset> mDatasets;
         private SaveInfo mSaveInfo;
-        private Bundle mCLientState;
+        private Bundle mClientState;
         private RemoteViews mPresentation;
         private IntentSender mAuthentication;
         private AutofillId[] mAuthenticationIds;
@@ -288,7 +288,7 @@
          */
         public Builder setClientState(@Nullable Bundle clientState) {
             throwIfDestroyed();
-            mCLientState = clientState;
+            mClientState = clientState;
             return this;
         }
 
diff --git a/core/java/android/view/autofill/AutoFillType.aidl b/core/java/android/view/autofill/AutoFillType.aidl
deleted file mode 100644
index 4606b48..0000000
--- a/core/java/android/view/autofill/AutoFillType.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * 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.
- */
-
-package android.view.autofill;
-
-/*
- * TODO(b/35956626): remove once clients use getAutoFilltype()
- */
-parcelable AutoFillType;
\ No newline at end of file
diff --git a/core/java/android/view/autofill/AutoFillValue.aidl b/core/java/android/view/autofill/AutoFillValue.aidl
deleted file mode 100644
index 05b7562..0000000
--- a/core/java/android/view/autofill/AutoFillValue.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * 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.
- */
-
-package android.view.autofill;
-
-//  @deprecated TODO(b/35956626): remove once clients use AutofillValue
-parcelable AutoFillValue;
\ No newline at end of file
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index af09592..384f4f8 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -476,17 +476,6 @@
         stopTextActionModeWithPreservingSelection();
     }
 
-    void invalidateMagnifier() {
-        final DisplayMetrics dm = mTextView.getResources().getDisplayMetrics();
-        invalidateMagnifier(0, 0, dm.widthPixels, dm.heightPixels);
-    }
-
-    void invalidateMagnifier(final float l, final float t, final float r, final float b) {
-        if (mMagnifier != null) {
-            mTextView.post(() -> mMagnifier.invalidate(new RectF(l, t, r, b)));
-        }
-    }
-
     private void discardTextDisplayLists() {
         if (mTextRenderNodes != null) {
             for (int i = 0; i < mTextRenderNodes.length; i++) {
@@ -4550,17 +4539,15 @@
             final Layout layout = mTextView.getLayout();
             final int lineNumber = layout.getLineForOffset(offset);
             // Horizontally snap to character offset.
-            final float xPosInView = getHorizontal(mTextView.getLayout(), offset);
+            final float xPosInView = getHorizontal(mTextView.getLayout(), offset)
+                    + mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
             // Vertically snap to middle of current line.
             final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
-                    + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f;
-            final int[] coordinatesOnScreen = new int[2];
-            mTextView.getLocationOnScreen(coordinatesOnScreen);
-            final float centerXOnScreen = mTextView.convertViewToScreenCoord(xPosInView, true);
-            final float centerYOnScreen = mTextView.convertViewToScreenCoord(yPosInView, false);
+                    + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
+                    + mTextView.getTotalPaddingTop() - mTextView.getScrollY();
 
             suspendBlink();
-            mMagnifier.show(centerXOnScreen, centerYOnScreen, MAGNIFIER_ZOOM);
+            mMagnifier.show(xPosInView, yPosInView, MAGNIFIER_ZOOM);
         }
 
         protected final void dismissMagnifier() {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 51277e4..e5ae0ca 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -16,11 +16,14 @@
 
 package android.widget;
 
-import android.Manifest;
+import android.annotation.WorkerThread;
+import android.app.IServiceConnection;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -29,7 +32,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
@@ -39,7 +41,6 @@
 import android.view.ViewGroup;
 import android.widget.RemoteViews.OnClickHandler;
 
-import com.android.internal.widget.IRemoteViewsAdapterConnection;
 import com.android.internal.widget.IRemoteViewsFactory;
 
 import java.lang.ref.WeakReference;
@@ -49,52 +50,33 @@
 import java.util.concurrent.Executor;
 
 /**
- * An adapter to a RemoteViewsService which fetches and caches RemoteViews
- * to be later inflated as child views.
+ * An adapter to a RemoteViewsService which fetches and caches RemoteViews to be later inflated as
+ * child views.
+ *
+ * The adapter runs in the host process, typically a Launcher app.
+ *
+ * It makes a service connection to the {@link RemoteViewsService} running in the
+ * AppWidgetsProvider's process. This connection is made on a background thread (and proxied via
+ * the platform to get the bind permissions) and all interaction with the service is done on the
+ * background thread.
+ *
+ * On first bind, the adapter will load can cache the RemoteViews locally. Afterwards the
+ * connection is only made when new RemoteViews are required.
+ * @hide
  */
-/** @hide */
 public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback {
-    private static final String MULTI_USER_PERM = Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 
     private static final String TAG = "RemoteViewsAdapter";
 
     // The max number of items in the cache
-    private static final int sDefaultCacheSize = 40;
+    private static final int DEFAULT_CACHE_SIZE = 40;
     // The delay (in millis) to wait until attempting to unbind from a service after a request.
     // This ensures that we don't stay continually bound to the service and that it can be destroyed
     // if we need the memory elsewhere in the system.
-    private static final int sUnbindServiceDelay = 5000;
+    private static final int UNBIND_SERVICE_DELAY = 5000;
 
     // Default height for the default loading view, in case we cannot get inflate the first view
-    private static final int sDefaultLoadingViewHeight = 50;
-
-    // Type defs for controlling different messages across the main and worker message queues
-    private static final int sDefaultMessageType = 0;
-    private static final int sUnbindServiceMessageType = 1;
-
-    private final Context mContext;
-    private final Intent mIntent;
-    private final int mAppWidgetId;
-    private final Executor mAsyncViewLoadExecutor;
-
-    private RemoteViewsAdapterServiceConnection mServiceConnection;
-    private WeakReference<RemoteAdapterConnectionCallback> mCallback;
-    private OnClickHandler mRemoteViewsOnClickHandler;
-    private final FixedSizeRemoteViewsCache mCache;
-    private int mVisibleWindowLowerBound;
-    private int mVisibleWindowUpperBound;
-
-    // A flag to determine whether we should notify data set changed after we connect
-    private boolean mNotifyDataSetChangedAfterOnServiceConnected = false;
-
-    // The set of requested views that are to be notified when the associated RemoteViews are
-    // loaded.
-    private RemoteViewsFrameLayoutRefSet mRequestedViews;
-
-    private HandlerThread mWorkerThread;
-    // items may be interrupted within the normally processed queues
-    private Handler mWorkerQueue;
-    private Handler mMainQueue;
+    private static final int DEFAULT_LOADING_VIEW_HEIGHT = 50;
 
     // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
     // structures;
@@ -111,6 +93,26 @@
     // duration, the cache is dropped.
     private static final int REMOTE_VIEWS_CACHE_DURATION = 5000;
 
+    private final Context mContext;
+    private final Intent mIntent;
+    private final int mAppWidgetId;
+    private final Executor mAsyncViewLoadExecutor;
+
+    private OnClickHandler mRemoteViewsOnClickHandler;
+    private final FixedSizeRemoteViewsCache mCache;
+    private int mVisibleWindowLowerBound;
+    private int mVisibleWindowUpperBound;
+
+    // The set of requested views that are to be notified when the associated RemoteViews are
+    // loaded.
+    private RemoteViewsFrameLayoutRefSet mRequestedViews;
+
+    private final HandlerThread mWorkerThread;
+    // items may be interrupted within the normally processed queues
+    private final Handler mMainHandler;
+    private final RemoteServiceHandler mServiceHandler;
+    private final RemoteAdapterConnectionCallback mCallback;
+
     // Used to indicate to the AdapterView that it can use this Adapter immediately after
     // construction (happens when we have a cached FixedSizeRemoteViewsCache).
     private boolean mDataReady = false;
@@ -158,154 +160,192 @@
         }
     }
 
+    static final int MSG_REQUEST_BIND = 1;
+    static final int MSG_NOTIFY_DATA_SET_CHANGED = 2;
+    static final int MSG_LOAD_NEXT_ITEM = 3;
+    static final int MSG_UNBIND_SERVICE = 4;
+
+    private static final int MSG_MAIN_HANDLER_COMMIT_METADATA = 1;
+    private static final int MSG_MAIN_HANDLER_SUPER_NOTIFY_DATA_SET_CHANGED = 2;
+    private static final int MSG_MAIN_HANDLER_REMOTE_ADAPTER_CONNECTED = 3;
+    private static final int MSG_MAIN_HANDLER_REMOTE_ADAPTER_DISCONNECTED = 4;
+    private static final int MSG_MAIN_HANDLER_REMOTE_VIEWS_LOADED = 5;
+
     /**
-     * The service connection that gets populated when the RemoteViewsService is
-     * bound.  This must be a static inner class to ensure that no references to the outer
-     * RemoteViewsAdapter instance is retained (this would prevent the RemoteViewsAdapter from being
-     * garbage collected, and would cause us to leak activities due to the caching mechanism for
-     * FrameLayouts in the adapter).
+     * Handler for various interactions with the {@link RemoteViewsService}.
      */
-    private static class RemoteViewsAdapterServiceConnection extends
-            IRemoteViewsAdapterConnection.Stub {
-        private boolean mIsConnected;
-        private boolean mIsConnecting;
-        private WeakReference<RemoteViewsAdapter> mAdapter;
+    private static class RemoteServiceHandler extends Handler implements ServiceConnection {
+
+        private final WeakReference<RemoteViewsAdapter> mAdapter;
+        private final Context mContext;
+
         private IRemoteViewsFactory mRemoteViewsFactory;
 
-        public RemoteViewsAdapterServiceConnection(RemoteViewsAdapter adapter) {
-            mAdapter = new WeakReference<RemoteViewsAdapter>(adapter);
+        // The last call to notifyDataSetChanged didn't succeed, try again on next service bind.
+        private boolean mNotifyDataSetChangedPending = false;
+        private boolean mBindRequested = false;
+
+        RemoteServiceHandler(Looper workerLooper, RemoteViewsAdapter adapter, Context context) {
+            super(workerLooper);
+            mAdapter = new WeakReference<>(adapter);
+            mContext = context;
         }
 
-        public synchronized void bind(Context context, int appWidgetId, Intent intent) {
-            if (!mIsConnecting) {
-                try {
-                    RemoteViewsAdapter adapter;
-                    final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
-                    if ((adapter = mAdapter.get()) != null) {
-                        mgr.bindRemoteViewsService(context.getOpPackageName(), appWidgetId,
-                                intent, asBinder());
-                    } else {
-                        Slog.w(TAG, "bind: adapter was null");
-                    }
-                    mIsConnecting = true;
-                } catch (Exception e) {
-                    Log.e("RVAServiceConnection", "bind(): " + e.getMessage());
-                    mIsConnecting = false;
-                    mIsConnected = false;
-                }
-            }
-        }
-
-        public synchronized void unbind(Context context, int appWidgetId, Intent intent) {
-            try {
-                RemoteViewsAdapter adapter;
-                final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
-                if ((adapter = mAdapter.get()) != null) {
-                    mgr.unbindRemoteViewsService(context.getOpPackageName(), appWidgetId, intent);
-                } else {
-                    Slog.w(TAG, "unbind: adapter was null");
-                }
-                mIsConnecting = false;
-            } catch (Exception e) {
-                Log.e("RVAServiceConnection", "unbind(): " + e.getMessage());
-                mIsConnecting = false;
-                mIsConnected = false;
-            }
-        }
-
-        public synchronized void onServiceConnected(IBinder service) {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            // This is called on the same thread.
             mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service);
+            enqueueDeferredUnbindServiceMessage();
 
-            // Remove any deferred unbind messages
-            final RemoteViewsAdapter adapter = mAdapter.get();
-            if (adapter == null) return;
+            RemoteViewsAdapter adapter = mAdapter.get();
+            if (adapter == null) {
+                return;
+            }
 
-            // Queue up work that we need to do for the callback to run
-            adapter.mWorkerQueue.post(new Runnable() {
-                @Override
-                public void run() {
-                    if (adapter.mNotifyDataSetChangedAfterOnServiceConnected) {
-                        // Handle queued notifyDataSetChanged() if necessary
-                        adapter.onNotifyDataSetChanged();
-                    } else {
-                        IRemoteViewsFactory factory =
-                            adapter.mServiceConnection.getRemoteViewsFactory();
-                        try {
-                            if (!factory.isCreated()) {
-                                // We only call onDataSetChanged() if this is the factory was just
-                                // create in response to this bind
-                                factory.onDataSetChanged();
-                            }
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error notifying factory of data set changed in " +
-                                        "onServiceConnected(): " + e.getMessage());
-
-                            // Return early to prevent anything further from being notified
-                            // (effectively nothing has changed)
-                            return;
-                        } catch (RuntimeException e) {
-                            Log.e(TAG, "Error notifying factory of data set changed in " +
-                                    "onServiceConnected(): " + e.getMessage());
-                        }
-
-                        // Request meta data so that we have up to date data when calling back to
-                        // the remote adapter callback
-                        adapter.updateTemporaryMetaData();
-
-                        // Notify the host that we've connected
-                        adapter.mMainQueue.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                synchronized (adapter.mCache) {
-                                    adapter.mCache.commitTemporaryMetaData();
-                                }
-
-                                final RemoteAdapterConnectionCallback callback =
-                                    adapter.mCallback.get();
-                                if (callback != null) {
-                                    callback.onRemoteAdapterConnected();
-                                }
-                            }
-                        });
-                    }
-
-                    // Enqueue unbind message
-                    adapter.enqueueDeferredUnbindServiceMessage();
-                    mIsConnected = true;
-                    mIsConnecting = false;
+            if (mNotifyDataSetChangedPending) {
+                mNotifyDataSetChangedPending = false;
+                Message msg = Message.obtain(this, MSG_NOTIFY_DATA_SET_CHANGED);
+                handleMessage(msg);
+                msg.recycle();
+            } else {
+                if (!sendNotifyDataSetChange(false)) {
+                    return;
                 }
-            });
+
+                // Request meta data so that we have up to date data when calling back to
+                // the remote adapter callback
+                adapter.updateTemporaryMetaData(mRemoteViewsFactory);
+                adapter.mMainHandler.sendEmptyMessage(MSG_MAIN_HANDLER_COMMIT_METADATA);
+                adapter.mMainHandler.sendEmptyMessage(MSG_MAIN_HANDLER_REMOTE_ADAPTER_CONNECTED);
+            }
         }
 
-        public synchronized void onServiceDisconnected() {
-            mIsConnected = false;
-            mIsConnecting = false;
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
             mRemoteViewsFactory = null;
+            RemoteViewsAdapter adapter = mAdapter.get();
+            if (adapter != null) {
+                adapter.mMainHandler.sendEmptyMessage(MSG_MAIN_HANDLER_REMOTE_ADAPTER_DISCONNECTED);
+            }
+        }
 
-            // Clear the main/worker queues
-            final RemoteViewsAdapter adapter = mAdapter.get();
-            if (adapter == null) return;
+        @Override
+        public void handleMessage(Message msg) {
+            RemoteViewsAdapter adapter = mAdapter.get();
 
-            adapter.mMainQueue.post(new Runnable() {
-                @Override
-                public void run() {
-                    // Dequeue any unbind messages
-                    adapter.mMainQueue.removeMessages(sUnbindServiceMessageType);
-
-                    final RemoteAdapterConnectionCallback callback = adapter.mCallback.get();
-                    if (callback != null) {
-                        callback.onRemoteAdapterDisconnected();
+            switch (msg.what) {
+                case MSG_REQUEST_BIND: {
+                    if (adapter == null || mRemoteViewsFactory != null) {
+                        enqueueDeferredUnbindServiceMessage();
                     }
+                    if (mBindRequested) {
+                        return;
+                    }
+                    int flags = Context.BIND_AUTO_CREATE
+                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE;
+                    final IServiceConnection sd = mContext.getServiceDispatcher(this, this, flags);
+                    Intent intent = (Intent) msg.obj;
+                    int appWidgetId = msg.arg1;
+                    mBindRequested = AppWidgetManager.getInstance(mContext)
+                            .bindRemoteViewsService(mContext, appWidgetId, intent, sd, flags);
+                    return;
                 }
-            });
+                case MSG_NOTIFY_DATA_SET_CHANGED: {
+                    enqueueDeferredUnbindServiceMessage();
+                    if (adapter == null) {
+                        return;
+                    }
+                    if (mRemoteViewsFactory == null) {
+                        mNotifyDataSetChangedPending = true;
+                        adapter.requestBindService();
+                        return;
+                    }
+                    if (!sendNotifyDataSetChange(true)) {
+                        return;
+                    }
+
+                    // Flush the cache so that we can reload new items from the service
+                    synchronized (adapter.mCache) {
+                        adapter.mCache.reset();
+                    }
+
+                    // Re-request the new metadata (only after the notification to the factory)
+                    adapter.updateTemporaryMetaData(mRemoteViewsFactory);
+                    int newCount;
+                    int[] visibleWindow;
+                    synchronized (adapter.mCache.getTemporaryMetaData()) {
+                        newCount = adapter.mCache.getTemporaryMetaData().count;
+                        visibleWindow = adapter.getVisibleWindow(newCount);
+                    }
+
+                    // Pre-load (our best guess of) the views which are currently visible in the
+                    // AdapterView. This mitigates flashing and flickering of loading views when a
+                    // widget notifies that its data has changed.
+                    for (int position : visibleWindow) {
+                        // Because temporary meta data is only ever modified from this thread
+                        // (ie. mWorkerThread), it is safe to assume that count is a valid
+                        // representation.
+                        if (position < newCount) {
+                            adapter.updateRemoteViews(mRemoteViewsFactory, position, false);
+                        }
+                    }
+
+                    // Propagate the notification back to the base adapter
+                    adapter.mMainHandler.sendEmptyMessage(MSG_MAIN_HANDLER_COMMIT_METADATA);
+                    adapter.mMainHandler.sendEmptyMessage(
+                            MSG_MAIN_HANDLER_SUPER_NOTIFY_DATA_SET_CHANGED);
+                    return;
+                }
+
+                case MSG_LOAD_NEXT_ITEM: {
+                    if (adapter == null || mRemoteViewsFactory == null) {
+                        return;
+                    }
+                    removeMessages(MSG_UNBIND_SERVICE);
+                    // Get the next index to load
+                    final int position = adapter.mCache.getNextIndexToLoad();
+                    if (position > -1) {
+                        // Load the item, and notify any existing RemoteViewsFrameLayouts
+                        adapter.updateRemoteViews(mRemoteViewsFactory, position, true);
+
+                        // Queue up for the next one to load
+                        sendEmptyMessage(MSG_LOAD_NEXT_ITEM);
+                    } else {
+                        // No more items to load, so queue unbind
+                        enqueueDeferredUnbindServiceMessage();
+                    }
+                    return;
+                }
+                case MSG_UNBIND_SERVICE: {
+                    unbindNow();
+                    return;
+                }
+            }
         }
 
-        public synchronized IRemoteViewsFactory getRemoteViewsFactory() {
-            return mRemoteViewsFactory;
+        protected void unbindNow() {
+            if (mBindRequested) {
+                mBindRequested = false;
+                mContext.unbindService(this);
+            }
+            mRemoteViewsFactory = null;
         }
 
-        public synchronized boolean isConnected() {
-            return mIsConnected;
+        private boolean sendNotifyDataSetChange(boolean always) {
+            try {
+                if (always || !mRemoteViewsFactory.isCreated()) {
+                    mRemoteViewsFactory.onDataSetChanged();
+                }
+                return true;
+            } catch (RemoteException | RuntimeException e) {
+                Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
+                return false;
+            }
+        }
+
+        private void enqueueDeferredUnbindServiceMessage() {
+            removeMessages(MSG_UNBIND_SERVICE);
+            sendEmptyMessageDelayed(MSG_UNBIND_SERVICE, UNBIND_SERVICE_DELAY);
         }
     }
 
@@ -507,7 +547,6 @@
      *
      */
     private static class FixedSizeRemoteViewsCache {
-        private static final String TAG = "FixedSizeRemoteViewsCache";
 
         // The meta data related to all the RemoteViews, ie. count, is stable, etc.
         // The meta data objects are made final so that they can be locked on independently
@@ -671,7 +710,7 @@
                 }
             }
 
-            int count = 0;
+            int count;
             synchronized (mMetaData) {
                 count = mMetaData.count;
             }
@@ -786,9 +825,11 @@
         // Initialize the worker thread
         mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
         mWorkerThread.start();
-        mWorkerQueue = new Handler(mWorkerThread.getLooper());
-        mMainQueue = new Handler(Looper.myLooper(), this);
+        mMainHandler = new Handler(Looper.myLooper(), this);
+        mServiceHandler = new RemoteServiceHandler(mWorkerThread.getLooper(), this,
+                context.getApplicationContext());
         mAsyncViewLoadExecutor = useAsyncLoader ? new HandlerThreadExecutor(mWorkerThread) : null;
+        mCallback = callback;
 
         if (sCacheRemovalThread == null) {
             sCacheRemovalThread = new HandlerThread("RemoteViewsAdapter-cachePruner");
@@ -796,10 +837,6 @@
             sCacheRemovalQueue = new Handler(sCacheRemovalThread.getLooper());
         }
 
-        // Initialize the cache and the service connection on startup
-        mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
-        mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
-
         RemoteViewsCacheKey key = new RemoteViewsCacheKey(new Intent.FilterComparison(mIntent),
                 mAppWidgetId);
 
@@ -814,7 +851,7 @@
                     }
                 }
             } else {
-                mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
+                mCache = new FixedSizeRemoteViewsCache(DEFAULT_CACHE_SIZE);
             }
             if (!mDataReady) {
                 requestBindService();
@@ -825,9 +862,8 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mWorkerThread != null) {
-                mWorkerThread.quit();
-            }
+            mServiceHandler.unbindNow();
+            mWorkerThread.quit();
         } finally {
             super.finalize();
         }
@@ -864,16 +900,13 @@
                 sCachedRemoteViewsCaches.put(key, mCache);
             }
 
-            Runnable r = new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (sCachedRemoteViewsCaches) {
-                        if (sCachedRemoteViewsCaches.containsKey(key)) {
-                            sCachedRemoteViewsCaches.remove(key);
-                        }
-                        if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) {
-                            sRemoteViewsCacheRemoveRunnables.remove(key);
-                        }
+            Runnable r = () -> {
+                synchronized (sCachedRemoteViewsCaches) {
+                    if (sCachedRemoteViewsCaches.containsKey(key)) {
+                        sCachedRemoteViewsCaches.remove(key);
+                    }
+                    if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) {
+                        sRemoteViewsCacheRemoveRunnables.remove(key);
                     }
                 }
             };
@@ -882,54 +915,8 @@
         }
     }
 
-    private void loadNextIndexInBackground() {
-        mWorkerQueue.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mServiceConnection.isConnected()) {
-                    // Get the next index to load
-                    int position = -1;
-                    synchronized (mCache) {
-                        position = mCache.getNextIndexToLoad();
-                    }
-                    if (position > -1) {
-                        // Load the item, and notify any existing RemoteViewsFrameLayouts
-                        updateRemoteViews(position, true);
-
-                        // Queue up for the next one to load
-                        loadNextIndexInBackground();
-                    } else {
-                        // No more items to load, so queue unbind
-                        enqueueDeferredUnbindServiceMessage();
-                    }
-                }
-            }
-        });
-    }
-
-    private void processException(String method, Exception e) {
-        Log.e("RemoteViewsAdapter", "Error in " + method + ": " + e.getMessage());
-
-        // If we encounter a crash when updating, we should reset the metadata & cache and trigger
-        // a notifyDataSetChanged to update the widget accordingly
-        final RemoteViewsMetaData metaData = mCache.getMetaData();
-        synchronized (metaData) {
-            metaData.reset();
-        }
-        synchronized (mCache) {
-            mCache.reset();
-        }
-        mMainQueue.post(new Runnable() {
-            @Override
-            public void run() {
-                superNotifyDataSetChanged();
-            }
-        });
-    }
-
-    private void updateTemporaryMetaData() {
-        IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
-
+    @WorkerThread
+    private void updateTemporaryMetaData(IRemoteViewsFactory factory) {
         try {
             // get the properties/first view (so that we can use it to
             // measure our dummy views)
@@ -953,40 +940,40 @@
                 tmpMetaData.count = count;
                 tmpMetaData.loadingTemplate = loadingTemplate;
             }
-        } catch(RemoteException e) {
-            processException("updateMetaData", e);
-        } catch(RuntimeException e) {
-            processException("updateMetaData", e);
+        } catch (RemoteException | RuntimeException e) {
+            Log.e("RemoteViewsAdapter", "Error in updateMetaData: " + e.getMessage());
+
+            // If we encounter a crash when updating, we should reset the metadata & cache
+            // and trigger a notifyDataSetChanged to update the widget accordingly
+            synchronized (mCache.getMetaData()) {
+                mCache.getMetaData().reset();
+            }
+            synchronized (mCache) {
+                mCache.reset();
+            }
+            mMainHandler.sendEmptyMessage(MSG_MAIN_HANDLER_SUPER_NOTIFY_DATA_SET_CHANGED);
         }
     }
 
-    private void updateRemoteViews(final int position, boolean notifyWhenLoaded) {
-        IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
-
+    @WorkerThread
+    private void updateRemoteViews(IRemoteViewsFactory factory, int position,
+            boolean notifyWhenLoaded) {
         // Load the item information from the remote service
-        RemoteViews remoteViews = null;
-        long itemId = 0;
+        final RemoteViews remoteViews;
+        final long itemId;
         try {
             remoteViews = factory.getViewAt(position);
             itemId = factory.getItemId(position);
-        } catch (RemoteException e) {
+
+            if (remoteViews == null) {
+                throw new RuntimeException("Null remoteViews");
+            }
+        } catch (RemoteException | RuntimeException e) {
             Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage());
 
             // Return early to prevent additional work in re-centering the view cache, and
             // swapping from the loading view
             return;
-        } catch (RuntimeException e) {
-            Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + e.getMessage());
-            return;
-        }
-
-        if (remoteViews == null) {
-            // If a null view was returned, we break early to prevent it from getting
-            // into our cache and causing problems later. The effect is that the child  at this
-            // position will remain as a loading view until it is updated.
-            Log.e(TAG, "Error in updateRemoteViews(" + position + "): " + " null RemoteViews " +
-                    "returned from RemoteViewsFactory.");
-            return;
         }
 
         if (remoteViews.mApplication != null) {
@@ -1013,21 +1000,15 @@
         }
         synchronized (mCache) {
             if (viewTypeInRange) {
-                int[] visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
-                        mVisibleWindowUpperBound, cacheCount);
+                int[] visibleWindow = getVisibleWindow(cacheCount);
                 // Cache the RemoteViews we loaded
                 mCache.insert(position, remoteViews, itemId, visibleWindow);
 
-                // Notify all the views that we have previously returned for this index that
-                // there is new data for it.
-                final RemoteViews rv = remoteViews;
                 if (notifyWhenLoaded) {
-                    mMainQueue.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mRequestedViews.notifyOnRemoteViewsLoaded(position, rv);
-                        }
-                    });
+                    // Notify all the views that we have previously returned for this index that
+                    // there is new data for it.
+                    Message.obtain(mMainHandler, MSG_MAIN_HANDLER_REMOTE_VIEWS_LOADED, position, 0,
+                            remoteViews).sendToTarget();
                 }
             } else {
                 // We need to log an error here, as the the view type count specified by the
@@ -1066,7 +1047,7 @@
     }
 
     public int getItemViewType(int position) {
-        int typeId = 0;
+        final int typeId;
         synchronized (mCache) {
             if (mCache.containsMetaDataAt(position)) {
                 typeId = mCache.getMetaDataAt(position).typeId;
@@ -1097,14 +1078,13 @@
         synchronized (mCache) {
             RemoteViews rv = mCache.getRemoteViewsAt(position);
             boolean isInCache = (rv != null);
-            boolean isConnected = mServiceConnection.isConnected();
             boolean hasNewItems = false;
 
             if (convertView != null && convertView instanceof RemoteViewsFrameLayout) {
                 mRequestedViews.removeView((RemoteViewsFrameLayout) convertView);
             }
 
-            if (!isInCache && !isConnected) {
+            if (!isInCache) {
                 // Requesting bind service will trigger a super.notifyDataSetChanged(), which will
                 // in turn trigger another request to getView()
                 requestBindService();
@@ -1124,7 +1104,9 @@
             if (isInCache) {
                 // Apply the view synchronously if possible, to avoid flickering
                 layout.onRemoteViewsLoaded(rv, mRemoteViewsOnClickHandler, false);
-                if (hasNewItems) loadNextIndexInBackground();
+                if (hasNewItems) {
+                    mServiceHandler.sendEmptyMessage(MSG_LOAD_NEXT_ITEM);
+                }
             } else {
                 // If the views is not loaded, apply the loading view. If the loading view doesn't
                 // exist, the layout will create a default view based on the firstView height.
@@ -1134,7 +1116,7 @@
                         false);
                 mRequestedViews.add(position, layout);
                 mCache.queueRequestedPositionToLoad(position);
-                loadNextIndexInBackground();
+                mServiceHandler.sendEmptyMessage(MSG_LOAD_NEXT_ITEM);
             }
             return layout;
         }
@@ -1158,69 +1140,12 @@
         return getCount() <= 0;
     }
 
-    private void onNotifyDataSetChanged() {
-        // Complete the actual notifyDataSetChanged() call initiated earlier
-        IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
-        try {
-            factory.onDataSetChanged();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
-
-            // Return early to prevent from further being notified (since nothing has
-            // changed)
-            return;
-        } catch (RuntimeException e) {
-            Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
-            return;
-        }
-
-        // Flush the cache so that we can reload new items from the service
-        synchronized (mCache) {
-            mCache.reset();
-        }
-
-        // Re-request the new metadata (only after the notification to the factory)
-        updateTemporaryMetaData();
-        int newCount;
-        int[] visibleWindow;
-        synchronized(mCache.getTemporaryMetaData()) {
-            newCount = mCache.getTemporaryMetaData().count;
-            visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
-                    mVisibleWindowUpperBound, newCount);
-        }
-
-        // Pre-load (our best guess of) the views which are currently visible in the AdapterView.
-        // This mitigates flashing and flickering of loading views when a widget notifies that
-        // its data has changed.
-        for (int i: visibleWindow) {
-            // Because temporary meta data is only ever modified from this thread (ie.
-            // mWorkerThread), it is safe to assume that count is a valid representation.
-            if (i < newCount) {
-                updateRemoteViews(i, false);
-            }
-        }
-
-        // Propagate the notification back to the base adapter
-        mMainQueue.post(new Runnable() {
-            @Override
-            public void run() {
-                synchronized (mCache) {
-                    mCache.commitTemporaryMetaData();
-                }
-
-                superNotifyDataSetChanged();
-                enqueueDeferredUnbindServiceMessage();
-            }
-        });
-
-        // Reset the notify flagflag
-        mNotifyDataSetChangedAfterOnServiceConnected = false;
-    }
-
     /**
      * Returns a sorted array of all integers between lower and upper.
      */
-    private int[] getVisibleWindow(int lower, int upper, int count) {
+    private int[] getVisibleWindow(int count) {
+        int lower = mVisibleWindowLowerBound;
+        int upper = mVisibleWindowUpperBound;
         // In the case that the window is invalid or uninitialized, return an empty window.
         if ((lower == 0 && upper == 0) || lower < 0 || upper < 0) {
             return new int[0];
@@ -1250,23 +1175,8 @@
     }
 
     public void notifyDataSetChanged() {
-        // Dequeue any unbind messages
-        mMainQueue.removeMessages(sUnbindServiceMessageType);
-
-        // If we are not connected, queue up the notifyDataSetChanged to be handled when we do
-        // connect
-        if (!mServiceConnection.isConnected()) {
-            mNotifyDataSetChangedAfterOnServiceConnected = true;
-            requestBindService();
-            return;
-        }
-
-        mWorkerQueue.post(new Runnable() {
-            @Override
-            public void run() {
-                onNotifyDataSetChanged();
-            }
-        });
+        mServiceHandler.removeMessages(MSG_UNBIND_SERVICE);
+        mServiceHandler.sendEmptyMessage(MSG_NOTIFY_DATA_SET_CHANGED);
     }
 
     void superNotifyDataSetChanged() {
@@ -1275,35 +1185,38 @@
 
     @Override
     public boolean handleMessage(Message msg) {
-        boolean result = false;
         switch (msg.what) {
-        case sUnbindServiceMessageType:
-            if (mServiceConnection.isConnected()) {
-                mServiceConnection.unbind(mContext, mAppWidgetId, mIntent);
+            case MSG_MAIN_HANDLER_COMMIT_METADATA: {
+                mCache.commitTemporaryMetaData();
+                return true;
             }
-            result = true;
-            break;
-        default:
-            break;
+            case MSG_MAIN_HANDLER_SUPER_NOTIFY_DATA_SET_CHANGED: {
+                superNotifyDataSetChanged();
+                return true;
+            }
+            case MSG_MAIN_HANDLER_REMOTE_ADAPTER_CONNECTED: {
+                if (mCallback != null) {
+                    mCallback.onRemoteAdapterConnected();
+                }
+                return true;
+            }
+            case MSG_MAIN_HANDLER_REMOTE_ADAPTER_DISCONNECTED: {
+                if (mCallback != null) {
+                    mCallback.onRemoteAdapterDisconnected();
+                }
+                return true;
+            }
+            case MSG_MAIN_HANDLER_REMOTE_VIEWS_LOADED: {
+                mRequestedViews.notifyOnRemoteViewsLoaded(msg.arg1, (RemoteViews) msg.obj);
+                return true;
+            }
         }
-        return result;
+        return false;
     }
 
-    private void enqueueDeferredUnbindServiceMessage() {
-        // Remove any existing deferred-unbind messages
-        mMainQueue.removeMessages(sUnbindServiceMessageType);
-        mMainQueue.sendEmptyMessageDelayed(sUnbindServiceMessageType, sUnbindServiceDelay);
-    }
-
-    private boolean requestBindService() {
-        // Try binding the service (which will start it if it's not already running)
-        if (!mServiceConnection.isConnected()) {
-            mServiceConnection.bind(mContext, mAppWidgetId, mIntent);
-        }
-
-        // Remove any existing deferred-unbind messages
-        mMainQueue.removeMessages(sUnbindServiceMessageType);
-        return mServiceConnection.isConnected();
+    private void requestBindService() {
+        mServiceHandler.removeMessages(MSG_UNBIND_SERVICE);
+        Message.obtain(mServiceHandler, MSG_REQUEST_BIND, mAppWidgetId, 0, mIntent).sendToTarget();
     }
 
     private static class HandlerThreadExecutor implements Executor {
@@ -1331,7 +1244,7 @@
             remoteViews = views;
 
             float density = context.getResources().getDisplayMetrics().density;
-            defaultHeight = Math.round(sDefaultLoadingViewHeight * density);
+            defaultHeight = Math.round(DEFAULT_LOADING_VIEW_HEIGHT * density);
         }
 
         public void loadFirstViewHeight(
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ce80552..d9bc51f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9219,36 +9219,6 @@
         }
     }
 
-    @Override
-    public void invalidate() {
-        super.invalidate();
-
-        if (mEditor != null) {
-            mEditor.invalidateMagnifier();
-        }
-    }
-
-    @Override
-    public void invalidate(int l, int t, int r, int b) {
-        super.invalidate(l, t, r, b);
-
-        if (mEditor != null) {
-            mEditor.invalidateMagnifier(
-                    convertViewToScreenCoord(l, true /* isHorizontal */),
-                    convertViewToScreenCoord(t, false /* isHorizontal */),
-                    convertViewToScreenCoord(r, true /* isHorizontal */),
-                    convertViewToScreenCoord(b, false /* isHorizontal */));
-        }
-    }
-
-    float convertViewToScreenCoord(float viewCoord, boolean isHorizontal) {
-        final int[] coordinatesOnScreen = new int[2];
-        getLocationOnScreen(coordinatesOnScreen);
-        return isHorizontal
-                ? viewCoord + getTotalPaddingLeft() - getScrollX() + coordinatesOnScreen[0]
-                : viewCoord + getTotalPaddingTop() - getScrollY() + coordinatesOnScreen[1];
-    }
-
     /**
      * @return whether or not the cursor is visible (assuming this TextView is editable)
      *
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index caf35b3..a4da6b9c 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -26,6 +26,8 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.widget.RemoteViews;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
 
 /** {@hide} */
 interface IAppWidgetService {
@@ -62,9 +64,9 @@
     void setBindAppWidgetPermission(in String packageName, int userId, in boolean permission);
     boolean bindAppWidgetId(in String callingPackage, int appWidgetId,
             int providerProfileId, in ComponentName providerComponent, in Bundle options);
-    void bindRemoteViewsService(String callingPackage, int appWidgetId, in Intent intent,
-            in IBinder connection);
-    void unbindRemoteViewsService(String callingPackage, int appWidgetId, in Intent intent);
+    boolean bindRemoteViewsService(String callingPackage, int appWidgetId, in Intent intent,
+            IApplicationThread caller, IBinder token, IServiceConnection connection, int flags);
+
     int[] getAppWidgetIds(in ComponentName providerComponent);
     boolean isBoundWidgetPackage(String packageName, int userId);
     boolean requestPinAppWidget(String packageName, in ComponentName providerComponent,
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 46098c5..70b6f96 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -47,17 +47,19 @@
     protected final int mCmd, mArg1, mArg2;
     @VisibleForTesting
     protected final Object mObj;
+    private final Runnable mRunnable;
     private boolean mScheduled;
 
     public WakeupMessage(Context context, Handler handler,
             String cmdName, int cmd, int arg1, int arg2, Object obj) {
-        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        mAlarmManager = getAlarmManager(context);
         mHandler = handler;
         mCmdName = cmdName;
         mCmd = cmd;
         mArg1 = arg1;
         mArg2 = arg2;
         mObj = obj;
+        mRunnable = null;
     }
 
     public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
@@ -73,6 +75,21 @@
         this(context, handler, cmdName, cmd, 0, 0, null);
     }
 
+    public WakeupMessage(Context context, Handler handler, String cmdName, Runnable runnable) {
+        mAlarmManager = getAlarmManager(context);
+        mHandler = handler;
+        mCmdName = cmdName;
+        mCmd = 0;
+        mArg1 = 0;
+        mArg2 = 0;
+        mObj = null;
+        mRunnable = runnable;
+    }
+
+    private static AlarmManager getAlarmManager(Context context) {
+        return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+    }
+
     /**
      * Schedule the message to be delivered at the time in milliseconds of the
      * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
@@ -107,7 +124,12 @@
             mScheduled = false;
         }
         if (stillScheduled) {
-            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
+            Message msg;
+            if (mRunnable == null) {
+                msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
+            } else {
+                msg = Message.obtain(mHandler, mRunnable);
+            }
             mHandler.dispatchMessage(msg);
             msg.recycle();
         }
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
deleted file mode 100644
index 7294124..0000000
--- a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.os.IBinder;
-
-/** {@hide} */
-oneway interface IRemoteViewsAdapterConnection {
-    void onServiceConnected(IBinder service);
-    void onServiceDisconnected();
-}
diff --git a/core/java/com/android/internal/widget/Magnifier.java b/core/java/com/android/internal/widget/Magnifier.java
index 9bc0778..6d54d7b 100644
--- a/core/java/com/android/internal/widget/Magnifier.java
+++ b/core/java/com/android/internal/widget/Magnifier.java
@@ -22,9 +22,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Point;
-import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Handler;
 import android.util.Log;
 import android.view.Gravity;
@@ -38,13 +36,15 @@
 import com.android.internal.R;
 import com.android.internal.util.Preconditions;
 
+import java.util.Timer;
+import java.util.TimerTask;
+
 /**
  * Android magnifier widget. Can be used by any view which is attached to window.
  */
 public final class Magnifier {
     private static final String LOG_TAG = "magnifier";
-    // Use this to specify that a previous configuration value does not exist.
-    private static final int INEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
+    private static final int MAGNIFIER_REFRESH_RATE_MS = 33; // ~30fps
     // The view for which this magnifier is attached.
     private final View mView;
     // The window containing the magnifier.
@@ -62,15 +62,10 @@
     // The callback of the pixel copy request will be invoked on this Handler when
     // the copy is finished.
     private final Handler mPixelCopyHandler = Handler.getMain();
-
-    private RectF mTmpRectF;
-
-    // Variables holding previous states, used for detecting redundant calls and invalidation.
-    private Point mPrevStartCoordsOnScreen = new Point(
-            INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
-    private PointF mPrevCenterCoordsOnScreen = new PointF(
-            INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
-    private float mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+    // Current magnification scale.
+    private float mScale;
+    // Timer used to schedule the copy task.
+    private Timer mTimer;
 
     /**
      * Initializes a magnifier.
@@ -82,6 +77,7 @@
         mView = Preconditions.checkNotNull(view);
         final Context context = mView.getContext();
         final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
+        content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
         mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
         mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
         final float elevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
@@ -101,15 +97,15 @@
     /**
      * Shows the magnifier on the screen.
      *
-     * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source. The
-     *        lower end is clamped to 0
-     * @param centerYOnScreen vertical coordinate of the center point of the magnifier source. The
-     *        lower end is clamped to 0
+     * @param xPosInView horizontal coordinate of the center point of the magnifier source relative
+     *        to the view. The lower end is clamped to 0
+     * @param yPosInView vertical coordinate of the center point of the magnifier source
+     *        relative to the view. The lower end is clamped to 0
      * @param scale the scale at which the magnifier zooms on the source content. The
      *        lower end is clamped to 1 and the higher end to 4
      */
-    public void show(@FloatRange(from=0) float centerXOnScreen,
-            @FloatRange(from=0) float centerYOnScreen,
+    public void show(@FloatRange(from=0) float xPosInView,
+            @FloatRange(from=0) float yPosInView,
             @FloatRange(from=1, to=4) float scale) {
         if (scale > 4) {
             scale = 4;
@@ -119,27 +115,29 @@
             scale = 1;
         }
 
-        if (centerXOnScreen < 0) {
-            centerXOnScreen = 0;
+        if (xPosInView < 0) {
+            xPosInView = 0;
         }
 
-        if (centerYOnScreen < 0) {
-            centerYOnScreen = 0;
+        if (yPosInView < 0) {
+            yPosInView = 0;
         }
 
-        showInternal(centerXOnScreen, centerYOnScreen, scale, false);
-    }
-
-    private void showInternal(@FloatRange(from=0) float centerXOnScreen,
-            @FloatRange(from=0) float centerYOnScreen,
-            @FloatRange(from=1, to=4) float scale,
-            boolean forceShow) {
-        if (mPrevScale != scale) {
+        if (mScale != scale) {
             resizeBitmap(scale);
-            mPrevScale = scale;
         }
-        configureCoordinates(centerXOnScreen, centerYOnScreen);
-        maybePerformPixelCopy(scale, forceShow);
+        mScale = scale;
+        configureCoordinates(xPosInView, yPosInView);
+
+        if (mTimer == null) {
+            mTimer = new Timer();
+            mTimer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    performPixelCopy();
+                }
+            }, 0 /* delay */, MAGNIFIER_REFRESH_RATE_MS);
+        }
 
         if (mWindow.isShowing()) {
             mWindow.update(mWindowCoords.x, mWindowCoords.y, mWindow.getWidth(),
@@ -148,9 +146,6 @@
             mWindow.showAtLocation(mView.getRootView(), Gravity.NO_GRAVITY,
                     mWindowCoords.x, mWindowCoords.y);
         }
-
-        mPrevCenterCoordsOnScreen.x = centerXOnScreen;
-        mPrevCenterCoordsOnScreen.y = centerYOnScreen;
     }
 
     /**
@@ -159,36 +154,10 @@
     public void dismiss() {
         mWindow.dismiss();
 
-        mPrevStartCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
-        mPrevStartCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
-        mPrevCenterCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
-        mPrevCenterCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
-        mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
-    }
-
-    /**
-     * Forces the magnifier to update content by taking and showing a new snapshot using the
-     * previous coordinates. It does this only if the magnifier is showing and the dirty rectangle
-     * intersects the rectangle which holds the content to be magnified.
-     *
-     * @param dirtyRectOnScreen the rectangle representing the screen bounds of the dirty region
-     */
-    public void invalidate(RectF dirtyRectOnScreen) {
-        if (mWindow.isShowing() && mPrevCenterCoordsOnScreen.x != INEXISTENT_PREVIOUS_CONFIG_VALUE
-                && mPrevCenterCoordsOnScreen.y != INEXISTENT_PREVIOUS_CONFIG_VALUE
-                && mPrevScale != INEXISTENT_PREVIOUS_CONFIG_VALUE) {
-            // Update the current showing RectF.
-            mTmpRectF = new RectF(mPrevStartCoordsOnScreen.x,
-                    mPrevStartCoordsOnScreen.y,
-                    mPrevStartCoordsOnScreen.x + mBitmap.getWidth(),
-                    mPrevStartCoordsOnScreen.y + mBitmap.getHeight());
-
-            // Update only if we are currently showing content that has been declared as invalid.
-            if (RectF.intersects(dirtyRectOnScreen, mTmpRectF)) {
-                // Update the contents shown in the magnifier.
-                showInternal(mPrevCenterCoordsOnScreen.x, mPrevCenterCoordsOnScreen.y, mPrevScale,
-                        true /* forceShow */);
-            }
+        if (mTimer != null) {
+            mTimer.cancel();
+            mTimer.purge();
+            mTimer = null;
         }
     }
 
@@ -213,7 +182,12 @@
         getImageView().setImageBitmap(mBitmap);
     }
 
-    private void configureCoordinates(float posXOnScreen, float posYOnScreen) {
+    private void configureCoordinates(float xPosInView, float yPosInView) {
+        final int[] coordinatesOnScreen = new int[2];
+        mView.getLocationOnScreen(coordinatesOnScreen);
+        final float posXOnScreen = xPosInView + coordinatesOnScreen[0];
+        final float posYOnScreen = yPosInView + coordinatesOnScreen[1];
+
         mCenterZoomCoords.x = (int) posXOnScreen;
         mCenterZoomCoords.y = (int) posYOnScreen;
 
@@ -223,7 +197,7 @@
         mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalMagnifierOffset;
     }
 
-    private void maybePerformPixelCopy(final float scale, final boolean forceShow) {
+    private void performPixelCopy() {
         final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
         int rawStartX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;
 
@@ -234,13 +208,6 @@
             rawStartX = mView.getWidth() - mBitmap.getWidth();
         }
 
-        if (!forceShow && rawStartX == mPrevStartCoordsOnScreen.x
-                && startY == mPrevStartCoordsOnScreen.y
-                && scale == mPrevScale) {
-            // Skip, we are already showing the desired content.
-            return;
-        }
-
         final int startX = rawStartX;
         final ViewRootImpl viewRootImpl = mView.getViewRootImpl();
 
@@ -251,11 +218,7 @@
                     new Rect(startX, startY, startX + mBitmap.getWidth(),
                             startY + mBitmap.getHeight()),
                     mBitmap,
-                    result -> {
-                        getImageView().invalidate();
-                        mPrevStartCoordsOnScreen.x = startX;
-                        mPrevStartCoordsOnScreen.y = startY;
-                    },
+                    result -> getImageView().invalidate(),
                     mPixelCopyHandler);
         } else {
             Log.d(LOG_TAG, "Could not perform PixelCopy request");
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c6801bf..9e6985c 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -56,9 +56,9 @@
     if (langs != nullptr) {
         ScopedUtfChars str(env, langs);
         builder = new NativeFamilyBuilder(
-                minikin::FontStyle::registerLanguageList(str.c_str()), variant);
+                minikin::FontStyle::registerLocaleList(str.c_str()), variant);
     } else {
-        builder = new NativeFamilyBuilder(minikin::FontStyle::registerLanguageList(""), variant);
+        builder = new NativeFamilyBuilder(minikin::FontStyle::registerLocaleList(""), variant);
     }
     return reinterpret_cast<jlong>(builder);
 }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 93bd16b2..fd62a19f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -544,7 +544,7 @@
     static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         ScopedUtfChars localesChars(env, locales);
-        jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
+        jint minikinLangListId = minikin::FontStyle::registerLocaleList(localesChars.c_str());
         obj->setMinikinLangListId(minikinLangListId);
         return minikinLangListId;
     }
diff --git a/core/res/res/layout/magnifier.xml b/core/res/res/layout/magnifier.xml
index 181e5e5..d6cd8b4 100644
--- a/core/res/res/layout/magnifier.xml
+++ b/core/res/res/layout/magnifier.xml
@@ -18,10 +18,17 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="?android:attr/floatingToolbarPopupBackgroundDrawable">
-    <ImageView
-        android:id="@+id/magnifier_image"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
+    android:layout_height="wrap_content">
+    <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/magnifier_inner"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+        android:elevation="@android:dimen/magnifier_elevation">
+        <ImageView
+            android:id="@+id/magnifier_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+    </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dec5fd9..571aad9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3128,4 +3128,7 @@
     <!-- Class names of device specific services inheriting com.android.server.SystemService. The
          classes are instantiated in the order of the array. -->
     <string-array translatable="false" name="config_deviceSpecificSystemServices"></string-array>
+
+    <!-- Component name of media projection permission dialog -->
+    <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 14069e7..08e2233 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -521,7 +521,7 @@
     <dimen name="content_rect_bottom_clip_allowance">20dp</dimen>
 
     <!-- Magnifier dimensions -->
-    <dimen name="magnifier_width">200dp</dimen>
+    <dimen name="magnifier_width">164dp</dimen>
     <dimen name="magnifier_height">48dp</dimen>
     <dimen name="magnifier_elevation">2dp</dimen>
     <dimen name="magnifier_offset">42dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7bbd17e..1627a0e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2479,6 +2479,7 @@
 
   <!-- Magnifier -->
   <java-symbol type="id" name="magnifier_image" />
+  <java-symbol type="id" name="magnifier_inner" />
   <java-symbol type="layout" name="magnifier" />
   <java-symbol type="dimen" name="magnifier_width" />
   <java-symbol type="dimen" name="magnifier_height" />
@@ -3123,4 +3124,7 @@
   <java-symbol type="string" name="shortcut_restore_not_supported" />
   <java-symbol type="string" name="shortcut_restore_signature_mismatch" />
   <java-symbol type="string" name="shortcut_restore_unknown_issue" />
+
+  <!-- From media projection -->
+  <java-symbol type="string" name="config_mediaProjectionPermissionDialogComponent" />
 </resources>
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
new file mode 100644
index 0000000..06b860a
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
@@ -0,0 +1,380 @@
+/*
+ * 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.
+ */
+
+package android.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.IServiceConnection;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.database.DataSetObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+import com.android.internal.widget.IRemoteViewsFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+/**
+ * Tests for RemoteViewsAdapter.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RemoteViewsAdapterTest {
+
+    @Mock AppWidgetManager mAppWidgetManager;
+    @Mock IServiceConnection mIServiceConnection;
+    @Mock RemoteViewsAdapter.RemoteAdapterConnectionCallback mCallback;
+
+    private Handler mMainHandler;
+    private TestContext mContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mAppWidgetManager
+                .bindRemoteViewsService(any(), anyInt(), any(), any(), anyInt())).thenReturn(true);
+        mContext = new TestContext();
+        mMainHandler = new Handler(Looper.getMainLooper());
+    }
+
+    @Test
+    public void onRemoteAdapterConnected_after_metadata_loaded() throws Throwable {
+        RemoteViewsAdapter adapter = getOnUiThread(
+                () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false));
+        assertFalse(adapter.isDataReady());
+
+        assertNotNull(mContext.conn.get());
+
+        ViewsFactory factory = new ViewsFactory(1);
+        mContext.sendConnect(factory);
+
+        waitOnHandler(mMainHandler);
+        verify(mCallback, never()).onRemoteAdapterConnected();
+
+        factory.loadingView.set(createViews("loading"));
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+        verify(mCallback, times(1)).onRemoteAdapterConnected();
+
+        assertEquals((Integer) 1, getOnUiThread(adapter::getCount));
+
+        // Service is unbound
+        assertTrue(isUnboundOrScheduled());
+    }
+
+    @Test
+    public void viewReplaced_after_mainView_loaded() throws Throwable {
+        RemoteViewsAdapter adapter = getOnUiThread(
+                () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false));
+
+        ViewsFactory factory = new ViewsFactory(1);
+        factory.loadingView.set(createViews("loading"));
+        mContext.sendConnect(factory);
+
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+
+        // Returned view contains the loading text
+        View view = getOnUiThread(() -> adapter.getView(0, null, new FrameLayout(mContext)));
+        ArrayList<View> search = new ArrayList<>();
+        view.findViewsWithText(search, "loading", View.FIND_VIEWS_WITH_TEXT);
+        assertEquals(1, search.size());
+
+        // Send the final remoteViews
+        factory.views[0].set(createViews("updated"));
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+
+        // Existing view got updated with new text
+        search.clear();
+        view.findViewsWithText(search, "loading", View.FIND_VIEWS_WITH_TEXT);
+        assertTrue(search.isEmpty());
+        view.findViewsWithText(search, "updated", View.FIND_VIEWS_WITH_TEXT);
+        assertEquals(1, search.size());
+
+        // Service is unbound
+        assertTrue(isUnboundOrScheduled());
+    }
+
+    @Test
+    public void notifyDataSetChanged_deferred() throws Throwable {
+        RemoteViewsAdapter adapter = getOnUiThread(
+                () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false));
+
+        ViewsFactory factory = new ViewsFactory(1);
+        factory.loadingView.set(createViews("loading"));
+        mContext.sendConnect(factory);
+
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+        assertEquals((Integer) 1, getOnUiThread(adapter::getCount));
+
+        // Reset the loading view so that next refresh is blocked
+        factory.loadingView = new LockedValue<>();
+        factory.mCount = 3;
+        DataSetObserver observer = mock(DataSetObserver.class);
+        getOnUiThread(() -> {
+            adapter.registerDataSetObserver(observer);
+            adapter.notifyDataSetChanged();
+            return null;
+        });
+
+        waitOnHandler(mMainHandler);
+        // Still giving the old values
+        verify(observer, never()).onChanged();
+        assertEquals((Integer) 1, getOnUiThread(adapter::getCount));
+
+        factory.loadingView.set(createViews("refreshed"));
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+
+        // When the service returns new data, UI is updated.
+        verify(observer, times(1)).onChanged();
+        assertEquals((Integer) 3, getOnUiThread(adapter::getCount));
+
+        // Service is unbound
+        assertTrue(isUnboundOrScheduled());
+    }
+
+    @Test
+    public void serviceDisconnected_before_getView() throws Throwable {
+        RemoteViewsAdapter adapter = getOnUiThread(
+                () -> new RemoteViewsAdapter(mContext, new DistinctIntent(), mCallback, false));
+
+        ViewsFactory factory = new ViewsFactory(1);
+        factory.loadingView.set(createViews("loading"));
+        mContext.sendConnect(factory);
+
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+        verify(mCallback, times(1)).onRemoteAdapterConnected();
+        assertEquals((Integer) 1, getOnUiThread(adapter::getCount));
+
+        // Unbind the service
+        ServiceConnection conn = mContext.conn.get();
+        getOnHandler(mContext.handler.get(), () -> {
+            conn.onServiceDisconnected(null);
+            return null;
+        });
+
+        // Returned view contains the loading text
+        View view = getOnUiThread(() -> adapter.getView(0, null, new FrameLayout(mContext)));
+        ArrayList<View> search = new ArrayList<>();
+        view.findViewsWithText(search, "loading", View.FIND_VIEWS_WITH_TEXT);
+        assertEquals(1, search.size());
+
+        // Unbind is not scheduled
+        assertFalse(isUnboundOrScheduled());
+
+        mContext.sendConnect(factory);
+        waitOnHandler(mContext.handler.get());
+        waitOnHandler(mMainHandler);
+        verify(mCallback, times(2)).onRemoteAdapterConnected();
+    }
+
+    private RemoteViews createViews(String text) {
+        RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.remote_views_text);
+        views.setTextViewText(R.id.text, text);
+        return views;
+    }
+
+    private <T> T getOnUiThread(Supplier<T> supplier) throws Throwable {
+        return getOnHandler(mMainHandler, supplier);
+    }
+
+    private boolean isUnboundOrScheduled() throws Throwable {
+        Handler handler = mContext.handler.get();
+        return getOnHandler(handler, () -> mContext.boundCount == 0
+                || handler.hasMessages(RemoteViewsAdapter.MSG_UNBIND_SERVICE));
+    }
+
+    private static <T> T getOnHandler(Handler handler, Supplier<T> supplier) throws Throwable {
+        LockedValue<T> result = new LockedValue<>();
+        handler.post(() -> result.set(supplier.get()));
+        return result.get();
+    }
+
+    private class TestContext extends ContextWrapper {
+
+        public final LockedValue<ServiceConnection> conn = new LockedValue<>();
+        public final LockedValue<Handler> handler = new LockedValue<>();
+        public int boundCount;
+
+        TestContext() {
+            super(InstrumentationRegistry.getContext());
+        }
+
+        @Override
+        public void unbindService(ServiceConnection conn) {
+            boundCount--;
+        }
+
+        @Override
+        public Object getSystemService(String name) {
+            if (Context.APPWIDGET_SERVICE.equals(name)) {
+                return mAppWidgetManager;
+            }
+            return super.getSystemService(name);
+        }
+
+        @Override
+        public IServiceConnection getServiceDispatcher(
+                ServiceConnection conn, Handler handler, int flags) {
+            this.conn.set(conn);
+            this.handler.set(handler);
+            boundCount++;
+            return mIServiceConnection;
+        }
+
+        @Override
+        public Context getApplicationContext() {
+            return this;
+        }
+
+        public void sendConnect(ViewsFactory factory) throws Exception {
+            ServiceConnection connection = conn.get();
+            handler.get().post(() -> connection.onServiceConnected(null, factory.asBinder()));
+        }
+    }
+
+    private static void waitOnHandler(Handler handler) throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        handler.post(() -> latch.countDown());
+        latch.await(20, TimeUnit.SECONDS);
+    }
+
+    private static class ViewsFactory extends IRemoteViewsFactory.Stub {
+
+        public LockedValue<RemoteViews> loadingView = new LockedValue<>();
+        public LockedValue<RemoteViews>[] views;
+
+        private int mCount;
+
+        ViewsFactory(int count) {
+            mCount = count;
+            views = new LockedValue[count];
+            for (int i = 0; i < count; i++) {
+                views[i] = new LockedValue<>();
+            }
+        }
+
+        @Override
+        public void onDataSetChanged() {}
+
+        @Override
+        public void onDataSetChangedAsync() { }
+
+        @Override
+        public void onDestroy(Intent intent) { }
+
+        @Override
+        public int getCount() throws RemoteException {
+            return mCount;
+        }
+
+        @Override
+        public RemoteViews getViewAt(int position) throws RemoteException {
+            try {
+                return views[position].get();
+            } catch (Exception e) {
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        @Override
+        public RemoteViews getLoadingView() throws RemoteException {
+            try {
+                return loadingView.get();
+            } catch (Exception e) {
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 1;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return false;
+        }
+
+        @Override
+        public boolean isCreated() {
+            return false;
+        }
+    }
+
+    private static class DistinctIntent extends Intent {
+
+        @Override
+        public boolean filterEquals(Intent other) {
+            return false;
+        }
+    }
+
+    private static class LockedValue<T> {
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private T mValue;
+
+        public void set(T value) {
+            mValue = value;
+            mLatch.countDown();
+        }
+
+        public T get() throws Exception {
+            mLatch.await(10, TimeUnit.SECONDS);
+            return mValue;
+        }
+    }
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
index 7935880..734ebef 100644
--- a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -47,6 +47,7 @@
     private static final int TEST_ARG2 = 182;
     private static final Object TEST_OBJ = "hello";
 
+    @Mock Context mContext;
     @Mock AlarmManager mAlarmManager;
     WakeupMessage mMessage;
     // Make a spy so that we can verify calls to it
@@ -86,13 +87,12 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        Context context = mock(Context.class);
-        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+        when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
         // capture the listener for each AlarmManager.setExact call
         doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class),
                 mListenerCaptor.capture(), any(Handler.class));
 
-        mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
+        mMessage = new WakeupMessage(mContext, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
                 TEST_ARG2, TEST_OBJ);
     }
 
@@ -168,4 +168,19 @@
         verifyMessageDispatchedOnce();
     }
 
+    /**
+     * Verify that a Runnable is scheduled and dispatched.
+     */
+    @Test
+    public void scheduleRunnable() {
+        final long when = 1011;
+        final Runnable runnable = mock(Runnable.class);
+        WakeupMessage dut = new WakeupMessage(mContext, mHandler, TEST_CMD_NAME, runnable);
+        dut.schedule(when);
+        verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
+                eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
+        mListenerCaptor.getValue().onAlarm();
+        verify(runnable, times(1)).run();
+    }
+
 }
diff --git a/libs/services/Android.mk b/libs/services/Android.mk
index cbfd4b3..d72059a 100644
--- a/libs/services/Android.mk
+++ b/libs/services/Android.mk
@@ -21,7 +21,8 @@
 LOCAL_MODULE := libservices
 LOCAL_SRC_FILES := \
     ../../core/java/com/android/internal/os/IDropBoxManagerService.aidl \
-    src/os/DropBoxManager.cpp
+    src/os/DropBoxManager.cpp \
+    src/os/StatsLogEventWrapper.cpp
 
 LOCAL_AIDL_INCLUDES := \
     $(LOCAL_PATH)/../../core/java
diff --git a/libs/services/include/android/os/StatsLogEventWrapper.h b/libs/services/include/android/os/StatsLogEventWrapper.h
new file mode 100644
index 0000000..255619c
--- /dev/null
+++ b/libs/services/include/android/os/StatsLogEventWrapper.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef STATS_LOG_EVENT_WRAPPER_H
+#define STATS_LOG_EVENT_WRAPPER_H
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <utils/RefBase.h>
+#include <vector>
+
+namespace android {
+namespace os {
+
+// Represents a parcelable object. Only used to send data from Android OS to statsd.
+class StatsLogEventWrapper : public android::Parcelable {
+ public:
+  StatsLogEventWrapper();
+
+  StatsLogEventWrapper(StatsLogEventWrapper&& in) = default;
+
+  android::status_t writeToParcel(android::Parcel* out) const;
+
+  android::status_t readFromParcel(const android::Parcel* in);
+
+  // These are public for ease of conversion.
+  std::vector<uint8_t> bytes;
+};
+} // Namespace os
+} // Namespace android
+
+
+#endif  // STATS_LOG_EVENT_WRAPPER_H
+
diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp
new file mode 100644
index 0000000..8b3aa9a
--- /dev/null
+++ b/libs/services/src/os/StatsLogEventWrapper.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+#include <android/os/StatsLogEventWrapper.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <utils/RefBase.h>
+#include <vector>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+using std::vector;
+
+namespace android {
+namespace os {
+
+StatsLogEventWrapper::StatsLogEventWrapper(){};
+
+status_t StatsLogEventWrapper::writeToParcel(Parcel* out) const {
+    out->writeByteVector(bytes);
+    return ::android::NO_ERROR;
+};
+
+status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) {
+    in->readByteVector(&bytes);
+    return ::android::NO_ERROR;
+};
+
+} // Namespace os
+} // Namespace android
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 9f2c08e..aa0d0cc 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -20,8 +20,10 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.media.projection.IMediaProjection;
 import android.os.Handler;
 import android.os.IBinder;
@@ -71,8 +73,11 @@
      */
     public Intent createScreenCaptureIntent() {
         Intent i = new Intent();
-        i.setClassName("com.android.systemui",
-                "com.android.systemui.media.MediaProjectionPermissionActivity");
+        final ComponentName mediaProjectionPermissionDialogComponent =
+                ComponentName.unflattenFromString(mContext.getResources().getString(
+                        com.android.internal.R.string
+                        .config_mediaProjectionPermissionDialogComponent));
+        i.setComponent(mediaProjectionPermissionDialogComponent);
         return i;
     }
 
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 51afada..76e7782 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -21,9 +21,12 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManagerInternal;
@@ -99,7 +102,6 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.widget.IRemoteViewsAdapterConnection;
 import com.android.internal.widget.IRemoteViewsFactory;
 import com.android.server.LocalServices;
 import com.android.server.WidgetBackupProvider;
@@ -191,10 +193,6 @@
         }
     };
 
-    // Manages active connections to RemoteViewsServices.
-    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
-            mBoundRemoteViewsServices = new HashMap<>();
-
     // Manages persistent references to RemoteViewsServices from different App Widgets.
     private final HashMap<Pair<Integer, FilterComparison>, HashSet<Integer>>
             mRemoteViewsServicesAppWidgets = new HashMap<>();
@@ -1209,17 +1207,14 @@
     }
 
     @Override
-    public void bindRemoteViewsService(String callingPackage, int appWidgetId,
-            Intent intent, IBinder callbacks) {
+    public boolean bindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent,
+            IApplicationThread caller, IBinder activtiyToken, IServiceConnection connection,
+            int flags) {
         final int userId = UserHandle.getCallingUserId();
-
         if (DEBUG) {
             Slog.i(TAG, "bindRemoteViewsService() " + userId);
         }
 
-        // Make sure the package runs under the caller uid.
-        mSecurityPolicy.enforceCallFromPackage(callingPackage);
-
         synchronized (mLock) {
             ensureGroupStateLoadedLocked(userId);
 
@@ -1254,76 +1249,35 @@
             mSecurityPolicy.enforceServiceExistsAndRequiresBindRemoteViewsPermission(
                     componentName, widget.provider.getUserId());
 
-            // Good to go - the service pakcage is correct, it exists for the correct
+            // Good to go - the service package is correct, it exists for the correct
             // user, and requires the bind permission.
 
-            // If there is already a connection made for this service intent, then
-            // disconnect from that first. (This does not allow multiple connections
-            // to the same service under the same key).
-            ServiceConnectionProxy connection = null;
-            FilterComparison fc = new FilterComparison(intent);
-            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
+            final long callingIdentity = Binder.clearCallingIdentity();
+            try {
+                // Ask ActivityManager to bind it. Notice that we are binding the service with the
+                // caller app instead of DevicePolicyManagerService.
+                if(ActivityManager.getService().bindService(
+                        caller, activtiyToken, intent,
+                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                        connection, flags, mContext.getOpPackageName(),
+                        widget.provider.getUserId()) != 0) {
 
-            if (mBoundRemoteViewsServices.containsKey(key)) {
-                connection = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
-                connection.disconnect();
-                unbindService(connection);
-                mBoundRemoteViewsServices.remove(key);
-            }
-
-            // Bind to the RemoteViewsService (which will trigger a callback to the
-            // RemoteViewsAdapter.onServiceConnected())
-            connection = new ServiceConnectionProxy(callbacks);
-            bindService(intent, connection, widget.provider.info.getProfile());
-            mBoundRemoteViewsServices.put(key, connection);
-
-            // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
-            // can determine when we can call back to the RemoteViewsService later to
-            // destroy associated factories.
-            Pair<Integer, FilterComparison> serviceId = Pair.create(widget.provider.id.uid, fc);
-            incrementAppWidgetServiceRefCount(appWidgetId, serviceId);
-        }
-    }
-
-    @Override
-    public void unbindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent) {
-        final int userId = UserHandle.getCallingUserId();
-
-        if (DEBUG) {
-            Slog.i(TAG, "unbindRemoteViewsService() " + userId);
-        }
-
-        // Make sure the package runs under the caller uid.
-        mSecurityPolicy.enforceCallFromPackage(callingPackage);
-
-        synchronized (mLock) {
-            ensureGroupStateLoadedLocked(userId);
-
-            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
-            // RemoteViewsAdapter)
-            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
-                    new FilterComparison(intent));
-            if (mBoundRemoteViewsServices.containsKey(key)) {
-                // We don't need to use the appWidgetId until after we are sure there is something
-                // to unbind. Note that this may mask certain issues with apps calling unbind()
-                // more than necessary.
-
-                // NOTE: The lookup is enforcing security across users by making
-                // sure the caller can only access widgets it hosts or provides.
-                Widget widget = lookupWidgetLocked(appWidgetId,
-                        Binder.getCallingUid(), callingPackage);
-
-                if (widget == null) {
-                    throw new IllegalArgumentException("Bad widget id " + appWidgetId);
+                    // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
+                    // can determine when we can call back to the RemoteViewsService later to
+                    // destroy associated factories.
+                    incrementAppWidgetServiceRefCount(appWidgetId,
+                            Pair.create(widget.provider.id.uid, new FilterComparison(intent)));
+                    return true;
                 }
-
-                ServiceConnectionProxy connection = (ServiceConnectionProxy)
-                        mBoundRemoteViewsServices.get(key);
-                connection.disconnect();
-                mContext.unbindService(connection);
-                mBoundRemoteViewsServices.remove(key);
+            } catch (RemoteException ex) {
+                // Same process, should not happen.
+            } finally {
+                Binder.restoreCallingIdentity(callingIdentity);
             }
         }
+
+        // Failed to bind.
+        return false;
     }
 
     @Override
@@ -1754,7 +1708,9 @@
 
     private void deleteAppWidgetLocked(Widget widget) {
         // We first unbind all services that are bound to this id
-        unbindAppWidgetRemoteViewsServicesLocked(widget);
+        // Check if we need to destroy any services (if no other app widgets are
+        // referencing the same service)
+        decrementAppWidgetServiceRefCount(widget);
 
         Host host = widget.host;
         host.widgets.remove(widget);
@@ -1796,28 +1752,6 @@
         }
     }
 
-    // Unbinds from a RemoteViewsService when we delete an app widget
-    private void unbindAppWidgetRemoteViewsServicesLocked(Widget widget) {
-        int appWidgetId = widget.appWidgetId;
-        // Unbind all connections to Services bound to this AppWidgetId
-        Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet()
-                .iterator();
-        while (it.hasNext()) {
-            final Pair<Integer, Intent.FilterComparison> key = it.next();
-            if (key.first == appWidgetId) {
-                final ServiceConnectionProxy conn = (ServiceConnectionProxy)
-                        mBoundRemoteViewsServices.get(key);
-                conn.disconnect();
-                mContext.unbindService(conn);
-                it.remove();
-            }
-        }
-
-        // Check if we need to destroy any services (if no other app widgets are
-        // referencing the same service)
-        decrementAppWidgetServiceRefCount(widget);
-    }
-
     // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
     private void destroyRemoteViewsService(final Intent intent, Widget widget) {
         final ServiceConnection conn = new ServiceConnection() {
@@ -1853,7 +1787,7 @@
     // Adds to the ref-count for a given RemoteViewsService intent
     private void incrementAppWidgetServiceRefCount(int appWidgetId,
             Pair<Integer, FilterComparison> serviceId) {
-        HashSet<Integer> appWidgetIds = null;
+        final HashSet<Integer> appWidgetIds;
         if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) {
             appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId);
         } else {
@@ -4055,40 +3989,6 @@
         }
     }
 
-    /**
-     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This
-     * needs to be a static inner class since a reference to the ServiceConnection is held globally
-     * and may lead us to leak AppWidgetService instances (if there were more than one).
-     */
-    private static final class ServiceConnectionProxy implements ServiceConnection {
-        private final IRemoteViewsAdapterConnection mConnectionCb;
-
-        ServiceConnectionProxy(IBinder connectionCb) {
-            mConnectionCb = IRemoteViewsAdapterConnection.Stub
-                    .asInterface(connectionCb);
-        }
-
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            try {
-                mConnectionCb.onServiceConnected(service);
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Error passing service interface", re);
-            }
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-            disconnect();
-        }
-
-        public void disconnect() {
-            try {
-                mConnectionCb.onServiceDisconnected();
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Error clearing service interface", re);
-            }
-        }
-    }
-
     private class LoadedWidgetState {
         final Widget widget;
         final int hostTag;
@@ -4642,7 +4542,9 @@
                         // reconstructed due to the restore
                         host.widgets.remove(widget);
                         provider.widgets.remove(widget);
-                        unbindAppWidgetRemoteViewsServicesLocked(widget);
+                        // Check if we need to destroy any services (if no other app widgets are
+                        // referencing the same service)
+                        decrementAppWidgetServiceRefCount(widget);
                         removeWidgetLocked(widget);
                     }
                 }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 59fc34d..b720f74 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -846,12 +846,9 @@
      * when necessary.
      */
     public void logContextCommittedLocked() {
-        if (mResponses == null) {
-            if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): skipped (no responses)");
-            return;
-        }
+        final FillResponse lastResponse = getLastResponseLocked("logContextCommited()");
+        if (lastResponse == null) return;
 
-        final FillResponse lastResponse = mResponses.valueAt(mResponses.size() -1);
         final int flags = lastResponse.getFlags();
         if ((flags & FillResponse.FLAG_TRACK_CONTEXT_COMMITED) == 0) {
             if (sDebug) Slog.d(TAG, "logContextCommittedLocked(): ignored by flags " + flags);
@@ -1599,11 +1596,10 @@
      * Checks whether a view should be ignored.
      */
     private boolean isIgnoredLocked(AutofillId id) {
-        if (mResponses == null || mResponses.size() == 0) {
-            return false;
-        }
         // Always check the latest response only
-        final FillResponse response = mResponses.valueAt(mResponses.size() - 1);
+        final FillResponse response = getLastResponseLocked(null);
+        if (response == null) return false;
+
         return ArrayUtils.contains(response.getIgnoredIds(), id);
     }
 
@@ -1680,13 +1676,10 @@
     }
 
     private void updateTrackedIdsLocked() {
-        if (mResponses == null || mResponses.size() == 0) {
-            return;
-        }
-
         // Only track the views of the last response as only those are reported back to the
         // service, see #showSaveLocked
-        final FillResponse response = mResponses.valueAt(getLastResponseIndexLocked());
+        final FillResponse response = getLastResponseLocked(null);
+        if (response == null) return;
 
         ArraySet<AutofillId> trackedViews = null;
         boolean saveOnAllViewsInvisible = false;
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index 5d6e9b5..1dcb0ad 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -17,8 +17,6 @@
 package com.android.server.am;
 
 import android.content.Context;
-import android.os.Handler;
-import android.os.Message;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.WindowManager;
@@ -27,21 +25,19 @@
 import com.android.internal.R;
 
 /**
- *  Helper to manage showing/hiding a image to notify them that they are entering
- *  or exiting screen pinning mode.
+ *  Helper to manage showing/hiding a image to notify them that they are entering or exiting screen
+ *  pinning mode. All exposed methods should be called from a handler thread.
  */
 public class LockTaskNotify {
     private static final String TAG = "LockTaskNotify";
     private static final long SHOW_TOAST_MINIMUM_INTERVAL = 1000;
 
     private final Context mContext;
-    private final H mHandler;
     private Toast mLastToast;
     private long mLastShowToastTime;
 
     public LockTaskNotify(Context context) {
         mContext = context;
-        mHandler = new H();
     }
 
     /** Show "Screen pinned" toast. */
@@ -56,10 +52,6 @@
 
     /** Show a toast that describes the gesture the user should use to escape pinned mode. */
     void showEscapeToast() {
-        mHandler.obtainMessage(H.SHOW_ESCAPE_TOAST).sendToTarget();
-    }
-
-    private void handleShowEscapeToast() {
         long showToastTime = SystemClock.elapsedRealtime();
         if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) {
             Slog.i(TAG, "Ignore toast since it is requested in very short interval.");
@@ -79,17 +71,4 @@
         toast.show();
         return toast;
     }
-
-    private final class H extends Handler {
-        private static final int SHOW_ESCAPE_TOAST = 3;
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case SHOW_ESCAPE_TOAST:
-                    handleShowEscapeToast();
-                    break;
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 515fa39..755c5f0 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -34,8 +34,6 @@
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioAttributes;
-import android.nfc.INfcAdapter;
-import android.nfc.NfcAdapter;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -124,7 +122,6 @@
     private static String METRIC_RADIOS = "shutdown_radios";
     private static String METRIC_BT = "shutdown_bt";
     private static String METRIC_RADIO = "shutdown_radio";
-    private static String METRIC_NFC = "shutdown_nfc";
     private static String METRIC_SM = "shutdown_storage_manager";
 
     private final Object mActionDoneSync = new Object();
@@ -629,29 +626,14 @@
         Thread t = new Thread() {
             public void run() {
                 TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
-                boolean nfcOff;
                 boolean bluetoothReadyForShutdown;
                 boolean radioOff;
 
-                final INfcAdapter nfc =
-                        INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc"));
                 final ITelephony phone =
                         ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
                 final IBluetoothManager bluetooth =
                         IBluetoothManager.Stub.asInterface(ServiceManager.checkService(
                                 BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE));
-                try {
-                    nfcOff = nfc == null ||
-                             nfc.getState() == NfcAdapter.STATE_OFF;
-                    if (!nfcOff) {
-                        Log.w(TAG, "Turning off NFC...");
-                        metricStarted(METRIC_NFC);
-                        nfc.disable(false); // Don't persist new state
-                    }
-                } catch (RemoteException ex) {
-                Log.e(TAG, "RemoteException during NFC shutdown", ex);
-                    nfcOff = true;
-                }
 
                 try {
                     bluetoothReadyForShutdown = bluetooth == null ||
@@ -678,7 +660,7 @@
                     radioOff = true;
                 }
 
-                Log.i(TAG, "Waiting for NFC, Bluetooth and Radio...");
+                Log.i(TAG, "Waiting for Bluetooth and Radio...");
 
                 long delay = endTime - SystemClock.elapsedRealtime();
                 while (delay > 0) {
@@ -722,23 +704,9 @@
                                     .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
                         }
                     }
-                    if (!nfcOff) {
-                        try {
-                            nfcOff = nfc.getState() == NfcAdapter.STATE_OFF;
-                        } catch (RemoteException ex) {
-                            Log.e(TAG, "RemoteException during NFC shutdown", ex);
-                            nfcOff = true;
-                        }
-                        if (nfcOff) {
-                            Log.i(TAG, "NFC turned off.");
-                            metricEnded(METRIC_NFC);
-                            shutdownTimingsTraceLog
-                                    .logDuration("ShutdownNfc", TRON_METRICS.get(METRIC_NFC));
-                        }
-                    }
 
-                    if (radioOff && bluetoothReadyForShutdown && nfcOff) {
-                        Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete.");
+                    if (radioOff && bluetoothReadyForShutdown) {
+                        Log.i(TAG, "Radio and Bluetooth shutdown complete.");
                         done[0] = true;
                         break;
                     }
@@ -755,7 +723,7 @@
         } catch (InterruptedException ex) {
         }
         if (!done[0]) {
-            Log.w(TAG, "Timed out waiting for NFC, Radio and Bluetooth shutdown.");
+            Log.w(TAG, "Timed out waiting for Radio and Bluetooth shutdown.");
         }
     }
 
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index ca3dd05..22d2bcf 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -33,12 +33,14 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.StatsLogEventWrapper;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
 
 import java.util.ArrayList;
 import java.util.List;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.KernelWakelockReader;
 import com.android.internal.os.KernelWakelockStats;
@@ -49,6 +51,7 @@
 /**
  * Helper service for statsd (the native stats management service in cmds/statsd/).
  * Used for registering and receiving alarms on behalf of statsd.
+ *
  * @hide
  */
 public class StatsCompanionService extends IStatsCompanionService.Stub {
@@ -90,7 +93,7 @@
                         // Needed since the new user basically has a version of every app.
                         informAllUidsLocked(context);
                     } catch (RemoteException e) {
-                        Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
+                        Slog.e(TAG, "Failed to inform statsd latest update of all apps", e);
                         forgetEverything();
                     }
                 }
@@ -99,9 +102,9 @@
         Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED.");
     }
 
-    private final static int[] toIntArray(List<Integer> list){
+    private final static int[] toIntArray(List<Integer> list) {
         int[] ret = new int[list.size()];
-        for(int i = 0;i < ret.length;i++) {
+        for (int i = 0; i < ret.length; i++) {
             ret[i] = list.get(i);
         }
         return ret;
@@ -113,7 +116,7 @@
         PackageManager pm = context.getPackageManager();
         final List<UserInfo> users = um.getUsers(true);
         if (DEBUG) {
-            Slog.w(TAG, "Iterating over "+users.size() + " profiles.");
+            Slog.w(TAG, "Iterating over " + users.size() + " profiles.");
         }
 
         List<Integer> uids = new ArrayList();
@@ -122,23 +125,23 @@
 
         // Add in all the apps for every user/profile.
         for (UserInfo profile : users) {
-          List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
-          for (int j = 0; j < pi.size(); j++) {
-              if (pi.get(j).applicationInfo != null) {
-                  uids.add(pi.get(j).applicationInfo.uid);
-                  versions.add(pi.get(j).versionCode);
-                  apps.add(pi.get(j).packageName);
-              }
-          }
+            List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
+            for (int j = 0; j < pi.size(); j++) {
+                if (pi.get(j).applicationInfo != null) {
+                    uids.add(pi.get(j).applicationInfo.uid);
+                    versions.add(pi.get(j).versionCode);
+                    apps.add(pi.get(j).packageName);
+                }
+            }
         }
         sStatsd.informAllUidData(toIntArray(uids), toIntArray(versions), apps.toArray(new
-            String[apps.size()]));
+                String[apps.size()]));
         if (DEBUG) {
-            Slog.w(TAG, "Sent data for "+uids.size() +" apps");
+            Slog.w(TAG, "Sent data for " + uids.size() + " apps");
         }
     }
 
-    public final static class AppUpdateReceiver extends BroadcastReceiver  {
+    public final static class AppUpdateReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
@@ -147,7 +150,7 @@
              * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag.
              */
             if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) &&
-                intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                 return; // Keep only replacing or normal add and remove.
             }
             synchronized (sStatsdLock) {
@@ -180,9 +183,9 @@
                 }
             }
         }
-    };
+    }
 
-    public final static class AnomalyAlarmReceiver extends BroadcastReceiver  {
+    public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred.");
@@ -200,7 +203,7 @@
             }
             // AlarmManager releases its own wakelock here.
         }
-    };
+    }
 
     public final static class PollingAlarmReceiver extends BroadcastReceiver {
         @Override
@@ -220,7 +223,7 @@
             }
             // AlarmManager releases its own wakelock here.
         }
-    };
+    }
 
     @Override // Binder call
     public void setAnomalyAlarm(long timestampMs) {
@@ -286,33 +289,34 @@
     private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
 
     @Override // Binder call
-    public String pullData(int pullCode) {
+    public StatsLogEventWrapper[] pullData(int pullCode) {
         enforceCallingPermission();
-        if (DEBUG) Slog.d(TAG, "Fetching " + pullCode);
+        if (DEBUG) {
+            Slog.d(TAG, "Pulling " + pullCode);
+        }
 
-        StringBuilder s = new StringBuilder(); // TODO: use and return a Parcel instead of a string
+        List<StatsLogEventWrapper> ret = new ArrayList<>();
         switch (pullCode) {
-            case PULL_CODE_KERNEL_WAKELOCKS:
+            case PULL_CODE_KERNEL_WAKELOCKS: {
                 final KernelWakelockStats wakelockStats =
                         mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
-
                 for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
                     String name = ent.getKey();
                     KernelWakelockStats.Entry kws = ent.getValue();
-                    s.append("Wakelock ")
-                            .append(name)
-                            .append(", time=")
-                            .append(kws.mTotalTime)
-                            .append(", count=")
-                            .append(kws.mCount)
-                            .append('\n');
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(101, 4);
+                    e.writeInt(kws.mCount);
+                    e.writeInt(kws.mVersion);
+                    e.writeLong(kws.mTotalTime);
+                    e.writeString(name);
+                    ret.add(e);
                 }
                 break;
+            }
             default:
                 Slog.w(TAG, "No such pollable data as " + pullCode);
                 return null;
         }
-        return s.toString();
+        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
     }
 
     @Override // Binder call
@@ -331,7 +335,9 @@
 
     // Lifecycle and related code
 
-    /** Fetches the statsd IBinder service */
+    /**
+     * Fetches the statsd IBinder service
+     */
     private static IStatsManager fetchStatsdService() {
         return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
     }
@@ -363,13 +369,17 @@
         }
     }
 
-    /** Now that the android system is ready, StatsCompanion is ready too, so inform statsd. */
+    /**
+     * Now that the android system is ready, StatsCompanion is ready too, so inform statsd.
+     */
     private void systemReady() {
         if (DEBUG) Slog.d(TAG, "Learned that systemReady");
         sayHiToStatsd();
     }
 
-    /** Tells statsd that statscompanion is ready. If the binder call returns, link to statsd. */
+    /**
+     * Tells statsd that statscompanion is ready. If the binder call returns, link to statsd.
+     */
     private void sayHiToStatsd() {
         synchronized (sStatsdLock) {
             if (sStatsd != null) {
@@ -398,14 +408,14 @@
                 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
                 filter.addDataScheme("package");
                 mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null,
-                    null);
+                        null);
 
                 // Setup receiver for user initialize (which happens once for a new user) and
                 // if a user is removed.
                 filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
                 filter.addAction(Intent.ACTION_USER_REMOVED);
                 mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL,
-                    filter, null, null);
+                        filter, null, null);
 
                 // Pull the latest state of UID->app name, version mapping when statsd starts.
                 informAllUidsLocked(mContext);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c59f44e..80f6a4b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -175,6 +175,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
@@ -1682,6 +1683,10 @@
             return getCallingUid() == Process.myUid();
         }
 
+        void binderWithCleanCallingIdentity(@NonNull ThrowingRunnable action) {
+             Binder.withCleanCallingIdentity(action);
+        }
+
         final int userHandleGetCallingUserId() {
             return UserHandle.getUserId(binderGetCallingUid());
         }
@@ -9023,6 +9028,31 @@
     }
 
     @Override
+    public boolean setTime(ComponentName who, long millis) {
+        Preconditions.checkNotNull(who, "ComponentName is null in setTime");
+        getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        // Don't allow set time when auto time is on.
+        if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
+            return false;
+        }
+        mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
+        return true;
+    }
+
+    @Override
+    public boolean setTimeZone(ComponentName who, String timeZone) {
+        Preconditions.checkNotNull(who, "ComponentName is null in setTimeZone");
+        getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        // Don't allow set timezone when auto timezone is on.
+        if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
+            return false;
+        }
+        mInjector.binderWithCleanCallingIdentity(() ->
+            mInjector.getAlarmManager().setTimeZone(timeZone));
+        return true;
+    }
+
+    @Override
     public void setSecureSetting(ComponentName who, String setting, String value) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = mInjector.userHandleGetCallingUserId();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 5471715..ae4b569 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.devicepolicy;
 
+import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -34,11 +35,13 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.security.KeyChain;
+import android.support.annotation.NonNull;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Pair;
 import android.view.IWindowManager;
 
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
@@ -194,6 +197,9 @@
         }
 
         @Override
+        AlarmManager getAlarmManager() {return services.alarmManager;}
+
+        @Override
         LockPatternUtils newLockPatternUtils() {
             return services.lockPatternUtils;
         }
@@ -234,6 +240,11 @@
         }
 
         @Override
+        void binderWithCleanCallingIdentity(@NonNull ThrowingRunnable action) {
+            context.binder.withCleanCallingIdentity(action);
+        }
+
+        @Override
         int binderGetCallingUid() {
             return context.binder.getCallingUid();
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a8bf8f1..e1e9cf5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3090,6 +3090,47 @@
         assertEquals(-1, dpm.getLastSecurityLogRetrievalTime());
     }
 
+    public void testSetTime() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        dpm.setTime(admin1, 0);
+        verify(getServices().alarmManager).setTime(0);
+    }
+
+    public void testSetTimeFailWithPO() throws Exception {
+        setupProfileOwner();
+        assertExpectException(SecurityException.class, null, () -> dpm.setTime(admin1, 0));
+    }
+
+    public void testSetTimeWithAutoTimeOn() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        when(getServices().settings.settingsGlobalGetInt(Settings.Global.AUTO_TIME, 0))
+                .thenReturn(1);
+        assertFalse(dpm.setTime(admin1, 0));
+    }
+
+    public void testSetTimeZone() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        dpm.setTimeZone(admin1, "Asia/Shanghai");
+        verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
+    }
+
+    public void testSetTimeZoneFailWithPO() throws Exception {
+        setupProfileOwner();
+        assertExpectException(SecurityException.class, null,
+                () -> dpm.setTimeZone(admin1, "Asia/Shanghai"));
+    }
+
+    public void testSetTimeZoneWithAutoTimeZoneOn() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        when(getServices().settings.settingsGlobalGetInt(Settings.Global.AUTO_TIME_ZONE, 0))
+                .thenReturn(1);
+        assertFalse(dpm.setTimeZone(admin1, "Asia/Shanghai"));
+    }
+
     public void testGetLastBugReportRequestTime() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 9702118..7e11e87 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -30,8 +30,12 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
+import android.support.annotation.NonNull;
 import android.test.mock.MockContext;
 import android.util.ArrayMap;
+import android.util.ExceptionUtils;
+
+import com.android.internal.util.FunctionalUtils;
 
 import org.junit.Assert;
 
@@ -95,6 +99,21 @@
             callingPid = (int) token;
         }
 
+        public void withCleanCallingIdentity(@NonNull FunctionalUtils.ThrowingRunnable action) {
+            long callingIdentity = clearCallingIdentity();
+            Throwable throwableToPropagate = null;
+            try {
+                action.run();
+            } catch (Throwable throwable) {
+                throwableToPropagate = throwable;
+            } finally {
+                restoreCallingIdentity(callingIdentity);
+                if (throwableToPropagate != null) {
+                    throw ExceptionUtils.propagate(throwableToPropagate);
+                }
+            }
+        }
+
         public int getCallingUid() {
             return callingUid;
         }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 56a3fb0..b8e8946 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -89,6 +89,9 @@
     public void setUp() throws Exception {
         if (!sOneTimeSetupDone) {
             sOneTimeSetupDone = true;
+
+            // Allows to mock package local classes and methods
+            System.setProperty("dexmaker.share_classloader", "true");
             MockitoAnnotations.initMocks(this);
         }
 
diff --git a/tools/locked_region_code_injection/Android.mk b/tools/locked_region_code_injection/Android.mk
index bb5f4d6..3f65151 100644
--- a/tools/locked_region_code_injection/Android.mk
+++ b/tools/locked_region_code_injection/Android.mk
@@ -6,10 +6,10 @@
 LOCAL_MODULE := lockedregioncodeinjection
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    asm-6.0_BETA \
-    asm-commons-6.0_BETA \
-    asm-tree-6.0_BETA \
-    asm-analysis-6.0_BETA \
+    asm-6.0 \
+    asm-commons-6.0 \
+    asm-tree-6.0 \
+    asm-analysis-6.0 \
     guava-21.0 \
 
 include $(BUILD_HOST_JAVA_LIBRARY)