Merge "crash_reporter: Remove udev collector from Android build"
diff --git a/adb/Android.mk b/adb/Android.mk
index 9c8ab6d..d629223 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -349,8 +349,6 @@
libcutils \
libbase \
libcrypto_static \
- libminijail \
- libminijail_generated \
- libcap
+ libminijail
include $(BUILD_EXECUTABLE)
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 78db69d..4721e2f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -124,12 +124,9 @@
AID_INET, AID_NET_BT, AID_NET_BT_ADMIN,
AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
AID_READPROC};
- if (minijail_set_supplementary_gids(
- jail.get(),
- sizeof(groups) / sizeof(groups[0]),
- groups) != 0) {
- LOG(FATAL) << "Could not configure supplementary groups";
- }
+ minijail_set_supplementary_gids(jail.get(),
+ sizeof(groups) / sizeof(groups[0]),
+ groups);
// Don't listen on a port (default 5037) if running in secure mode.
// Don't run as root if running in secure mode.
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index e8fe6c9..4ec8979 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -67,7 +67,7 @@
void LinePrinter::Print(string to_print, LineType type) {
if (!smart_terminal_) {
- Out(to_print);
+ Out(to_print + "\n");
return;
}
diff --git a/adb/services.cpp b/adb/services.cpp
index 20166ce..cd33e7b 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -368,8 +368,9 @@
while (true) {
bool is_ambiguous = false;
std::string error = "unknown error";
- atransport* t = acquire_one_transport(sinfo->transport_type, sinfo->serial.c_str(),
- &is_ambiguous, &error);
+ const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
+ atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
+
if (t != nullptr && t->connection_state == sinfo->state) {
SendOkay(fd);
break;
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index de0f943..9e4f1f7 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -62,7 +62,7 @@
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object
+LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 0afa895..58b629b 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -24,11 +24,12 @@
#include <dirent.h>
#include <time.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
#include <elf.h>
-#include <sys/stat.h>
#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
#include <selinux/android.h>
@@ -363,6 +364,37 @@
}
#endif
+ // Fork a child to handle the rest of the request.
+ pid_t fork_pid = fork();
+ if (fork_pid == -1) {
+ ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
+ return;
+ } else if (fork_pid != 0) {
+ waitpid(fork_pid, nullptr, 0);
+ return;
+ }
+
+ // Open the tombstone file if we need it.
+ std::string tombstone_path;
+ int tombstone_fd = -1;
+ switch (request.action) {
+ case DEBUGGER_ACTION_DUMP_TOMBSTONE:
+ case DEBUGGER_ACTION_CRASH:
+ tombstone_fd = open_tombstone(&tombstone_path);
+ if (tombstone_fd == -1) {
+ ALOGE("debuggerd: failed to open tombstone file: %s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+
+ case DEBUGGER_ACTION_DUMP_BACKTRACE:
+ break;
+
+ default:
+ ALOGE("debuggerd: unexpected request action: %d", request.action);
+ exit(1);
+ }
+
// At this point, the thread that made the request is blocked in
// a read() call. If the thread has crashed, then this gives us
// time to PTRACE_ATTACH to it before it has a chance to really fault.
@@ -374,19 +406,32 @@
// See details in bionic/libc/linker/debugger.c, in function
// debugger_signal_handler().
if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
- ALOGE("ptrace attach failed: %s\n", strerror(errno));
- return;
+ ALOGE("debuggerd: ptrace attach failed: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Generate the backtrace map before dropping privileges.
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
+
+ // Now that we've done everything that requires privileges, we can drop them.
+ if (setresgid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
+ ALOGE("debuggerd: failed to setresgid");
+ exit(1);
+ }
+
+ if (setresuid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
+ ALOGE("debuggerd: failed to setresuid");
+ exit(1);
}
bool detach_failed = false;
bool tid_unresponsive = false;
bool attach_gdb = should_attach_gdb(&request);
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
- ALOGE("failed responding to client: %s\n", strerror(errno));
- return;
+ ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
+ exit(1);
}
- std::unique_ptr<char> tombstone_path;
int total_sleep_time_usec = 0;
while (true) {
int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
@@ -399,9 +444,9 @@
case SIGSTOP:
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
ALOGV("stopped -- dumping to tombstone\n");
- tombstone_path.reset(engrave_tombstone(
- request.pid, request.tid, signal, request.original_si_code, request.abort_msg_address,
- true, &detach_failed, &total_sleep_time_usec));
+ engrave_tombstone(tombstone_fd, backtrace_map.get(), request.pid, request.tid, signal,
+ request.original_si_code, request.abort_msg_address, true,
+ &detach_failed, &total_sleep_time_usec);
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
ALOGV("stopped -- dumping to fd\n");
dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, &total_sleep_time_usec);
@@ -409,7 +454,7 @@
ALOGV("stopped -- continuing\n");
status = ptrace(PTRACE_CONT, request.tid, 0, 0);
if (status) {
- ALOGE("ptrace continue failed: %s\n", strerror(errno));
+ ALOGE("debuggerd: ptrace continue failed: %s\n", strerror(errno));
}
continue; // loop again
}
@@ -432,21 +477,21 @@
kill(request.pid, SIGSTOP);
// don't dump sibling threads when attaching to GDB because it
// makes the process less reliable, apparently...
- tombstone_path.reset(engrave_tombstone(
- request.pid, request.tid, signal, request.original_si_code, request.abort_msg_address,
- !attach_gdb, &detach_failed, &total_sleep_time_usec));
+ engrave_tombstone(tombstone_fd, backtrace_map.get(), request.pid, request.tid, signal,
+ request.original_si_code, request.abort_msg_address, !attach_gdb,
+ &detach_failed, &total_sleep_time_usec);
break;
default:
- ALOGE("process stopped due to unexpected signal %d\n", signal);
+ ALOGE("debuggerd: process stopped due to unexpected signal %d\n", signal);
break;
}
break;
}
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
- if (tombstone_path) {
- write(fd, tombstone_path.get(), strlen(tombstone_path.get()));
+ if (!tombstone_path.empty()) {
+ write(fd, tombstone_path.c_str(), tombstone_path.length());
}
}
@@ -457,7 +502,7 @@
kill(request.pid, SIGSTOP);
}
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
+ ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
detach_failed = true;
} else if (attach_gdb) {
// if debug.db.uid is set, its value indicates if we should wait
@@ -468,16 +513,9 @@
}
}
- // resume stopped process (so it can crash in peace).
+ // Resume the stopped process so it can crash in peace, and exit.
kill(request.pid, SIGCONT);
-
- // If we didn't successfully detach, we're still the parent, and the
- // actual parent won't receive a death notification via wait(2). At this point
- // there's not much we can do about that.
- if (detach_failed) {
- ALOGE("debuggerd committing suicide to free the zombie!\n");
- kill(getpid(), SIGKILL);
- }
+ exit(0);
}
static int do_server() {
diff --git a/debuggerd/test/selinux/android.h b/debuggerd/test/selinux/android.h
new file mode 100644
index 0000000..abed087
--- /dev/null
+++ b/debuggerd/test/selinux/android.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+extern "C" int selinux_android_restorecon(const char*, unsigned int);
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 5f422e3..b2f203d 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -632,7 +632,7 @@
}
// Dumps all information about the specified pid to the tombstone.
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code,
+static bool dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid, int signal, int si_code,
uintptr_t abort_msg_address, bool dump_sibling_threads,
int* total_sleep_time_usec) {
// don't copy log messages to tombstone unless this is a dev device
@@ -659,8 +659,7 @@
dump_signal_info(log, tid, signal, si_code);
}
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
dump_abort_message(backtrace.get(), log, abort_msg_address);
dump_registers(log, tid);
if (backtrace->Unwind(0)) {
@@ -669,8 +668,8 @@
ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
}
dump_memory_and_code(log, backtrace.get());
- if (map.get() != nullptr) {
- dump_all_maps(backtrace.get(), map.get(), log, tid);
+ if (map) {
+ dump_all_maps(backtrace.get(), map, log, tid);
}
if (want_logs) {
@@ -679,7 +678,7 @@
bool detach_failed = false;
if (dump_sibling_threads) {
- detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map.get());
+ detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map);
}
if (want_logs) {
@@ -698,53 +697,57 @@
return detach_failed;
}
-// find_and_open_tombstone - find an available tombstone slot, if any, of the
+// open_tombstone - find an available tombstone slot, if any, of the
// form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
// file is available, we reuse the least-recently-modified file.
-//
-// Returns the path of the tombstone file, allocated using malloc(). Caller must free() it.
-static char* find_and_open_tombstone(int* fd) {
+int open_tombstone(std::string* out_path) {
// In a single pass, find an available slot and, in case none
// exist, find and record the least-recently-modified file.
char path[128];
+ int fd = -1;
int oldest = -1;
struct stat oldest_sb;
for (int i = 0; i < MAX_TOMBSTONES; i++) {
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
struct stat sb;
- if (!stat(path, &sb)) {
+ if (stat(path, &sb) == 0) {
if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) {
oldest = i;
oldest_sb.st_mtime = sb.st_mtime;
}
continue;
}
- if (errno != ENOENT)
- continue;
+ if (errno != ENOENT) continue;
- *fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
- if (*fd < 0)
- continue; // raced ?
+ fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
+ if (fd < 0) continue; // raced ?
- fchown(*fd, AID_SYSTEM, AID_SYSTEM);
- return strdup(path);
+ if (out_path) {
+ *out_path = path;
+ }
+ fchown(fd, AID_SYSTEM, AID_SYSTEM);
+ return fd;
}
if (oldest < 0) {
- ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n");
+ ALOGE("debuggerd: failed to find a valid tombstone, default to using tombstone 0.\n");
oldest = 0;
}
// we didn't find an available file, so we clobber the oldest one
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
- *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
- if (*fd < 0) {
- ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
- return NULL;
+ fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
+ if (fd < 0) {
+ ALOGE("debuggerd: failed to open tombstone file '%s': %s\n", path, strerror(errno));
+ return -1;
}
- fchown(*fd, AID_SYSTEM, AID_SYSTEM);
- return strdup(path);
+
+ if (out_path) {
+ *out_path = path;
+ }
+ fchown(fd, AID_SYSTEM, AID_SYSTEM);
+ return fd;
}
static int activity_manager_connect() {
@@ -777,49 +780,27 @@
return amfd;
}
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
- uintptr_t abort_msg_address, bool dump_sibling_threads,
- bool* detach_failed, int* total_sleep_time_usec) {
-
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid, int signal,
+ int original_si_code, uintptr_t abort_msg_address, bool dump_sibling_threads,
+ bool* detach_failed, int* total_sleep_time_usec) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
- if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
- ALOGE("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
- }
-
- if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
- ALOGE("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
- }
-
- int fd = -1;
- char* path = NULL;
- if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
- path = find_and_open_tombstone(&fd);
- } else {
- ALOGE("Failed to restore security context, not writing tombstone.\n");
- }
-
- if (fd < 0) {
- ALOGE("Skipping tombstone write, nothing to do.\n");
+ if (tombstone_fd < 0) {
+ ALOGE("debuggerd: skipping tombstone write, nothing to do.\n");
*detach_failed = false;
- return NULL;
+ return;
}
- log.tfd = fd;
+ log.tfd = tombstone_fd;
// Preserve amfd since it can be modified through the calls below without
// being closed.
int amfd = activity_manager_connect();
log.amfd = amfd;
- *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
+ *detach_failed = dump_crash(&log, map, pid, tid, signal, original_si_code, abort_msg_address,
dump_sibling_threads, total_sleep_time_usec);
- _LOG(&log, logtype::BACKTRACE, "\nTombstone written to: %s\n", path);
-
- // Either of these file descriptors can be -1, any error is ignored.
+ // This file descriptor can be -1, any error is ignored.
close(amfd);
- close(fd);
-
- return path;
}
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 7e2b2fe..5f2d239 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -17,15 +17,23 @@
#ifndef _DEBUGGERD_TOMBSTONE_H
#define _DEBUGGERD_TOMBSTONE_H
-#include <stddef.h>
#include <stdbool.h>
+#include <stddef.h>
#include <sys/types.h>
+#include <string>
+
+class BacktraceMap;
+
+/* Create and open a tombstone file for writing.
+ * Returns a writable file descriptor, or -1 with errno set appropriately.
+ * If out_path is non-null, *out_path is set to the path of the tombstone file.
+ */
+int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it.
* Returns the path of the tombstone, which must be freed using free(). */
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
- uintptr_t abort_msg_address,
- bool dump_sibling_threads, bool* detach_failed,
- int* total_sleep_time_usec);
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid, int signal,
+ int original_si_code, uintptr_t abort_msg_address, bool dump_sibling_threads,
+ bool* detach_failed, int* total_sleep_time_usec);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 5b66366..bd17485 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -282,8 +282,6 @@
" getvar <variable> Display a bootloader variable.\n"
" set_active <suffix> Sets the active slot. If slots are\n"
" not supported, this does nothing.\n"
- " note: suffixes starting with a '-'\n"
- " must use set_active -- <suffix>\n"
" boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
" flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
" Create bootimage and flash it.\n"
@@ -320,9 +318,10 @@
" device supports slots. This will be\n"
" added to all partition names that use\n"
" slots. 'all' can be given to refer\n"
- " to all slots. If this is not given,\n"
- " slotted partitions will default to\n"
- " the current active slot.\n"
+ " to all slots. 'other' can be given to\n"
+ " refer to a non-current slot. If this\n"
+ " flag is not used, slotted partitions\n"
+ " will default to the current active slot.\n"
" -a, --set-active[=<suffix>] Sets the active slot. If no suffix is\n"
" provided, this will default to the value\n"
" given by --slot. If slots are not\n"
@@ -739,12 +738,28 @@
if (!suffixes.empty()) {
return suffixes[0];
} else {
- fprintf(stderr, "No known slots.\n");
- exit(1);
+ die("No known slots.");
}
}
}
+
std::vector<std::string> suffixes = get_suffixes(transport);
+
+ if (strcmp(slot, "other") == 0) {
+ std::string current_slot;
+ if (!fb_getvar(transport, "current-slot", ¤t_slot)) {
+ die("Failed to identify current slot.");
+ }
+ if (!suffixes.empty()) {
+ for (size_t i = 0; i < suffixes.size(); i++) {
+ if (current_slot == suffixes[i])
+ return suffixes[(i+1)%suffixes.size()];
+ }
+ } else {
+ die("No known slots.");
+ }
+ }
+
for (const std::string &suffix : suffixes) {
if (suffix == slot)
return slot;
@@ -1411,7 +1426,6 @@
std::string slot = verify_slot(transport, argv[1], false);
fb_set_active(slot.c_str());
skip(2);
- wants_reboot = true;
} else if(!strcmp(*argv, "oem")) {
argc = do_oem_command(argc, argv);
} else if(!strcmp(*argv, "flashing")) {
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index bbe4486..9876e34 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -83,6 +83,10 @@
#define AID_TLSDATE 1039 /* tlsdate unprivileged user */
#define AID_MEDIA_EX 1040 /* mediaextractor process */
#define AID_AUDIOSERVER 1041 /* audioserver process */
+#define AID_METRICS_COLL 1042 /* metrics_collector process */
+#define AID_METRICSD 1043 /* metricsd process */
+#define AID_WEBSERV 1044 /* webservd process */
+#define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -184,6 +188,10 @@
{ "tlsdate", AID_TLSDATE, },
{ "mediaex", AID_MEDIA_EX, },
{ "audioserver", AID_AUDIOSERVER, },
+ { "metrics_coll", AID_METRICS_COLL },
+ { "metricsd", AID_METRICSD },
+ { "webserv", AID_WEBSERV },
+ { "debuggerd", AID_DEBUGGERD, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/init/Android.mk b/init/Android.mk
index d6cb4e5..66ce8a8 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -52,7 +52,7 @@
service.cpp \
util.cpp \
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES := libbase libselinux
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 10f9d81..d2291bb 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -39,6 +39,7 @@
#include <selinux/label.h>
#include <fs_mgr.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
@@ -53,6 +54,7 @@
#include "log.h"
#include "property_service.h"
#include "service.h"
+#include "signal_handler.h"
#include "util.h"
#define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
@@ -62,6 +64,8 @@
// System call provided by bionic but not in any header file.
extern "C" int init_module(void *, unsigned long, const char *);
+static const int kTerminateServiceDelayMicroSeconds = 50000;
+
static int insmod(const char *filename, const char *options) {
std::string module;
if (!read_file(filename, &module)) {
@@ -608,6 +612,42 @@
return -EINVAL;
}
+ std::string timeout = property_get("ro.build.shutdown_timeout");
+ unsigned int delay = 0;
+
+ if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) {
+ Timer t;
+ // Ask all services to terminate.
+ ServiceManager::GetInstance().ForEachService(
+ [] (Service* s) { s->Terminate(); });
+
+ while (t.duration() < delay) {
+ ServiceManager::GetInstance().ReapAnyOutstandingChildren();
+
+ int service_count = 0;
+ ServiceManager::GetInstance().ForEachService(
+ [&service_count] (Service* s) {
+ // Count the number of services running.
+ // Exclude the console as it will ignore the SIGTERM signal
+ // and not exit.
+ // Note: SVC_CONSOLE actually means "requires console" but
+ // it is only used by the shell.
+ if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
+ service_count++;
+ }
+ });
+
+ if (service_count == 0) {
+ // All terminable services terminated. We can exit early.
+ break;
+ }
+
+ // Wait a bit before recounting the number or running services.
+ usleep(kTerminateServiceDelayMicroSeconds);
+ }
+ NOTICE("Terminating running services took %.02f seconds", t.duration());
+ }
+
return android_reboot_with_callback(cmd, 0, reboot_target,
callback_on_ro_remount);
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 806608e..5c1ae79 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -113,18 +113,6 @@
return check_mac_perms(ctl_name, sctx, cr);
}
-/*
- * Checks permissions for setting system properties.
- * Returns 1 if uid allowed, 0 otherwise.
- */
-static int check_perms(const char *name, char *sctx, struct ucred *cr)
-{
- if(!strncmp(name, "ro.", 3))
- name +=3;
-
- return check_mac_perms(name, sctx, cr);
-}
-
std::string property_get(const char* name) {
char value[PROP_VALUE_MAX] = {0};
__system_property_get(name, value);
@@ -312,7 +300,7 @@
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else {
- if (check_perms(msg.name, source_ctx, &cr)) {
+ if (check_mac_perms(msg.name, source_ctx, &cr)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
diff --git a/init/service.cpp b/init/service.cpp
index 40a4bc7..0ddc484 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
@@ -531,6 +532,17 @@
StopOrReset(SVC_DISABLED);
}
+void Service::Terminate() {
+ flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
+ flags_ |= SVC_DISABLED;
+ if (pid_) {
+ NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(),
+ pid_);
+ kill(-pid_, SIGTERM);
+ NotifyStateChange("stopping");
+ }
+}
+
void Service::Restart() {
if (flags_ & SVC_RUNNING) {
/* Stop, wait, then start the service. */
@@ -724,9 +736,9 @@
return nullptr;
}
-void ServiceManager::ForEachService(void (*func)(Service* svc)) const {
+void ServiceManager::ForEachService(std::function<void(Service*)> callback) const {
for (const auto& s : services_) {
- func(s.get());
+ callback(s.get());
}
}
@@ -767,6 +779,53 @@
INFO("\n");
}
+bool ServiceManager::ReapOneProcess() {
+ int status;
+ pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
+ if (pid == 0) {
+ return false;
+ } else if (pid == -1) {
+ ERROR("waitpid failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ Service* svc = FindServiceByPid(pid);
+
+ std::string name;
+ if (svc) {
+ name = android::base::StringPrintf("Service '%s' (pid %d)",
+ svc->name().c_str(), pid);
+ } else {
+ name = android::base::StringPrintf("Untracked pid %d", pid);
+ }
+
+ if (WIFEXITED(status)) {
+ NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status));
+ } else if (WIFSTOPPED(status)) {
+ NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status));
+ } else {
+ NOTICE("%s state changed", name.c_str());
+ }
+
+ if (!svc) {
+ return true;
+ }
+
+ if (svc->Reap()) {
+ waiting_for_exec = false;
+ RemoveService(*svc);
+ }
+
+ return true;
+}
+
+void ServiceManager::ReapAnyOutstandingChildren() {
+ while (ReapOneProcess()) {
+ }
+}
+
bool ServiceParser::ParseSection(const std::vector<std::string>& args,
std::string* err) {
if (args.size() < 3) {
diff --git a/init/service.h b/init/service.h
index 10eb736..35abde9 100644
--- a/init/service.h
+++ b/init/service.h
@@ -82,6 +82,7 @@
bool Enable();
void Reset();
void Stop();
+ void Terminate();
void Restart();
void RestartIfNeeded(time_t& process_needs_restart);
bool Reap();
@@ -167,17 +168,22 @@
Service* FindServiceByName(const std::string& name) const;
Service* FindServiceByPid(pid_t pid) const;
Service* FindServiceByKeychord(int keychord_id) const;
- void ForEachService(void (*func)(Service* svc)) const;
+ void ForEachService(std::function<void(Service*)> callback) const;
void ForEachServiceInClass(const std::string& classname,
void (*func)(Service* svc)) const;
void ForEachServiceWithFlags(unsigned matchflags,
void (*func)(Service* svc)) const;
+ void ReapAnyOutstandingChildren();
void RemoveService(const Service& svc);
void DumpState() const;
private:
ServiceManager();
+ // Cleans up a child process that exited.
+ // Returns true iff a children was cleaned up.
+ bool ReapOneProcess();
+
static int exec_count_; // Every service needs a unique name.
std::vector<std::unique_ptr<Service>> services_;
};
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index e7d42cb..ea483d4 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -37,62 +37,12 @@
static int signal_write_fd = -1;
static int signal_read_fd = -1;
-static std::string DescribeStatus(int status) {
- if (WIFEXITED(status)) {
- return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- return android::base::StringPrintf("killed by signal %d", WTERMSIG(status));
- } else if (WIFSTOPPED(status)) {
- return android::base::StringPrintf("stopped by signal %d", WSTOPSIG(status));
- } else {
- return "state changed";
- }
-}
-
-static bool wait_for_one_process() {
- int status;
- pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
- if (pid == 0) {
- return false;
- } else if (pid == -1) {
- ERROR("waitpid failed: %s\n", strerror(errno));
- return false;
- }
-
- Service* svc = ServiceManager::GetInstance().FindServiceByPid(pid);
-
- std::string name;
- if (svc) {
- name = android::base::StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
- } else {
- name = android::base::StringPrintf("Untracked pid %d", pid);
- }
-
- NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
-
- if (!svc) {
- return true;
- }
-
- if (svc->Reap()) {
- waiting_for_exec = false;
- ServiceManager::GetInstance().RemoveService(*svc);
- }
-
- return true;
-}
-
-static void reap_any_outstanding_children() {
- while (wait_for_one_process()) {
- }
-}
-
static void handle_signal() {
// Clear outstanding requests.
char buf[32];
read(signal_read_fd, buf, sizeof(buf));
- reap_any_outstanding_children();
+ ServiceManager::GetInstance().ReapAnyOutstandingChildren();
}
static void SIGCHLD_handler(int) {
@@ -119,7 +69,7 @@
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, 0);
- reap_any_outstanding_children();
+ ServiceManager::GetInstance().ReapAnyOutstandingChildren();
register_epoll_handler(signal_read_fd, handle_signal);
}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 878feb8..ee883f0 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -71,6 +71,7 @@
// $(LOCAL_PATH)/event.logtags)
// so make sure we do not regret hard-coding it as follows:
"-DLIBLOG_LOG_TAG=1005",
+ "-DSNET_EVENT_LOG_TAG=1397638484",
],
compile_multilib: "both",
stl: "none",
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 4ab5006..a183db8 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -22,7 +22,7 @@
# 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
# $(LOCAL_PATH)/event.logtags)
# so make sure we do not regret hard-coding it as follows:
-liblog_cflags := -DLIBLOG_LOG_TAG=1005 -DSNET_EVENT_LOG_TAG=1397638484
+liblog_cflags := -DLIBLOG_LOG_TAG=1005
liblog_host_sources := logd_write.c log_event_write.c fake_log_device.c event.logtags
liblog_target_sources := logd_write.c log_event_write.c event_tag_map.c log_time.cpp log_is_loggable.c
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index ec86e6b..5406c50 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -221,48 +221,50 @@
return -EPERM;
}
} else if (log_id == LOG_ID_EVENTS) {
+ static atomic_uintptr_t map;
+ int ret;
+ const char *tag;
+ EventTagMap *m, *f;
+
if (vec[0].iov_len < 4) {
return -EINVAL;
}
- if (((uint32_t *)vec[0].iov_base)[0] != htole32(SNET_EVENT_LOG_TAG)) {
- static atomic_uintptr_t map;
- int ret;
- const char *tag = NULL;
- EventTagMap *m, *f = NULL;
- m = (EventTagMap *)atomic_load(&map);
+ tag = NULL;
+ f = NULL;
+ m = (EventTagMap *)atomic_load(&map);
+
+ if (!m) {
+ ret = trylock();
+ m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
if (!m) {
- ret = trylock();
- m = (EventTagMap *)atomic_load(&map); /* trylock flush cache */
- if (!m) {
- m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
- if (ret) { /* trylock failed, local copy, mark for close */
- f = m;
- } else {
- if (!m) { /* One chance to open map file */
- m = (EventTagMap *)(uintptr_t)-1LL;
- }
- atomic_store(&map, (uintptr_t)m);
+ m = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ if (ret) { /* trylock failed, use local copy, mark for close */
+ f = m;
+ } else {
+ if (!m) { /* One chance to open map file */
+ m = (EventTagMap *)(uintptr_t)-1LL;
}
- }
- if (!ret) { /* trylock succeeded, unlock */
- unlock();
+ atomic_store(&map, (uintptr_t)m);
}
}
- if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
- tag = android_lookupEventTag(
+ if (!ret) { /* trylock succeeded, unlock */
+ unlock();
+ }
+ }
+ if (m && (m != (EventTagMap *)(uintptr_t)-1LL)) {
+ tag = android_lookupEventTag(
m,
htole32(((uint32_t *)vec[0].iov_base)[0]));
- }
- ret = __android_log_is_loggable(ANDROID_LOG_INFO,
- tag,
- ANDROID_LOG_VERBOSE);
- if (f) { /* local copy marked for close */
- android_closeEventTagMap(f);
- }
- if (!ret) {
- return -EPERM;
- }
+ }
+ ret = __android_log_is_loggable(ANDROID_LOG_INFO,
+ tag,
+ ANDROID_LOG_VERBOSE);
+ if (f) { /* local copy marked for close */
+ android_closeEventTagMap(f);
+ }
+ if (!ret) {
+ return -EPERM;
}
} else {
/* Validate the incoming tag, tag content can not split across iovec */
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 403a4f4..6e6b0b9 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -48,7 +48,9 @@
"libm.so:"
"libOpenMAXAL.so:"
"libOpenSLES.so:"
+ "libRS.so:"
"libstdc++.so:"
+ "libwebviewchromium_plat_support.so:"
"libz.so";
class LibraryNamespaces {
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 956ed30..e0a9f7f 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -253,6 +253,7 @@
int prefixlen) {
int ifindex, s, len, ret;
struct sockaddr_storage ss;
+ int saved_errno;
void *addr;
size_t addrlen;
struct {
@@ -317,15 +318,21 @@
memcpy(RTA_DATA(rta), addr, addrlen);
s = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
- if (send(s, &req, req.n.nlmsg_len, 0) < 0) {
- close(s);
+ if (s < 0) {
return -errno;
}
+ if (send(s, &req, req.n.nlmsg_len, 0) < 0) {
+ saved_errno = errno;
+ close(s);
+ return -saved_errno;
+ }
+
len = recv(s, buf, sizeof(buf), 0);
+ saved_errno = errno;
close(s);
if (len < 0) {
- return -errno;
+ return -saved_errno;
}
// Parse the acknowledgement to find the return code.
diff --git a/logd/Android.mk b/logd/Android.mk
index d19c255..feca8d5 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -38,9 +38,7 @@
# event_flag := $(call event_logtags,auditd)
# event_flag += $(call event_logtags,logd)
# so make sure we do not regret hard-coding it as follows:
-event_flag := -DAUDITD_LOG_TAG=1003 \
- -DLOGD_LOG_TAG=1004 \
- -DSNET_EVENT_LOG_TAG=1397638484
+event_flag := -DAUDITD_LOG_TAG=1003 -DLOGD_LOG_TAG=1004
LOCAL_CFLAGS := -Werror $(event_flag)
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index cb3d1c2..48036d3 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -36,7 +36,7 @@
mLogMask(logMask),
mPid(pid),
mStart(start),
- mTimeout(timeout) {
+ mTimeout((start > 1) ? timeout : 0) {
}
// runSocketCommand is called once for every open client on the
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1b829c6..cdf5d08 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -32,7 +32,7 @@
#include "LogReader.h"
// Default
-#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
+#define LOG_BUFFER_SIZE (256 * 1024) // Tuned with ro.logd.size per-platform
#define log_buffer_size(id) mMaxSize[id]
#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
@@ -109,6 +109,9 @@
}
log_id_for_each(i) {
+ mLastSet[i] = false;
+ mLast[i] = mLogElements.begin();
+
char key[PROP_NAME_MAX];
snprintf(key, sizeof(key), "%s.%s",
@@ -205,20 +208,16 @@
LogBufferElement *elem = new LogBufferElement(log_id, realtime,
uid, pid, tid, msg, len);
- if (log_id != LOG_ID_SECURITY) { // whitelist LOG_ID_SECURITY
+ if (log_id != LOG_ID_SECURITY) {
int prio = ANDROID_LOG_INFO;
- const char *tag = (const char *)-1;
+ const char *tag = NULL;
if (log_id == LOG_ID_EVENTS) {
- // whitelist "snet_event_log"
- if (elem->getTag() != SNET_EVENT_LOG_TAG) {
- tag = android::tagToName(elem->getTag());
- }
+ tag = android::tagToName(elem->getTag());
} else {
prio = *msg;
tag = msg + 1;
}
- if ((tag != (const char *)-1) &&
- !__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+ if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
// Log traffic received to total
pthread_mutex_lock(&mLogElementsLock);
stats.add(elem);
@@ -333,7 +332,15 @@
}
}
+ bool setLast = mLastSet[id] && (it == mLast[id]);
it = mLogElements.erase(it);
+ if (setLast) {
+ if (it == mLogElements.end()) { // unlikely
+ mLastSet[id] = false;
+ } else {
+ mLast[id] = it;
+ }
+ }
if (coalesce) {
stats.erase(element);
} else {
@@ -494,7 +501,8 @@
if (caller_uid != AID_ROOT) {
// Only here if clearAll condition (pruneRows == ULONG_MAX)
- for(it = mLogElements.begin(); it != mLogElements.end();) {
+ it = mLastSet[id] ? mLast[id] : mLogElements.begin();
+ while (it != mLogElements.end()) {
LogBufferElement *element = *it;
if ((element->getLogId() != id) || (element->getUid() != caller_uid)) {
@@ -502,6 +510,11 @@
continue;
}
+ if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
+ mLast[id] = it;
+ mLastSet[id] = true;
+ }
+
if (oldest && (oldest->mStart <= element->getSequence())) {
busy = true;
if (oldest->mTimeout.tv_sec || oldest->mTimeout.tv_nsec) {
@@ -570,7 +583,7 @@
bool kick = false;
bool leading = true;
- it = mLogElements.begin();
+ it = mLastSet[id] ? mLast[id] : mLogElements.begin();
// Perform at least one mandatory garbage collection cycle in following
// - clear leading chatty tags
// - coalesce chatty tags
@@ -619,6 +632,11 @@
continue;
}
+ if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
+ mLast[id] = it;
+ mLastSet[id] = true;
+ }
+
unsigned short dropped = element->getDropped();
// remove any leading drops
@@ -729,7 +747,7 @@
bool whitelist = false;
bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
- it = mLogElements.begin();
+ it = mLastSet[id] ? mLast[id] : mLogElements.begin();
while((pruneRows > 0) && (it != mLogElements.end())) {
LogBufferElement *element = *it;
@@ -738,6 +756,11 @@
continue;
}
+ if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
+ mLast[id] = it;
+ mLastSet[id] = true;
+ }
+
if (oldest && (oldest->mStart <= element->getSequence())) {
busy = true;
if (whitelist) {
@@ -768,7 +791,7 @@
// Do not save the whitelist if we are reader range limited
if (whitelist && (pruneRows > 0)) {
- it = mLogElements.begin();
+ it = mLastSet[id] ? mLast[id] : mLogElements.begin();
while((it != mLogElements.end()) && (pruneRows > 0)) {
LogBufferElement *element = *it;
@@ -777,6 +800,11 @@
continue;
}
+ if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
+ mLast[id] = it;
+ mLastSet[id] = true;
+ }
+
if (oldest && (oldest->mStart <= element->getSequence())) {
busy = true;
if (stats.sizes(id) > (2 * log_buffer_size(id))) {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 2667e78..03739c7 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -82,6 +82,9 @@
LogStatistics stats;
PruneList mPrune;
+ // watermark for last per log id
+ LogBufferElementCollection::iterator mLast[LOG_ID_MAX];
+ bool mLastSet[LOG_ID_MAX];
// watermark of any worst/chatty uid processing
typedef std::unordered_map<uid_t,
LogBufferElementCollection::iterator>
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 5348a2d..846dd7c 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -15,6 +15,7 @@
*/
#include <limits.h>
+#include <sys/cdefs.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -46,7 +47,7 @@
+ LOGGER_ENTRY_MAX_PAYLOAD];
struct iovec iov = { buffer, sizeof(buffer) };
- char control[CMSG_SPACE(sizeof(struct ucred))];
+ char control[CMSG_SPACE(sizeof(struct ucred))] __aligned(4);
struct msghdr hdr = {
NULL,
0,
diff --git a/logd/README.property b/logd/README.property
index 75d9eb0..22f86b9 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -15,7 +15,11 @@
persist.logd.size number ro Global default size of the buffer for
all log ids at initial startup, at
runtime use: logcat -b all -G <value>
-ro.logd.size number svelte default for persist.logd.size
+ro.logd.size number svelte default for persist.logd.size. Larger
+ platform default sizes than 256KB are
+ known to not scale well under log spam
+ pressure. Address the spam first,
+ resist increasing the log buffer.
persist.logd.size.<buffer> number ro Size of the buffer for <buffer> log
ro.logd.size.<buffer> number svelte default for persist.logd.size.<buffer>
ro.config.low_ram bool false if true, logd.statistics, logd.kernel
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 2cd1f7b..7381703 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -28,7 +28,7 @@
collectors/cpu_usage_collector.cc \
collectors/disk_usage_collector.cc \
metrics_collector.cc \
- metrics_collector_service_trampoline.cc \
+ metrics_collector_service_impl.cc \
persistent_integer.cc
metricsd_common := \
@@ -102,13 +102,13 @@
# ==========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libmetricscollectorservice
+LOCAL_CLANG := true
LOCAL_SHARED_LIBRARIES := libbinder libbrillo-binder libchrome libutils
LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := \
aidl/android/brillo/metrics/IMetricsCollectorService.aidl \
- metrics_collector_service_impl.cc \
metrics_collector_service_client.cc
include $(BUILD_STATIC_LIBRARY)
diff --git a/metricsd/README b/metricsd/README
deleted file mode 100644
index d4c9a0e..0000000
--- a/metricsd/README
+++ /dev/null
@@ -1,150 +0,0 @@
-Copyright (C) 2015 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.
-
-================================================================================
-
-The Chrome OS "metrics" package contains utilities for client-side user metric
-collection.
-When Chrome is installed, Chrome will take care of aggregating and uploading the
-metrics to the UMA server.
-When Chrome is not installed (embedded build) and the metrics_uploader USE flag
-is set, metrics_daemon will aggregate and upload the metrics itself.
-
-
-================================================================================
-The Metrics Library: libmetrics
-================================================================================
-
-libmetrics is a small library that implements the basic C and C++ API for
-metrics collection. All metrics collection is funneled through this library. The
-easiest and recommended way for a client-side module to collect user metrics is
-to link libmetrics and use its APIs to send metrics to Chrome for transport to
-UMA. In order to use the library in a module, you need to do the following:
-
-- Add a dependence (DEPEND and RDEPEND) on chromeos-base/metrics to the module's
- ebuild.
-
-- Link the module with libmetrics (for example, by passing -lmetrics to the
- module's link command). Both libmetrics.so and libmetrics.a are built and
- installed under $SYSROOT/usr/lib/. Note that by default -lmetrics will link
- against libmetrics.so, which is preferred.
-
-- To access the metrics library API in the module, include the
- <metrics/metrics_library.h> header file. The file is installed in
- $SYSROOT/usr/include/ when the metrics library is built and installed.
-
-- The API is documented in metrics_library.h under src/platform/metrics/. Before
- using the API methods, a MetricsLibrary object needs to be constructed and
- initialized through its Init method.
-
- For more information on the C API see c_metrics_library.h.
-
-- Samples are sent to Chrome only if the "/home/chronos/Consent To Send Stats"
- file exists or the metrics are declared enabled in the policy file (see the
- AreMetricsEnabled API method).
-
-- On the target platform, shortly after the sample is sent, it should be visible
- in Chrome through "about:histograms".
-
-
-================================================================================
-Histogram Naming Convention
-================================================================================
-
-Use TrackerArea.MetricName. For example:
-
-Platform.DailyUseTime
-Network.TimeToDrop
-
-
-================================================================================
-Server Side
-================================================================================
-
-If the histogram data is visible in about:histograms, it will be sent by an
-official Chrome build to UMA, assuming the user has opted into metrics
-collection. To make the histogram visible on "chromedashboard", the histogram
-description XML file needs to be updated (steps 2 and 3 after following the
-"Details on how to add your own histograms" link under the Histograms tab).
-Include the string "Chrome OS" in the histogram description so that it's easier
-to distinguish Chrome OS specific metrics from general Chrome histograms.
-
-The UMA server logs and keeps the collected field data even if the metric's name
-is not added to the histogram XML. However, the dashboard histogram for that
-metric will show field data as of the histogram XML update date; it will not
-include data for older dates. If past data needs to be displayed, manual
-server-side intervention is required. In other words, one should assume that
-field data collection starts only after the histogram XML has been updated.
-
-
-================================================================================
-The Metrics Client: metrics_client
-================================================================================
-
-metrics_client is a simple shell command-line utility for sending histogram
-samples and user actions. It's installed under /usr/bin on the target platform
-and uses libmetrics to send the data to Chrome. The utility is useful for
-generating metrics from shell scripts.
-
-For usage information and command-line options, run "metrics_client" on the
-target platform or look for "Usage:" in metrics_client.cc.
-
-
-================================================================================
-The Metrics Daemon: metrics_daemon
-================================================================================
-
-metrics_daemon is a daemon that runs in the background on the target platform
-and is intended for passive or ongoing metrics collection, or metrics collection
-requiring feedback from multiple modules. For example, it listens to D-Bus
-signals related to the user session and screen saver states to determine if the
-user is actively using the device or not and generates the corresponding
-data. The metrics daemon uses libmetrics to send the data to Chrome.
-
-The recommended way to generate metrics data from a module is to link and use
-libmetrics directly. However, the module could instead send signals to or
-communicate in some alternative way with the metrics daemon. Then the metrics
-daemon needs to monitor for the relevant events and take appropriate action --
-for example, aggregate data and send the histogram samples.
-
-
-================================================================================
-FAQ
-================================================================================
-
-Q. What should my histogram's |min| and |max| values be set at?
-
-A. You should set the values to a range that covers the vast majority of samples
- that would appear in the field. Note that samples below the |min| will still
- be collected in the underflow bucket and samples above the |max| will end up
- in the overflow bucket. Also, the reported mean of the data will be correct
- regardless of the range.
-
-Q. How many buckets should I use in my histogram?
-
-A. You should allocate as many buckets as necessary to perform proper analysis
- on the collected data. Note, however, that the memory allocated in Chrome for
- each histogram is proportional to the number of buckets. Therefore, it is
- strongly recommended to keep this number low (e.g., 50 is normal, while 100
- is probably high).
-
-Q. When should I use an enumeration (linear) histogram vs. a regular
- (exponential) histogram?
-
-A. Enumeration histograms should really be used only for sampling enumerated
- events and, in some cases, percentages. Normally, you should use a regular
- histogram with exponential bucket layout that provides higher resolution at
- the low end of the range and lower resolution at the high end. Regular
- histograms are generally used for collecting performance data (e.g., timing,
- memory usage, power) as well as aggregated event counts.
diff --git a/metricsd/README.md b/metricsd/README.md
new file mode 100644
index 0000000..8d4828c
--- /dev/null
+++ b/metricsd/README.md
@@ -0,0 +1,124 @@
+Metricsd
+========
+
+The metricsd daemon is used to gather metrics from the platform and application,
+aggregate them and upload them periodically to a server.
+The metrics will then be available in their aggregated form to the developer
+for analysis.
+
+Three components are provided to interact with `metricsd`: `libmetrics`,
+`metrics_collector` and `metrics_client`.
+
+The Metrics Library: libmetrics
+-------------------------------
+
+`libmetrics` is a small library that implements the basic C++ API for
+metrics collection. All metrics collection is funneled through this library. The
+easiest and recommended way for a client-side module to collect user metrics is
+to link `libmetrics` and use its APIs to send metrics to `metricsd` for transport to
+UMA. In order to use the library in a module, you need to do the following:
+
+- Add a dependency on the shared library in your Android.mk file:
+ `LOCAL_SHARED_LIBRARIES += libmetrics`
+
+- To access the metrics library API in the module, include the
+ <metrics/metrics_library.h> header file.
+
+- The API is documented in `metrics_library.h`. Before using the API methods, a
+ MetricsLibrary object needs to be constructed and initialized through its
+ Init method.
+
+- Samples are uploaded only if the `/data/misc/metrics/enabled` file exists.
+
+
+Server Side
+-----------
+
+You will be able to see all uploaded metrics on the metrics dashboard,
+accessible via the developer console.
+
+*** note
+It usually takes a day for metrics to be available on the dashboard.
+***
+
+
+The Metrics Client: metrics_client
+----------------------------------
+
+`metrics_client` is a simple shell command-line utility for sending histogram
+samples and querying `metricsd`. It's installed under `/system/bin` on the target
+platform and uses `libmetrics`.
+
+For usage information and command-line options, run `metrics_client` on the
+target platform or look for "Usage:" in `metrics_client.cc`.
+
+
+The Metrics Daemon: metricsd
+----------------------------
+
+`metricsd` is the daemon that listens for metrics logging calls (via Binder),
+aggregates the metrics and uploads them periodically. This daemon should start as
+early as possible so that depending daemons can log at any time.
+
+`metricsd` is made of two threads that work as follows:
+
+* The binder thread listens for one-way Binder calls, aggregates the metrics in
+ memory (via `base::StatisticsRecorder`) and increments the crash counters when a
+ crash is reported. This thread is kept as simple as possible to ensure the
+ maximum throughput possible.
+* The uploader thread takes care of backing up the metrics to disk periodically
+ (to avoid losing metrics on crashes), collecting metadata about the client
+ (version number, channel, etc..) and uploading the metrics periodically to the
+ server.
+
+
+The Metrics Collector: metrics_collector
+----------------------------------------
+
+metrics_collector is a daemon that runs in the background on the target platform,
+gathers health information about the system and maintains long running counters
+(ex: number of crashes per week).
+
+The recommended way to generate metrics data from a module is to link and use
+libmetrics directly. However, we may not want to add a dependency on libmetrics
+to some modules (ex: kernel). In this case, we can add a collector to
+metrics_collector that will, for example, take measurements and report them
+periodically to metricsd (this is the case for the disk utilization histogram).
+
+
+FAQ
+---
+
+### What should my histogram's |min| and |max| values be set at?
+
+You should set the values to a range that covers the vast majority of samples
+that would appear in the field. Note that samples below the |min| will still
+be collected in the underflow bucket and samples above the |max| will end up
+in the overflow bucket. Also, the reported mean of the data will be correct
+regardless of the range.
+
+### How many buckets should I use in my histogram?
+
+You should allocate as many buckets as necessary to perform proper analysis
+on the collected data. Note, however, that the memory allocated in metricsd
+for each histogram is proportional to the number of buckets. Therefore, it is
+strongly recommended to keep this number low (e.g., 50 is normal, while 100
+is probably high).
+
+### When should I use an enumeration (linear) histogram vs. a regular (exponential) histogram?
+
+Enumeration histograms should really be used only for sampling enumerated
+events and, in some cases, percentages. Normally, you should use a regular
+histogram with exponential bucket layout that provides higher resolution at
+the low end of the range and lower resolution at the high end. Regular
+histograms are generally used for collecting performance data (e.g., timing,
+memory usage, power) as well as aggregated event counts.
+
+### How can I test that my histogram was reported correctly?
+
+* Make sure no error messages appear in logcat when you log a sample.
+* Run `metrics_client -d` to dump the currently aggregated metrics. Your
+ histogram should appear in the list.
+* Make sure that the aggregated metrics were uploaded to the server successfully
+ (check for an OK message from `metricsd` in logcat).
+* After a day, your histogram should be available on the dashboard.
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index a5daab5..2cf2338 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -30,12 +30,13 @@
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <brillo/binder_watcher.h>
#include <brillo/osrelease_reader.h>
#include <dbus/dbus.h>
#include <dbus/message.h>
#include "constants.h"
-#include "metrics_collector_service_trampoline.h"
+#include "metrics_collector_service_impl.h"
using base::FilePath;
using base::StringPrintf;
@@ -70,6 +71,7 @@
const char kVmStatFileName[] = "/proc/vmstat";
const char kWeaveComponent[] = "metrics";
+const char kWeaveTrait[] = "_metrics";
} // namespace
@@ -128,10 +130,18 @@
version_cumulative_cpu_use_->Set(0);
}
- // Start metricscollectorservice via trampoline
- MetricsCollectorServiceTrampoline metricscollectorservice_trampoline(this);
- metricscollectorservice_trampoline.Run();
+ // Start metricscollectorservice
+ android::sp<BnMetricsCollectorServiceImpl> metrics_collector_service =
+ new BnMetricsCollectorServiceImpl(this);
+ android::status_t status = android::defaultServiceManager()->addService(
+ metrics_collector_service->getInterfaceDescriptor(),
+ metrics_collector_service);
+ CHECK(status == android::OK)
+ << "failed to register service metricscollectorservice";
+ // Watch Binder events in the main loop
+ brillo::BinderWatcher binder_watcher;
+ CHECK(binder_watcher.Init()) << "Binder FD watcher init failed";
return brillo::DBusDaemon::Run();
}
@@ -225,23 +235,15 @@
bus_->AssertOnDBusThread();
CHECK(bus_->SetUpAsyncOperations());
- device_ = weaved::Device::CreateInstance(
- bus_,
- base::Bind(&MetricsCollector::UpdateWeaveState, base::Unretained(this)));
- device_->AddComponent(kWeaveComponent, {"_metrics"});
- device_->AddCommandHandler(
- kWeaveComponent,
- "_metrics.enableAnalyticsReporting",
- base::Bind(&MetricsCollector::OnEnableMetrics, base::Unretained(this)));
- device_->AddCommandHandler(
- kWeaveComponent,
- "_metrics.disableAnalyticsReporting",
- base::Bind(&MetricsCollector::OnDisableMetrics, base::Unretained(this)));
+ weave_service_subscription_ = weaved::Service::Connect(
+ brillo::MessageLoop::current(),
+ base::Bind(&MetricsCollector::OnWeaveServiceConnected,
+ weak_ptr_factory_.GetWeakPtr()));
latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
- base::Unretained(this)),
+ weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
return EX_OK;
@@ -251,12 +253,28 @@
brillo::DBusDaemon::OnShutdown(return_code);
}
-void MetricsCollector::OnEnableMetrics(
- const std::weak_ptr<weaved::Command>& cmd) {
- auto command = cmd.lock();
- if (!command)
+void MetricsCollector::OnWeaveServiceConnected(
+ const std::weak_ptr<weaved::Service>& service) {
+ service_ = service;
+ auto weave_service = service_.lock();
+ if (!weave_service)
return;
+ weave_service->AddComponent(kWeaveComponent, {kWeaveTrait}, nullptr);
+ weave_service->AddCommandHandler(
+ kWeaveComponent, kWeaveTrait, "enableAnalyticsReporting",
+ base::Bind(&MetricsCollector::OnEnableMetrics,
+ weak_ptr_factory_.GetWeakPtr()));
+ weave_service->AddCommandHandler(
+ kWeaveComponent, kWeaveTrait, "disableAnalyticsReporting",
+ base::Bind(&MetricsCollector::OnDisableMetrics,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ UpdateWeaveState();
+}
+
+void MetricsCollector::OnEnableMetrics(
+ std::unique_ptr<weaved::Command> command) {
if (base::WriteFile(
shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
0) {
@@ -271,11 +289,7 @@
}
void MetricsCollector::OnDisableMetrics(
- const std::weak_ptr<weaved::Command>& cmd) {
- auto command = cmd.lock();
- if (!command)
- return;
-
+ std::unique_ptr<weaved::Command> command) {
if (!base::DeleteFile(
shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
PLOG(ERROR) << "Could not delete the consent file.";
@@ -289,16 +303,16 @@
}
void MetricsCollector::UpdateWeaveState() {
- if (!device_)
+ auto weave_service = service_.lock();
+ if (!weave_service)
return;
std::string enabled =
metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
- if (!device_->SetStateProperty(kWeaveComponent,
- "_metrics.analyticsReportingState",
- enabled,
- nullptr)) {
+ if (!weave_service->SetStateProperty(kWeaveComponent, kWeaveTrait,
+ "analyticsReportingState", enabled,
+ nullptr)) {
LOG(ERROR) << "failed to update weave's state";
}
}
@@ -372,8 +386,8 @@
}
base::TimeDelta waitDelta = base::TimeDelta::FromSeconds(wait);
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&MetricsCollector::MeminfoCallback, base::Unretained(this),
- waitDelta),
+ base::Bind(&MetricsCollector::MeminfoCallback,
+ weak_ptr_factory_.GetWeakPtr(), waitDelta),
waitDelta);
}
@@ -387,8 +401,8 @@
// Make both calls even if the first one fails.
if (ProcessMeminfo(meminfo_raw)) {
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&MetricsCollector::MeminfoCallback, base::Unretained(this),
- wait),
+ base::Bind(&MetricsCollector::MeminfoCallback,
+ weak_ptr_factory_.GetWeakPtr(), wait),
wait);
}
}
@@ -555,7 +569,8 @@
return;
}
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&MetricsCollector::MemuseCallback, base::Unretained(this)),
+ base::Bind(&MetricsCollector::MemuseCallback,
+ weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(interval));
}
@@ -741,6 +756,6 @@
UpdateStats(TimeTicks::Now(), Time::Now());
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
- base::Unretained(this)),
+ weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
}
diff --git a/metricsd/metrics_collector.h b/metricsd/metrics_collector.h
index 45ef63d..ca4ae52 100644
--- a/metricsd/metrics_collector.h
+++ b/metricsd/metrics_collector.h
@@ -25,10 +25,12 @@
#include <vector>
#include <base/files/file_path.h>
+#include <base/memory/weak_ptr.h>
#include <base/time/time.h>
+#include <brillo/binder_watcher.h>
#include <brillo/daemons/dbus_daemon.h>
#include <libweaved/command.h>
-#include <libweaved/device.h>
+#include <libweaved/service.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "collectors/averaged_statistics_collector.h"
@@ -114,10 +116,10 @@
};
// Enables metrics reporting.
- void OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd);
+ void OnEnableMetrics(std::unique_ptr<weaved::Command> command);
// Disables metrics reporting.
- void OnDisableMetrics(const std::weak_ptr<weaved::Command>& cmd);
+ void OnDisableMetrics(std::unique_ptr<weaved::Command> command);
// Updates the weave device state.
void UpdateWeaveState();
@@ -216,6 +218,10 @@
// Reads a string from a file and converts it to uint64_t.
static bool ReadFileToUint64(const base::FilePath& path, uint64_t* value);
+ // Callback invoked when a connection to weaved's service is established
+ // over Binder interface.
+ void OnWeaveServiceConnected(const std::weak_ptr<weaved::Service>& service);
+
// VARIABLES
// Test mode.
@@ -272,7 +278,10 @@
unique_ptr<DiskUsageCollector> disk_usage_collector_;
unique_ptr<AveragedStatisticsCollector> averaged_stats_collector_;
- std::unique_ptr<weaved::Device> device_;
+ unique_ptr<weaved::Service::Subscription> weave_service_subscription_;
+ std::weak_ptr<weaved::Service> service_;
+
+ base::WeakPtrFactory<MetricsCollector> weak_ptr_factory_{this};
};
#endif // METRICS_METRICS_COLLECTOR_H_
diff --git a/metricsd/metrics_collector.rc b/metricsd/metrics_collector.rc
index 2e7e0ae..3dcb2d7 100644
--- a/metricsd/metrics_collector.rc
+++ b/metricsd/metrics_collector.rc
@@ -1,4 +1,4 @@
service metricscollector /system/bin/metrics_collector --foreground --logtosyslog
class late_start
- user system
- group system dbus
+ user metrics_coll
+ group metrics_coll dbus
diff --git a/metricsd/metrics_collector_service_impl.cc b/metricsd/metrics_collector_service_impl.cc
index dbb0578..4d9a05a 100644
--- a/metricsd/metrics_collector_service_impl.cc
+++ b/metricsd/metrics_collector_service_impl.cc
@@ -18,27 +18,18 @@
#include <binder/IServiceManager.h>
#include <binder/Status.h>
-#include <brillo/binder_watcher.h>
#include <utils/Errors.h>
-#include "metrics_collector_service_trampoline.h"
+#include "metrics_collector.h"
using namespace android;
BnMetricsCollectorServiceImpl::BnMetricsCollectorServiceImpl(
- MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline) {
- metrics_collector_service_trampoline_ = metrics_collector_service_trampoline;
-}
-
-void BnMetricsCollectorServiceImpl::Run() {
- status_t status =
- defaultServiceManager()->addService(getInterfaceDescriptor(), this);
- CHECK(status == OK) << "libmetricscollectorservice: failed to add service";
- binder_watcher_.reset(new ::brillo::BinderWatcher);
- CHECK(binder_watcher_->Init()) << "Binder FD watcher init failed";
+ MetricsCollector* metrics_collector)
+ : metrics_collector_(metrics_collector) {
}
android::binder::Status BnMetricsCollectorServiceImpl::notifyUserCrash() {
- metrics_collector_service_trampoline_->ProcessUserCrash();
+ metrics_collector_->ProcessUserCrash();
return android::binder::Status::ok();
}
diff --git a/metricsd/metrics_collector_service_impl.h b/metricsd/metrics_collector_service_impl.h
index bdcab50..8db418a 100644
--- a/metricsd/metrics_collector_service_impl.h
+++ b/metricsd/metrics_collector_service_impl.h
@@ -18,45 +18,31 @@
#define METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
// metrics_collector binder service implementation. Constructed by
-// MetricsCollectorServiceTrampoline, which we use to call back into
-// MetricsCollector. The trampoline isolates us from the -frtti code of
-// metrics_collector / libbrillo.
+// MetricsCollector.
#include "android/brillo/metrics/BnMetricsCollectorService.h"
-#include <memory>
-
#include <binder/Status.h>
-#include <brillo/binder_watcher.h>
-class MetricsCollectorServiceTrampoline;
-
-//#include "metrics_collector_service_trampoline.h"
+class MetricsCollector;
class BnMetricsCollectorServiceImpl
: public android::brillo::metrics::BnMetricsCollectorService {
public:
- // Passed a this pointer from the MetricsCollectorServiceTrampoline
- // object that constructs us.
+ // Passed a this pointer from the MetricsCollector object that constructs us.
explicit BnMetricsCollectorServiceImpl(
- MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline);
+ MetricsCollector* metrics_collector_service);
virtual ~BnMetricsCollectorServiceImpl() = default;
- // Starts the binder main loop.
- void Run();
-
// Called by crash_reporter to report a userspace crash event. We relay
- // this to MetricsCollector using the trampoline.
+ // this to MetricsCollector.
android::binder::Status notifyUserCrash();
private:
- // Trampoline object that constructs us, we use this to call MetricsCollector
- // methods via the trampoline.
- MetricsCollectorServiceTrampoline* metrics_collector_service_trampoline_;
-
- // BinderWatcher object we construct for handling Binder traffic
- std::unique_ptr<brillo::BinderWatcher> binder_watcher_;
+ // MetricsCollector object that constructs us, we use this to call back
+ // to it.
+ MetricsCollector* metrics_collector_;
};
#endif // METRICSD_METRICS_COLLECTOR_SERVICE_IMPL_H_
diff --git a/metricsd/metrics_collector_service_trampoline.cc b/metricsd/metrics_collector_service_trampoline.cc
deleted file mode 100644
index 12b80a1..0000000
--- a/metricsd/metrics_collector_service_trampoline.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 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 "metrics_collector_service_trampoline.h"
-#include "metrics_collector.h"
-#include "metrics_collector_service_impl.h"
-
-MetricsCollectorServiceTrampoline::MetricsCollectorServiceTrampoline(
- MetricsCollector* metrics_collector) {
- metrics_collector_ = metrics_collector;
-}
-
-void MetricsCollectorServiceTrampoline::Run() {
- // Start metricscollectorservice binder service
- metrics_collector_service.reset(new BnMetricsCollectorServiceImpl(this));
- metrics_collector_service->Run();
-}
-
-void MetricsCollectorServiceTrampoline::ProcessUserCrash() {
- metrics_collector_->ProcessUserCrash();
-}
diff --git a/metricsd/metrics_collector_service_trampoline.h b/metricsd/metrics_collector_service_trampoline.h
deleted file mode 100644
index 5da9fa5..0000000
--- a/metricsd/metrics_collector_service_trampoline.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 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 METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
-#define METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
-
-// Trampoline between the -fno-rtti compile of libmetricsservice and the
-// -frtti compile of metrics_collector. MetricsCollectorServiceTrampoline
-// is called from MetricsCollector to run the IMetricsCollectorService
-// server, and acts as a go-between for calls from server back to
-// MetricsCollector.
-
-#include <memory>
-
-#include "metrics_collector_service_impl.h"
-
-// Forward declaration of MetricsCollector. Don't include the header file
-// for the class here, as it pulls in -frtti stuff.
-class MetricsCollector;
-
-class MetricsCollectorServiceTrampoline {
- public:
- // Constructor take a this pointer from the MetricsCollector class that
- // constructs these objects.
- explicit MetricsCollectorServiceTrampoline(
- MetricsCollector* metrics_collector);
-
- // Initialize and run the IMetricsCollectorService
- void Run();
-
- // Called from IMetricsCollectorService to trampoline into the
- // MetricsCollector method of the same name.
- void ProcessUserCrash();
-
- private:
- // The MetricsCollector object that constructs us, for which we act as
- // the go-between for MetricsCollectorServiceImpl use.
- MetricsCollector* metrics_collector_;
-
- // The IMetricsCollectorService implementation we construct.
- std::unique_ptr<BnMetricsCollectorServiceImpl> metrics_collector_service;
-};
-
-#endif // METRICSD_METRICS_COLLECTOR_SERVICE_TRAMPOLINE_H_
diff --git a/metricsd/metricsd.rc b/metricsd/metricsd.rc
index 359d0d1..825c87f 100644
--- a/metricsd/metricsd.rc
+++ b/metricsd/metricsd.rc
@@ -1,9 +1,9 @@
on post-fs-data
- mkdir /data/misc/metrics 0770 system system
- mkdir /data/misc/metricsd 0700 system system
- mkdir /data/misc/metrics_collector 0700 system system
+ mkdir /data/misc/metrics 0750 metrics_coll system
+ mkdir /data/misc/metricsd 0700 metricsd metricsd
+ mkdir /data/misc/metrics_collector 0700 metrics_coll metrics_coll
service metricsd /system/bin/metricsd --foreground --logtosyslog
class late_start
- user system
+ user metricsd
group system dbus inet
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
index 1d36121..420653e 100644
--- a/metricsd/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -34,30 +34,33 @@
class SystemProfileSetter;
-// Service responsible for uploading the metrics periodically to the server.
-// This service works as a simple 2-state state-machine.
+// Service responsible for backing up the currently aggregated metrics to disk
+// and uploading them periodically to the server.
//
-// The two states are the presence or not of a staged log.
-// A staged log is a compressed protobuffer containing both the aggregated
-// metrics and event and information about the client. (product,
-// model_manifest_id, etc...).
+// A given metrics sample can be in one of three locations.
+// * in-memory metrics: in memory aggregated metrics, waiting to be staged for
+// upload.
+// * saved log: protobuf message, written to disk periodically and on shutdown
+// to make a backup of metrics data for uploading later.
+// * staged log: protobuf message waiting to be uploaded.
//
-// At regular intervals, the upload event will be triggered and the following
-// will happen:
-// * if a staged log is present:
-// The previous upload may have failed for various reason. We then retry to
-// upload the same log.
-// - if the upload is successful, we discard the log (therefore
-// transitioning back to no staged log)
-// - if the upload fails, we keep the log to try again later.
+// The service works as follows:
+// On startup, we create the in-memory metrics from the saved log if it exists.
//
-// * if no staged logs are present:
-// Take a snapshot of the aggregated metrics, save it to disk and try to send
-// it:
-// - if the upload succeeds, we discard the staged log (transitioning back
-// to the no staged log state)
-// - if the upload fails, we continue and will retry to upload later.
+// Periodically (every |disk_persistence_interval_| seconds), we take a snapshot
+// of the in-memory metrics and save them to disk.
//
+// Periodically (every |upload_interval| seconds), we:
+// * take a snapshot of the in-memory metrics and create the staged log
+// * save the staged log to disk to avoid losing it if metricsd or the system
+// crashes between two uploads.
+// * delete the last saved log: all the metrics contained in it are also in the
+// newly created staged log.
+//
+// On shutdown (SIGINT or SIGTERM), we save the in-memory metrics to disk.
+//
+// Note: the in-memory metrics can be stored in |current_log_| or
+// base::StatisticsRecorder.
class UploadService : public base::HistogramFlattener, public brillo::Daemon {
public:
UploadService(const std::string& server,
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a52d87d..d322402 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -332,6 +332,7 @@
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
+ mkdir /data/misc/vold 0700 root root
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/trace 0700 root root
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 3bc540d..ecc1c9f 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -57,7 +57,7 @@
int prio, nice, rtprio, sched, psr;
struct passwd *pw;
- sprintf(statline, "/proc/%d", pid);
+ sprintf(statline, "/proc/%d", tid ? tid : pid);
stat(statline, &stats);
if(tid) {