Merge branch 'security-aosp-tm-release' into int/13/fp3

* security-aosp-tm-release:
  Make log reader thread a class member

Change-Id: Ibef975b420ce9dec411870c5378d689efd00f9a7
diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json
index 0fb3227..af99f74 100644
--- a/apex/apex_manifest.json
+++ b/apex/apex_manifest.json
@@ -1,5 +1,5 @@
 {
   "name": "com.android.os.statsd",
-  "version": 339990000
+  "version": 330400000
 }
 
diff --git a/statsd/src/main.cpp b/statsd/src/main.cpp
index bd2c0e4..67bb65d 100644
--- a/statsd/src/main.cpp
+++ b/statsd/src/main.cpp
@@ -39,20 +39,12 @@
 
 shared_ptr<StatsService> gStatsService = nullptr;
 sp<StatsSocketListener> gSocketListener = nullptr;
+int gCtrlPipe[2];
 
 void signalHandler(int sig) {
-    if (sig == SIGPIPE) {
-        // ShellSubscriber uses SIGPIPE as a signal to detect the end of the
-        // client process. Don't prematurely exit(1) here. Instead, ignore the
-        // signal and allow the write call to return EPIPE.
-        ALOGI("statsd received SIGPIPE. Ignoring signal.");
-        return;
-    }
-
-    if (gSocketListener != nullptr) gSocketListener->stopListener();
-    if (gStatsService != nullptr) gStatsService->Terminate();
     ALOGW("statsd terminated on receiving signal %d.", sig);
-    exit(1);
+    const char c = 'q';
+    write(gCtrlPipe[1], &c, 1);
 }
 
 void registerSignalHandlers()
@@ -60,11 +52,15 @@
     struct sigaction sa;
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
-    sa.sa_handler = signalHandler;
+
+    sa.sa_handler = SIG_IGN;
+    // ShellSubscriber uses SIGPIPE as a signal to detect the end of the
+    // client process. Don't prematurely exit(1) here. Instead, ignore the
+    // signal and allow the write call to return EPIPE.
     sigaction(SIGPIPE, &sa, nullptr);
-    sigaction(SIGHUP, &sa, nullptr);
-    sigaction(SIGINT, &sa, nullptr);
-    sigaction(SIGQUIT, &sa, nullptr);
+
+    pipe2(gCtrlPipe, O_CLOEXEC);
+    sa.sa_handler = signalHandler;
     sigaction(SIGTERM, &sa, nullptr);
 }
 
@@ -92,8 +88,6 @@
         return -1;
     }
 
-    registerSignalHandlers();
-
     gStatsService->sayHiToStatsCompanion();
 
     gStatsService->Startup();
@@ -106,6 +100,22 @@
         exit(1);
     }
 
+    // Use self-pipe to notify this thread to gracefully quit
+    // when receiving SIGTERM
+    registerSignalHandlers();
+    std::thread([] {
+        while (true) {
+            char c;
+            int i = read(gCtrlPipe[0], &c, 1);
+            if (i < 0) {
+                if (errno == EINTR) continue;
+            }
+            gSocketListener->stopListener();
+            gStatsService->Terminate();
+            exit(1);
+        }
+    }).detach();
+
     // Loop forever -- the reports run on this thread in a handler, and the
     // binder calls remain responsive in their pool of one thread.
     while (true) {
diff --git a/tests/src/android/cts/statsd/atom/AtomTestCase.java b/tests/src/android/cts/statsd/atom/AtomTestCase.java
index 1f33c20..83ca2a2 100644
--- a/tests/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/tests/src/android/cts/statsd/atom/AtomTestCase.java
@@ -125,6 +125,8 @@
     public static final String FEATURE_INCREMENTAL_DELIVERY =
             "android.software.incremental_delivery";
 
+    public static final int SHELL_UID = 2000;
+
     // Telephony phone types
     public static final int PHONE_TYPE_GSM = 1;
     public static final int PHONE_TYPE_CDMA = 2;
@@ -300,13 +302,14 @@
         getDevice().pushFile(configFile, remotePath);
         getDevice().executeShellCommand(
                 String.join(" ", "cat", remotePath, "|", UPDATE_CONFIG_CMD,
-                        String.valueOf(CONFIG_ID)));
+                        String.valueOf(SHELL_UID), String.valueOf(CONFIG_ID)));
         getDevice().executeShellCommand("rm " + remotePath);
     }
 
     protected void removeConfig(long configId) throws Exception {
         getDevice().executeShellCommand(
-                String.join(" ", REMOVE_CONFIG_CMD, String.valueOf(configId)));
+                String.join(" ", REMOVE_CONFIG_CMD,
+                        String.valueOf(SHELL_UID), String.valueOf(configId)));
     }
 
     /** Gets the statsd report and sorts it. Note that this also deletes that report from statsd. */
