Merge "Tracks isolated uid's and their parent uid."
diff --git a/Android.mk b/Android.mk
index c4f222e..817aa80 100644
--- a/Android.mk
+++ b/Android.mk
@@ -137,6 +137,7 @@
 	../../system/bt/binder/android/bluetooth/IBluetoothPbap.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothPbapClient.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothSap.aidl \
+	../../system/bt/binder/android/bluetooth/IBluetoothSocketManager.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothStateChangeCallback.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothHeadsetClient.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothHidDevice.aidl \
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 87d318b..d99136f 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -38,7 +38,7 @@
     src/matchers/CombinationLogMatchingTracker.cpp \
     src/matchers/matcher_util.cpp \
     src/matchers/SimpleLogMatchingTracker.cpp \
-    src/metrics/CountAnomalyTracker.cpp \
+    src/anomaly/DiscreteAnomalyTracker.cpp \
     src/metrics/MetricProducer.cpp \
     src/metrics/EventMetricProducer.cpp \
     src/metrics/CountMetricProducer.cpp \
@@ -150,6 +150,7 @@
 LOCAL_SRC_FILES := \
     $(statsd_common_src) \
     tests/AnomalyMonitor_test.cpp \
+    tests/anomaly/AnomalyTracker_test.cpp \
     tests/ConditionTracker_test.cpp \
     tests/ConfigManager_test.cpp \
     tests/indexed_priority_queue_test.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index f0689d2..7ff42b6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -18,7 +18,6 @@
 #include "statslog.h"
 
 #include "StatsLogProcessor.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "metrics/CountMetricProducer.h"
 #include "stats_util.h"
 
@@ -26,6 +25,13 @@
 #include <utils/Errors.h>
 
 using namespace android;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
 using std::make_unique;
 using std::unique_ptr;
 using std::vector;
@@ -34,6 +40,14 @@
 namespace os {
 namespace statsd {
 
+// for ConfigMetricsReport
+const int FIELD_ID_CONFIG_KEY = 1;
+const int FIELD_ID_METRICS = 2;
+const int FIELD_ID_UID_MAP = 3;
+// for ConfigKey
+const int FIELD_ID_UID = 1;
+const int FIELD_ID_NAME = 1;
+
 StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
                                      const std::function<void(const vector<uint8_t>&)>& pushLog)
     : mUidMap(uidMap), mPushLog(pushLog) {
@@ -87,27 +101,46 @@
     }
 }
 
-ConfigMetricsReport StatsLogProcessor::onDumpReport(const ConfigKey& key) {
-    ConfigMetricsReport report;
-
+vector<uint8_t> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
     auto it = mMetricsManagers.find(key);
     if (it == mMetricsManagers.end()) {
         ALOGW("Config source %s does not exist", key.ToString().c_str());
-        return report;
+        return vector<uint8_t>();
     }
 
-    auto set_key = report.mutable_config_key();
-    set_key->set_uid(key.GetUid());
-    set_key->set_name(key.GetName());
-    for (auto m : it->second->onDumpReport()) {
-        // Transfer the vector of StatsLogReport into a field
-        // TODO: perhaps we just have bytes being returned from onDumpReport and transfer bytes
-        auto dest = report.add_metrics();
-        *dest = m;
+    ProtoOutputStream proto;
+
+    // Fill in ConfigKey.
+    long long configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
+    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
+    proto.write(FIELD_TYPE_STRING | FIELD_ID_NAME, key.GetName());
+    proto.end(configKeyToken);
+
+    // Fill in StatsLogReport's.
+    for (auto& m : it->second->onDumpReport()) {
+        // Add each vector of StatsLogReport into a repeated field.
+        proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_METRICS, reinterpret_cast<char*>(m.get()->data()),
+                    m.get()->size());
     }
-    auto temp = mUidMap->getOutput(key);
-    report.mutable_uid_map()->Swap(&temp);
-    return report;
+
+    // Fill in UidMap.
+    auto uidMap = mUidMap->getOutput(key);
+    const int uidMapSize = uidMap.ByteSize();
+    char uidMapBuffer[uidMapSize];
+    uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize);
+    proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
+
+    vector<uint8_t> buffer(proto.size());
+    size_t pos = 0;
+    auto iter = proto.data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&buffer[pos], iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+
+    return buffer;
 }
 
 void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 0083827..f38d715 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -41,8 +41,7 @@
     void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
     void OnConfigRemoved(const ConfigKey& key);
 
-    // TODO: Once we have the ProtoOutputStream in c++, we can just return byte array.
-    ConfigMetricsReport onDumpReport(const ConfigKey& key);
+    vector<uint8_t> onDumpReport(const ConfigKey& key);
 
     /* Request a flush through a binder call. */
     void flush();
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index e2ac623..d9207e9 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -55,6 +55,7 @@
     };
 };
 
+// TODO: Rename this file to AnomalyAlarmMonitor.
 /**
  * Manages alarms for Anomaly Detection.
  */
@@ -95,6 +96,15 @@
     unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
             uint32_t timestampSec);
 
