Allow statsd_config be able to set destination value AUTO/EXPLICIT.

Also move incidentd integration to its own files.
clang-format -style=file -i src/anomaly/* and src/subscribers/Incidentd*

Bug: 70239380
Test: manual
Change-Id: I7bfe14d704d9e86d925365a8a21ffed726723e60
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 1d5ab59..654036e 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -46,6 +46,7 @@
 checkIncidentPermissions(const IncidentReportArgs& args)
 {
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    pid_t callingPid = IPCThreadState::self()->getCallingPid();
     if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
         // root doesn't have permission.DUMP if don't do this!
         return Status::ok();
@@ -54,13 +55,13 @@
     // checking calling permission.
     if (!checkCallingPermission(DUMP_PERMISSION)) {
         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
-                IPCThreadState::self()->getCallingPid(), callingUid);
+                callingPid, callingUid);
         return Status::fromExceptionCode(Status::EX_SECURITY,
                 "Calling process does not have permission: android.permission.DUMP");
     }
     if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
-                IPCThreadState::self()->getCallingPid(), callingUid);
+                callingPid, callingUid);
         return Status::fromExceptionCode(Status::EX_SECURITY,
                 "Calling process does not have permission: android.permission.USAGE_STATS");
     }
@@ -68,13 +69,17 @@
     // checking calling request uid permission.
     switch (args.dest()) {
         case DEST_LOCAL:
-            if (callingUid != AID_SHELL || callingUid != AID_ROOT) {
+            if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
+                ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
+                        callingPid, callingUid);
                 return Status::fromExceptionCode(Status::EX_SECURITY,
                     "Calling process does not have permission to get local data.");
             }
         case DEST_EXPLICIT:
-            if (callingUid != AID_SHELL || callingUid != AID_ROOT ||
-                callingUid != AID_STATSD || callingUid != AID_SYSTEM) {
+            if (callingUid != AID_SHELL && callingUid != AID_ROOT &&
+                callingUid != AID_STATSD && callingUid != AID_SYSTEM) {
+                ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
+                        callingPid, callingUid);
                 return Status::fromExceptionCode(Status::EX_SECURITY,
                     "Calling process does not have permission to get explicit data.");
             }
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index b0019ac..b46c5c1 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -65,6 +65,7 @@
     src/storage/StorageManager.cpp \
     src/StatsLogProcessor.cpp \
     src/StatsService.cpp \
+    src/subscriber/IncidentdReporter.cpp \
     src/subscriber/SubscriberReporter.cpp \
     src/HashableDimensionKey.cpp \
     src/guardrail/MemoryLeakTrackUtil.cpp \
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index c84a5b4..7c5e45e 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -19,13 +19,11 @@
 
 #include "AnomalyTracker.h"
 #include "external/Perfetto.h"
-#include "guardrail/StatsdStats.h"
 #include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+#include "guardrail/StatsdStats.h"
+#include "subscriber/IncidentdReporter.h"
 #include "subscriber/SubscriberReporter.h"
 
-#include <android/os/IIncidentManager.h>
-#include <android/os/IncidentReportArgs.h>
-#include <binder/IServiceManager.h>
 #include <statslog.h>
 #include <time.h>
 
@@ -35,20 +33,17 @@
 
 // TODO: Get rid of bucketNumbers, and return to the original circular array method.
 AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
-    : mAlert(alert),
-      mConfigKey(configKey),
-      mNumOfPastBuckets(mAlert.num_buckets() - 1) {
+    : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
     VLOG("AnomalyTracker() called");
     if (mAlert.num_buckets() <= 0) {
-        ALOGE("Cannot create AnomalyTracker with %lld buckets",
-              (long long)mAlert.num_buckets());
+        ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets());
         return;
     }
     if (!mAlert.has_trigger_if_sum_gt()) {
         ALOGE("Cannot create AnomalyTracker without threshold");
         return;
     }
-    resetStorage(); // initialization
+    resetStorage();  // initialization
 }
 
 AnomalyTracker::~AnomalyTracker() {
@@ -171,8 +166,8 @@
         // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
         addPastBucket(key, 0, currentBucketNum - 1);
     }
-    return mAlert.has_trigger_if_sum_gt()
-            && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
+    return mAlert.has_trigger_if_sum_gt() &&
+           getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
 }
 
 void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key) {
@@ -188,7 +183,7 @@
 
     if (!mSubscriptions.empty()) {
         if (mAlert.has_id()) {
-            ALOGI("An anomaly (%llu) has occurred! Informing subscribers.",mAlert.id());
+            ALOGI("An anomaly (%llu) has occurred! Informing subscribers.", mAlert.id());
             informSubscribers(key);
         } else {
             ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
@@ -233,44 +228,26 @@
         return;
     }
 
-    std::set<int> incidentdSections;
-
     for (const Subscription& subscription : mSubscriptions) {
         switch (subscription.subscriber_information_case()) {
             case Subscription::SubscriberInformationCase::kIncidentdDetails:
-                for (int i = 0; i < subscription.incidentd_details().section_size(); i++) {
-                    incidentdSections.insert(subscription.incidentd_details().section(i));
+                if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) {
+                    ALOGW("Failed to generate incident report.");
                 }
                 break;
             case Subscription::SubscriberInformationCase::kPerfettoDetails:
-                CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details());
+                if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
+                    ALOGW("Failed to generate prefetto traces.");
+                }
                 break;
             case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
-                SubscriberReporter::getInstance()
-                        .alertBroadcastSubscriber(mConfigKey, subscription, key);
+                SubscriberReporter::getInstance().alertBroadcastSubscriber(mConfigKey, subscription,
+                                                                           key);
                 break;
             default:
                 break;
         }
     }
-    if (!incidentdSections.empty()) {
-        sp<IIncidentManager> service = interface_cast<IIncidentManager>(
-                defaultServiceManager()->getService(android::String16("incident")));
-        if (service != NULL) {
-            IncidentReportArgs incidentReport;
-            for (const auto section : incidentdSections) {
-                incidentReport.addSection(section);
-            }
-            android::os::IncidentHeaderProto header;
-            header.set_alert_id(mAlert.id());
-            header.mutable_config_key()->set_uid(mConfigKey.GetUid());
-            header.mutable_config_key()->set_id(mConfigKey.GetId());
-            incidentReport.addHeader(header);
-            service->reportIncident(incidentReport);
-        } else {
-            ALOGW("Couldn't get the incident service.");
-        }
-    }
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index f01a97f..3be959d 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -16,22 +16,24 @@
 
 #pragma once
 
+#include <memory>  // unique_ptr
+
+#include <stdlib.h>
+
 #include <gtest/gtest_prod.h>
+#include <utils/RefBase.h>
+
 #include "AnomalyMonitor.h"
 #include "config/ConfigKey.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>
-#include <utils/RefBase.h>
-
 namespace android {
 namespace os {
 namespace statsd {
 
-using std::unordered_map;
 using std::shared_ptr;
+using std::unordered_map;
 
 // Does NOT allow negative values.
 class AnomalyTracker : public virtual RefBase {
@@ -60,12 +62,11 @@
 
     // Detects the alert and informs the incidentd when applicable.
     void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
-                                 const MetricDimensionKey& key,
-                                 const int64_t& currentBucketValue);
+                                 const MetricDimensionKey& key, const int64_t& currentBucketValue);
 
     // Init the AnomalyMonitor which is shared across anomaly trackers.
     virtual void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
-        return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
+        return;  // Base AnomalyTracker class has no need for the AnomalyMonitor.
     }
 
     // Helper function to return the sum value of past buckets at given dimension.
@@ -92,9 +93,10 @@
 
     // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
     // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
-    virtual void informAlarmsFired(const uint64_t& timestampNs,
+    virtual void informAlarmsFired(
+            const uint64_t& timestampNs,
             unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
-        return; // The base AnomalyTracker class doesn't have alarms.
+        return;  // The base AnomalyTracker class doesn't have alarms.
     }
 
 protected:
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index bbee9fa..e459f76 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -52,8 +52,7 @@
 }
 
 void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
-                                const uint64_t& timestampNs) {
-
+                                        const uint64_t& timestampNs) {
     uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
     if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
         VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
@@ -86,15 +85,15 @@
     }
 }
 
-void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+void DurationAnomalyTracker::informAlarmsFired(
+        const uint64_t& timestampNs,
         unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
-
     if (firedAlarms.empty() || mAlarms.empty()) return;
     // Find the intersection of firedAlarms and mAlarms.
     // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
     // seldomly called. The alternative would be having AnomalyAlarms store information about the
-    // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that is
-    // rarely ever called.
+    // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
+    // is rarely ever called.
     unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
     for (const auto& kv : mAlarms) {
         if (firedAlarms.count(kv.second) > 0) {
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 052fdf57..ba687da 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -53,7 +53,8 @@
     // and removes it from firedAlarms.
     // Note that this will generally be called from a different thread from the other functions;
     // the caller is responsible for thread safety.
-    void informAlarmsFired(const uint64_t& timestampNs,
+    void informAlarmsFired(
+            const uint64_t& timestampNs,
             unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) override;
 
 protected:
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 3eaf7a1..5a326a4 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -275,6 +275,12 @@
 
 message IncidentdDetails {
   repeated int32 section = 1;
+
+  enum Destination {
+    AUTOMATIC = 0;
+    EXPLICIT = 1;
+  }
+  optional Destination dest = 2;
 }
 
 message PerfettoDetails {
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
new file mode 100644
index 0000000..d9a8fc8
--- /dev/null
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define DEBUG true
+#include "Log.h"
+
+#include "IncidentdReporter.h"
+#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+                            const ConfigKey& configKey) {
+    if (config.section_size() == 0) {
+        VLOG("The alert %lld contains zero section in config(%d,%lld)", alert.id(),
+            configKey.GetUid(), (long long) configKey.GetId());
+        return false;
+    }
+
+    IncidentReportArgs incidentReport;
+
+    android::os::IncidentHeaderProto header;
+    header.set_alert_id(alert.id());
+    header.mutable_config_key()->set_uid(configKey.GetUid());
+    header.mutable_config_key()->set_id(configKey.GetId());
+    incidentReport.addHeader(header);
+
+    for (int i = 0; i < config.section_size(); i++) {
+        incidentReport.addSection(config.section(i));
+    }
+
+    uint8_t dest;
+    switch (config.dest()) {
+        case IncidentdDetails_Destination_AUTOMATIC:
+            dest = android::os::DEST_AUTOMATIC;
+            break;
+        case IncidentdDetails_Destination_EXPLICIT:
+            dest = android::os::DEST_EXPLICIT;
+            break;
+        default:
+            dest = android::os::DEST_AUTOMATIC;
+    }
+    incidentReport.setDest(dest);
+
+    sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+            defaultServiceManager()->getService(android::String16("incident")));
+    if (service == nullptr) {
+        ALOGW("Failed to fetch incident service.");
+        return false;
+    }
+    VLOG("Calling incidentd %p", service.get());
+    binder::Status s = service->reportIncident(incidentReport);
+    VLOG("Report incident status: %s", s.toString8().string());
+    return s.isOk();
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h
new file mode 100644
index 0000000..229ed77
--- /dev/null
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert, IncidentdDetails
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Calls incidentd to trigger an incident report and put in dropbox for uploading.
+ */
+bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+                            const ConfigKey& configKey);
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android