@@ -521,8 +524,8 @@
     protected ConfigMetricsReportList getReportList() throws Exception {
         try {
             ConfigMetricsReportList reportList = getDump(ConfigMetricsReportList.parser(),
-                    String.join(" ", DUMP_REPORT_CMD, String.valueOf(CONFIG_ID),
-                            "--include_current_bucket", "--proto"));
+                    String.join(" ", DUMP_REPORT_CMD, String.valueOf(SHELL_UID),
+                            String.valueOf(CONFIG_ID), "--include_current_bucket", "--proto"));
             return reportList;
         } catch (com.google.protobuf.InvalidProtocolBufferException e) {
             LogUtil.CLog.e("Failed to fetch and parse the statsd output report. "
@@ -872,21 +875,9 @@
         data.subList(lastStateIdx+1, data.size()).clear();
     }
 
-    /** Returns the UID of the host, which should always either be SHELL (2000) or ROOT (0). */
+    /** Returns the UID of the host, which should always either be SHELL (2000). */
     protected int getHostUid() throws DeviceNotAvailableException {
-        String strUid = "";
-        try {
-            strUid = getDevice().executeShellCommand("id -u");
-            return Integer.parseInt(strUid.trim());
-        } catch (NumberFormatException e) {
-            LogUtil.CLog.e("Failed to get host's uid via shell command. Found " + strUid);
-            // Fall back to alternative method...
-            if (getDevice().isAdbRoot()) {
-                return 0; // ROOT
-            } else {
-                return 2000; // SHELL
-            }
-        }
+        return SHELL_UID;
     }
 
     protected String getProperty(String prop) throws Exception {
@@ -990,7 +981,7 @@
 
     public void doAppBreadcrumbReported(int label, int state) throws Exception {
         getDevice().executeShellCommand(String.format(
-                "cmd stats log-app-breadcrumb %d %d", label, state));
+                "cmd stats log-app-breadcrumb %d %d %d", SHELL_UID, label, state));
     }
 
     protected void setBatteryLevel(int level) throws Exception {
diff --git a/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java b/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java
index dacbac9..99df717 100644
--- a/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java
+++ b/tests/src/android/cts/statsd/atom/DeviceAtomTestCase.java
@@ -302,9 +302,9 @@
 
     protected void rebootDeviceAndWaitUntilReady() throws Exception {
         rebootDevice();
-        // Wait for 2 mins.
+        // Wait for 3 mins.
         assertWithMessage("Device failed to boot")
-            .that(getDevice().waitForBootComplete(120_000)).isTrue();
+            .that(getDevice().waitForBootComplete(180_000)).isTrue();
         assertWithMessage("Stats service failed to start")
             .that(waitForStatsServiceStart(60_000)).isTrue();
         Thread.sleep(2_000);
diff --git a/tests/src/android/cts/statsd/metric/CountMetricsTests.java b/tests/src/android/cts/statsd/metric/CountMetricsTests.java
index ef077f3..1f1dccb 100644
--- a/tests/src/android/cts/statsd/metric/CountMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/CountMetricsTests.java
@@ -385,6 +385,23 @@
                     .setWhat(whatMatcherId)
                     .addSliceByState(stateId)
                     .addStateLink(stateLink)
+                    .setDimensionsInWhat(
+                        FieldMatcher.newBuilder()
+                            .setField(whatAtomId)
+                            .addChild(FieldMatcher.newBuilder()
+                                    .setField(1)
+                                    .setPosition(Position.FIRST)
+                                    .addChild(FieldMatcher.newBuilder()
+                                            .setField(AttributionNode.UID_FIELD_NUMBER)
+                                    )
+                            )
+                            .addChild(FieldMatcher.newBuilder()
+                                    .setField(2)
+                            )
+                            .addChild(FieldMatcher.newBuilder()
+                                    .setField(3)
+                        )
+                    )
                 )
                 .addAtomMatcher(whatMatcher)
                 .addState(state);
diff --git a/tests/src/android/cts/statsd/metric/MetricActivationTests.java b/tests/src/android/cts/statsd/metric/MetricActivationTests.java
index 25fa031..8e796cf 100644
--- a/tests/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/tests/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -494,6 +494,7 @@
         // Metric 2 Activation 1: 0 seconds
         // Metric 2 Activation 2: 0 seconds
         rebootDeviceAndWaitUntilReady();
+        Thread.sleep(3_000L);
 
         // Metric 1 event ignored.
         // Metric 2 event ignored.
diff --git a/tests/src/android/cts/statsd/metric/ValueMetricsTests.java b/tests/src/android/cts/statsd/metric/ValueMetricsTests.java
index 0cf5bbb..d0370e1 100644
--- a/tests/src/android/cts/statsd/metric/ValueMetricsTests.java
+++ b/tests/src/android/cts/statsd/metric/ValueMetricsTests.java
@@ -319,11 +319,6 @@
     LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
     assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
     assertThat(metricReport.getValueMetrics().getDataList()).isEmpty();
-    // Bucket is skipped because metric is not activated.
-    assertThat(metricReport.getValueMetrics().getSkippedList()).isNotEmpty();
-    assertThat(metricReport.getValueMetrics().getSkipped(0).getDropEventList()).isNotEmpty();
-    assertThat(metricReport.getValueMetrics().getSkipped(0).getDropEvent(0).getDropReason())
-            .isEqualTo(BucketDropReason.NO_DATA);
   }
 
     public void testValueMetricWithConditionAndActivation() throws Exception {