+    // TODO: Function that uses popSoonerThan to get all alarms that have fired, and then
+    // iterates over all DurationAnomalyTracker, looking for those alarms. When they're found,
+    // have them declareAnomaly on those alarms. This means that DurationAnomalyTracker
+    // must be thread-safe (since this is being called on a different thread). There is no
+    // worry about missing the alarms (due to them being cancelled after this function being called)
+    // because DurationAnomalyTracker guarantees that it checks for anaomlies when it cancels
+    // alarms anyway.
+    // void declareAnomalies(uint32_t timestampSec);
+
     /**
      * Returns the projected alarm timestamp that is registered with
      * StatsCompanionService. This may not be equal to the soonest alarm,
diff --git a/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp
new file mode 100644
index 0000000..9c9bde9
--- /dev/null
+++ b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
+#include "DiscreteAnomalyTracker.h"
+
+#include <time.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+DiscreteAnomalyTracker::DiscreteAnomalyTracker(const Alert& alert) : mAlert(alert) {
+    VLOG("DiscreteAnomalyTracker() called");
+    if (mAlert.number_of_buckets() <= 0) {
+        ALOGE("Cannot create DiscreteAnomalyTracker with %lld buckets",
+              (long long)mAlert.number_of_buckets());
+        return;
+    }
+    mPastBuckets.resize(mAlert.number_of_buckets());
+    reset(); // initialization
+}
+
+DiscreteAnomalyTracker::~DiscreteAnomalyTracker() {
+    VLOG("~DiscreteAnomalyTracker() called");
+}
+
+void DiscreteAnomalyTracker::reset() {
+    VLOG("reset() called.");
+    mPastBuckets.clear();
+    mPastBuckets.resize(mAlert.number_of_buckets());
+    mSumOverPastBuckets.clear();
+    mCurrentBucketIndex = -1;
+    mLastAlarmAtBucketIndex = -1;
+    mAnomalyDeclared = 0;
+}
+
+size_t DiscreteAnomalyTracker::index(int64_t bucketNum) {
+    return bucketNum % mAlert.number_of_buckets();
+}
+
+void DiscreteAnomalyTracker::addOrUpdateBucket(std::shared_ptr<const DimToValMap> BucketValues,
+                                               int64_t bucketIndex) {
+    VLOG("addPastBucket() called.");
+    if (bucketIndex <= mCurrentBucketIndex - mAlert.number_of_buckets()) {
+        ALOGE("Cannot add a past bucket %lld units in past", (long long)bucketIndex);
+        return;
+    }
+
+    // Empty out old mPastBuckets[i] values and update mSumOverPastBuckets.
+    if (bucketIndex - mCurrentBucketIndex >= mAlert.number_of_buckets()) {
+        mPastBuckets.clear();
+        mPastBuckets.resize(mAlert.number_of_buckets());
+        mSumOverPastBuckets.clear();
+    } else {
+        for (int64_t i = std::max(
+                     0LL, (long long)(mCurrentBucketIndex - mAlert.number_of_buckets() + 1));
+             i < bucketIndex - mAlert.number_of_buckets(); i++) {
+            const int idx = index(i);
+            subtractBucketFromSum(mPastBuckets[idx]);
+            mPastBuckets[idx] = nullptr;  // release (but not clear) the old bucket.
+        }
+    }
+    subtractBucketFromSum(mPastBuckets[index(bucketIndex)]);
+    mPastBuckets[index(bucketIndex)] = nullptr;  // release (but not clear) the old bucket.
+
+    // Replace the oldest bucket with the new bucket we are adding.
+    mPastBuckets[index(bucketIndex)] = BucketValues;
+    addBucketToSum(BucketValues);
+
+    mCurrentBucketIndex = std::max(mCurrentBucketIndex, bucketIndex);
+}
+
+void DiscreteAnomalyTracker::subtractBucketFromSum(const shared_ptr<const DimToValMap>& bucket) {
+    if (bucket == nullptr) {
+        return;
+    }
+    // For each dimension present in the bucket, subtract its value from its corresponding sum.
+    for (const auto& keyValuePair : *bucket) {
+        auto itr = mSumOverPastBuckets.find(keyValuePair.first);
+        if (itr == mSumOverPastBuckets.end()) {
+            continue;
+        }
+        itr->second -= keyValuePair.second;
+        // TODO: No need to look up the object twice like this. Use a var.
+        if (itr->second == 0) {
+            mSumOverPastBuckets.erase(itr);
+        }
+    }
+}
+
+void DiscreteAnomalyTracker::addBucketToSum(const shared_ptr<const DimToValMap>& bucket) {
+    if (bucket == nullptr) {
+        return;
+    }
+    // For each dimension present in the bucket, add its value to its corresponding sum.
+    for (const auto& keyValuePair : *bucket) {
+        mSumOverPastBuckets[keyValuePair.first] += keyValuePair.second;
+    }
+}
+
+bool DiscreteAnomalyTracker::detectAnomaly() {
+    for (auto itr = mSumOverPastBuckets.begin(); itr != mSumOverPastBuckets.end(); itr++) {
+        if (mAlert.has_trigger_if_sum_gt() && itr->second > mAlert.trigger_if_sum_gt()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void DiscreteAnomalyTracker::declareAndDeclareAnomaly() {
+    if (detectAnomaly()) {
+        declareAnomaly();
+    }
+}
+
+void DiscreteAnomalyTracker::declareAnomaly() {
+    if (mLastAlarmAtBucketIndex >= 0 && mCurrentBucketIndex - mLastAlarmAtBucketIndex <=
+                                        (long long)mAlert.refractory_period_in_buckets()) {
+        VLOG("Skipping anomaly check since within refractory period");
+        return;
+    }
+    mAnomalyDeclared++;
+    // TODO(guardrail): Consider guarding against too short refractory periods.
+    mLastAlarmAtBucketIndex = mCurrentBucketIndex;
+
+    if (mAlert.has_incidentd_details()) {
+        const Alert_IncidentdDetails& incident = mAlert.incidentd_details();
+        if (incident.has_alert_name()) {
+            ALOGW("An anomaly (%s) has occurred! Informing incidentd.",
+                  incident.alert_name().c_str());
+        } else {
+            // TODO: Can construct a name based on the criteria (and/or relay the criteria).
+            ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
+        }
+        // TODO: Send incidentd_details.name and incidentd_details.incidentd_sections to incidentd
+    } else {
+        ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h
new file mode 100644
index 0000000..ed7d5d7
--- /dev/null
+++ b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest_prod.h>
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
+#include "stats_util.h" // HashableDimensionKey and DimToValMap
+
+#include <memory> // unique_ptr
+#include <stdlib.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::unordered_map;
+using std::shared_ptr;
+
+// This anomaly track assmues that all values are non-negative.
+class DiscreteAnomalyTracker {
+ public:
+    DiscreteAnomalyTracker(const Alert& alert);
+
+    virtual ~DiscreteAnomalyTracker();
+
+    // Adds a new bucket or updates an existing bucket.
+    // Bucket index starts from 0.
+    void addOrUpdateBucket(std::shared_ptr<const DimToValMap> BucketValues, int64_t bucketIndex);
+
+    // Returns true if detected anomaly for the existing buckets on one or more dimension keys.
+    bool detectAnomaly();
+
+    // Informs incidentd about the detected alert.
+    void declareAnomaly();
+
+    // Detects the alert and informs the incidentd when applicable.
+    void declareAndDeclareAnomaly();
+
+private:
+    // statsd_config.proto Alert message that defines this tracker.
+    const Alert mAlert;
+
+    // The exisiting bucket list.
+    std::vector<shared_ptr<const DimToValMap>> mPastBuckets;
+
+    // Sum over all existing buckets cached in mPastBuckets.
+    DimToValMap mSumOverPastBuckets;
+
+    // Current bucket index of the current anomaly detection window. Bucket index starts from 0.
+    int64_t mCurrentBucketIndex = -1;
+
+    // The bucket index when the last anomaly was declared.
+    int64_t mLastAlarmAtBucketIndex = -1;
+
+    // The total number of declared anomalies.
+    int64_t mAnomalyDeclared = 0;
+
+    // Add the information in the given bucket to mSumOverPastBuckets.
+    void addBucketToSum(const shared_ptr<const DimToValMap>& bucket);
+
+    // Subtract the information in the given bucket from mSumOverPastBuckets
+    // and remove any items with value 0.
+    void subtractBucketFromSum(const shared_ptr<const DimToValMap>& bucket);
+
+    // Calculates the corresponding bucket index within the circular array.
+    size_t index(int64_t bucketNum);
+
+    // Resets all data. For use when all the data gets stale.
+    void reset();
+
+    FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
+    FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 40d41be..2618a21 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -25,7 +25,6 @@
 #include <unordered_map>
 #include "../matchers/matcher_util.h"
 #include "ConditionTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
index 47e245e..4167bf9 100644
--- a/cmds/statsd/src/condition/condition_util.h
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -19,7 +19,6 @@
 
 #include <vector>
 #include "../matchers/matcher_util.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index a58766d..19ccfcf 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
 #include "config/ConfigKey.h"
 
 #include <utils/RefBase.h>
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 02e6903..94566ff 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -165,6 +165,12 @@
     KeyMatcher* keyMatcher = metric->add_dimension();
     keyMatcher->set_key(UID_PROCESS_STATE_UID_KEY);
 
+    // Anomaly threshold for background count.
+    alert = metric->add_alerts();
+    alert->set_number_of_buckets(4);
+    alert->set_trigger_if_sum_gt(30);
+    alert->set_refractory_period_secs(20);
+
     // Count process state changes, slice by uid, while SCREEN_IS_OFF
     metric = config.add_count_metric();
     metric->set_metric_id(3);
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 006d74c..adb691e 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -22,7 +22,6 @@
 #include <unordered_map>
 #include <vector>
 #include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index d82da3b..ffbf248 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -17,7 +17,6 @@
 #ifndef LOG_MATCHING_TRACKER_H
 #define LOG_MATCHING_TRACKER_H
 
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "logd/LogEvent.h"
 #include "matchers/matcher_util.h"
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index e110ec8..5dca55e 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -23,7 +23,6 @@
 #include <unordered_map>
 #include <vector>
 #include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 6aa2211..cccc9b3 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -16,7 +16,6 @@
 
 #include "Log.h"
 
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "matchers/LogMatchingTracker.h"
 #include "matchers/matcher_util.h"
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
deleted file mode 100644
index 7aa748f..0000000
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG true  // STOPSHIP if true
-#include "Log.h"
-
-#include "CountAnomalyTracker.h"
-
-#include <time.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-CountAnomalyTracker::CountAnomalyTracker(const Alert& alert)
-    : mAlert(alert),
-      mNumPastBuckets(alert.number_of_buckets() > 0 ? alert.number_of_buckets() - 1 : 0),
-      mPastBuckets(mNumPastBuckets > 0 ? (new int[mNumPastBuckets]) : nullptr) {
-
-    VLOG("CountAnomalyTracker() called");
-    if (alert.number_of_buckets() < 1) {
-        ALOGE("Cannot create CountAnomalyTracker with %d buckets", alert.number_of_buckets());
-    }
-    reset(); // initialization
-}
-
-CountAnomalyTracker::~CountAnomalyTracker() {
-    VLOG("~CountAnomalyTracker() called");
-}
-
-void CountAnomalyTracker::addPastBucket(int pastBucketCount,
-                                        time_t numberOfBucketsAgo) {
-    VLOG("addPastBucket() called.");
-    if (numberOfBucketsAgo < 1) {
-        ALOGE("Cannot add a past bucket %ld units in past", numberOfBucketsAgo);
-        return;
-    }
-    // If past bucket was ancient, just empty out all past info.
-    // This always applies if mNumPastBuckets == 0 (i.e. store no past buckets).
-    if (numberOfBucketsAgo > (time_t) mNumPastBuckets) {
-        reset();
-        return;
-    }
-
-    // Empty out old mPastBuckets[i] values and update mSumPastCounters.
-    for (size_t i = mOldestBucketIndex;
-                        i < mOldestBucketIndex + numberOfBucketsAgo; i++) {
-        mSumPastCounters -= mPastBuckets[index(i)];
-        mPastBuckets[index(i)] = 0;
-    }
-
-    // Replace the oldest bucket with the new bucket we are adding.
-    mPastBuckets[mOldestBucketIndex] = pastBucketCount;
-    mSumPastCounters += pastBucketCount;
-
-    // Advance the oldest bucket index by numberOfBucketsAgo units.
-    mOldestBucketIndex = index(mOldestBucketIndex + numberOfBucketsAgo);
-
-    // TODO: Once dimensions are added to mSumPastCounters:
-    // iterate through mSumPastCounters and remove any entries that are 0.
-}
-
-void CountAnomalyTracker::reset() {
-    VLOG("reset() called.");
-    for (size_t i = 0; i < mNumPastBuckets; i++) {
-        mPastBuckets[i] = 0;
-    }
-    mSumPastCounters = 0;
-    mOldestBucketIndex = 0;
-}
-
-void CountAnomalyTracker::checkAnomaly(int currentCount) {
-    // Skip the check if in refractory period.
-    if (time(nullptr) < mRefractoryPeriodEndsSec) {
-        VLOG("Skipping anomaly check since within refractory period");
-        return;
-    }
-
-    // TODO: Remove these extremely verbose debugging log.
-    VLOG("Checking whether %d + %d > %lld",
-         mSumPastCounters, currentCount, mAlert.trigger_if_sum_gt());
-
-    // Note that this works even if mNumPastBuckets < 1 (since then
-    // mSumPastCounters = 0 so the comparison is based only on currentCount).
-    if (mAlert.has_trigger_if_sum_gt() &&
-            mSumPastCounters + currentCount > mAlert.trigger_if_sum_gt()) {
-        declareAnomaly();
-    }
-}
-
-void CountAnomalyTracker::declareAnomaly() {
-    // TODO(guardrail): Consider guarding against too short refractory periods.
-    time_t currTime = time(nullptr);
-    mRefractoryPeriodEndsSec = currTime + mAlert.refractory_period_secs();
-
-    // TODO: If we had access to the bucket_size_millis, consider calling reset()
-    // if (mAlert.refractory_period_secs() > mNumPastBuckets * bucket_size_millis * 1000).
-
-    if (mAlert.has_incidentd_details()) {
-        const Alert_IncidentdDetails& incident = mAlert.incidentd_details();
-        if (incident.has_alert_name()) {
-            ALOGW("An anomaly (%s) has occurred! Informing incidentd.",
-                  incident.alert_name().c_str());
-        } else {
-            // TODO: Can construct a name based on the criteria (and/or relay the criteria).
-            ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
-        }
-        // TODO: Send incidentd_details.name and incidentd_details.incidentd_sections to incidentd
-    } else {
-        ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.h b/cmds/statsd/src/metrics/CountAnomalyTracker.h
deleted file mode 100644
index 79c47d2a..0000000
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef COUNT_ANOMALY_TRACKER_H
-#define COUNT_ANOMALY_TRACKER_H
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
-
-#include <memory> // unique_ptr
-#include <stdlib.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// TODO: Can probably be used for Count, Value, and Gauge. If so, rename to ValueAnomalyTracker.
-// (caveat: currently, the value cannot be negative. Probably fine for P.)
-class CountAnomalyTracker {
-public:
-    CountAnomalyTracker(const Alert& alert);
-
-    virtual ~CountAnomalyTracker();
-
-
-    // Adds a new past bucket, holding pastBucketCount, and then advances the
-    // present by numberOfBucketsAgo buckets (filling any intervening buckets
-    // with 0s).
-    // Thus, the newly added bucket (which holds pastBucketCount) is stored
-    // numberOfBucketsAgo buckets ago.
-    void addPastBucket(int pastBucketCount, time_t numberOfBucketsAgo);
-
-    // Informs the anomaly tracker of the current bucket's count, so that it can
-    // determine whether an anomaly has occurred. This value is not stored.
-    void checkAnomaly(int currentCount);
-
-private:
-    // statsd_config.proto Alert message that defines this tracker.
-    const Alert mAlert;
-
-    // Number of past buckets. One less than the total number of buckets needed
-    // for the anomaly detection (since the current bucket is not in the past).
-    const size_t mNumPastBuckets;
-
-    // Count values for each of the past mNumPastBuckets buckets.
-    // TODO: Add dimensions. This parallels the type of CountMetricProducer.mCounter.
-    std::unique_ptr<int[]> mPastBuckets;
-
-    // Sum over all of mPastBuckets (cached).
-    // TODO: Add dimensions. This parallels the type of CountMetricProducer.mCounter.
-    //       At that point, mSumPastCounters must never contain entries of 0.
-    int mSumPastCounters;
-
-    // Index of the oldest bucket (i.e. the next bucket to be overwritten).
-    size_t mOldestBucketIndex = 0;
-
-    // Timestamp that the refractory period (if this anomaly was declared) ends, in seconds.
-    // If an anomaly was never declared, set to 0.
-    time_t mRefractoryPeriodEndsSec = 0;
-
-    void declareAnomaly();
-
-    // Calculates the corresponding index within the circular array.
-    size_t index(size_t unsafeIndex) {
-        return unsafeIndex % mNumPastBuckets;
-    }
-
-    // Resets all data. For use when all the data gets stale.
-    void reset();
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // COUNT_ANOMALY_TRACKER_H
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 94f4adf..0c9e522 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -17,7 +17,7 @@
 #define DEBUG true  // STOPSHIP if true
 #include "Log.h"
 
-#include "CountAnomalyTracker.h"
+#include "../anomaly/DiscreteAnomalyTracker.h"
 #include "CountMetricProducer.h"
 #include "stats_util.h"
 
@@ -61,6 +61,7 @@
 const int FIELD_ID_COUNT = 3;
 
 // TODO: add back AnomalyTracker.
+
 CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
                                          const sp<ConditionWizard>& wizard,
                                          const uint64_t startTimeNs)
@@ -76,7 +77,7 @@
     for (int i = 0; i < metric.alerts_size(); i++) {
         const Alert& alert = metric.alerts(i);
         if (alert.trigger_if_sum_gt() > 0 && alert.number_of_buckets() > 0) {
-            mAnomalyTrackers.push_back(std::make_unique<CountAnomalyTracker>(alert));
+            mAnomalyTrackers.push_back(std::make_unique<DiscreteAnomalyTracker>(alert));
         } else {
             ALOGW("Ignoring invalid count metric alert: threshold=%lld num_buckets= %d",
                   alert.trigger_if_sum_gt(), alert.number_of_buckets());
@@ -116,7 +117,7 @@
     VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
 }
 
-StatsLogReport CountMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
     long long endTime = time(nullptr) * NS_PER_SEC;
 
     // Dump current bucket if it's stale.
@@ -171,15 +172,13 @@
                   (long long)mCurrentBucketStartTimeNs);
 
     VLOG("metric %lld dump report now...", mMetric.metric_id());
-    std::unique_ptr<uint8_t[]> buffer = serializeProto();
+    std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(endTime);
     mPastBuckets.clear();
     mByteSize = 0;
 
-    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
-    // return std::move(buffer);
-    return StatsLogReport();
+    return buffer;
 
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
@@ -201,25 +200,19 @@
         return;
     }
 
-    auto it = mCurrentSlicedCounter.find(eventKey);
+    auto it = mCurrentSlicedCounter->find(eventKey);
 
-    if (it == mCurrentSlicedCounter.end()) {
+    if (it == mCurrentSlicedCounter->end()) {
         // create a counter for the new key
-        mCurrentSlicedCounter[eventKey] = 1;
-
+        (*mCurrentSlicedCounter)[eventKey] = 1;
     } else {
         // increment the existing value
         auto& count = it->second;
         count++;
     }
 
-    // TODO: Re-add anomaly detection (similar to):
-    // for (auto& tracker : mAnomalyTrackers) {
-    //     tracker->checkAnomaly(mCounter);
-    // }
-
     VLOG("metric %lld %s->%d", mMetric.metric_id(), eventKey.c_str(),
-         mCurrentSlicedCounter[eventKey]);
+         (*mCurrentSlicedCounter)[eventKey]);
 }
 
 // When a new matched event comes in, we check if event falls into the current
@@ -230,12 +223,13 @@
     }
 
     // adjust the bucket start time
-    int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+    // TODO: This (and addPastBucket to which it goes) doesn't really need to be an int64.
+    uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
 
     CountBucket info;
     info.mBucketStartNs = mCurrentBucketStartTimeNs;
     info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
-    for (const auto& counter : mCurrentSlicedCounter) {
+    for (const auto& counter : *mCurrentSlicedCounter) {
         info.mCount = counter.second;
         auto& bucketList = mPastBuckets[counter.first];
         bucketList.push_back(info);
@@ -244,15 +238,16 @@
         mByteSize += sizeof(info);
     }
 
-    // TODO: Re-add anomaly detection (similar to):
-    // for (auto& tracker : mAnomalyTrackers) {
-    //     tracker->addPastBucket(mCounter, numBucketsForward);
-    //}
+    for (auto& tracker : mAnomalyTrackers) {
+        tracker->addOrUpdateBucket(mCurrentSlicedCounter, mCurrentBucketNum);
+        tracker->declareAndDeclareAnomaly();
+    }
 
-    // Reset counters
-    mCurrentSlicedCounter.clear();
+    // Reset counters (do not clear, since the old one is still referenced in mAnomalyTrackers).
+    mCurrentSlicedCounter = std::make_shared<DimToValMap>();
 
     mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
+    mCurrentBucketNum += numBucketsForward;
     VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
          (long long)mCurrentBucketStartTimeNs);
 }
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index c3af006..b7e480c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -23,14 +23,11 @@
 #include <gtest/gtest_prod.h>
 #include "../condition/ConditionTracker.h"
 #include "../matchers/matcher_util.h"
-#include "CountAnomalyTracker.h"
+#include "../anomaly/DiscreteAnomalyTracker.h"
 #include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
-using namespace std;
-
 namespace android {
 namespace os {
 namespace statsd {
@@ -54,7 +51,7 @@
     void finish() override;
 
     // TODO: Pass a timestamp as a parameter in onDumpReport.
-    StatsLogReport onDumpReport() override;
+    std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
 
     void onSlicedConditionMayChange(const uint64_t eventTime) override;
 
@@ -82,9 +79,9 @@
     size_t mByteSize;
 
     // The current bucket.
-    std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
+    std::shared_ptr<DimToValMap> mCurrentSlicedCounter = std::make_shared<DimToValMap>();
 
-    vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers;
+    vector<std::unique_ptr<DiscreteAnomalyTracker>> mAnomalyTrackers;
 
     void flushCounterIfNeeded(const uint64_t newEventTime);
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index c0a0d98..2783bcea 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -159,7 +159,7 @@
     }
 }
 
-StatsLogReport DurationMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
     long long endTime = time(nullptr) * NS_PER_SEC;
 
     // Dump current bucket if it's stale.
@@ -214,14 +214,12 @@
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
                   (long long)mCurrentBucketStartTimeNs);
 
-    std::unique_ptr<uint8_t[]> buffer = serializeProto();
+    std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(endTime);
     mPastBuckets.clear();
 
-    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
-    // return std::move(buffer);
-    return StatsLogReport();
+    return buffer;
 }
 
 void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 8fdd0d4..eea00454 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -26,7 +26,6 @@
 #include "duration_helper/DurationTracker.h"
 #include "duration_helper/MaxDurationTracker.h"
 #include "duration_helper/OringDurationTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
@@ -50,7 +49,7 @@
     void finish() override;
 
     // TODO: Pass a timestamp as a parameter in onDumpReport.
-    StatsLogReport onDumpReport() override;
+    std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
 
     void onSlicedConditionMayChange(const uint64_t eventTime) override;
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index ee0bfde..f516cc7 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -84,20 +84,18 @@
 void EventMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
 }
 
-StatsLogReport EventMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReport() {
     long long endTime = time(nullptr) * NS_PER_SEC;
     mProto->end(mProtoToken);
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
 
     size_t bufferSize = mProto->size();
     VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize);
-    std::unique_ptr<uint8_t[]> buffer = serializeProto();
+    std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(endTime);
 
-    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
-    // return std::move(buffer);
-    return StatsLogReport();
+    return buffer;
 }
 
 void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 2ca8181..0dccdf4 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -24,7 +24,6 @@
 #include "../condition/ConditionTracker.h"
 #include "../matchers/matcher_util.h"
 #include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
@@ -50,7 +49,7 @@
     void finish() override;
 
     // TODO: Pass a timestamp as a parameter in onDumpReport.
-    StatsLogReport onDumpReport() override;
+    std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
 
     void onSlicedConditionMayChange(const uint64_t eventTime) override;
 
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index dcfcc19..285d29b 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -106,7 +106,7 @@
 void GaugeMetricProducer::finish() {
 }
 
-StatsLogReport GaugeMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> GaugeMetricProducer::onDumpReport() {
     VLOG("gauge metric %lld dump report now...", mMetric.metric_id());
 
     // Dump current bucket if it's stale.
@@ -159,15 +159,13 @@
     mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
                   (long long)mCurrentBucketStartTimeNs);
 
-    std::unique_ptr<uint8_t[]> buffer = serializeProto();
+    std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
     mPastBuckets.clear();
     mByteSize = 0;
 
-    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
-    // return std::move(buffer);
-    return StatsLogReport();
+    return buffer;
 
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 3757174..d80672d 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -24,7 +24,6 @@
 #include "../external/StatsPullerManager.h"
 #include "../matchers/matcher_util.h"
 #include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
@@ -60,7 +59,7 @@
     void finish() override;
 
     // TODO: Pass a timestamp as a parameter in onDumpReport.
-    StatsLogReport onDumpReport() override;
+    std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
 
     size_t byteSize() override;
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 5ca83b2..3c4dd90 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -64,16 +64,16 @@
                               scheduledPull);
 }
 
-std::unique_ptr<uint8_t[]> MetricProducer::serializeProto() {
+std::unique_ptr<std::vector<uint8_t>> MetricProducer::serializeProto() {
     size_t bufferSize = mProto->size();
 
-    std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
+    std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
 
     size_t pos = 0;
     auto it = mProto->data();
     while (it.readBuffer() != NULL) {
         size_t toRead = it.currentToRead();
-        std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+        std::memcpy(&buffer.get()[pos], it.readBuffer(), toRead);
         pos += toRead;
         it.rp()->move(toRead);
     }
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 7ac97a8..c0930e3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -23,7 +23,6 @@
 
 #include <log/logprint.h>
 #include <utils/RefBase.h>
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 
 namespace android {
 namespace os {
@@ -39,6 +38,7 @@
                    const sp<ConditionWizard>& wizard)
         : mStartTimeNs(startTimeNs),
           mCurrentBucketStartTimeNs(startTimeNs),
+          mCurrentBucketNum(0),
           mCondition(conditionIndex >= 0 ? false : true),
           mConditionSliced(false),
           mWizard(wizard),
@@ -61,7 +61,7 @@
 
     // TODO: Pass a timestamp as a parameter in onDumpReport and update all its
     // implementations.
-    virtual StatsLogReport onDumpReport() = 0;
+    virtual std::unique_ptr<std::vector<uint8_t>> onDumpReport() = 0;
 
     virtual bool isConditionSliced() const {
         return mConditionSliced;
@@ -74,6 +74,8 @@
 
     uint64_t mCurrentBucketStartTimeNs;
 
+    uint64_t mCurrentBucketNum;
+
     int64_t mBucketSizeNs;
 
     bool mCondition;
@@ -118,7 +120,7 @@
 
     virtual void startNewProtoOutputStream(long long timestamp) = 0;
 
-    std::unique_ptr<uint8_t[]> serializeProto();
+    std::unique_ptr<std::vector<uint8_t>> serializeProto();
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 80b325f..19317ee 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -56,10 +56,10 @@
     }
 }
 
-vector<StatsLogReport> MetricsManager::onDumpReport() {
+vector<std::unique_ptr<vector<uint8_t>>> MetricsManager::onDumpReport() {
     VLOG("=========================Metric Reports Start==========================");
     // one StatsLogReport per MetricProduer
-    vector<StatsLogReport> reportList;
+    vector<std::unique_ptr<vector<uint8_t>>> reportList;
     for (auto& metric : mAllMetricProducers) {
         reportList.push_back(metric->onDumpReport());
     }
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 63e2c33..39c79f9 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -44,7 +44,7 @@
     void finish();
 
     // Config source owner can call onDumpReport() to get all the metrics collected.
-    std::vector<StatsLogReport> onDumpReport();
+    std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
 
     size_t byteSize();
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 41b7a5d..2a63073 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -108,7 +108,7 @@
     VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
 }
 
-StatsLogReport ValueMetricProducer::onDumpReport() {
+std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReport() {
     VLOG("metric %lld dump report now...", mMetric.metric_id());
 
     for (const auto& pair : mPastBuckets) {
@@ -156,15 +156,13 @@
                   (long long)mCurrentBucketStartTimeNs);
 
     VLOG("metric %lld dump report now...", mMetric.metric_id());
-    std::unique_ptr<uint8_t[]> buffer = serializeProto();
+    std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
 
     startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
     mPastBuckets.clear();
     mByteSize = 0;
 
-    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
-    // return std::move(buffer);
-    return StatsLogReport();
+    return buffer;
 
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 8437665..ef9868b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -21,9 +21,7 @@
 #include "../condition/ConditionTracker.h"
 #include "../external/PullDataReceiver.h"
 #include "../external/StatsPullerManager.h"
-#include "CountAnomalyTracker.h"
 #include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
@@ -49,7 +47,7 @@
     void finish() override;
 
     // TODO: Pass a timestamp as a parameter in onDumpReport.
-    StatsLogReport onDumpReport() override;
+    std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
 
     void onSlicedConditionMayChange(const uint64_t eventTime);
 
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index aeb234d..5c76d0e 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -20,8 +20,6 @@
 #include "condition/ConditionWizard.h"
 #include "stats_util.h"
 
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-
 namespace android {
 namespace os {
 namespace statsd {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index de53d62..b095884 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -19,8 +19,6 @@
 
 #include "DurationTracker.h"
 
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-
 namespace android {
 namespace os {
 namespace statsd {
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index a9507bf..e1d0aceb 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -13,8 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef STATS_UTIL_H
-#define STATS_UTIL_H
+
+#pragma once
 
 #include "logd/LogReader.h"
 #include "storage/DropboxWriter.h"
@@ -22,6 +22,8 @@
 #include <log/logprint.h>
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
+#include <unordered_map>
+
 namespace android {
 namespace os {
 namespace statsd {
@@ -33,6 +35,10 @@
 
 typedef std::map<std::string, HashableDimensionKey> ConditionKey;
 
+// TODO: For P, change int to int64_t.
+// TODO: Should HashableDimensionKey be marked here as const?
+typedef std::unordered_map<HashableDimensionKey, int> DimToValMap;
+
 EventMetricData parse(log_msg msg);
 
 int getTagId(log_msg msg);
@@ -41,5 +47,3 @@
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATS_UTIL_H
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index f3e6894..3b8eeaf 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -117,6 +117,8 @@
   optional int32 refractory_period_secs = 4;
 
   optional int64 trigger_if_sum_gt = 5;
+
+  optional int32 refractory_period_in_buckets = 6;
 }
 
 message EventMetric {
@@ -168,7 +170,6 @@
   repeated Alert alerts = 7;
 
   repeated EventConditionLink links = 8;
-
 }
 
 message GaugeMetric {
@@ -235,4 +236,6 @@
   repeated LogEntryMatcher log_entry_matcher = 7;
 
   repeated Condition condition = 8;
+
+  repeated Alert alerts = 9;
 }
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
new file mode 100644
index 0000000..b8150d0
--- /dev/null
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -0,0 +1,239 @@
+// 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 "src/anomaly/DiscreteAnomalyTracker.h"
+
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void AddValueToBucket(const std::vector<std::pair<string, long>>& key_value_pair_list,
+                      std::shared_ptr<DimToValMap> bucket) {
+    for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
+        (*bucket)[itr->first] += itr->second;
+    }
+}
+
+std::shared_ptr<DimToValMap> MockeBucket(
+        const std::vector<std::pair<string, long>>& key_value_pair_list) {
+    std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
+    AddValueToBucket(key_value_pair_list, bucket);
+    return bucket;
+}
+
+TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
+    Alert alert;
+    alert.set_number_of_buckets(3);
+    alert.set_refractory_period_in_buckets(3);
+    alert.set_trigger_if_sum_gt(2);
+
+    DiscreteAnomalyTracker anomaly_tracker(alert);
+
+    std::shared_ptr<DimToValMap> bucket0 = MockeBucket({{"a", 1}, {"b", 2}, {"c", 1}});
+    // Adds bucket #0
+    anomaly_tracker.addOrUpdateBucket(bucket0, 0);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 0L);
+
+    // Adds bucket #0 again. The sum does not change.
+    anomaly_tracker.addOrUpdateBucket(bucket0, 0);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 0L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 0L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, -1L);
+
+    // Adds bucket #1.
+    std::shared_ptr<DimToValMap> bucket1 = MockeBucket({{"b", 2}});
+    anomaly_tracker.addOrUpdateBucket(bucket1, 1);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 1L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    // Alarm.
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+    // Adds bucket #1 again. The sum does not change.
+    anomaly_tracker.addOrUpdateBucket(bucket1, 1);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 1L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    // Alarm.
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+    // Adds bucket #2.
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}}), 2);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 2L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 2);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    // Within refractory period.
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+    // Adds bucket #3.
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}}), 3);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 3L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 2UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 2);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+    EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+
+    // Adds bucket #3.
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 2}}), 4);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 4L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 4);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    // Within refractory period.
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}}), 5);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 5L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 4);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    // Within refractory period.
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 2L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 5L);
+}
+
+TEST(AnomalyTrackerTest, TestSparseBuckets) {
+    Alert alert;
+    alert.set_number_of_buckets(3);
+    alert.set_refractory_period_in_buckets(3);
+    alert.set_trigger_if_sum_gt(2);
+
+    DiscreteAnomalyTracker anomaly_tracker(alert);
+
+    // Add bucket #9
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}, {"b", 2}, {"c", 1}}), 9);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 9L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 0L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, -1L);
+
+    // Add bucket #16
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 4}}), 16);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 16L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 16L);
+
+    // Add bucket #18
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 1}, {"c", 1}}), 18);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 18L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 2UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 5);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    // Within refractory period.
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 16L);
+
+    // Add bucket #18 again.
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 1}, {"c", 1}}), 18);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 18L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 2UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 5);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 16L);
+
+    // Add bucket #20
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 3}, {"d", 1}}), 20);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 20L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("d")->second, 1);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 2L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 20L);
+
+    // Add bucket #25
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"d", 1}}), 25);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 25L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("d")->second, 1L);
+    EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 2L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 20L);
+
+    // Add bucket #28
+    anomaly_tracker.addOrUpdateBucket(MockeBucket({{"e", 5}}), 28);
+    EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 28L);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+    EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("e")->second, 5L);
+    EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+    anomaly_tracker.declareAndDeclareAnomaly();
+    EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 3L);
+    EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 28L);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index dfd3bbf..26efda1 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -2105,6 +2105,7 @@
                 break;
             case DENSITY_DPI_NONE:
                 parts.add("nodpi");
+                break;
             default:
                 parts.add(config.densityDpi + "dpi");
                 break;
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/core/java/android/os/ParcelFileDescriptor.aidl
index 5857aae..6bbd99e 100644
--- a/core/java/android/os/ParcelFileDescriptor.aidl
+++ b/core/java/android/os/ParcelFileDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.os;
 
-parcelable ParcelFileDescriptor;
+parcelable ParcelFileDescriptor cpp_header "android/os/parcel_file_descriptor.h";
diff --git a/core/java/android/os/ParcelUuid.aidl b/core/java/android/os/ParcelUuid.aidl
index f7e080a..6f36297 100644
--- a/core/java/android/os/ParcelUuid.aidl
+++ b/core/java/android/os/ParcelUuid.aidl
@@ -16,4 +16,4 @@
 
 package android.os;
 
-parcelable ParcelUuid;
+parcelable ParcelUuid cpp_header "android/os/parcel_uuid.h";
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index d5820b6..02c82d7 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -16,11 +16,11 @@
 package android.os;
 
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
-import android.app.ApplicationErrorReport;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -75,6 +75,8 @@
 import java.util.Arrays;
 import java.util.Deque;
 import java.util.HashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -163,12 +165,14 @@
     private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear";
 
     /**
-     * Quick feature-flag that can be used to disable the defaults provided by
-     * {@link #initThreadDefaults(ApplicationInfo)} and
-     * {@link #initVmDefaults(ApplicationInfo)}.
+     * Quick feature-flag that can be used to disable the defaults provided by {@link
+     * #initThreadDefaults(ApplicationInfo)} and {@link #initVmDefaults(ApplicationInfo)}.
      */
     private static final boolean DISABLE = false;
 
