Snap for 10103804 from 230b6fd6e1b304922b5d7ed4c84eb2cf20057b5b to mainline-tzdata5-release

Change-Id: If44a490e22f249adde14ffbb39201269901b482c
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 14481dc..33a1eb2 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -7,6 +7,9 @@
       "name": "CtsLogdTestCases"
     },
     {
+      "name": "logd_integration_test"
+    },
+    {
       "name": "MicrodroidHostTestCases"
     }
   ],
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index b5cbf25..e8b5b8d 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -272,11 +272,9 @@
 
 // clang-format off
 static void show_help() {
-    const char* cmd = getprogname();
+    printf(R"logcat(
+  Usage: logcat [OPTION]... [FILTERSPEC]...
 
-    fprintf(stderr, "Usage: %s [OPTION]... [FILTERSPEC]...\n", cmd);
-
-    fprintf(stderr, R"logcat(
   General options:
 
   -b BUFFER, --buffer=BUFFER
@@ -795,7 +793,7 @@
                 return EXIT_SUCCESS;
 
             case '?':
-                error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind - 1]);
+                error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind]);
                 break;
 
             default:
@@ -1101,8 +1099,8 @@
             WriteFully(&log_msg, log_msg.len());
         } else {
             ProcessBuffer(&log_msg);
-            if (blocking && output_file_ == stdout) fflush(stdout);
         }
+        if (blocking && output_file_ == stdout) fflush(stdout);
     }
     return EXIT_SUCCESS;
 }
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 17c2237..01c78c2 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -222,9 +222,6 @@
         *cp = ' ';
     }
 
-    while ((cp = strstr(str, "  "))) {
-        memmove(cp, cp + 1, strlen(cp + 1) + 1);
-    }
     pid_t pid = getpid();
     pid_t tid = gettid();
     uid_t uid = AID_LOGD;
diff --git a/logd/integration_test/Android.bp b/logd/integration_test/Android.bp
new file mode 100644
index 0000000..4cb279d
--- /dev/null
+++ b/logd/integration_test/Android.bp
@@ -0,0 +1,16 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test_host {
+    name: "logd_integration_test",
+    main: "logd_integration_test.py",
+    srcs: [
+        "logd_integration_test.py",
+    ],
+    test_config: "logd_integration_test.xml",
+    test_suites: ["general-tests"],
+    test_options: {
+        unit_test: false,
+    },
+}
diff --git a/logd/integration_test/logd_integration_test.py b/logd/integration_test/logd_integration_test.py
new file mode 100755
index 0000000..8001871
--- /dev/null
+++ b/logd/integration_test/logd_integration_test.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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.
+#
+
+import re
+import subprocess
+import unittest
+
+KNOWN_NON_LOGGING_SERVICES = [
+    "vendor.ir-default",
+
+    "SELF_TEST_SERVICE_DOES_NOT_EXIST",
+]
+
+KNOWN_LOGGING_SERVICES = [
+    "vendor.wifi_hal_legacy",
+    "zygote",
+
+    # b/210919187 - main log is too busy, gets dropped off
+    # "statsd",
+    # "vendor.audio-hal-aidl",
+
+    "SELF_TEST_SERVICE_DOES_NOT_EXIST",
+]
+
+def get_service_pid(svc):
+    return int(subprocess.check_output(["adb", "shell", "getprop", "init.svc_debug_pid." + svc]))
+
+def get_pid_logs(pid):
+    return subprocess.check_output(["adb", "logcat", "--pid", str(pid), "-d"]).decode()
+
+def iter_service_pids(test_case, services):
+    a_service_worked = False
+    for service in services:
+        try:
+            yield service, get_service_pid(service)
+            a_service_worked = True
+        except subprocess.CalledProcessError:
+            continue
+        except ValueError:
+            continue
+    test_case.assertTrue(a_service_worked)
+
+def get_dropped_logs(test_case, buffer):
+        output = subprocess.check_output(["adb", "logcat", "-b", buffer, "--statistics"]).decode()
+        output = iter(output.split("\n"))
+
+        res = []
+
+        # Search for these lines, in order. Consider output:
+        # :) adb logcat -b system -S | grep -E "Total|Now"
+        # size/num system             Total
+        # Total    883973/6792        883973/6792
+        # Now      883973/6792        883973/6792
+        for indication in ["Total", "Now"]:
+            reLineCount = re.compile(f"^{indication}.*\s+[0-9]+/([0-9]+)")
+            while True:
+                line = next(output)
+                match = reLineCount.match(line)
+                if match:
+                    res.append(int(match.group(1)))
+                    break
+
+        total, now = res
+        return total - now
+
+class LogdIntegrationTest(unittest.TestCase):
+    def test_no_logs(self):
+        for service, pid in iter_service_pids(self, KNOWN_NON_LOGGING_SERVICES):
+            with self.subTest(service):
+                lines = get_pid_logs(pid)
+                self.assertFalse("\n" in lines, f"{service} ({pid}) shouldn't have logs, but found: {lines}")
+
+    def test_has_logs(self):
+        for service, pid in iter_service_pids(self, KNOWN_LOGGING_SERVICES):
+            with self.subTest(service):
+                lines = get_pid_logs(pid)
+                self.assertTrue("\n" in lines, f"{service} ({pid}) should have logs, but found: {lines}")
+
+    def test_no_dropped_logs(self):
+        for buffer in ["system", "main", "kernel", "crash"]:
+            dropped = get_dropped_logs(self, buffer)
+            if buffer == "main":
+                # after b/276957640, should be able to reduce this to ~4000
+                self.assertLess(dropped, 30000, f"Buffer {buffer} has {dropped} dropped logs.")
+            else:
+                self.assertEqual(dropped, 0, f"Buffer {buffer} has {dropped} dropped logs.")
+
+def main():
+    unittest.main(verbosity=3)
+
+if __name__ == "__main__":
+    main()
diff --git a/logd/integration_test/logd_integration_test.xml b/logd/integration_test/logd_integration_test.xml
new file mode 100644
index 0000000..207fe11
--- /dev/null
+++ b/logd/integration_test/logd_integration_test.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<configuration description="Config to run logd integration tests">
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
+        <option name="par-file-name" value="logd_integration_test" />
+        <option name="inject-android-serial" value="true" />
+        <option name="test-timeout" value="5m" />
+    </test>
+</configuration>