--- /dev/null
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
LOCAL_PATH:= $(call my-dir)
+
+# bugreportz
+# ==========
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= bugreportz.cpp
+LOCAL_SRC_FILES:= \
+ bugreportz.cpp \
+ main.cpp \
LOCAL_MODULE:= bugreportz
-LOCAL_CFLAGS := -Wall
+LOCAL_CFLAGS := -Werror -Wall
-LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
include $(BUILD_EXECUTABLE)
+
+# bugreportz_test
+# ===============
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bugreportz_test
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Werror -Wall
+
+LOCAL_SRC_FILES := \
+ bugreportz.cpp \
+ bugreportz_test.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+ libgmock \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libutils \
+
+include $(BUILD_NATIVE_TEST)
*/
#include <errno.h>
-#include <getopt.h>
#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-static constexpr char VERSION[] = "1.0";
-
-static void show_usage() {
- fprintf(stderr,
- "usage: bugreportz [-h | -v]\n"
- " -h: to display this help message\n"
- " -v: to display the version\n"
- " or no arguments to generate a zipped bugreport\n");
-}
-
-static void show_version() {
- fprintf(stderr, "%s\n", VERSION);
-}
-
-int main(int argc, char *argv[]) {
-
- if (argc > 1) {
- /* parse arguments */
- int c;
- while ((c = getopt(argc, argv, "vh")) != -1) {
- switch (c) {
- case 'h':
- show_usage();
- return EXIT_SUCCESS;
- case 'v':
- show_version();
- return EXIT_SUCCESS;
- default:
- show_usage();
- return EXIT_FAILURE;
- }
- }
- // passed an argument not starting with -
- if (optind > 1 || argv[optind] != nullptr) {
- show_usage();
- return EXIT_FAILURE;
- }
- }
-
- // TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value);
- // should be reused instead.
-
- // Start the dumpstatez service.
- property_set("ctl.start", "dumpstatez");
-
- // Socket will not be available until service starts.
- int s;
- for (int i = 0; i < 20; i++) {
- s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
- if (s >= 0)
- break;
- // Try again in 1 second.
- sleep(1);
- }
-
- if (s == -1) {
- printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
- return EXIT_SUCCESS;
- }
-
- // Set a timeout so that if nothing is read in 10 minutes, we'll stop
- // reading and quit. No timeout in dumpstate is longer than 60 seconds,
- // so this gives lots of leeway in case of unforeseen time outs.
- struct timeval tv;
- tv.tv_sec = 10 * 60;
- tv.tv_usec = 0;
- if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
- fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
- }
+#include "bugreportz.h"
+int bugreportz(int s) {
while (1) {
char buffer[65536];
- ssize_t bytes_read = TEMP_FAILURE_RETRY(
- read(s, buffer, sizeof(buffer)));
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
if (bytes_read == 0) {
break;
} else if (bytes_read == -1) {
ssize_t bytes_written;
do {
bytes_written = TEMP_FAILURE_RETRY(
- write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send,
- bytes_to_send));
+ write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send, bytes_to_send));
if (bytes_written == -1) {
fprintf(stderr,
- "Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
+ "Failed to write data to stdout: read %zd, trying to send %zd "
+ "(%s)\n",
bytes_read, bytes_to_send, strerror(errno));
break;
}
--- /dev/null
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 BUGREPORTZ_H
+#define BUGREPORTZ_H
+
+// Calls dumpstate using the given socket and output its result to stdout.
+int bugreportz(int s);
+
+#endif // BUGREPORTZ_H
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "bugreportz.h"
+
+using ::testing::StrEq;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStdout;
+
+class BugreportzTest : public ::testing::Test {
+ public:
+ // Creates the pipe used to communicate with bugreportz()
+ void SetUp() {
+ int fds[2];
+ ASSERT_EQ(0, pipe(fds));
+ read_fd_ = fds[0];
+ write_fd_ = fds[1];
+ }
+
+ // Closes the pipe FDs.
+ // If a FD is closed manually during a test, set it to -1 to prevent TearDown() trying to close
+ // it again.
+ void TearDown() {
+ for (int fd : {read_fd_, write_fd_}) {
+ if (fd >= 0) {
+ close(fd);
+ }
+ }
+ }
+
+ // Emulates dumpstate output by writing to the socket passed to bugreportz()
+ void WriteToSocket(const std::string& data) {
+ if (write_fd_ < 0) {
+ ADD_FAILURE() << "cannot write '" << data << "' because socket is already closed";
+ return;
+ }
+ int expected = data.length();
+ int actual = write(write_fd_, data.data(), data.length());
+ ASSERT_EQ(expected, actual) << "wrong number of bytes written to socket";
+ }
+
+ void AssertStdoutEquals(const std::string& expected) {
+ ASSERT_THAT(stdout_, StrEq(expected)) << "wrong stdout output";
+ }
+
+ // Calls bugreportz() using the internal pipe.
+ //
+ // Tests must call WriteToSocket() to set what's written prior to calling it, since the writing
+ // end of the pipe will be closed before calling bugreportz() (otherwise that function would
+ // hang).
+ void Bugreportz() {
+ close(write_fd_);
+ write_fd_ = -1;
+
+ CaptureStdout();
+ int status = bugreportz(read_fd_);
+
+ close(read_fd_);
+ read_fd_ = -1;
+ stdout_ = GetCapturedStdout();
+
+ ASSERT_EQ(0, status) << "bugrepotz() call failed (stdout: " << stdout_ << ")";
+ }
+
+ private:
+ int read_fd_;
+ int write_fd_;
+ std::string stdout_;
+};
+
+// Tests 'bugreportz', without any argument - it will just echo dumpstate's output to stdout.
+TEST_F(BugreportzTest, NoArgument) {
+ WriteToSocket("What happens on 'dumpstate',");
+ WriteToSocket("stays on 'bugreportz'.\n");
+
+ Bugreportz();
+
+ AssertStdoutEquals("What happens on 'dumpstate',stays on 'bugreportz'.\n");
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+#include "bugreportz.h"
+
+static constexpr char VERSION[] = "1.0";
+
+static void show_usage() {
+ fprintf(stderr,
+ "usage: bugreportz [-h | -v]\n"
+ " -h: to display this help message\n"
+ " -v: to display the version\n"
+ " or no arguments to generate a zipped bugreport\n");
+}
+
+static void show_version() {
+ fprintf(stderr, "%s\n", VERSION);
+}
+
+int main(int argc, char* argv[]) {
+ if (argc > 1) {
+ /* parse arguments */
+ int c;
+ while ((c = getopt(argc, argv, "vh")) != -1) {
+ switch (c) {
+ case 'h':
+ show_usage();
+ return EXIT_SUCCESS;
+ case 'v':
+ show_version();
+ return EXIT_SUCCESS;
+ default:
+ show_usage();
+ return EXIT_FAILURE;
+ }
+ }
+ // passed an argument not starting with -
+ if (optind > 1 || argv[optind] != nullptr) {
+ show_usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ // TODO: code below was copy-and-pasted from bugreport.cpp (except by the
+ // timeout value);
+ // should be reused instead.
+
+ // Start the dumpstatez service.
+ property_set("ctl.start", "dumpstatez");
+
+ // Socket will not be available until service starts.
+ int s;
+ for (int i = 0; i < 20; i++) {
+ s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+ if (s >= 0) break;
+ // Try again in 1 second.
+ sleep(1);
+ }
+
+ if (s == -1) {
+ printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
+ return EXIT_SUCCESS;
+ }
+
+ // Set a timeout so that if nothing is read in 10 minutes, we'll stop
+ // reading and quit. No timeout in dumpstate is longer than 60 seconds,
+ // so this gives lots of leeway in case of unforeseen time outs.
+ struct timeval tv;
+ tv.tv_sec = 10 * 60;
+ tv.tv_usec = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+ fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+ }
+
+ bugreportz(s);
+}