+    // Only apply VM penalties for the same violation at this interval.
+    private static final long MIN_VM_INTERVAL_MS = 1000;
+
     // Only log a duplicate stack trace to the logs every second.
     private static final long MIN_LOG_INTERVAL_MS = 1000;
 
@@ -374,6 +378,32 @@
 
     private static volatile ViolationLogger sLogger = LOGCAT_LOGGER;
 
+    private static final ThreadLocal<OnThreadViolationListener> sThreadViolationListener =
+            new ThreadLocal<>();
+    private static final ThreadLocal<Executor> sThreadViolationExecutor = new ThreadLocal<>();
+
+    /**
+     * When #{@link ThreadPolicy.Builder#penaltyListener} is enabled, the listener is called on the
+     * provided executor when a Thread violation occurs.
+     *
+     * @hide
+     */
+    public interface OnThreadViolationListener {
+        /** Called on a thread policy violation. */
+        void onThreadViolation(Violation v);
+    }
+
+    /**
+     * When #{@link VmPolicy.Builder#penaltyListener} is enabled, the listener is called on the
+     * provided executor when a VM violation occurs.
+     *
+     * @hide
+     */
+    public interface OnVmViolationListener {
+        /** Called on a VM policy violation. */
+        void onVmViolation(Violation v);
+    }
+
     /** {@hide} */
     @TestApi
     public static void setViolationLogger(ViolationLogger listener) {
@@ -403,12 +433,16 @@
      */
     public static final class ThreadPolicy {
         /** The default, lax policy which doesn't catch anything. */
-        public static final ThreadPolicy LAX = new ThreadPolicy(0);
+        public static final ThreadPolicy LAX = new ThreadPolicy(0, null, null);
 
         final int mask;
+        final OnThreadViolationListener mListener;
+        final Executor mCallbackExecutor;
 
-        private ThreadPolicy(int mask) {
+        private ThreadPolicy(int mask, OnThreadViolationListener listener, Executor executor) {
             this.mask = mask;
+            mListener = listener;
+            mCallbackExecutor = executor;
         }
 
         @Override
@@ -436,6 +470,8 @@
          */
         public static final class Builder {
             private int mMask = 0;
+            private OnThreadViolationListener mListener;
+            private Executor mExecutor;
 
             /**
              * Create a Builder that detects nothing and has no violations. (but note that {@link
@@ -601,6 +637,22 @@
                 return enable(PENALTY_DROPBOX);
             }
 
+            /**
+             * Call #{@link OnThreadViolationListener#onThreadViolation(Violation)} on specified
+             * executor every violation.
+             *
+             * @hide
+             */
+            public Builder penaltyListener(
+                    @NonNull OnThreadViolationListener listener, @NonNull Executor executor) {
+                if (executor == null) {
+                    throw new NullPointerException("executor must not be null");
+                }
+                mListener = listener;
+                mExecutor = executor;
+                return this;
+            }
+
             private Builder enable(int bit) {
                 mMask |= bit;
                 return this;
@@ -620,7 +672,8 @@
             public ThreadPolicy build() {
                 // If there are detection bits set but no violation bits
                 // set, enable simple logging.
-                if (mMask != 0
+                if (mListener == null
+                        && mMask != 0
                         && (mMask
                                         & (PENALTY_DEATH
                                                 | PENALTY_LOG
@@ -629,7 +682,7 @@
                                 == 0) {
                     penaltyLog();
                 }
-                return new ThreadPolicy(mMask);
+                return new ThreadPolicy(mMask, mListener, mExecutor);
             }
         }
     }
@@ -641,19 +694,27 @@
      */
     public static final class VmPolicy {
         /** The default, lax policy which doesn't catch anything. */
-        public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);
+        public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP, null, null);
 
         final int mask;
+        final OnVmViolationListener mListener;
+        final Executor mCallbackExecutor;
 
         // Map from class to max number of allowed instances in memory.
         final HashMap<Class, Integer> classInstanceLimit;
 
-        private VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit) {
+        private VmPolicy(
+                int mask,
+                HashMap<Class, Integer> classInstanceLimit,
+                OnVmViolationListener listener,
+                Executor executor) {
             if (classInstanceLimit == null) {
                 throw new NullPointerException("classInstanceLimit == null");
             }
             this.mask = mask;
             this.classInstanceLimit = classInstanceLimit;
+            mListener = listener;
+            mCallbackExecutor = executor;
         }
 
         @Override
@@ -681,6 +742,8 @@
          */
         public static final class Builder {
             private int mMask;
+            private OnVmViolationListener mListener;
+            private Executor mExecutor;
 
             private HashMap<Class, Integer> mClassInstanceLimit; // null until needed
             private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write
@@ -694,6 +757,8 @@
                 mMask = base.mask;
                 mClassInstanceLimitNeedCow = true;
                 mClassInstanceLimit = base.classInstanceLimit;
+                mListener = base.mListener;
+                mExecutor = base.mCallbackExecutor;
             }
 
             /**
@@ -910,6 +975,21 @@
                 return enable(PENALTY_DROPBOX);
             }
 
+            /**
+             * Call #{@link OnVmViolationListener#onVmViolation(Violation)} on every violation.
+             *
+             * @hide
+             */
+            public Builder penaltyListener(
+                    @NonNull OnVmViolationListener listener, @NonNull Executor executor) {
+                if (executor == null) {
+                    throw new NullPointerException("executor must not be null");
+                }
+                mListener = listener;
+                mExecutor = executor;
+                return this;
+            }
+
             private Builder enable(int bit) {
                 mMask |= bit;
                 return this;
@@ -929,7 +1009,8 @@
             public VmPolicy build() {
                 // If there are detection bits set but no violation bits
                 // set, enable simple logging.
-                if (mMask != 0
+                if (mListener == null
+                        && mMask != 0
                         && (mMask
                                         & (PENALTY_DEATH
                                                 | PENALTY_LOG
@@ -940,7 +1021,9 @@
                 }
                 return new VmPolicy(
                         mMask,
-                        mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
+                        mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP,
+                        mListener,
+                        mExecutor);
             }
         }
     }
@@ -973,6 +1056,8 @@
      */
     public static void setThreadPolicy(final ThreadPolicy policy) {
         setThreadPolicyMask(policy.mask);
+        sThreadViolationListener.set(policy.mListener);
+        sThreadViolationExecutor.set(policy.mCallbackExecutor);
     }
 
     /** @hide */
@@ -1029,7 +1114,10 @@
         // introduce VmPolicy cleanly) but this isn't particularly
         // optimal for users who might call this method often.  This
         // should be in a thread-local and not allocate on each call.
-        return new ThreadPolicy(getThreadPolicyMask());
+        return new ThreadPolicy(
+                getThreadPolicyMask(),
+                sThreadViolationListener.get(),
+                sThreadViolationExecutor.get());
     }
 
     /**
@@ -1042,7 +1130,10 @@
      *     end of a block
      */
     public static ThreadPolicy allowThreadDiskWrites() {
-        return new ThreadPolicy(allowThreadDiskWritesMask());
+        return new ThreadPolicy(
+                allowThreadDiskWritesMask(),
+                sThreadViolationListener.get(),
+                sThreadViolationExecutor.get());
     }
 
     /** @hide */
@@ -1063,7 +1154,10 @@
      * @return the old policy, to be passed to setThreadPolicy to restore the policy.
      */
     public static ThreadPolicy allowThreadDiskReads() {
-        return new ThreadPolicy(allowThreadDiskReadsMask());
+        return new ThreadPolicy(
+                allowThreadDiskReadsMask(),
+                sThreadViolationListener.get(),
+                sThreadViolationExecutor.get());
     }
 
     /** @hide */
@@ -1076,16 +1170,27 @@
         return oldPolicyMask;
     }
 
+    private static ThreadPolicy allowThreadViolations() {
+        ThreadPolicy oldPolicy = getThreadPolicy();
+        setThreadPolicyMask(0);
+        return oldPolicy;
+    }
+
+    private static VmPolicy allowVmViolations() {
+        VmPolicy oldPolicy = getVmPolicy();
+        sVmPolicy = VmPolicy.LAX;
+        return oldPolicy;
+    }
+
     /**
-     * Determine if the given app is "bundled" as part of the system image.
-     * These bundled apps are developed in lock-step with the OS, and they
-     * aren't updated outside of an OTA, so we want to chase any
-     * {@link StrictMode} regressions by enabling detection when running on
-     * {@link Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds.
-     * <p>
-     * Unbundled apps included in the system image are expected to detect and
-     * triage their own {@link StrictMode} issues separate from the OS release
-     * process, which is why we don't enable them here.
+     * Determine if the given app is "bundled" as part of the system image. These bundled apps are
+     * developed in lock-step with the OS, and they aren't updated outside of an OTA, so we want to
+     * chase any {@link StrictMode} regressions by enabling detection when running on {@link
+     * Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds.
+     *
+     * <p>Unbundled apps included in the system image are expected to detect and triage their own
+     * {@link StrictMode} issues separate from the OS release process, which is why we don't enable
+     * them here.
      *
      * @hide
      */
@@ -1122,8 +1227,8 @@
      */
     public static void initThreadDefaults(ApplicationInfo ai) {
         final ThreadPolicy.Builder builder = new ThreadPolicy.Builder();
-        final int targetSdkVersion = (ai != null) ? ai.targetSdkVersion
-                : Build.VERSION_CODES.CUR_DEVELOPMENT;
+        final int targetSdkVersion =
+                (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT;
 
         // Starting in HC, we don't allow network usage on the main thread
         if (targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
@@ -1162,8 +1267,8 @@
      */
     public static void initVmDefaults(ApplicationInfo ai) {
         final VmPolicy.Builder builder = new VmPolicy.Builder();
-        final int targetSdkVersion = (ai != null) ? ai.targetSdkVersion
-                : Build.VERSION_CODES.CUR_DEVELOPMENT;
+        final int targetSdkVersion =
+                (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT;
 
         // Starting in N, we don't allow file:// Uri exposure
         if (targetSdkVersion >= Build.VERSION_CODES.N) {
@@ -1204,7 +1309,9 @@
                         sVmPolicy.mask
                                 | DETECT_VM_FILE_URI_EXPOSURE
                                 | PENALTY_DEATH_ON_FILE_URI_EXPOSURE,
-                        sVmPolicy.classInstanceLimit);
+                        sVmPolicy.classInstanceLimit,
+                        sVmPolicy.mListener,
+                        sVmPolicy.mCallbackExecutor);
     }
 
     /**
@@ -1219,7 +1326,9 @@
                         sVmPolicy.mask
                                 & ~(DETECT_VM_FILE_URI_EXPOSURE
                                         | PENALTY_DEATH_ON_FILE_URI_EXPOSURE),
-                        sVmPolicy.classInstanceLimit);
+                        sVmPolicy.classInstanceLimit,
+                        sVmPolicy.mListener,
+                        sVmPolicy.mCallbackExecutor);
     }
 
     /**
@@ -1409,7 +1518,7 @@
             //       go into this immediate mode?
             if (looper == null || (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
                 info.durationMillis = -1; // unknown (redundant, already set)
-                handleViolation(info);
+                onThreadPolicyViolation(info);
                 return;
             }
 
@@ -1447,30 +1556,28 @@
             THREAD_HANDLER
                     .get()
                     .postAtFrontOfQueue(
-                            new Runnable() {
-                                public void run() {
-                                    long loopFinishTime = SystemClock.uptimeMillis();
+                            () -> {
+                                long loopFinishTime = SystemClock.uptimeMillis();
 
-                                    // Note: we do this early, before handling the
-                                    // violation below, as handling the violation
-                                    // may include PENALTY_DEATH and we don't want
-                                    // to keep the red border on.
-                                    if (windowManager != null) {
-                                        try {
-                                            windowManager.showStrictModeViolation(false);
-                                        } catch (RemoteException unused) {
-                                        }
+                                // Note: we do this early, before handling the
+                                // violation below, as handling the violation
+                                // may include PENALTY_DEATH and we don't want
+                                // to keep the red border on.
+                                if (windowManager != null) {
+                                    try {
+                                        windowManager.showStrictModeViolation(false);
+                                    } catch (RemoteException unused) {
                                     }
-
-                                    for (int n = 0; n < records.size(); ++n) {
-                                        ViolationInfo v = records.get(n);
-                                        v.violationNumThisLoop = n + 1;
-                                        v.durationMillis =
-                                                (int) (loopFinishTime - v.violationUptimeMillis);
-                                        handleViolation(v);
-                                    }
-                                    records.clear();
                                 }
+
+                                for (int n = 0; n < records.size(); ++n) {
+                                    ViolationInfo v = records.get(n);
+                                    v.violationNumThisLoop = n + 1;
+                                    v.durationMillis =
+                                            (int) (loopFinishTime - v.violationUptimeMillis);
+                                    onThreadPolicyViolation(v);
+                                }
+                                records.clear();
                             });
         }
 
@@ -1479,13 +1586,13 @@
         // violation fired and now (after the violating code ran) due
         // to people who push/pop temporary policy in regions of code,
         // hence the policy being passed around.
-        void handleViolation(final ViolationInfo info) {
-            if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.mPolicy);
+        void onThreadPolicyViolation(final ViolationInfo info) {
+            if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; policy=" + info.mPolicy);
 
             if (info.penaltyEnabled(PENALTY_GATHER)) {
                 ArrayList<ViolationInfo> violations = gatheredViolations.get();
                 if (violations == null) {
-                    violations = new ArrayList<ViolationInfo>(1);
+                    violations = new ArrayList<>(1);
                     gatheredViolations.set(violations);
                 }
                 for (ViolationInfo previous : violations) {
@@ -1519,6 +1626,8 @@
                 sLogger.log(info);
             }
 
+            final Violation violation = info.mViolation;
+
             // The violationMaskSubset, passed to ActivityManager, is a
             // subset of the original StrictMode policy bitmask, with
             // only the bit violated and penalty bits to be executed
@@ -1552,15 +1661,32 @@
             }
 
             if ((info.getPolicyMask() & PENALTY_DEATH) != 0) {
-                executeDeathPenalty(info);
+                throw new RuntimeException("StrictMode ThreadPolicy violation", violation);
+            }
+
+            // penaltyDeath will cause penaltyCallback to no-op since we cannot guarantee the
+            // executor finishes before crashing.
+            final OnThreadViolationListener listener = sThreadViolationListener.get();
+            final Executor executor = sThreadViolationExecutor.get();
+            if (listener != null && executor != null) {
+                try {
+                    executor.execute(
+                            () -> {
+                                // Lift violated policy to prevent infinite recursion.
+                                ThreadPolicy oldPolicy = allowThreadViolations();
+                                try {
+                                    listener.onThreadViolation(violation);
+                                } finally {
+                                    setThreadPolicy(oldPolicy);
+                                }
+                            });
+                } catch (RejectedExecutionException e) {
+                    Log.e(TAG, "ThreadPolicy penaltyCallback failed", e);
+                }
             }
         }
     }
 
-    private static void executeDeathPenalty(ViolationInfo info) {
-        throw new RuntimeException("StrictMode death penalty", info.mViolation);
-    }
-
     /**
      * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any
      * violations but not showing a dialog, not loggging, and not killing the process. In these
@@ -1736,9 +1862,8 @@
      * #setThreadPolicy}.
      */
     public static void enableDefaults() {
-        StrictMode.setThreadPolicy(
-                new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
-        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
+        setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
+        setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
     }
 
     /** @hide */
@@ -1857,11 +1982,11 @@
     }
 
     /** @hide */
-    public static void onVmPolicyViolation(Violation originStack, boolean forceDeath) {
+    public static void onVmPolicyViolation(Violation violation, boolean forceDeath) {
         final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0;
         final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath;
         final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0;
-        final ViolationInfo info = new ViolationInfo(originStack, sVmPolicy.mask);
+        final ViolationInfo info = new ViolationInfo(violation, sVmPolicy.mask);
 
         // Erase stuff not relevant for process-wide violations
         info.numAnimationsRunning = 0;
@@ -1870,37 +1995,37 @@
 
         final Integer fingerprint = info.hashCode();
         final long now = SystemClock.uptimeMillis();
-        long lastViolationTime = 0;
+        long lastViolationTime;
         long timeSinceLastViolationMillis = Long.MAX_VALUE;
         synchronized (sLastVmViolationTime) {
             if (sLastVmViolationTime.containsKey(fingerprint)) {
                 lastViolationTime = sLastVmViolationTime.get(fingerprint);
                 timeSinceLastViolationMillis = now - lastViolationTime;
             }
-            if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+            if (timeSinceLastViolationMillis > MIN_VM_INTERVAL_MS) {
                 sLastVmViolationTime.put(fingerprint, now);
             }
         }
-
-        if (penaltyLog && sLogger != null) {
-            sLogger.log(info);
+        if (timeSinceLastViolationMillis <= MIN_VM_INTERVAL_MS) {
+            // Rate limit all penalties.
+            return;
         }
-        if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+
+        if (penaltyLog && sLogger != null && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
             sLogger.log(info);
         }
 
         int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicy.mask);
 
-        if (penaltyDropbox && !penaltyDeath) {
-            // Common case for userdebug/eng builds.  If no death and
-            // just dropboxing, we can do the ActivityManager call
-            // asynchronously.
-            dropboxViolationAsync(violationMaskSubset, info);
-            return;
-        }
-
-        if (penaltyDropbox && lastViolationTime == 0) {
-            handleApplicationStrictModeViolation(violationMaskSubset, info);
+        if (penaltyDropbox) {
+            if (penaltyDeath) {
+                handleApplicationStrictModeViolation(violationMaskSubset, info);
+            } else {
+                // Common case for userdebug/eng builds.  If no death and
+                // just dropboxing, we can do the ActivityManager call
+                // asynchronously.
+                dropboxViolationAsync(violationMaskSubset, info);
+            }
         }
 
         if (penaltyDeath) {
@@ -1908,6 +2033,26 @@
             Process.killProcess(Process.myPid());
             System.exit(10);
         }
+
+        // If penaltyDeath, we can't guarantee this callback finishes before the process dies for
+        // all executors. penaltyDeath supersedes penaltyCallback.
+        if (sVmPolicy.mListener != null && sVmPolicy.mCallbackExecutor != null) {
+            final OnVmViolationListener listener = sVmPolicy.mListener;
+            try {
+                sVmPolicy.mCallbackExecutor.execute(
+                        () -> {
+                            // Lift violated policy to prevent infinite recursion.
+                            VmPolicy oldPolicy = allowVmViolations();
+                            try {
+                                listener.onVmViolation(violation);
+                            } finally {
+                                setVmPolicy(oldPolicy);
+                            }
+                        });
+            } catch (RejectedExecutionException e) {
+                Log.e(TAG, "VmPolicy penaltyCallback failed", e);
+            }
+        }
     }
 
     /** Called from Parcel.writeNoException() */
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 0c2e4b7..cd233b8 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -97,6 +97,10 @@
     public static final String ACTION_RESOLVE_NO_PRIVILEGES =
             "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
 
+    /** Ask the user to input carrier confirmation code. */
+    public static final String ACTION_RESOLVE_CONFIRMATION_CODE =
+            "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
+
     /** Intent extra set for resolution requests containing the package name of the calling app. */
     public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
             "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
@@ -105,6 +109,8 @@
     public static final int RESULT_OK = 0;
     /** Result code indicating that an active SIM must be deactivated to perform the operation. */
     public static final int RESULT_MUST_DEACTIVATE_SIM = -1;
+    /** Result code indicating that the user must input a carrier confirmation code. */
+    public static final int RESULT_NEED_CONFIRMATION_CODE = -2;
     // New predefined codes should have negative values.
 
     /** Start of implementation-specific error results. */
@@ -119,10 +125,13 @@
         RESOLUTION_ACTIONS = new ArraySet<>();
         RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM);
         RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES);
+        RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE);
     }
 
     /** Boolean extra for resolution actions indicating whether the user granted consent. */
     public static final String RESOLUTION_EXTRA_CONSENT = "consent";
+    /** String extra for resolution actions indicating the carrier confirmation code. */
+    public static final String RESOLUTION_EXTRA_CONFIRMATION_CODE = "confirmation_code";
 
     private final IEuiccService.Stub mStubWrapper;
 
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 3e992ec..080482b 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
+import android.app.ActivityManager;
 import android.app.INotificationManager;
 import android.app.Service;
 import android.content.ComponentName;
@@ -56,6 +57,8 @@
  *           &lt;/meta-data>
  * &lt;/service></pre>
  *
+ *  <p> Condition providers cannot be bound by the system on
+ * {@link ActivityManager#isLowRamDevice() low ram} devices</p>
  */
 public abstract class ConditionProviderService extends Service {
     private final String TAG = ConditionProviderService.class.getSimpleName()
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 08d3118..dac663e7 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -21,6 +21,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.ActivityManager;
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.Notification.Builder;
@@ -82,6 +83,8 @@
  * method is the <i>only</i> one that is safe to call before {@link #onListenerConnected()}
  * or after {@link #onListenerDisconnected()}.
  * </p>
+ * <p> Notification listeners cannot get notification access or be bound by the system on
+ * {@link ActivityManager#isLowRamDevice() low ram} devices</p>
  */
 public abstract class NotificationListenerService extends Service {
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c043dca..e12c0b0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14218,6 +14218,7 @@
      */
     public void setScaleX(float scaleX) {
         if (scaleX != getScaleX()) {
+            requireIsFinite(scaleX, "scaleX");
             invalidateViewProperty(true, false);
             mRenderNode.setScaleX(scaleX);
             invalidateViewProperty(false, true);
@@ -14254,6 +14255,7 @@
      */
     public void setScaleY(float scaleY) {
         if (scaleY != getScaleY()) {
+            requireIsFinite(scaleY, "scaleY");
             invalidateViewProperty(true, false);
             mRenderNode.setScaleY(scaleY);
             invalidateViewProperty(false, true);
@@ -14803,6 +14805,15 @@
         }
     }
 
+    private static void requireIsFinite(float transform, String propertyName) {
+        if (Float.isNaN(transform)) {
+            throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN");
+        }
+        if (Float.isInfinite(transform)) {
+            throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity");
+        }
+    }
+
     /**
      * The visual x position of this view, in pixels. This is equivalent to the
      * {@link #setTranslationX(float) translationX} property plus the current
@@ -14889,6 +14900,7 @@
      */
     public void setElevation(float elevation) {
         if (elevation != getElevation()) {
+            requireIsFinite(elevation, "elevation");
             invalidateViewProperty(true, false);
             mRenderNode.setElevation(elevation);
             invalidateViewProperty(false, true);
@@ -14981,6 +14993,7 @@
      */
     public void setTranslationZ(float translationZ) {
         if (translationZ != getTranslationZ()) {
+            requireIsFinite(translationZ, "translationZ");
             invalidateViewProperty(true, false);
             mRenderNode.setTranslationZ(translationZ);
             invalidateViewProperty(false, true);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f7e0b46..161a0c2 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -258,6 +258,11 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.settings.intelligence">
+        <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.sharedstoragebackup">
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
     </privapp-permissions>
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 5484cf0..251b2e7 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -98,6 +98,9 @@
             enabled: true,
         },
     },
+    sanitize: {
+        blacklist: "libandroidfw_blacklist.txt",
+    },
 }
 
 common_test_libs = [
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blacklist.txt
new file mode 100644
index 0000000..dd17e4d
--- /dev/null
+++ b/libs/androidfw/libandroidfw_blacklist.txt
@@ -0,0 +1 @@
+src:*/ResourceTypes.cpp
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index b7f1fb2..530e82e 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -31,11 +31,7 @@
 namespace uirenderer {
 
 Extensions::Extensions() {
-    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        // Extensions class is used only by OpenGL and SkiaGL pipelines
-        // The code below will crash for SkiaVulkan, because OpenGL is not initialized
-        // TODO: instantiate Extensions class only for OpenGL pipeline
-        // TODO: remove the only usage of Extensions by SkiaGL in SkiaOpenGLReadback::copyImageInto
+    if (Properties::isSkiaEnabled()) {
         return;
     }
     const char* version = (const char*)glGetString(GL_VERSION);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 6db57ca..288d039 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -66,14 +66,8 @@
             break;
     }
 
-    /* Ideally, we would call grContext->caps()->isConfigRenderable(...). We
-     * currently can't do that since some devices (i.e. SwiftShader) supports all
-     * the appropriate half float extensions, but only allow the buffer to be read
-     * back as full floats.  We can relax this extension if Skia implements support
-     * for reading back float buffers (skbug.com/6945).
-     */
     if (pixelConfig == kRGBA_half_GrPixelConfig &&
-        !DeviceInfo::get()->extensions().hasRenderableFloatTextures()) {
+            !grContext->caps()->isConfigRenderable(kRGBA_half_GrPixelConfig, false)) {
         ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
         return CopyResult::DestinationInvalid;
     }
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index fa50943..478297f 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -80,6 +80,9 @@
     // The minimum allowed max packet size is 255 according to the OBEX specification
     public static final int LOWER_LIMIT_MAX_PACKET_SIZE = 255;
 
+    // The length of OBEX Byte Sequency Header Id according to the OBEX specification
+    public static final int OBEX_BYTE_SEQ_HEADER_LEN = 0x03;
+
     /**
      * Temporary workaround to be able to push files to Windows 7.
      * TODO: Should be removed as soon as Microsoft updates their driver.
@@ -205,12 +208,15 @@
                     case 0x40:
                         boolean trimTail = true;
                         index++;
-                        length = 0xFF & headerArray[index];
-                        length = length << 8;
-                        index++;
-                        length += 0xFF & headerArray[index];
-                        length -= 3;
-                        index++;
+                        length = ((0xFF & headerArray[index]) << 8) +
+                                 (0xFF & headerArray[index + 1]);
+                        index += 2;
+                        if (length <= OBEX_BYTE_SEQ_HEADER_LEN) {
+                            Log.e(TAG, "Remote sent an OBEX packet with " +
+                                  "incorrect header length = " + length);
+                            break;
+                        }
+                        length -= OBEX_BYTE_SEQ_HEADER_LEN;
                         value = new byte[length];
                         System.arraycopy(headerArray, index, value, 0, length);
                         if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d3dcf5a..8e93d19 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4680,6 +4680,16 @@
     // OS: P
     DIALOG_FIRMWARE_VERSION = 1247;
 
+    // OPEN: Settings > Network & internet > Menu > Private DNS
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_PRIVATE_DNS = 1248;
+
+    // ACTION: A private dns mode been selected by user
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_PRIVATE_DNS_MODE = 1249;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e609bd7..831c9cb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1356,31 +1356,6 @@
         }
     }
 
-    public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
-        if (!checkNotifyPermission("notifyOemHookRawEventForSubscriber")) {
-            return;
-        }
-
-        synchronized (mRecords) {
-            for (Record r : mRecords) {
-                if (VDBG) {
-                    log("notifyOemHookRawEventForSubscriber:  r=" + r + " subId=" + subId);
-                }
-                if ((r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT)) &&
-                        ((r.subId == subId) ||
-                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) {
-                    try {
-                        r.callback.onOemHookRawEvent(rawData);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -1673,11 +1648,6 @@
                     android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
 
         }
-
-        if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
-        }
     }
 
     private void handleRemoveListLocked() {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index caf85b0..7837940 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -8084,28 +8084,22 @@
     private int updateLightNavigationBarLw(int vis, WindowState opaque,
             WindowState opaqueOrDimming) {
         final WindowState imeWin = mWindowManagerFuncs.getInputMethodWindowLw();
-        final boolean isImeShownWithBottomNavBar =
-                imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM;
-        if (isImeShownWithBottomNavBar) {
-            final int winFlags = PolicyControl.getWindowFlags(imeWin, null);
-            if ((winFlags & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
-                // If the IME window is visible and explicitly requesting custom nav bar background
-                // rendering, respect its light flag.
-                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-                vis |= PolicyControl.getSystemUiVisibility(imeWin, null)
-                        & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-                return vis;
-            }
+
+        final WindowState navColorWin;
+        if (imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+            navColorWin = imeWin;
+        } else {
+            navColorWin = opaqueOrDimming;
         }
 
-        if (opaqueOrDimming != null) {
-            if (opaqueOrDimming == opaque) {
-                // If the top fullscreen-or-dimming window is also the top fullscreen window,
-                // respect its light flag.
+        if (navColorWin != null) {
+            if (navColorWin == opaque) {
+                // If the top fullscreen-or-dimming window is also the top fullscreen, respect
+                // its light flag.
                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-                vis |= PolicyControl.getSystemUiVisibility(opaqueOrDimming, null)
+                vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
                         & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-            } else if (opaqueOrDimming.isDimming() || isImeShownWithBottomNavBar) {
+            } else if (navColorWin.isDimming() || navColorWin == imeWin) {
                 // Otherwise if it's dimming or it's the IME window, clear the light flag.
                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
             }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 061e55a..0030ab6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1650,6 +1650,26 @@
     public static final String KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL =
             "identify_high_definition_calls_in_call_log_bool";
 
+    /**
+     * Flag specifying whether to use the {@link ServiceState} roaming status, which can be
+     * affected by other carrier configs (e.g.
+     * {@link #KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY}), when setting the SPN display.
+     * <p>
+     * If {@code true}, the SPN display uses {@link ServiceState#getRoaming}.
+     * If {@code false} the SPN display checks if the current MCC/MNC is different from the
+     * SIM card's MCC/MNC.
+     *
+     * @see KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_NON_ROAMING_OPERATOR_STRING_ARRAY
+     * @see KEY_ROAMING_OPERATOR_STRING_ARRAY
+     * @see KEY_FORCE_HOME_NETWORK_BOOL
+     *
+     * @hide
+     */
+    public static final String KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL =
+            "spn_display_rule_use_roaming_from_service_state_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1928,6 +1948,7 @@
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
+        sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index afff6d5..9ccfa94 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -204,16 +204,6 @@
     public static final int LISTEN_VOLTE_STATE                              = 0x00004000;
 
     /**
-     * Listen for OEM hook raw event
-     *
-     * @see #onOemHookRawEvent
-     * @hide
-     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
-     */
-    @Deprecated
-    public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;
-
-    /**
      * Listen for carrier network changes indicated by a carrier app.
      *
      * @see #onCarrierNetworkRequest
@@ -359,9 +349,6 @@
                     case LISTEN_DATA_ACTIVATION_STATE:
                         PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
                         break;
-                    case LISTEN_OEM_HOOK_RAW_EVENT:
-                        PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
-                        break;
                     case LISTEN_CARRIER_NETWORK_CHANGE:
                         PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj);
                         break;
@@ -556,16 +543,6 @@
     }
 
     /**
-     * Callback invoked when OEM hook raw event is received. Requires
-     * the READ_PRIVILEGED_PHONE_STATE permission.
-     * @param rawData is the byte array of the OEM hook raw data.
-     * @hide
-     */
-    public void onOemHookRawEvent(byte[] rawData) {
-        // default implementation empty
-    }
-
-    /**
      * Callback invoked when telephony has received notice from a carrier
      * app that a network action that could result in connectivity loss
      * has been requested by an app using
@@ -677,10 +654,6 @@
             send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
         }
 
-        public void onOemHookRawEvent(byte[] rawData) {
-            send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
-        }
-
         public void onCarrierNetworkChange(boolean active) {
             send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 42c3de5..4ffb3c3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5709,29 +5709,6 @@
         return retVal;
     }
 
-    /**
-     * Returns the result and response from RIL for oem request
-     *
-     * @param oemReq the data is sent to ril.
-     * @param oemResp the respose data from RIL.
-     * @return negative value request was not handled or get error
-     *         0 request was handled succesfully, but no response data
-     *         positive value success, data length of response
-     * @hide
-     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
-     */
-    @Deprecated
-    public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.invokeOemRilRequestRaw(oemReq, oemResp);
-        } catch (RemoteException ex) {
-        } catch (NullPointerException ex) {
-        }
-        return -1;
-    }
-
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index b5484e34..01041c8 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -53,6 +53,8 @@
     @Nullable
     public final String encodedActivationCode;
 
+    @Nullable private String confirmationCode;
+
     // see getCarrierName and setCarrierName
     @Nullable
     private String carrierName;
@@ -66,6 +68,7 @@
 
     private DownloadableSubscription(Parcel in) {
         encodedActivationCode = in.readString();
+        confirmationCode = in.readString();
         carrierName = in.readString();
         accessRules = in.createTypedArray(UiccAccessRule.CREATOR);
     }
@@ -83,6 +86,21 @@
     }
 
     /**
+     * Sets the confirmation code.
+     */
+    public void setConfirmationCode(String confirmationCode) {
+        this.confirmationCode = confirmationCode;
+    }
+
+    /**
+     * Returns the confirmation code.
+     */
+    @Nullable
+    public String getConfirmationCode() {
+        return confirmationCode;
+    }
+
+    /**
      * Set the user-visible carrier name.
      * @hide
      *
@@ -134,6 +152,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(encodedActivationCode);
+        dest.writeString(confirmationCode);
         dest.writeString(carrierName);
         dest.writeTypedArray(accessRules, flags);
     }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index e9c5461..ac16139 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -45,7 +45,6 @@
     void onVoLteServiceStateChanged(in VoLteServiceState lteState);
     void onVoiceActivationStateChanged(int activationState);
     void onDataActivationStateChanged(int activationState);
-    void onOemHookRawEvent(in byte[] rawData);
     void onCarrierNetworkChange(in boolean active);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2ac11b5..3cc9bde 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1000,17 +1000,6 @@
             in List<String> cdmaNonRoamingList);
 
     /**
-     * Returns the result and response from RIL for oem request
-     *
-     * @param oemReq the data is sent to ril.
-     * @param oemResp the respose data from RIL.
-     * @return negative value request was not handled or get error
-     *         0 request was handled succesfully, but no response data
-     *         positive value success, data length of response
-     */
-    int invokeOemRilRequestRaw(in byte[] oemReq, out byte[] oemResp);
-
-    /**
      * Check if any mobile Radios need to be shutdown.
      *
      * @return true is any mobile radio needs to be shutdown
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2c2206c..75d8f3f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -67,7 +67,6 @@
     void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
     void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
             int activationState, int activationType);
-    void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
     void notifySubscriptionInfoChanged();
     void notifyCarrierNetworkChange(in boolean active);
 }