Merge "Create new ephemeral app directory"
diff --git a/adb/adb.h b/adb/adb.h
index 491fff3..5187c81 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -151,7 +151,7 @@
void get_my_path(char *s, size_t maxLen);
int launch_server(int server_port);
-int adb_main(int is_daemon, int server_port, int ack_reply_fd);
+int adb_server_main(int is_daemon, int server_port, int ack_reply_fd);
/* initialize a transport object's func pointers and state */
#if ADB_HOST
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index d5b1fd5..1b75090 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -33,21 +33,17 @@
};
static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
- asocket *s;
-
- if(ev & FDE_READ) {
+ if (ev & FDE_READ) {
struct sockaddr addr;
- socklen_t alen;
- int fd;
+ socklen_t alen = sizeof(addr);
+ int fd = adb_socket_accept(_fd, &addr, &alen);
+ if (fd < 0) return;
- alen = sizeof(addr);
- fd = adb_socket_accept(_fd, &addr, &alen);
- if(fd < 0) return;
+ int rcv_buf_size = CHUNK_SIZE;
+ adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
- adb_socket_setbufsize(fd, CHUNK_SIZE);
-
- s = create_local_socket(fd);
- if(s) {
+ asocket* s = create_local_socket(fd);
+ if (s) {
connect_to_smartsocket(s);
return;
}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 8d01af3..04b9882 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -86,8 +86,7 @@
static void setup_daemon_logging(void) {
const std::string log_file_path(GetLogFilePath());
- int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND,
- 0640);
+ int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
if (fd == -1) {
fatal("cannot open '%s': %s", log_file_path.c_str(), strerror(errno));
}
@@ -103,10 +102,10 @@
LOG(INFO) << adb_version();
}
-int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
+int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) {
#if defined(_WIN32)
// adb start-server starts us up with stdout and stderr hooked up to
- // anonymous pipes to. When the C Runtime sees this, it makes stderr and
+ // anonymous pipes. When the C Runtime sees this, it makes stderr and
// stdout buffered, but to improve the chance that error output is seen,
// unbuffer stdout and stderr just like if we were run at the console.
// This also keeps stderr unbuffered when it is redirected to adb.log.
@@ -120,8 +119,6 @@
}
SetConsoleCtrlHandler(ctrlc_handler, TRUE);
-#else
- signal(SIGPIPE, SIG_IGN);
#endif
init_transport_registration();
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 73c8912..bd3813e 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1296,6 +1296,11 @@
TransportType transport_type = kTransportAny;
int ack_reply_fd = -1;
+#if !defined(_WIN32)
+ // We'd rather have EPIPE than SIGPIPE.
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
// If defined, this should be an absolute path to
// the directory containing all of the various system images
// for a particular product. If not defined, and the adb
@@ -1427,7 +1432,7 @@
fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
return usage();
}
- r = adb_main(is_daemon, server_port, ack_reply_fd);
+ r = adb_server_main(is_daemon, server_port, ack_reply_fd);
} else {
r = launch_server(server_port);
}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index ad38369..9ad7bad 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -103,9 +103,9 @@
// Sending header, payload, and footer in a single write makes a huge
// difference to "adb sync" performance.
bool SendSmallFile(const char* path_and_mode,
- const char* rpath,
- const char* data, size_t data_length,
- unsigned mtime) {
+ const char* lpath, const char* rpath,
+ unsigned mtime,
+ const char* data, size_t data_length) {
Print(rpath);
size_t path_length = strlen(path_and_mode);
@@ -116,8 +116,8 @@
}
std::vector<char> buf(sizeof(SyncRequest) + path_length +
- sizeof(SyncRequest) + data_length +
- sizeof(SyncRequest));
+ sizeof(SyncRequest) + data_length +
+ sizeof(SyncRequest));
char* p = &buf[0];
SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
@@ -139,12 +139,71 @@
req_done->path_length = mtime;
p += sizeof(SyncRequest);
- if (!WriteFdExactly(fd, &buf[0], (p - &buf[0]))) return false;
-
+ WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
total_bytes += data_length;
return true;
}
+ bool SendLargeFile(const char* path_and_mode,
+ const char* lpath, const char* rpath,
+ unsigned mtime) {
+ if (!SendRequest(ID_SEND, path_and_mode)) {
+ Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
+ return false;
+ }
+
+ struct stat st;
+ if (stat(lpath, &st) == -1) {
+ Error("cannot stat '%s': %s", lpath, strerror(errno));
+ return false;
+ }
+
+ uint64_t total_size = st.st_size;
+ uint64_t bytes_copied = 0;
+
+ int lfd = adb_open(lpath, O_RDONLY);
+ if (lfd < 0) {
+ Error("opening '%s' locally failed: %s", lpath, strerror(errno));
+ return false;
+ }
+
+ syncsendbuf sbuf;
+ sbuf.id = ID_DATA;
+ while (true) {
+ int bytes_read = adb_read(lfd, sbuf.data, max);
+ if (bytes_read == -1) {
+ Error("reading '%s' locally failed: %s", lpath, strerror(errno));
+ adb_close(lfd);
+ return false;
+ } else if (bytes_read == 0) {
+ break;
+ }
+
+ sbuf.size = bytes_read;
+ WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + bytes_read);
+
+ total_bytes += bytes_read;
+ bytes_copied += bytes_read;
+
+ if (total_size == 0) {
+ // This case can happen if we're racing against something that wrote to the file
+ // between our stat and our read, or if we're reading a magic file that lies about
+ // its size.
+ Printf("%s: ?%%", rpath);
+ } else {
+ int percentage = static_cast<int>(bytes_copied * 100 / total_size);
+ Printf("%s: %d%%", rpath, percentage);
+ }
+ }
+
+ adb_close(lfd);
+
+ syncmsg msg;
+ msg.data.id = ID_DONE;
+ msg.data.size = mtime;
+ return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
+ }
+
bool CopyDone(const char* from, const char* to) {
syncmsg msg;
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
@@ -235,6 +294,27 @@
return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
}
+ bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
+ if (!WriteFdExactly(fd, data, data_length)) {
+ if (errno == ECONNRESET) {
+ // Assume adbd told us why it was closing the connection, and
+ // try to read failure reason from adbd.
+ syncmsg msg;
+ if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
+ Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
+ } else if (msg.status.id != ID_FAIL) {
+ Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
+ } else {
+ ReportCopyFailure(from, to, msg);
+ }
+ } else {
+ Error("%zu-byte write failed: %s", data_length, strerror(errno));
+ }
+ _exit(1);
+ }
+ return true;
+ }
+
static uint64_t CurrentTimeMs() {
struct timeval tv;
gettimeofday(&tv, 0); // (Not clock_gettime because of Mac/Windows.)
@@ -285,68 +365,6 @@
return sc.SendRequest(ID_STAT, path) && sync_finish_stat(sc, timestamp, mode, size);
}
-static bool SendLargeFile(SyncConnection& sc, const char* path_and_mode,
- const char* lpath, const char* rpath,
- unsigned mtime) {
- if (!sc.SendRequest(ID_SEND, path_and_mode)) {
- sc.Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
- return false;
- }
-
- struct stat st;
- if (stat(lpath, &st) == -1) {
- sc.Error("cannot stat '%s': %s", lpath, strerror(errno));
- return false;
- }
-
- uint64_t total_size = st.st_size;
- uint64_t bytes_copied = 0;
-
- int lfd = adb_open(lpath, O_RDONLY);
- if (lfd < 0) {
- sc.Error("cannot open '%s': %s", lpath, strerror(errno));
- return false;
- }
-
- syncsendbuf sbuf;
- sbuf.id = ID_DATA;
- while (true) {
- int ret = adb_read(lfd, sbuf.data, sc.max);
- if (ret <= 0) {
- if (ret < 0) {
- sc.Error("cannot read '%s': %s", lpath, strerror(errno));
- adb_close(lfd);
- return false;
- }
- break;
- }
-
- sbuf.size = ret;
- if (!WriteFdExactly(sc.fd, &sbuf, sizeof(unsigned) * 2 + ret)) {
- adb_close(lfd);
- return false;
- }
- sc.total_bytes += ret;
-
- bytes_copied += ret;
-
- int percentage = static_cast<int>(bytes_copied * 100 / total_size);
- sc.Printf("%s: %d%%", rpath, percentage);
- }
-
- adb_close(lfd);
-
- syncmsg msg;
- msg.data.id = ID_DONE;
- msg.data.size = mtime;
- if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
- sc.Error("failed to send ID_DONE message for '%s': %s", rpath, strerror(errno));
- return false;
- }
-
- return true;
-}
-
static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath,
unsigned mtime, mode_t mode)
{
@@ -362,7 +380,9 @@
}
buf[data_length++] = '\0';
- if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, buf, data_length, mtime)) return false;
+ if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
+ return false;
+ }
return sc.CopyDone(lpath, rpath);
#endif
}
@@ -383,11 +403,12 @@
sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
return false;
}
- if (!sc.SendSmallFile(path_and_mode.c_str(), rpath, data.data(), data.size(), mtime)) {
+ if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
+ data.data(), data.size())) {
return false;
}
} else {
- if (!SendLargeFile(sc, path_and_mode.c_str(), lpath, rpath, mtime)) {
+ if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
return false;
}
}
@@ -458,8 +479,14 @@
bytes_copied += msg.data.size;
- int percentage = static_cast<int>(bytes_copied * 100 / size);
- sc.Printf("%s: %d%%", rpath, percentage);
+ if (size == 0) {
+ // This case can happen if we're racing against something that wrote to the file between
+ // our stat and our read, or if we're reading a magic file that lies about its size.
+ sc.Printf("%s: ?%%", rpath);
+ } else {
+ int percentage = static_cast<int>(bytes_copied * 100 / size);
+ sc.Printf("%s: %d%%", rpath, percentage);
+ }
}
adb_close(lfd);
@@ -552,11 +579,12 @@
} else {
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
sc.Error("skipping special file '%s'", lpath.c_str());
+ ci.skip = true;
} else {
ci.time = st.st_mtime;
ci.size = st.st_size;
- filelist->push_back(ci);
}
+ filelist->push_back(ci);
}
}
@@ -723,8 +751,7 @@
bool empty_dir = true;
// Put the files/dirs in rpath on the lists.
- auto callback = [&](unsigned mode, unsigned size, unsigned time,
- const char* name) {
+ auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
if (IsDotOrDotDot(name)) {
return;
}
@@ -735,12 +762,18 @@
copyinfo ci = mkcopyinfo(lpath, rpath, name, mode);
if (S_ISDIR(mode)) {
dirlist.push_back(ci);
- } else if (S_ISREG(mode) || S_ISLNK(mode)) {
- ci.time = time;
- ci.size = size;
- filelist->push_back(ci);
} else {
- sc.Warning("skipping special file '%s'\n", name);
+ if (S_ISREG(mode)) {
+ ci.time = time;
+ ci.size = size;
+ } else if (S_ISLNK(mode)) {
+ sc.Warning("skipping symlink '%s'", name);
+ ci.skip = true;
+ } else {
+ sc.Warning("skipping special file '%s'", name);
+ ci.skip = true;
+ }
+ filelist->push_back(ci);
}
};
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 7484a7c..945fa5a 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -394,6 +394,18 @@
void file_sync_service(int fd, void* cookie) {
std::vector<char> buffer(SYNC_DATA_MAX);
+ // If there's a problem on the device, we'll send an ID_FAIL message and
+ // close the socket. Unfortunately the kernel will sometimes throw that
+ // data away if the other end keeps writing without reading (which is
+ // the normal case with our protocol --- they won't read until the end).
+ // So set SO_LINGER to give the client 20s to get around to reading our
+ // failure response. Without this, the other side's ability to report
+ // useful errors is reduced.
+ struct linger l;
+ l.l_onoff = 1;
+ l.l_linger = 20;
+ adb_setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+
while (handle_sync_command(fd, buffer)) {
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index cba66fc..22c9b39 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -242,18 +242,6 @@
#undef setsockopt
#define setsockopt ___xxx_setsockopt
-static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
-{
- int opt = bufsize;
- return adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void*)&opt, sizeof(opt));
-}
-
-static __inline__ void disable_tcp_nagle( int fd )
-{
- int on = 1;
- adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void*)&on, sizeof(on));
-}
-
extern int adb_socketpair( int sv[2] );
static __inline__ int adb_is_absolute_host_path(const char* path) {
@@ -670,18 +658,6 @@
#endif
}
-static __inline__ int adb_socket_setbufsize(int fd, int bufsize )
-{
- int opt = bufsize;
- return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
-}
-
-static __inline__ void disable_tcp_nagle(int fd)
-{
- int on = 1;
- setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
-}
-
static __inline__ int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen )
{
return setsockopt( fd, level, optname, optval, optlen );
@@ -739,4 +715,9 @@
#endif /* !_WIN32 */
+static inline void disable_tcp_nagle(int fd) {
+ int off = 1;
+ adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
+}
+
#endif /* _ADB_SYSDEPS_H */
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 3495a71..ceed8fa 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -456,56 +456,40 @@
return 0;
}
-static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
-{
- size_t count = 0;
-
- while (count < length) {
- int ret = adb_write(bulk_in, buf + count, length - count);
- if (ret < 0) return -1;
- count += ret;
- }
-
- D("[ bulk_write done fd=%d ]", bulk_in);
- return count;
-}
-
-static int usb_ffs_write(usb_handle* h, const void* data, int len)
-{
+static int usb_ffs_write(usb_handle* h, const void* data, int len) {
D("about to write (fd=%d, len=%d)", h->bulk_in, len);
- int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len);
- if (n != len) {
- D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
- return -1;
+
+ // Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
+ const char* buf = static_cast<const char*>(data);
+ while (len > 0) {
+ int write_len = (len > 16384) ? 16384 : len;
+ int n = adb_write(h->bulk_in, buf, write_len);
+ if (n < 0) {
+ D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
+ return -1;
+ }
+ buf += n;
+ len -= n;
}
+
D("[ done fd=%d ]", h->bulk_in);
return 0;
}
-static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
-{
- size_t count = 0;
+static int usb_ffs_read(usb_handle* h, void* data, int len) {
+ D("about to read (fd=%d, len=%d)", h->bulk_out, len);
- while (count < length) {
- int ret = adb_read(bulk_out, buf + count, length - count);
- if (ret < 0) {
- D("[ bulk_read failed fd=%d length=%zu count=%zu ]", bulk_out, length, count);
+ char* buf = static_cast<char*>(data);
+ while (len > 0) {
+ int n = adb_read(h->bulk_out, buf, len);
+ if (n < 0) {
+ D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
return -1;
}
- count += ret;
+ buf += n;
+ len -= n;
}
- return count;
-}
-
-static int usb_ffs_read(usb_handle* h, void* data, int len)
-{
- D("about to read (fd=%d, len=%d)", h->bulk_out, len);
- int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len);
- if (n != len) {
- D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
- return -1;
- }
D("[ done fd=%d ]", h->bulk_out);
return 0;
}
diff --git a/base/include/android-base b/base/include/android-base
new file mode 120000
index 0000000..8681f8b
--- /dev/null
+++ b/base/include/android-base
@@ -0,0 +1 @@
+base
\ No newline at end of file
diff --git a/crash_reporter/crash_sender b/crash_reporter/crash_sender
index 95204a4..a430ab5 100755
--- a/crash_reporter/crash_sender
+++ b/crash_reporter/crash_sender
@@ -65,6 +65,7 @@
# Path to a directory of restricted certificates which includes
# a certificate for the crash server.
RESTRICTED_CERTIFICATES_PATH="/system/etc/security/cacerts"
+RESTRICTED_CERTIFICATES_PATH_GOOGLE="/system/etc/security/cacerts_google"
# File whose existence implies we're running and not to start again.
RUN_FILE="${CRASH_STATE_DIR}/run/crash_sender.pid"
@@ -183,6 +184,18 @@
fi
}
+# Returns the path of the certificates directory to be used when sending
+# reports to the crash server.
+# If crash_reporter.full_certs=1, return the full certificates path.
+# Otherwise return the Google-specific certificates path.
+get_certificates_path() {
+ if [ "$(getprop crash_reporter.full_certs)" = "1" ]; then
+ echo "${RESTRICTED_CERTIFICATES_PATH}"
+ else
+ echo "${RESTRICTED_CERTIFICATES_PATH_GOOGLE}"
+ fi
+}
+
# Return 0 if the uploading of device coredumps is allowed.
is_device_coredump_upload_allowed() {
[ -f "${DEVCOREDUMP_UPLOAD_FLAG_FILE}" ] && return 0
@@ -455,7 +468,7 @@
set +e
curl "${url}" -f -v ${proxy:+--proxy "$proxy"} \
- --capath "${RESTRICTED_CERTIFICATES_PATH}" --ciphers HIGH \
+ --capath "$(get_certificates_path)" --ciphers HIGH \
-F "prod=${product}" \
-F "ver=${version}" \
-F "bdk_version=${bdk_version}" \
@@ -682,7 +695,7 @@
# (like with autotests) that we're still running.
echo $$ > "${RUN_FILE}"
- for dependency in "${RESTRICTED_CERTIFICATES_PATH}"; do
+ for dependency in "$(get_certificates_path)"; do
if [ ! -x "${dependency}" ]; then
lecho "Fatal: Crash sending disabled: ${dependency} not found."
exit 1
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index a16d7dd..afdfd0e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -81,6 +81,8 @@
static unsigned second_offset = 0x00f00000;
static unsigned tags_offset = 0x00000100;
+static const std::string convert_fbe_marker_filename("convert_fbe");
+
enum fb_buffer_type {
FB_BUFFER,
FB_BUFFER_SPARSE,
@@ -322,11 +324,17 @@
" provided, this will default to the value\n"
" given by --slot. If slots are not\n"
" supported, this does nothing.\n"
+#if !defined(_WIN32)
+ " --wipe-and-use-fbe On devices which support it,\n"
+ " erase userdata and cache, and\n"
+ " enable file-based encryption\n"
+#endif
" --unbuffered Do not buffer input or output.\n"
" --version Display version.\n"
" -h, --help show this message.\n"
);
}
+
static void* load_bootable_image(const char* kernel, const char* ramdisk,
const char* secondstage, int64_t* sz,
const char* cmdline) {
@@ -446,8 +454,60 @@
#define tmpfile win32_tmpfile
+static std::string make_temporary_directory() {
+ fprintf(stderr, "make_temporary_directory not supported under Windows, sorry!");
+ return "";
+}
+
+#else
+
+static std::string make_temporary_directory() {
+ const char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == nullptr) {
+ tmpdir = P_tmpdir;
+ }
+ std::string result = std::string(tmpdir) + "/fastboot_userdata_XXXXXX";
+ if (mkdtemp(&result[0]) == NULL) {
+ fprintf(stderr, "Unable to create temporary directory: %s\n",
+ strerror(errno));
+ return "";
+ }
+ return result;
+}
+
#endif
+static std::string create_fbemarker_tmpdir() {
+ std::string dir = make_temporary_directory();
+ if (dir.empty()) {
+ fprintf(stderr, "Unable to create local temp directory for FBE marker\n");
+ return "";
+ }
+ std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+ int fd = open(marker_file.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "Unable to create FBE marker file %s locally: %d, %s\n",
+ marker_file.c_str(), errno, strerror(errno));
+ return "";
+ }
+ close(fd);
+ return dir;
+}
+
+static void delete_fbemarker_tmpdir(const std::string& dir) {
+ std::string marker_file = dir + "/" + convert_fbe_marker_filename;
+ if (unlink(marker_file.c_str()) == -1) {
+ fprintf(stderr, "Unable to delete FBE marker file %s locally: %d, %s\n",
+ marker_file.c_str(), errno, strerror(errno));
+ return;
+ }
+ if (rmdir(dir.c_str()) == -1) {
+ fprintf(stderr, "Unable to delete FBE marker directory %s locally: %d, %s\n",
+ dir.c_str(), errno, strerror(errno));
+ return;
+ }
+}
+
static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
FILE* fp = tmpfile();
if (fp == nullptr) {
@@ -994,7 +1054,8 @@
static void fb_perform_format(Transport* transport,
const char* partition, int skip_if_not_supported,
- const char* type_override, const char* size_override) {
+ const char* type_override, const char* size_override,
+ const std::string& initial_dir) {
std::string partition_type, partition_size;
struct fastboot_buffer buf;
@@ -1058,7 +1119,7 @@
}
fd = fileno(tmpfile());
- if (fs_generator_generate(gen, fd, size)) {
+ if (fs_generator_generate(gen, fd, size, initial_dir)) {
fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
close(fd);
return;
@@ -1087,6 +1148,7 @@
bool wants_reboot_bootloader = false;
bool wants_set_active = false;
bool erase_first = true;
+ bool set_fbe_marker = false;
void *data;
int64_t sz;
int longindex;
@@ -1109,6 +1171,9 @@
{"slot", required_argument, 0, 0},
{"set_active", optional_argument, 0, 'a'},
{"set-active", optional_argument, 0, 'a'},
+#if !defined(_WIN32)
+ {"wipe-and-use-fbe", no_argument, 0, 0},
+#endif
{0, 0, 0, 0}
};
@@ -1190,6 +1255,15 @@
return 0;
} else if (strcmp("slot", longopts[longindex].name) == 0) {
slot_override = std::string(optarg);
+#if !defined(_WIN32)
+ } else if (strcmp("wipe-and-use-fbe", longopts[longindex].name) == 0) {
+ wants_wipe = true;
+ set_fbe_marker = true;
+#endif
+ } else {
+ fprintf(stderr, "Internal error in options processing for %s\n",
+ longopts[longindex].name);
+ return 1;
}
break;
default:
@@ -1283,7 +1357,8 @@
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
- fb_perform_format(transport, partition.c_str(), 0, type_override, size_override);
+ fb_perform_format(transport, partition.c_str(), 0,
+ type_override, size_override, "");
};
do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
skip(2);
@@ -1413,13 +1488,23 @@
if (wants_wipe) {
fprintf(stderr, "wiping userdata...\n");
fb_queue_erase("userdata");
- fb_perform_format(transport, "userdata", 1, nullptr, nullptr);
+ if (set_fbe_marker) {
+ fprintf(stderr, "setting FBE marker...\n");
+ std::string initial_userdata_dir = create_fbemarker_tmpdir();
+ if (initial_userdata_dir.empty()) {
+ return 1;
+ }
+ fb_perform_format(transport, "userdata", 1, nullptr, nullptr, initial_userdata_dir);
+ delete_fbemarker_tmpdir(initial_userdata_dir);
+ } else {
+ fb_perform_format(transport, "userdata", 1, nullptr, nullptr, "");
+ }
std::string cache_type;
if (fb_getvar(transport, "partition-type:cache", &cache_type) && !cache_type.empty()) {
fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
- fb_perform_format(transport, "cache", 1, nullptr, nullptr);
+ fb_perform_format(transport, "cache", 1, nullptr, nullptr, "");
}
}
if (wants_set_active) {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 90d8474..8539e23 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -1,7 +1,8 @@
+#include "fs.h"
+
#include "fastboot.h"
#include "make_ext4fs.h"
#include "make_f2fs.h"
-#include "fs.h"
#include <errno.h>
#include <stdio.h>
@@ -13,24 +14,32 @@
#include <sparse/sparse.h>
-static int generate_ext4_image(int fd, long long partSize)
+static int generate_ext4_image(int fd, long long partSize, const std::string& initial_dir)
{
- make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
-
+ if (initial_dir.empty()) {
+ make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+ } else {
+ make_ext4fs_sparse_fd_directory(fd, partSize, NULL, NULL, initial_dir.c_str());
+ }
return 0;
}
#ifdef USE_F2FS
-static int generate_f2fs_image(int fd, long long partSize)
+static int generate_f2fs_image(int fd, long long partSize, const std::string& initial_dir)
{
+ if (!initial_dir.empty()) {
+ fprintf(stderr, "Unable to set initial directory on F2FS filesystem\n");
+ return -1;
+ }
return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
}
#endif
static const struct fs_generator {
-
const char* fs_type; //must match what fastboot reports for partition type
- int (*generate)(int fd, long long partSize); //returns 0 or error value
+
+ //returns 0 or error value
+ int (*generate)(int fd, long long partSize, const std::string& initial_dir);
} generators[] = {
{ "ext4", generate_ext4_image},
@@ -48,7 +57,8 @@
return nullptr;
}
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+ const std::string& initial_dir)
{
- return gen->generate(tmpFileNo, partSize);
+ return gen->generate(tmpFileNo, partSize, initial_dir);
}
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 289488b..0a68507 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,11 +1,13 @@
#ifndef _FS_H_
#define _FS_H_
+#include <string>
#include <stdint.h>
struct fs_generator;
const struct fs_generator* fs_get_generator(const std::string& fs_type);
-int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize,
+ const std::string& initial_dir);
#endif
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index beb95de..1c7da30 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -88,6 +88,16 @@
msg->data.removed.finger.fid,
msg->data.removed.finger.gid);
break;
+ case FINGERPRINT_TEMPLATE_ENUMERATING:
+ ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
+ msg->data.enumerated.finger.fid,
+ msg->data.enumerated.finger.gid,
+ msg->data.enumerated.remaining_templates);
+ callback->onEnumerate(device,
+ msg->data.enumerated.finger.fid,
+ msg->data.enumerated.finger.gid,
+ msg->data.enumerated.remaining_templates);
+ break;
default:
ALOGE("invalid msg type: %d", msg->type);
return;
@@ -158,6 +168,11 @@
return mDevice->remove(mDevice, groupId, fingerId);
}
+int32_t FingerprintDaemonProxy::enumerate() {
+ ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
+ return mDevice->enumerate(mDevice);
+}
+
uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
return mDevice->get_authenticator_id(mDevice);
}
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
index 871c0e6..145b4c9 100644
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -40,6 +40,7 @@
virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
virtual int32_t stopAuthentication();
virtual int32_t remove(int32_t fingerId, int32_t groupId);
+ virtual int32_t enumerate();
virtual uint64_t getAuthenticatorId();
virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
virtual int64_t openHal();
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
index 7131793..bc4af56 100644
--- a/fingerprintd/IFingerprintDaemon.cpp
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -125,6 +125,16 @@
reply->writeInt32(ret);
return NO_ERROR;
}
+ case ENUMERATE: {
+ CHECK_INTERFACE(IFingerprintDaemon, data, reply);
+ if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
+ return PERMISSION_DENIED;
+ }
+ const int32_t ret = enumerate();
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
case GET_AUTHENTICATOR_ID: {
CHECK_INTERFACE(IFingerprintDaemon, data, reply);
if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
index 1eb4ac1..23c36ff 100644
--- a/fingerprintd/IFingerprintDaemon.h
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -44,6 +44,7 @@
CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
+ ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12,
};
IFingerprintDaemon() { }
@@ -60,6 +61,7 @@
virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
virtual int32_t stopAuthentication() = 0;
virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
+ virtual int32_t enumerate() = 0;
virtual uint64_t getAuthenticatorId() = 0;
virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
virtual int64_t openHal() = 0;
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 44d8020..19838c9 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -74,13 +74,13 @@
return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
- int32_t sz) {
+ virtual status_t onEnumerate(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
Parcel data, reply;
data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
data.writeInt64(devId);
- data.writeInt32Array(sz, fpIds);
- data.writeInt32Array(sz, gpIds);
+ data.writeInt32(fpId);
+ data.writeInt32(gpId);
+ data.writeInt32(rem);
return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
}
};
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
index 6e32213..e343cb4 100644
--- a/fingerprintd/IFingerprintDaemonCallback.h
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -44,8 +44,7 @@
virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
virtual status_t onError(int64_t devId, int32_t error) = 0;
virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
- virtual status_t onEnumerate(int64_t devId, const int32_t* fpIds, const int32_t* gpIds,
- int32_t sz) = 0;
+ virtual status_t onEnumerate(int64_t devId, int32_t fingerId, int32_t groupId, int32_t rem) = 0;
DECLARE_META_INTERFACE(FingerprintDaemonCallback);
};
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 3fda34f..2ff6273 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -101,6 +101,7 @@
char tmpmnt_opts[64] = "errors=remount-ro";
char *e2fsck_argv[] = {
E2FSCK_BIN,
+ "-f",
"-y",
blk_device
};
@@ -448,8 +449,15 @@
"%s/convert_fbe", rec->mount_point);
bool convert_fbe = (access(convert_fbe_name, F_OK) == 0);
+ /* Check for existence of convert_fbe breadcrumb file */
+ char convert_fde_name[PATH_MAX];
+ snprintf(convert_fde_name, sizeof(convert_fbe_name),
+ "%s/misc/vold/convert_fde", rec->mount_point);
+ bool convert_fde = (access(convert_fde_name, F_OK) == 0);
+
/* If this is block encryptable, need to trigger encryption */
if ( (rec->fs_mgr_flags & MF_FORCECRYPT)
+ || ((rec->fs_mgr_flags & MF_CRYPT) && convert_fde)
|| ((rec->fs_mgr_flags & MF_FORCEFDEORFBE) && !convert_fbe)
|| (device_is_force_encrypted() && fs_mgr_is_encryptable(rec))) {
if (umount(rec->mount_point) == 0) {
diff --git a/include/log/log.h b/include/log/log.h
index 1cdf7bc..086d742 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -614,9 +614,11 @@
/*
* Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log.
+ * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
+ * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
+ * any other value.
*/
-int __android_log_is_loggable(int prio, const char *tag, int def);
+int __android_log_is_loggable(int prio, const char *tag, int default_prio);
int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
uint32_t dataLen);
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 1741fb2..ed96fe4 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -200,11 +200,11 @@
return false;
}
Entry* entry = *find_result;
+ mSet->erase(entry);
if (mListener) {
(*mListener)(entry->key, entry->value);
}
detachFromCache(*entry);
- mSet->erase(entry);
delete entry;
return true;
}
diff --git a/init/init.cpp b/init/init.cpp
index 86aed9a..958db36 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -602,6 +602,7 @@
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
+ restorecon("/property_contexts");
restorecon_recursive("/sys");
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 96b4a37..66e46f8 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -79,7 +79,8 @@
property_area_initialized = true;
if (__system_property_area_init()) {
- return;
+ ERROR("Failed to initialize property area\n");
+ exit(1);
}
pa_workspace.size = 0;
diff --git a/init/util.cpp b/init/util.cpp
index b316d6e..c7d0314 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -105,8 +105,12 @@
int fd, ret;
char *filecon;
- if (socketcon)
- setsockcreatecon(socketcon);
+ if (socketcon) {
+ if (setsockcreatecon(socketcon) == -1) {
+ ERROR("setsockcreatecon(\"%s\") failed: %s\n", socketcon, strerror(errno));
+ return -1;
+ }
+ }
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 9ead452..555e8cf 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -93,16 +93,26 @@
}
std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
- const char* map_name;
- if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) {
- map_name = frame->map.name.c_str();
+ uintptr_t relative_pc;
+ std::string map_name;
+ if (BacktraceMap::IsValid(frame->map)) {
+ relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
+ if (!frame->map.name.empty()) {
+ map_name = frame->map.name.c_str();
+ if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
+ map_name.resize(map_name.size() - 1);
+ map_name += StringPrintf(":%" PRIPTR "]", frame->map.start);
+ }
+ } else {
+ map_name = StringPrintf("<anonymous:%" PRIPTR ">", frame->map.start);
+ }
} else {
map_name = "<unknown>";
+ relative_pc = frame->pc;
}
- uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
-
- std::string line(StringPrintf("#%02zu pc %" PRIPTR " %s", frame->num, relative_pc, map_name));
+ std::string line(StringPrintf("#%02zu pc %" PRIPTR " ", frame->num, relative_pc));
+ line += map_name;
// Special handling for non-zero offset maps, we need to print that
// information.
if (frame->map.offset != 0) {
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9ebd639..ce04817 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -775,16 +775,29 @@
backtrace->FormatFrameData(&frame));
// Check map name empty, but exists.
- frame.map.start = 1;
- frame.map.end = 1;
+ frame.pc = 0xb0020;
+ frame.map.start = 0xb0000;
+ frame.map.end = 0xbffff;
frame.map.load_base = 0;
#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000000000001 <unknown>",
+ EXPECT_EQ("#01 pc 0000000000000020 <anonymous:00000000000b0000>",
#else
- EXPECT_EQ("#01 pc 00000001 <unknown>",
+ EXPECT_EQ("#01 pc 00000020 <anonymous:000b0000>",
#endif
backtrace->FormatFrameData(&frame));
+ // Check map name begins with a [.
+ frame.pc = 0xc0020;
+ frame.map.start = 0xc0000;
+ frame.map.end = 0xcffff;
+ frame.map.load_base = 0;
+ frame.map.name = "[anon:thread signal stack]";
+#if defined(__LP64__)
+ EXPECT_EQ("#01 pc 0000000000000020 [anon:thread signal stack:00000000000c0000]",
+#else
+ EXPECT_EQ("#01 pc 00000020 [anon:thread signal stack:000c0000]",
+#endif
+ backtrace->FormatFrameData(&frame));
// Check relative pc is set and map name is set.
frame.pc = 0x12345679;
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 0f79145..1f68290 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -16,28 +16,27 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
-commonSources := \
- hashmap.c \
- atomic.c.arm \
- native_handle.c \
- config_utils.c \
- load_file.c \
- strlcpy.c \
- open_memstream.c \
- strdup16to8.c \
- strdup8to16.c \
- record_stream.c \
- process_name.c \
- threads.c \
- sched_policy.c \
- iosched_policy.c \
- str_parms.c \
- fs_config.c
+libcutils_common_sources := \
+ hashmap.c \
+ atomic.c.arm \
+ native_handle.c \
+ config_utils.c \
+ load_file.c \
+ strlcpy.c \
+ open_memstream.c \
+ strdup16to8.c \
+ strdup8to16.c \
+ record_stream.c \
+ process_name.c \
+ threads.c \
+ sched_policy.c \
+ iosched_policy.c \
+ fs_config.c
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
# which are also hard or even impossible to port to native Win32
-nonWindowsSources := \
+libcutils_nonwindows_sources := \
fs.c \
multiuser.c \
socket_inaddr_any_server.c \
@@ -47,8 +46,9 @@
socket_loopback_server.c \
socket_network_client.c \
sockets.c \
+ str_parms.c \
-nonWindowsHostSources := \
+libcutils_nonwindows_host_sources := \
ashmem-host.c \
trace-host.c
@@ -56,24 +56,22 @@
# Shared and static library for host
# ========================================================
LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(nonWindowsSources) $(nonWindowsHostSources)
-LOCAL_SRC_FILES_linux := $(nonWindowsSources) $(nonWindowsHostSources)
+LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
+LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
+LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS_darwin := -Werror -Wall -Wextra
-LOCAL_CFLAGS_linux := -Werror -Wall -Wextra
+LOCAL_CFLAGS := -Werror -Wall -Wextra
LOCAL_MULTILIB := both
LOCAL_MODULE_HOST_OS := darwin linux windows
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(nonWindowsSources) $(nonWindowsHostSources)
-LOCAL_SRC_FILES_linux := $(nonWindowsSources) $(nonWindowsHostSources)
+LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
+LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
+LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS_darwin := -Werror -Wall -Wextra
-LOCAL_CFLAGS_linux := -Werror -Wall -Wextra
+LOCAL_CFLAGS := -Werror -Wall -Wextra
LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -84,8 +82,8 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) \
- $(nonWindowsSources) \
+LOCAL_SRC_FILES := $(libcutils_common_sources) \
+ $(libcutils_nonwindows_sources) \
android_reboot.c \
ashmem-dev.c \
debugger.c \
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 5a4720a..645edd1 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -134,12 +134,10 @@
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" },
- /* the following four files are INTENTIONALLY set-uid, but they
+ /* the following two files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
{ 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
- { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
- { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 34e7f92..878feb8 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -52,6 +52,7 @@
},
windows: {
srcs: ["uio.c"],
+ enabled: true,
},
not_windows: {
srcs: ["event_tag_map.c"],
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 8a8ece2..cb80ee6 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -99,6 +99,10 @@
static void lock()
{
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
pthread_mutex_lock(&fakeLogDeviceLock);
}
@@ -106,9 +110,12 @@
{
pthread_mutex_unlock(&fakeLogDeviceLock);
}
+
#else // !defined(_WIN32)
+
#define lock() ((void)0)
#define unlock() ((void)0)
+
#endif // !defined(_WIN32)
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 814d96d..e128edb 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -23,6 +23,22 @@
#include <android/log.h>
+static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
+
+static void lock()
+{
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
+ pthread_mutex_lock(&lock_loggable);
+}
+
+static void unlock()
+{
+ pthread_mutex_unlock(&lock_loggable);
+}
+
struct cache {
const prop_info *pinfo;
uint32_t serial;
@@ -49,9 +65,7 @@
cache->c = buf[0];
}
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
-static int __android_log_level(const char *tag, int def)
+static int __android_log_level(const char *tag, int default_prio)
{
/* sizeof() is used on this array below */
static const char log_namespace[] = "persist.log.tag.";
@@ -86,7 +100,7 @@
strcpy(key, log_namespace);
- pthread_mutex_lock(&lock);
+ lock();
current_global_serial = __system_property_area_serial();
@@ -156,7 +170,7 @@
global_serial = current_global_serial;
- pthread_mutex_unlock(&lock);
+ unlock();
switch (toupper(c)) {
case 'V': return ANDROID_LOG_VERBOSE;
@@ -168,36 +182,47 @@
case 'A': return ANDROID_LOG_FATAL;
case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
}
- return def;
+ return default_prio;
}
-int __android_log_is_loggable(int prio, const char *tag, int def)
+int __android_log_is_loggable(int prio, const char *tag, int default_prio)
{
- int logLevel = __android_log_level(tag, def);
+ int logLevel = __android_log_level(tag, default_prio);
return logLevel >= 0 && prio >= logLevel;
}
+/*
+ * Timestamp state generally remains constant, since a change is
+ * rare, we can accept a trylock failure gracefully. Use a separate
+ * lock from is_loggable to keep contention down b/25563384.
+ */
+static pthread_mutex_t lock_timestamp = PTHREAD_MUTEX_INITIALIZER;
+
char android_log_timestamp()
{
static struct cache r_time_cache = { NULL, -1, 0 };
static struct cache p_time_cache = { NULL, -1, 0 };
- static uint32_t serial;
- uint32_t current_serial;
char retval;
- pthread_mutex_lock(&lock);
+ if (pthread_mutex_trylock(&lock_timestamp)) {
+ /* We are willing to accept some race in this context */
+ if (!(retval = p_time_cache.c)) {
+ retval = r_time_cache.c;
+ }
+ } else {
+ static uint32_t serial;
+ uint32_t current_serial = __system_property_area_serial();
+ if (current_serial != serial) {
+ refresh_cache(&r_time_cache, "ro.logd.timestamp");
+ refresh_cache(&p_time_cache, "persist.logd.timestamp");
+ serial = current_serial;
+ }
+ if (!(retval = p_time_cache.c)) {
+ retval = r_time_cache.c;
+ }
- current_serial = __system_property_area_serial();
- if (current_serial != serial) {
- refresh_cache(&r_time_cache, "ro.logd.timestamp");
- refresh_cache(&p_time_cache, "persist.logd.timestamp");
- serial = current_serial;
+ pthread_mutex_unlock(&lock_timestamp);
}
- if (!(retval = p_time_cache.c)) {
- retval = r_time_cache.c;
- }
-
- pthread_mutex_unlock(&lock);
return tolower(retval ?: 'r');
}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index a4310ae..83c6dc2 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -54,14 +54,35 @@
static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
-#if !defined(_WIN32)
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
+#if !defined(_WIN32)
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void lock()
+{
+ /*
+ * If we trigger a signal handler in the middle of locked activity and the
+ * signal handler logs a message, we could get into a deadlock state.
+ */
+ pthread_mutex_lock(&log_init_lock);
+}
+
+static void unlock()
+{
+ pthread_mutex_unlock(&log_init_lock);
+}
+
+#else /* !defined(_WIN32) */
+
+#define lock() ((void)0)
+#define unlock() ((void)0)
+
+#endif /* !defined(_WIN32) */
+
#if FAKE_LOG_DEVICE
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
#else
@@ -277,15 +298,11 @@
if (ret < 0) {
ret = -errno;
if (ret == -ENOTCONN) {
-#if !defined(_WIN32)
- pthread_mutex_lock(&log_init_lock);
-#endif
+ lock();
close(logd_fd);
logd_fd = -1;
ret = __write_to_log_initialize();
-#if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
-#endif
+ unlock();
if (ret < 0) {
return ret;
@@ -329,18 +346,14 @@
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
-#if !defined(_WIN32)
- pthread_mutex_lock(&log_init_lock);
-#endif
+ lock();
if (write_to_log == __write_to_log_init) {
int ret;
ret = __write_to_log_initialize();
if (ret < 0) {
-#if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
-#endif
+ unlock();
#if (FAKE_LOG_DEVICE == 0)
if (pstore_fd >= 0) {
__write_to_log_daemon(log_id, vec, nr);
@@ -352,9 +365,7 @@
write_to_log = __write_to_log_daemon;
}
-#if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
-#endif
+ unlock();
return write_to_log(log_id, vec, nr);
}
diff --git a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
index 2b25223..b680b60 100644
--- a/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-mips64/assembler/mips64_assembler_test.cpp
@@ -228,26 +228,26 @@
{0xA039,INSTR_SUB,{1,R_a5,R_a6,2,7},GE,0,2,NA,1,1,NA,NA,NA,2,1,2},
{0xA040,INSTR_SUB,{1,R_a5,R_a6,1,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,1},
{0xA041,INSTR_SUB,{1,R_a5,R_a6,0,1},HS,0,2,NA,1,1,NA,NA,NA,2,1,2},
- {0xA042,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1<< 16,0,0,0,NA,1,(uint64_t)(1 -(1<<16))},
+ {0xA042,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1<< 16,0,0,0,NA,1,UINT64_C(1) -(1<<16)},
{0xA043,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,0,0,0,NA,1,MAX_64BIT-1},
{0xA044,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,1,1,0,0,0,NA,1,0},
- {0xA045,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(uint64_t)(1 -(1<<16))},
+ {0xA045,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,UINT64_C(1) -(1<<16)},
{0xA046,INSTR_SUB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,MAX_64BIT-1},
{0xA047,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0},
- {0xA048,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(uint64_t)(1 -(1<<16))},
+ {0xA048,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,UINT64_C(1) -(1<<16)},
{0xA049,INSTR_SUB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT,SHIFT_LSL,31,NA,1,1},
{0xA050,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0},
{0xA051,INSTR_SUB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0},
- {0xA052,INSTR_RSB,{1,R_a5,R_a6,4,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,(uint64_t)-2},
- {0xA053,INSTR_RSB,{1,R_a5,R_a6,-1,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,2},
+ {0xA052,INSTR_RSB,{1,R_a5,R_a6,4,1},GE,0,2,NA,1,0,NA,NA,NA,2,1,UINT64_C(-2)},
+ {0xA053,INSTR_RSB,{1,R_a5,R_a6,UINT64_C(-1),1},GE,0,2,NA,1,0,NA,NA,NA,2,1,2},
{0xA054,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1<<16,NA,NA,NA,NA,1,(1<<16)-1},
- {0xA055,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,(uint64_t)(1-MAX_64BIT)},
+ {0xA055,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,UINT64_C(1)-MAX_64BIT},
{0xA056,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,1,1,NA,NA,NA,NA,1,0},
{0xA057,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1<<16,0,0,NA,1,(1<<16)-1},
- {0xA058,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,(uint64_t)(1-MAX_64BIT)},
+ {0xA058,INSTR_RSB,{0,0,0,0,0},AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,UINT64_C(1)-MAX_64BIT},
{0xA059,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,0,0,NA,1,0},
{0xA060,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(1<<16)-1},
- {0xA061,INSTR_RSB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,(uint64_t)(-1)},
+ {0xA061,INSTR_RSB,{0,0,0,0,0},AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,UINT64_C(-1)},
{0xA062,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0},
{0xA063,INSTR_RSB,{0,0,0,0,0},AL,0,1,NA,0,NA,MAX_32BIT,SHIFT_LSR,31,NA,1,0},
{0xA064,INSTR_MOV,{0,0,0,0,0},AL,0,NA,NA,1,0x80000001,NA,NA,NA,NA,1,0xFFFFFFFF80000001},
@@ -263,28 +263,28 @@
{0xA074,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,MAX_64BIT -1,SHIFT_ASR,1,NA,1,MAX_64BIT},
{0xA075,INSTR_MOV,{0,0,0,0,0},AL,1,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1},
{0xA076,INSTR_MOV,{2,R_a5,R_a6,6,8},MI,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA077,INSTR_MOV,{2,R_a5,R_a6,-4,-8},MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
- {0xA078,INSTR_MOV,{1,R_a5,R_a6,-1,-1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA079,INSTR_MOV,{1,R_a5,R_a6,-1,1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA080,INSTR_MOV,{1,R_a5,R_a6,-1,-5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
+ {0xA077,INSTR_MOV,{2,R_a5,R_a6,UINT64_C(-4),UINT64_C(-8)},MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
+ {0xA078,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
+ {0xA079,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+ {0xA080,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-5)},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
{0xA081,INSTR_MOV,{1,R_a5,R_a6,5,5},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
- {0xA082,INSTR_MOV,{1,R_a5,R_a6,-1,1},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,2},
+ {0xA082,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,2},
{0xA083,INSTR_MOV,{1,R_a5,R_a6,4,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2},
- {0xA084,INSTR_MOV,{1,R_a5,R_a6,-1,-1},LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA085,INSTR_MOV,{1,R_a5,R_a6,-1,1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
+ {0xA084,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+ {0xA085,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},LE,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,31,2,1,0xFFFFFFFF80000000},
{0xA086,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA087,INSTR_MOV,{1,R_a5,R_a6,-1,-3},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
- {0xA088,INSTR_MOV,{1,R_a5,R_a6,-1,0},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA089,INSTR_MOV,{1,R_a5,R_a6,-1,-1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
+ {0xA087,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-3)},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+ {0xA088,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),0},GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
+ {0xA089,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),UINT64_C(-1)},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
{0xA090,INSTR_MOV,{1,R_a5,R_a6,6,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,0xFFFFFFFF80000001},
- {0xA091,INSTR_MOV,{1,R_a5,R_a6,-1,1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
+ {0xA091,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2},
{0xA092,INSTR_MOV,{1,R_a5,R_a6,1,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,2},
{0xA093,INSTR_MOV,{1,R_a5,R_a6,4,1},GT,0,NA,NA,0,0,MAX_32BIT,SHIFT_LSL,1,2,1,MAX_64BIT-1},
- {0xA094,INSTR_MOV,{1,R_a5,R_a6,-1,1},GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2},
- {0xA095,INSTR_MOV,{1,R_a5,R_a6,1,-1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
- {0xA096,INSTR_MOV,{1,R_a5,R_a6,-1,1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
+ {0xA094,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2},
+ {0xA095,INSTR_MOV,{1,R_a5,R_a6,1,UINT64_C(-1)},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2},
+ {0xA096,INSTR_MOV,{1,R_a5,R_a6,UINT64_C(-1),1},HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0xFFFFFFFF80000001},
{0xA097,INSTR_MVN,{1,R_a5,R_a6,1,4},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,2},
- {0xA098,INSTR_MVN,{1,R_a5,R_a6,-1,1},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,1},
+ {0xA098,INSTR_MVN,{1,R_a5,R_a6,UINT64_C(-1),1},HS,0,NA,NA,1,MAX_32BIT-1,NA,NA,NA,2,1,1},
{0xA099,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,1,0,NA,NA,NA,2,1,MAX_64BIT},
{0xA100,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,MAX_32BIT-1,NA,0,2,1,1},
{0xA101,INSTR_MVN,{0,0,0,0,0},AL,0,NA,NA,0,NA,0x80000001,NA,0,2,1,0x7FFFFFFE},
diff --git a/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp b/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp
index 41f6f3e..22efa9f 100644
--- a/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp
+++ b/libpixelflinger/tests/arch-mips64/disassembler/mips64_disassembler_test.cpp
@@ -123,13 +123,13 @@
};
static test_branches_table_entry_t test_branches_table [] = {
- { 0x1000ffff, "b\t", 0xffff },
- { 0x13df0008, "beq\ts8,ra,", 0x8 },
- { 0x042100ff, "bgez\tat,", 0xff },
- { 0x1c40ff00, "bgtz\tv0,", 0xff00 },
- { 0x18605555, "blez\tv1,", 0x5555 },
- { 0x0480aaaa, "bltz\ta0,", 0xaaaa },
- { 0x14a68888, "bne\ta1,a2,", 0x8888 },
+ { 0x1000ffff, "b\t", static_cast<int16_t>(0xffff) },
+ { 0x13df0008, "beq\ts8,ra,", 0x8 },
+ { 0x042100ff, "bgez\tat,", 0xff },
+ { 0x1c40ff00, "bgtz\tv0,", static_cast<int16_t>(0xff00) },
+ { 0x18605555, "blez\tv1,", 0x5555 },
+ { 0x0480aaaa, "bltz\ta0,", static_cast<int16_t>(0xaaaa) },
+ { 0x14a68888, "bne\ta1,a2,", static_cast<int16_t>(0x8888) },
};
struct test_jump_table_entry_t
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 580b980..dd95c57 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -73,6 +73,13 @@
ssize_t ComplexValue::instanceCount = 0;
+struct KeyWithPointer {
+ int *ptr;
+ bool operator ==(const KeyWithPointer& other) const {
+ return *ptr == *other.ptr;
+ }
+};
+
} // namespace
@@ -84,6 +91,10 @@
return hash_type(value.k);
}
+template<> inline android::hash_t hash_type(const KeyWithPointer& value) {
+ return hash_type(*value.ptr);
+}
+
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
public:
EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
@@ -98,6 +109,14 @@
StringValue lastValue;
};
+class InvalidateKeyCallback : public OnEntryRemoved<KeyWithPointer, StringValue> {
+public:
+ void operator()(KeyWithPointer& k, StringValue&) {
+ delete k.ptr;
+ k.ptr = nullptr;
+ }
+};
+
class LruCacheTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -293,6 +312,25 @@
EXPECT_EQ(3, callback.callbackCount);
}
+TEST_F(LruCacheTest, CallbackRemovesKeyWorksOK) {
+ LruCache<KeyWithPointer, StringValue> cache(1);
+ InvalidateKeyCallback callback;
+ cache.setOnEntryRemovedListener(&callback);
+ KeyWithPointer key1;
+ key1.ptr = new int(1);
+ KeyWithPointer key2;
+ key2.ptr = new int(2);
+
+ cache.put(key1, "one");
+ // As the size of the cache is 1, the put will call the callback.
+ // Make sure everything goes smoothly even if the callback invalidates
+ // the key (b/24785286)
+ cache.put(key2, "two");
+ EXPECT_EQ(1U, cache.size());
+ EXPECT_STREQ("two", cache.get(key2));
+ cache.clear();
+}
+
TEST_F(LruCacheTest, IteratorCheck) {
LruCache<int, int> cache(100);
diff --git a/metricsd/.clang-format b/metricsd/.clang-format
new file mode 100644
index 0000000..65d8277
--- /dev/null
+++ b/metricsd/.clang-format
@@ -0,0 +1,9 @@
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+BinPackParameters: false
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+PointerAlignment: Left
+TabWidth: 2
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 97c0d28..839ab65 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -18,8 +18,6 @@
libmetrics_sources := \
c_metrics_library.cc \
metrics_library.cc \
- serialization/metric_sample.cc \
- serialization/serialization_utils.cc \
timer.cc
metrics_client_sources := \
@@ -30,18 +28,18 @@
collectors/cpu_usage_collector.cc \
collectors/disk_usage_collector.cc \
metrics_collector.cc \
- persistent_integer.cc \
+ persistent_integer.cc
metricsd_common := \
persistent_integer.cc \
- serialization/metric_sample.cc \
- serialization/serialization_utils.cc \
+ uploader/bn_metricsd_impl.cc \
+ uploader/crash_counters.cc \
uploader/metrics_hashes.cc \
uploader/metrics_log_base.cc \
uploader/metrics_log.cc \
uploader/sender_http.cc \
uploader/system_profile_cache.cc \
- uploader/upload_service.cc \
+ uploader/upload_service.cc
metrics_collector_tests_sources := \
collectors/averaged_statistics_collector_test.cc \
@@ -49,14 +47,13 @@
metrics_collector_test.cc \
metrics_library_test.cc \
persistent_integer_test.cc \
- serialization/serialization_utils_unittest.cc \
- timer_test.cc \
+ timer_test.cc
metricsd_tests_sources := \
uploader/metrics_hashes_unittest.cc \
uploader/metrics_log_base_unittest.cc \
uploader/mock/sender_mock.cc \
- uploader/upload_service_test.cc \
+ uploader/upload_service_test.cc
metrics_CFLAGS := -Wall \
-Wno-char-subscripts \
@@ -70,7 +67,7 @@
-fvisibility=default
metrics_includes := external/gtest/include \
$(LOCAL_PATH)/include
-libmetrics_shared_libraries := libchrome libbrillo
+libmetrics_shared_libraries := libchrome libbinder libbrillo libutils
metrics_collector_shared_libraries := $(libmetrics_shared_libraries) \
libbrillo-dbus \
libbrillo-http \
@@ -78,14 +75,24 @@
libdbus \
libmetrics \
librootdev \
- libweaved \
+ libweaved
metricsd_shared_libraries := \
+ libbinder \
libbrillo \
libbrillo-http \
libchrome \
libprotobuf-cpp-lite \
libupdate_engine_client \
+ libutils
+
+# Static proxy library for the binder interface.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metricsd_binder_proxy
+LOCAL_SHARED_LIBRARIES := libbinder libutils
+LOCAL_SRC_FILES := aidl/android/brillo/metrics/IMetricsd.aidl
+include $(BUILD_STATIC_LIBRARY)
# Shared library for metrics.
# ========================================================
@@ -100,6 +107,7 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries)
LOCAL_SRC_FILES := $(libmetrics_sources)
+LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
include $(BUILD_SHARED_LIBRARY)
# CLI client for metrics.
@@ -114,6 +122,7 @@
LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries) \
libmetrics
LOCAL_SRC_FILES := $(metrics_client_sources)
+LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
include $(BUILD_EXECUTABLE)
# Protobuf library for metricsd.
@@ -144,6 +153,7 @@
LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
LOCAL_SRC_FILES := $(metrics_collector_common) \
metrics_collector_main.cc
+LOCAL_STATIC_LIBRARIES := metricsd_binder_proxy
include $(BUILD_EXECUTABLE)
# metricsd daemon.
@@ -158,9 +168,8 @@
LOCAL_INIT_RC := metricsd.rc
LOCAL_REQUIRED_MODULES := \
metrics_collector
-LOCAL_RTTI_FLAG := -frtti
LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
-LOCAL_STATIC_LIBRARIES := metricsd_protos
+LOCAL_STATIC_LIBRARIES := metricsd_protos metricsd_binder_proxy
LOCAL_SRC_FILES := $(metricsd_common) \
metricsd_main.cc
include $(BUILD_EXECUTABLE)
@@ -173,10 +182,9 @@
LOCAL_CLANG := true
LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
-LOCAL_RTTI_FLAG := -frtti
-LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries) libmetrics
+LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
LOCAL_SRC_FILES := $(metricsd_tests_sources) $(metricsd_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos
+LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos metricsd_binder_proxy
include $(BUILD_NATIVE_TEST)
# Unit tests for metrics_collector.
@@ -191,7 +199,7 @@
LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
LOCAL_SRC_FILES := $(metrics_collector_tests_sources) \
$(metrics_collector_common)
-LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock
+LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_binder_proxy
include $(BUILD_NATIVE_TEST)
# Weave schema files
diff --git a/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
new file mode 100644
index 0000000..aa3cb34
--- /dev/null
+++ b/metricsd/aidl/android/brillo/metrics/IMetricsd.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package android.brillo.metrics;
+
+interface IMetricsd {
+ oneway void recordHistogram(String name, int sample, int min, int max,
+ int nbuckets);
+ oneway void recordLinearHistogram(String name, int sample, int max);
+ oneway void recordSparseHistogram(String name, int sample);
+ oneway void recordCrash(String type);
+ String getHistogramsDump();
+}
diff --git a/metricsd/c_metrics_library.cc b/metricsd/c_metrics_library.cc
index 0503876..47a543e 100644
--- a/metricsd/c_metrics_library.cc
+++ b/metricsd/c_metrics_library.cc
@@ -66,14 +66,6 @@
return lib->SendSparseToUMA(std::string(name), sample);
}
-extern "C" int CMetricsLibrarySendUserActionToUMA(CMetricsLibrary handle,
- const char* action) {
- MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
- if (lib == NULL)
- return 0;
- return lib->SendUserActionToUMA(std::string(action));
-}
-
extern "C" int CMetricsLibrarySendCrashToUMA(CMetricsLibrary handle,
const char* crash_kind) {
MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
diff --git a/metricsd/constants.h b/metricsd/constants.h
index 3a7569b..4815888 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -18,8 +18,10 @@
#define METRICS_CONSTANTS_H_
namespace metrics {
-static const char kMetricsDirectory[] = "/data/misc/metrics/";
-static const char kMetricsEventsFileName[] = "uma-events";
+static const char kSharedMetricsDirectory[] = "/data/misc/metrics/";
+static const char kMetricsdDirectory[] = "/data/misc/metricsd/";
+static const char kMetricsCollectorDirectory[] =
+ "/data/misc/metrics_collector/";
static const char kMetricsGUIDFileName[] = "Sysinfo.GUID";
static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
static const char kConsentFileName[] = "enabled";
diff --git a/metricsd/include/metrics/c_metrics_library.h b/metricsd/include/metrics/c_metrics_library.h
index 4e7e666..1e597c2 100644
--- a/metricsd/include/metrics/c_metrics_library.h
+++ b/metricsd/include/metrics/c_metrics_library.h
@@ -44,10 +44,6 @@
int CMetricsLibrarySendSparseToUMA(CMetricsLibrary handle,
const char* name, int sample);
-// C wrapper for MetricsLibrary::SendUserActionToUMA.
-int CMetricsLibrarySendUserActionToUMA(CMetricsLibrary handle,
- const char* action);
-
// C wrapper for MetricsLibrary::SendCrashToUMA.
int CMetricsLibrarySendCrashToUMA(CMetricsLibrary handle,
const char* crash_kind);
diff --git a/metricsd/include/metrics/metrics_library.h b/metricsd/include/metrics/metrics_library.h
index d2e98c8..a1bb926 100644
--- a/metricsd/include/metrics/metrics_library.h
+++ b/metricsd/include/metrics/metrics_library.h
@@ -24,9 +24,17 @@
#include <base/compiler_specific.h>
#include <base/files/file_path.h>
#include <base/macros.h>
-#include <base/memory/scoped_ptr.h>
+#include <binder/IServiceManager.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
+namespace android {
+namespace brillo {
+namespace metrics {
+class IMetricsd;
+} // namespace metrics
+} // namespace brillo
+} // namespace android
+
class MetricsLibraryInterface {
public:
virtual void Init() = 0;
@@ -36,7 +44,6 @@
virtual bool SendEnumToUMA(const std::string& name, int sample, int max) = 0;
virtual bool SendBoolToUMA(const std::string& name, bool sample) = 0;
virtual bool SendSparseToUMA(const std::string& name, int sample) = 0;
- virtual bool SendUserActionToUMA(const std::string& action) = 0;
virtual ~MetricsLibraryInterface() {}
};
@@ -106,18 +113,6 @@
// |sample| is the 32-bit integer value to be recorded.
bool SendSparseToUMA(const std::string& name, int sample) override;
- // Sends a user action to Chrome for transport to UMA and returns true on
- // success. This method results in the equivalent of an asynchronous
- // non-blocking RPC to UserMetrics::RecordAction. The new metric must be
- // added to chrome/tools/extract_actions.py in the Chromium repository, which
- // should then be run to generate a hash for the new action.
- //
- // Until http://crosbug.com/11125 is fixed, the metric must also be added to
- // chrome/browser/chromeos/external_metrics.cc.
- //
- // |action| is the user-generated event (e.g., "MuteKeyPressed").
- bool SendUserActionToUMA(const std::string& action) override;
-
// Sends a signal to UMA that a crash of the given |crash_kind|
// has occurred. Used by UMA to generate stability statistics.
bool SendCrashToUMA(const char *crash_kind);
@@ -130,6 +125,11 @@
// number in the histograms dashboard).
bool SendCrosEventToUMA(const std::string& event);
+ // Debugging only.
+ // Dumps the histograms aggregated since metricsd started into |dump|.
+ // Returns true iff the dump succeeds.
+ bool GetHistogramsDump(std::string* dump);
+
private:
friend class CMetricsLibraryTest;
friend class MetricsLibraryTest;
@@ -152,6 +152,10 @@
char* buffer, int buffer_size,
bool* result);
+ // Connects to IMetricsd if the proxy does not exist or is not alive.
+ // Don't block if we fail to get the proxy for any reason.
+ bool CheckService();
+
// Time at which we last checked if metrics were enabled.
time_t cached_enabled_time_;
@@ -161,7 +165,8 @@
// True iff we should cache the enabled/disabled status.
bool use_caching_;
- base::FilePath uma_events_file_;
+ android::sp<android::IServiceManager> manager_;
+ android::sp<android::brillo::metrics::IMetricsd> metricsd_proxy_;
base::FilePath consent_file_;
DISALLOW_COPY_AND_ASSIGN(MetricsLibrary);
diff --git a/metricsd/include/metrics/metrics_library_mock.h b/metricsd/include/metrics/metrics_library_mock.h
index db56f9e..3b0b24d 100644
--- a/metricsd/include/metrics/metrics_library_mock.h
+++ b/metricsd/include/metrics/metrics_library_mock.h
@@ -34,7 +34,6 @@
int max));
MOCK_METHOD2(SendBoolToUMA, bool(const std::string& name, bool sample));
MOCK_METHOD2(SendSparseToUMA, bool(const std::string& name, int sample));
- MOCK_METHOD1(SendUserActionToUMA, bool(const std::string& action));
bool AreMetricsEnabled() override {return metrics_enabled_;};
};
diff --git a/metricsd/metrics_client.cc b/metricsd/metrics_client.cc
index 78174ef..c66b975 100644
--- a/metricsd/metrics_client.cc
+++ b/metricsd/metrics_client.cc
@@ -17,19 +17,14 @@
#include <cstdio>
#include <cstdlib>
-#include <base/memory/scoped_vector.h>
-
#include "constants.h"
#include "metrics/metrics_library.h"
-#include "serialization/metric_sample.h"
-#include "serialization/serialization_utils.h"
enum Mode {
- kModeDumpLogs,
+ kModeDumpHistograms,
kModeSendSample,
kModeSendEnumSample,
kModeSendSparseSample,
- kModeSendUserAction,
kModeSendCrosEvent,
kModeHasConsent,
kModeIsGuestMode,
@@ -41,19 +36,17 @@
" metrics_client -e name sample max\n"
" metrics_client -s name sample\n"
" metrics_client -v event\n"
- " metrics_client -u action\n"
" metrics_client [-cdg]\n"
"\n"
" default: send metric with integer values \n"
" |min| > 0, |min| <= sample < |max|\n"
" -c: return exit status 0 if user consents to stats, 1 otherwise,\n"
" in guest mode always return 1\n"
- " -d: dump cached logs to the console\n"
+ " -d: dump the histograms recorded by metricsd to stdout\n"
" -e: send linear/enumeration histogram data\n"
" -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
" -s: send a sparse histogram sample\n"
" -t: convert sample from double seconds to int milliseconds\n"
- " -u: send a user action to Chrome\n"
" -v: send a Platform.CrOSEvent enum histogram sample\n");
exit(1);
}
@@ -78,6 +71,20 @@
return value;
}
+static int DumpHistograms() {
+ MetricsLibrary metrics_lib;
+ metrics_lib.Init();
+
+ std::string dump;
+ if (!metrics_lib.GetHistogramsDump(&dump)) {
+ printf("Failed to dump the histograms.");
+ return 1;
+ }
+
+ printf("%s\n", dump.c_str());
+ return 0;
+}
+
static int SendStats(char* argv[],
int name_index,
enum Mode mode,
@@ -106,14 +113,6 @@
return 0;
}
-static int SendUserAction(char* argv[], int action_index) {
- const char* action = argv[action_index];
- MetricsLibrary metrics_lib;
- metrics_lib.Init();
- metrics_lib.SendUserActionToUMA(action);
- return 0;
-}
-
static int SendCrosEvent(char* argv[], int action_index) {
const char* event = argv[action_index];
bool result;
@@ -139,58 +138,19 @@
return metrics_lib.IsGuestMode() ? 0 : 1;
}
-static int DumpLogs() {
- base::FilePath events_file = base::FilePath(
- metrics::kMetricsDirectory).Append(metrics::kMetricsEventsFileName);
- printf("Metrics from %s\n\n", events_file.value().data());
-
- ScopedVector<metrics::MetricSample> metrics;
- metrics::SerializationUtils::ReadMetricsFromFile(events_file.value(),
- &metrics);
-
- for (ScopedVector<metrics::MetricSample>::const_iterator i = metrics.begin();
- i != metrics.end(); ++i) {
- const metrics::MetricSample* sample = *i;
- printf("name: %s\t", sample->name().c_str());
- printf("type: ");
-
- switch (sample->type()) {
- case metrics::MetricSample::CRASH:
- printf("CRASH");
- break;
- case metrics::MetricSample::HISTOGRAM:
- printf("HISTOGRAM");
- break;
- case metrics::MetricSample::LINEAR_HISTOGRAM:
- printf("LINEAR_HISTOGRAM");
- break;
- case metrics::MetricSample::SPARSE_HISTOGRAM:
- printf("SPARSE_HISTOGRAM");
- break;
- case metrics::MetricSample::USER_ACTION:
- printf("USER_ACTION");
- break;
- }
-
- printf("\n");
- }
-
- return 0;
-}
-
int main(int argc, char** argv) {
enum Mode mode = kModeSendSample;
bool secs_to_msecs = false;
// Parse arguments
int flag;
- while ((flag = getopt(argc, argv, "abcdegstuv")) != -1) {
+ while ((flag = getopt(argc, argv, "abcdegstv")) != -1) {
switch (flag) {
case 'c':
mode = kModeHasConsent;
break;
case 'd':
- mode = kModeDumpLogs;
+ mode = kModeDumpHistograms;
break;
case 'e':
mode = kModeSendEnumSample;
@@ -204,9 +164,6 @@
case 't':
secs_to_msecs = true;
break;
- case 'u':
- mode = kModeSendUserAction;
- break;
case 'v':
mode = kModeSendCrosEvent;
break;
@@ -224,8 +181,6 @@
expected_args = 3;
else if (mode == kModeSendSparseSample)
expected_args = 2;
- else if (mode == kModeSendUserAction)
- expected_args = 1;
else if (mode == kModeSendCrosEvent)
expected_args = 1;
@@ -234,6 +189,8 @@
}
switch (mode) {
+ case kModeDumpHistograms:
+ return DumpHistograms();
case kModeSendSample:
case kModeSendEnumSample:
case kModeSendSparseSample:
@@ -244,16 +201,12 @@
arg_index,
mode,
secs_to_msecs);
- case kModeSendUserAction:
- return SendUserAction(argv, arg_index);
case kModeSendCrosEvent:
return SendCrosEvent(argv, arg_index);
case kModeHasConsent:
return HasConsent();
case kModeIsGuestMode:
return IsGuestMode();
- case kModeDumpLogs:
- return DumpLogs();
default:
ShowUsage();
return 0;
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index 28194a1..28f9ad3 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -149,51 +149,54 @@
return version_hash;
}
-void MetricsCollector::Init(bool testing,
- MetricsLibraryInterface* metrics_lib,
- const string& diskstats_path,
- const base::FilePath& metrics_directory) {
+void MetricsCollector::Init(bool testing, MetricsLibraryInterface* metrics_lib,
+ const string& diskstats_path,
+ const base::FilePath& private_metrics_directory,
+ const base::FilePath& shared_metrics_directory) {
CHECK(metrics_lib);
testing_ = testing;
- metrics_directory_ = metrics_directory;
+ shared_metrics_directory_ = shared_metrics_directory;
metrics_lib_ = metrics_lib;
- daily_active_use_.reset(
- new PersistentInteger("Platform.UseTime.PerDay"));
- version_cumulative_active_use_.reset(
- new PersistentInteger("Platform.CumulativeUseTime"));
- version_cumulative_cpu_use_.reset(
- new PersistentInteger("Platform.CumulativeCpuTime"));
+ daily_active_use_.reset(new PersistentInteger("Platform.UseTime.PerDay",
+ private_metrics_directory));
+ version_cumulative_active_use_.reset(new PersistentInteger(
+ "Platform.CumulativeUseTime", private_metrics_directory));
+ version_cumulative_cpu_use_.reset(new PersistentInteger(
+ "Platform.CumulativeCpuTime", private_metrics_directory));
- kernel_crash_interval_.reset(
- new PersistentInteger("Platform.KernelCrashInterval"));
- unclean_shutdown_interval_.reset(
- new PersistentInteger("Platform.UncleanShutdownInterval"));
- user_crash_interval_.reset(
- new PersistentInteger("Platform.UserCrashInterval"));
+ kernel_crash_interval_.reset(new PersistentInteger(
+ "Platform.KernelCrashInterval", private_metrics_directory));
+ unclean_shutdown_interval_.reset(new PersistentInteger(
+ "Platform.UncleanShutdownInterval", private_metrics_directory));
+ user_crash_interval_.reset(new PersistentInteger("Platform.UserCrashInterval",
+ private_metrics_directory));
- any_crashes_daily_count_.reset(
- new PersistentInteger("Platform.AnyCrashes.PerDay"));
- any_crashes_weekly_count_.reset(
- new PersistentInteger("Platform.AnyCrashes.PerWeek"));
- user_crashes_daily_count_.reset(
- new PersistentInteger("Platform.UserCrashes.PerDay"));
- user_crashes_weekly_count_.reset(
- new PersistentInteger("Platform.UserCrashes.PerWeek"));
- kernel_crashes_daily_count_.reset(
- new PersistentInteger("Platform.KernelCrashes.PerDay"));
- kernel_crashes_weekly_count_.reset(
- new PersistentInteger("Platform.KernelCrashes.PerWeek"));
- kernel_crashes_version_count_.reset(
- new PersistentInteger("Platform.KernelCrashesSinceUpdate"));
- unclean_shutdowns_daily_count_.reset(
- new PersistentInteger("Platform.UncleanShutdown.PerDay"));
- unclean_shutdowns_weekly_count_.reset(
- new PersistentInteger("Platform.UncleanShutdowns.PerWeek"));
+ any_crashes_daily_count_.reset(new PersistentInteger(
+ "Platform.AnyCrashes.PerDay", private_metrics_directory));
+ any_crashes_weekly_count_.reset(new PersistentInteger(
+ "Platform.AnyCrashes.PerWeek", private_metrics_directory));
+ user_crashes_daily_count_.reset(new PersistentInteger(
+ "Platform.UserCrashes.PerDay", private_metrics_directory));
+ user_crashes_weekly_count_.reset(new PersistentInteger(
+ "Platform.UserCrashes.PerWeek", private_metrics_directory));
+ kernel_crashes_daily_count_.reset(new PersistentInteger(
+ "Platform.KernelCrashes.PerDay", private_metrics_directory));
+ kernel_crashes_weekly_count_.reset(new PersistentInteger(
+ "Platform.KernelCrashes.PerWeek", private_metrics_directory));
+ kernel_crashes_version_count_.reset(new PersistentInteger(
+ "Platform.KernelCrashesSinceUpdate", private_metrics_directory));
+ unclean_shutdowns_daily_count_.reset(new PersistentInteger(
+ "Platform.UncleanShutdown.PerDay", private_metrics_directory));
+ unclean_shutdowns_weekly_count_.reset(new PersistentInteger(
+ "Platform.UncleanShutdowns.PerWeek", private_metrics_directory));
- daily_cycle_.reset(new PersistentInteger("daily.cycle"));
- weekly_cycle_.reset(new PersistentInteger("weekly.cycle"));
- version_cycle_.reset(new PersistentInteger("version.cycle"));
+ daily_cycle_.reset(
+ new PersistentInteger("daily.cycle", private_metrics_directory));
+ weekly_cycle_.reset(
+ new PersistentInteger("weekly.cycle", private_metrics_directory));
+ version_cycle_.reset(
+ new PersistentInteger("version.cycle", private_metrics_directory));
disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
averaged_stats_collector_.reset(
@@ -288,8 +291,9 @@
if (!command)
return;
- if (base::WriteFile(metrics_directory_.Append(metrics::kConsentFileName),
- "", 0) != 0) {
+ if (base::WriteFile(
+ shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
+ 0) {
PLOG(ERROR) << "Could not create the consent file.";
command->Abort("metrics_error", "Could not create the consent file",
nullptr);
@@ -306,8 +310,8 @@
if (!command)
return;
- if (!base::DeleteFile(metrics_directory_.Append(metrics::kConsentFileName),
- false)) {
+ if (!base::DeleteFile(
+ shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
PLOG(ERROR) << "Could not delete the consent file.";
command->Abort("metrics_error", "Could not delete the consent file",
nullptr);
diff --git a/metricsd/metrics_collector.h b/metricsd/metrics_collector.h
index e080ac0..69747d0 100644
--- a/metricsd/metrics_collector.h
+++ b/metricsd/metrics_collector.h
@@ -48,7 +48,8 @@
void Init(bool testing,
MetricsLibraryInterface* metrics_lib,
const std::string& diskstats_path,
- const base::FilePath& metrics_directory);
+ const base::FilePath& private_metrics_directory,
+ const base::FilePath& shared_metrics_directory);
// Initializes DBus and MessageLoop variables before running the MessageLoop.
int OnInit() override;
@@ -225,8 +226,8 @@
// Test mode.
bool testing_;
- // Root of the configuration files to use.
- base::FilePath metrics_directory_;
+ // Publicly readable metrics directory.
+ base::FilePath shared_metrics_directory_;
// The metrics library handle.
MetricsLibraryInterface* metrics_lib_;
diff --git a/metricsd/metrics_collector_main.cc b/metricsd/metrics_collector_main.cc
index 117426e..d7aaaf5 100644
--- a/metricsd/metrics_collector_main.cc
+++ b/metricsd/metrics_collector_main.cc
@@ -51,9 +51,13 @@
int main(int argc, char** argv) {
DEFINE_bool(foreground, false, "Don't daemonize");
- DEFINE_string(metrics_directory,
- metrics::kMetricsDirectory,
- "Root of the configuration files (testing only)");
+ DEFINE_string(private_directory, metrics::kMetricsCollectorDirectory,
+ "Path to the private directory used by metrics_collector "
+ "(testing only)");
+ DEFINE_string(shared_directory, metrics::kSharedMetricsDirectory,
+ "Path to the shared metrics directory, used by "
+ "metrics_collector, metricsd and all metrics clients "
+ "(testing only)");
DEFINE_bool(logtostderr, false, "Log to standard error");
DEFINE_bool(logtosyslog, false, "Log to syslog");
@@ -86,7 +90,8 @@
daemon.Init(false,
&metrics_lib,
MetricsMainDiskStatsPath(),
- base::FilePath(FLAGS_metrics_directory));
+ base::FilePath(FLAGS_private_directory),
+ base::FilePath(FLAGS_shared_directory));
daemon.Run();
}
diff --git a/metricsd/metrics_collector_test.cc b/metricsd/metrics_collector_test.cc
index a0e7087..956e56b 100644
--- a/metricsd/metrics_collector_test.cc
+++ b/metricsd/metrics_collector_test.cc
@@ -46,9 +46,13 @@
brillo::FlagHelper::Init(0, nullptr, "");
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
- chromeos_metrics::PersistentInteger::SetMetricsDirectory(
- temp_dir_.path().value());
- daemon_.Init(true, &metrics_lib_, "", temp_dir_.path());
+ base::FilePath private_dir = temp_dir_.path().Append("private");
+ base::FilePath shared_dir = temp_dir_.path().Append("shared");
+
+ EXPECT_TRUE(base::CreateDirectory(private_dir));
+ EXPECT_TRUE(base::CreateDirectory(shared_dir));
+
+ daemon_.Init(true, &metrics_lib_, "", private_dir, shared_dir);
}
// Adds a metrics library mock expectation that the specified metric
diff --git a/metricsd/metrics_library.cc b/metricsd/metrics_library.cc
index 735d39f..d211ab4 100644
--- a/metricsd/metrics_library.cc
+++ b/metricsd/metrics_library.cc
@@ -18,19 +18,21 @@
#include <base/logging.h>
#include <base/strings/stringprintf.h>
+#include <binder/IServiceManager.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/stat.h>
+#include <utils/String16.h>
#include <cstdio>
#include <cstring>
+#include "android/brillo/metrics/IMetricsd.h"
#include "constants.h"
-#include "serialization/metric_sample.h"
-#include "serialization/serialization_utils.h"
static const char kCrosEventHistogramName[] = "Platform.CrOSEvent";
static const int kCrosEventHistogramMax = 100;
+static const char kMetricsServiceName[] = "android.brillo.metrics.IMetricsd";
/* Add new cros events here.
*
@@ -53,6 +55,10 @@
"TPM.EarlyResetDuringCommand", // 12
};
+using android::binder::Status;
+using android::brillo::metrics::IMetricsd;
+using android::String16;
+
MetricsLibrary::MetricsLibrary() {}
MetricsLibrary::~MetricsLibrary() {}
@@ -123,6 +129,17 @@
return result && (access("/var/run/state/logged-in", F_OK) == 0);
}
+bool MetricsLibrary::CheckService() {
+ if (metricsd_proxy_.get() &&
+ android::IInterface::asBinder(metricsd_proxy_)->isBinderAlive())
+ return true;
+
+ const String16 name(kMetricsServiceName);
+ metricsd_proxy_ = android::interface_cast<IMetricsd>(
+ android::defaultServiceManager()->checkService(name));
+ return metricsd_proxy_.get();
+}
+
bool MetricsLibrary::AreMetricsEnabled() {
static struct stat stat_buffer;
time_t this_check_time = time(nullptr);
@@ -134,8 +151,7 @@
}
void MetricsLibrary::Init() {
- base::FilePath dir = base::FilePath(metrics::kMetricsDirectory);
- uma_events_file_ = dir.Append(metrics::kMetricsEventsFileName);
+ base::FilePath dir = base::FilePath(metrics::kSharedMetricsDirectory);
consent_file_ = dir.Append(metrics::kConsentFileName);
cached_enabled_ = false;
cached_enabled_time_ = 0;
@@ -148,54 +164,45 @@
}
void MetricsLibrary::InitForTest(const base::FilePath& metrics_directory) {
- uma_events_file_ = metrics_directory.Append(metrics::kMetricsEventsFileName);
consent_file_ = metrics_directory.Append(metrics::kConsentFileName);
cached_enabled_ = false;
cached_enabled_time_ = 0;
use_caching_ = true;
}
-bool MetricsLibrary::SendToUMA(const std::string& name,
- int sample,
- int min,
- int max,
- int nbuckets) {
- return metrics::SerializationUtils::WriteMetricToFile(
- *metrics::MetricSample::HistogramSample(name, sample, min, max, nbuckets)
- .get(),
- uma_events_file_.value());
+bool MetricsLibrary::SendToUMA(
+ const std::string& name, int sample, int min, int max, int nbuckets) {
+ return CheckService() &&
+ metricsd_proxy_->recordHistogram(String16(name.c_str()), sample, min,
+ max, nbuckets)
+ .isOk();
}
-bool MetricsLibrary::SendEnumToUMA(const std::string& name, int sample,
+bool MetricsLibrary::SendEnumToUMA(const std::string& name,
+ int sample,
int max) {
- return metrics::SerializationUtils::WriteMetricToFile(
- *metrics::MetricSample::LinearHistogramSample(name, sample, max).get(),
- uma_events_file_.value());
+ return CheckService() &&
+ metricsd_proxy_->recordLinearHistogram(String16(name.c_str()), sample,
+ max)
+ .isOk();
}
bool MetricsLibrary::SendBoolToUMA(const std::string& name, bool sample) {
- return metrics::SerializationUtils::WriteMetricToFile(
- *metrics::MetricSample::LinearHistogramSample(name,
- sample ? 1 : 0, 2).get(),
- uma_events_file_.value());
+ return CheckService() &&
+ metricsd_proxy_->recordLinearHistogram(String16(name.c_str()),
+ sample ? 1 : 0, 2)
+ .isOk();
}
bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) {
- return metrics::SerializationUtils::WriteMetricToFile(
- *metrics::MetricSample::SparseHistogramSample(name, sample).get(),
- uma_events_file_.value());
+ return CheckService() &&
+ metricsd_proxy_->recordSparseHistogram(String16(name.c_str()), sample)
+ .isOk();
}
-bool MetricsLibrary::SendUserActionToUMA(const std::string& action) {
- return metrics::SerializationUtils::WriteMetricToFile(
- *metrics::MetricSample::UserActionSample(action).get(),
- uma_events_file_.value());
-}
-
-bool MetricsLibrary::SendCrashToUMA(const char *crash_kind) {
- return metrics::SerializationUtils::WriteMetricToFile(
- *metrics::MetricSample::CrashSample(crash_kind).get(),
- uma_events_file_.value());
+bool MetricsLibrary::SendCrashToUMA(const char* crash_kind) {
+ return CheckService() &&
+ metricsd_proxy_->recordCrash(String16(crash_kind)).isOk();
}
bool MetricsLibrary::SendCrosEventToUMA(const std::string& event) {
@@ -206,3 +213,14 @@
}
return false;
}
+
+bool MetricsLibrary::GetHistogramsDump(std::string* dump) {
+ android::String16 temp_dump;
+ if (!CheckService() ||
+ !metricsd_proxy_->getHistogramsDump(&temp_dump).isOk()) {
+ return false;
+ }
+
+ *dump = android::String8(temp_dump).string();
+ return true;
+}
diff --git a/metricsd/metrics_library_test.cc b/metricsd/metrics_library_test.cc
index be8a4bb..52fcce3 100644
--- a/metricsd/metrics_library_test.cc
+++ b/metricsd/metrics_library_test.cc
@@ -29,7 +29,6 @@
virtual void SetUp() {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
lib_.InitForTest(temp_dir_.path());
- EXPECT_EQ(0, WriteFile(lib_.uma_events_file_, "", 0));
// Defeat metrics enabled caching between tests.
lib_.cached_enabled_time_ = 0;
}
diff --git a/metricsd/metricsd.rc b/metricsd/metricsd.rc
index b5e7b82..359d0d1 100644
--- a/metricsd/metricsd.rc
+++ b/metricsd/metricsd.rc
@@ -1,5 +1,7 @@
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
service metricsd /system/bin/metricsd --foreground --logtosyslog
class late_start
diff --git a/metricsd/metricsd_main.cc b/metricsd/metricsd_main.cc
index ab71e6b..f460268 100644
--- a/metricsd/metricsd_main.cc
+++ b/metricsd/metricsd_main.cc
@@ -14,46 +14,50 @@
* limitations under the License.
*/
+#include <thread>
+
#include <base/at_exit.h>
#include <base/command_line.h>
#include <base/files/file_path.h>
#include <base/logging.h>
+#include <base/metrics/statistics_recorder.h>
#include <base/strings/string_util.h>
#include <base/time/time.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include "constants.h"
+#include "uploader/bn_metricsd_impl.h"
+#include "uploader/crash_counters.h"
#include "uploader/upload_service.h"
-
int main(int argc, char** argv) {
DEFINE_bool(foreground, false, "Don't daemonize");
// Upload the metrics once and exit. (used for testing)
- DEFINE_bool(uploader_test,
- false,
- "run the uploader once and exit");
+ DEFINE_bool(uploader_test, false, "run the uploader once and exit");
// Upload Service flags.
- DEFINE_int32(upload_interval_secs,
- 1800,
+ DEFINE_int32(upload_interval_secs, 1800,
"Interval at which metrics_daemon sends the metrics. (needs "
"-uploader)");
- DEFINE_string(server,
- metrics::kMetricsServer,
+ DEFINE_string(server, metrics::kMetricsServer,
"Server to upload the metrics to. (needs -uploader)");
- DEFINE_string(metrics_directory,
- metrics::kMetricsDirectory,
- "Root of the configuration files (testing only)");
+ DEFINE_string(private_directory, metrics::kMetricsdDirectory,
+ "Path to the private directory used by metricsd "
+ "(testing only)");
+ DEFINE_string(shared_directory, metrics::kSharedMetricsDirectory,
+ "Path to the shared metrics directory, used by "
+ "metrics_collector, metricsd and all metrics clients "
+ "(testing only)");
DEFINE_bool(logtostderr, false, "Log to standard error");
DEFINE_bool(logtosyslog, false, "Log to syslog");
brillo::FlagHelper::Init(argc, argv, "Brillo metrics daemon.");
- int logging_location = (FLAGS_foreground ? brillo::kLogToStderr
- : brillo::kLogToSyslog);
+ int logging_location =
+ (FLAGS_foreground ? brillo::kLogToStderr : brillo::kLogToSyslog);
if (FLAGS_logtosyslog)
logging_location = brillo::kLogToSyslog;
@@ -72,9 +76,18 @@
return errno;
}
- UploadService service(FLAGS_server,
- base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
- base::FilePath(FLAGS_metrics_directory));
+ std::shared_ptr<CrashCounters> counters(new CrashCounters);
- service.Run();
+ UploadService upload_service(
+ FLAGS_server, base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),
+ base::FilePath(FLAGS_private_directory),
+ base::FilePath(FLAGS_shared_directory), counters);
+
+ base::StatisticsRecorder::Initialize();
+
+ // Create and start the binder thread.
+ BnMetricsdImpl binder_service(counters);
+ std::thread binder_thread(&BnMetricsdImpl::Run, &binder_service);
+
+ upload_service.Run();
}
diff --git a/metricsd/persistent_integer.cc b/metricsd/persistent_integer.cc
index ddc4b50..7fe355e 100644
--- a/metricsd/persistent_integer.cc
+++ b/metricsd/persistent_integer.cc
@@ -23,19 +23,15 @@
#include "constants.h"
-
namespace chromeos_metrics {
-// Static class member instantiation.
-std::string PersistentInteger::metrics_directory_ = metrics::kMetricsDirectory;
-
-PersistentInteger::PersistentInteger(const std::string& name) :
- value_(0),
+PersistentInteger::PersistentInteger(const std::string& name,
+ const base::FilePath& directory)
+ : value_(0),
version_(kVersion),
name_(name),
- synced_(false) {
- backing_file_name_ = metrics_directory_ + name_;
-}
+ backing_file_path_(directory.Append(name_)),
+ synced_(false) {}
PersistentInteger::~PersistentInteger() {}
@@ -62,23 +58,25 @@
}
void PersistentInteger::Write() {
- int fd = HANDLE_EINTR(open(backing_file_name_.c_str(),
+ int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(),
O_WRONLY | O_CREAT | O_TRUNC,
S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH));
- PCHECK(fd >= 0) << "cannot open " << backing_file_name_ << " for writing";
+ PCHECK(fd >= 0) << "cannot open " << backing_file_path_.value()
+ << " for writing";
PCHECK((HANDLE_EINTR(write(fd, &version_, sizeof(version_))) ==
sizeof(version_)) &&
(HANDLE_EINTR(write(fd, &value_, sizeof(value_))) ==
sizeof(value_)))
- << "cannot write to " << backing_file_name_;
+ << "cannot write to " << backing_file_path_.value();
close(fd);
synced_ = true;
}
bool PersistentInteger::Read() {
- int fd = HANDLE_EINTR(open(backing_file_name_.c_str(), O_RDONLY));
+ int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(), O_RDONLY));
if (fd < 0) {
- PLOG(WARNING) << "cannot open " << backing_file_name_ << " for reading";
+ PLOG(WARNING) << "cannot open " << backing_file_path_.value()
+ << " for reading";
return false;
}
int32_t version;
@@ -95,9 +93,4 @@
return read_succeeded;
}
-void PersistentInteger::SetMetricsDirectory(const std::string& directory) {
- metrics_directory_ = directory;
-}
-
-
} // namespace chromeos_metrics
diff --git a/metricsd/persistent_integer.h b/metricsd/persistent_integer.h
index ecef3d1..96d9fc0 100644
--- a/metricsd/persistent_integer.h
+++ b/metricsd/persistent_integer.h
@@ -21,6 +21,8 @@
#include <string>
+#include <base/files/file_path.h>
+
namespace chromeos_metrics {
// PersistentIntegers is a named 64-bit integer value backed by a file.
@@ -29,7 +31,7 @@
class PersistentInteger {
public:
- explicit PersistentInteger(const std::string& name);
+ PersistentInteger(const std::string& name, const base::FilePath& directory);
// Virtual only because of mock.
virtual ~PersistentInteger();
@@ -50,10 +52,6 @@
// Virtual only because of mock.
virtual void Add(int64_t x);
- // Sets the directory path for all persistent integers.
- // This is used in unittests to change where the counters are stored.
- static void SetMetricsDirectory(const std::string& directory);
-
private:
static const int kVersion = 1001;
@@ -68,8 +66,7 @@
int64_t value_;
int32_t version_;
std::string name_;
- std::string backing_file_name_;
- static std::string metrics_directory_;
+ base::FilePath backing_file_path_;
bool synced_;
};
diff --git a/metricsd/persistent_integer_mock.h b/metricsd/persistent_integer_mock.h
index acc5389..0be54d4 100644
--- a/metricsd/persistent_integer_mock.h
+++ b/metricsd/persistent_integer_mock.h
@@ -27,9 +27,10 @@
class PersistentIntegerMock : public PersistentInteger {
public:
- explicit PersistentIntegerMock(const std::string& name)
- : PersistentInteger(name) {}
- MOCK_METHOD1(Add, void(int64_t count));
+ explicit PersistentIntegerMock(const std::string& name,
+ const base::FilePath& directory)
+ : PersistentInteger(name, directory) {}
+ MOCK_METHOD1(Add, void(int64_t count));
};
} // namespace chromeos_metrics
diff --git a/metricsd/persistent_integer_test.cc b/metricsd/persistent_integer_test.cc
index 5e2067f..55d6cbc 100644
--- a/metricsd/persistent_integer_test.cc
+++ b/metricsd/persistent_integer_test.cc
@@ -24,7 +24,6 @@
#include "persistent_integer.h"
const char kBackingFileName[] = "1.pibakf";
-const char kBackingFilePattern[] = "*.pibakf";
using chromeos_metrics::PersistentInteger;
@@ -32,28 +31,15 @@
void SetUp() override {
// Set testing mode.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- chromeos_metrics::PersistentInteger::SetMetricsDirectory(
- temp_dir_.path().value());
}
- void TearDown() override {
- // Remove backing files. The convention is that they all end in ".pibakf".
- base::FileEnumerator f_enum(base::FilePath("."),
- false,
- base::FileEnumerator::FILES,
- FILE_PATH_LITERAL(kBackingFilePattern));
- for (base::FilePath name = f_enum.Next();
- !name.empty();
- name = f_enum.Next()) {
- base::DeleteFile(name, false);
- }
- }
-
+ protected:
base::ScopedTempDir temp_dir_;
};
TEST_F(PersistentIntegerTest, BasicChecks) {
- scoped_ptr<PersistentInteger> pi(new PersistentInteger(kBackingFileName));
+ scoped_ptr<PersistentInteger> pi(
+ new PersistentInteger(kBackingFileName, temp_dir_.path()));
// Test initialization.
EXPECT_EQ(0, pi->Get());
@@ -65,7 +51,7 @@
EXPECT_EQ(5, pi->Get());
// Test persistence.
- pi.reset(new PersistentInteger(kBackingFileName));
+ pi.reset(new PersistentInteger(kBackingFileName, temp_dir_.path()));
EXPECT_EQ(5, pi->Get());
// Test GetAndClear.
@@ -73,6 +59,6 @@
EXPECT_EQ(pi->Get(), 0);
// Another persistence test.
- pi.reset(new PersistentInteger(kBackingFileName));
+ pi.reset(new PersistentInteger(kBackingFileName, temp_dir_.path()));
EXPECT_EQ(0, pi->Get());
}
diff --git a/metricsd/serialization/metric_sample.cc b/metricsd/serialization/metric_sample.cc
deleted file mode 100644
index 76a47c0..0000000
--- a/metricsd/serialization/metric_sample.cc
+++ /dev/null
@@ -1,209 +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 "serialization/metric_sample.h"
-
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-
-namespace metrics {
-
-MetricSample::MetricSample(MetricSample::SampleType sample_type,
- const std::string& metric_name,
- int sample,
- int min,
- int max,
- int bucket_count)
- : type_(sample_type),
- name_(metric_name),
- sample_(sample),
- min_(min),
- max_(max),
- bucket_count_(bucket_count) {
-}
-
-MetricSample::~MetricSample() {
-}
-
-bool MetricSample::IsValid() const {
- return name().find(' ') == std::string::npos &&
- name().find('\0') == std::string::npos && !name().empty();
-}
-
-std::string MetricSample::ToString() const {
- if (type_ == CRASH) {
- return base::StringPrintf("crash%c%s%c",
- '\0',
- name().c_str(),
- '\0');
- } else if (type_ == SPARSE_HISTOGRAM) {
- return base::StringPrintf("sparsehistogram%c%s %d%c",
- '\0',
- name().c_str(),
- sample_,
- '\0');
- } else if (type_ == LINEAR_HISTOGRAM) {
- return base::StringPrintf("linearhistogram%c%s %d %d%c",
- '\0',
- name().c_str(),
- sample_,
- max_,
- '\0');
- } else if (type_ == HISTOGRAM) {
- return base::StringPrintf("histogram%c%s %d %d %d %d%c",
- '\0',
- name().c_str(),
- sample_,
- min_,
- max_,
- bucket_count_,
- '\0');
- } else {
- // The type can only be USER_ACTION.
- CHECK_EQ(type_, USER_ACTION);
- return base::StringPrintf("useraction%c%s%c",
- '\0',
- name().c_str(),
- '\0');
- }
-}
-
-int MetricSample::sample() const {
- CHECK_NE(type_, USER_ACTION);
- CHECK_NE(type_, CRASH);
- return sample_;
-}
-
-int MetricSample::min() const {
- CHECK_EQ(type_, HISTOGRAM);
- return min_;
-}
-
-int MetricSample::max() const {
- CHECK_NE(type_, CRASH);
- CHECK_NE(type_, USER_ACTION);
- CHECK_NE(type_, SPARSE_HISTOGRAM);
- return max_;
-}
-
-int MetricSample::bucket_count() const {
- CHECK_EQ(type_, HISTOGRAM);
- return bucket_count_;
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::CrashSample(
- const std::string& crash_name) {
- return scoped_ptr<MetricSample>(
- new MetricSample(CRASH, crash_name, 0, 0, 0, 0));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::HistogramSample(
- const std::string& histogram_name,
- int sample,
- int min,
- int max,
- int bucket_count) {
- return scoped_ptr<MetricSample>(new MetricSample(
- HISTOGRAM, histogram_name, sample, min, max, bucket_count));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::ParseHistogram(
- const std::string& serialized_histogram) {
- std::vector<std::string> parts;
- base::SplitString(serialized_histogram, ' ', &parts);
-
- if (parts.size() != 5)
- return scoped_ptr<MetricSample>();
- int sample, min, max, bucket_count;
- if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
- !base::StringToInt(parts[2], &min) ||
- !base::StringToInt(parts[3], &max) ||
- !base::StringToInt(parts[4], &bucket_count)) {
- return scoped_ptr<MetricSample>();
- }
-
- return HistogramSample(parts[0], sample, min, max, bucket_count);
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::SparseHistogramSample(
- const std::string& histogram_name,
- int sample) {
- return scoped_ptr<MetricSample>(
- new MetricSample(SPARSE_HISTOGRAM, histogram_name, sample, 0, 0, 0));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::ParseSparseHistogram(
- const std::string& serialized_histogram) {
- std::vector<std::string> parts;
- base::SplitString(serialized_histogram, ' ', &parts);
- if (parts.size() != 2)
- return scoped_ptr<MetricSample>();
- int sample;
- if (parts[0].empty() || !base::StringToInt(parts[1], &sample))
- return scoped_ptr<MetricSample>();
-
- return SparseHistogramSample(parts[0], sample);
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::LinearHistogramSample(
- const std::string& histogram_name,
- int sample,
- int max) {
- return scoped_ptr<MetricSample>(
- new MetricSample(LINEAR_HISTOGRAM, histogram_name, sample, 0, max, 0));
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::ParseLinearHistogram(
- const std::string& serialized_histogram) {
- std::vector<std::string> parts;
- int sample, max;
- base::SplitString(serialized_histogram, ' ', &parts);
- if (parts.size() != 3)
- return scoped_ptr<MetricSample>();
- if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
- !base::StringToInt(parts[2], &max)) {
- return scoped_ptr<MetricSample>();
- }
-
- return LinearHistogramSample(parts[0], sample, max);
-}
-
-// static
-scoped_ptr<MetricSample> MetricSample::UserActionSample(
- const std::string& action_name) {
- return scoped_ptr<MetricSample>(
- new MetricSample(USER_ACTION, action_name, 0, 0, 0, 0));
-}
-
-bool MetricSample::IsEqual(const MetricSample& metric) {
- return type_ == metric.type_ && name_ == metric.name_ &&
- sample_ == metric.sample_ && min_ == metric.min_ &&
- max_ == metric.max_ && bucket_count_ == metric.bucket_count_;
-}
-
-} // namespace metrics
diff --git a/metricsd/serialization/metric_sample.h b/metricsd/serialization/metric_sample.h
deleted file mode 100644
index 5a4e4ae..0000000
--- a/metricsd/serialization/metric_sample.h
+++ /dev/null
@@ -1,131 +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 METRICS_SERIALIZATION_METRIC_SAMPLE_H_
-#define METRICS_SERIALIZATION_METRIC_SAMPLE_H_
-
-#include <string>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace metrics {
-
-// This class is used by libmetrics (ChromeOS) to serialize
-// and deserialize measurements to send them to a metrics sending service.
-// It is meant to be a simple container with serialization functions.
-class MetricSample {
- public:
- // Types of metric sample used.
- enum SampleType {
- CRASH,
- HISTOGRAM,
- LINEAR_HISTOGRAM,
- SPARSE_HISTOGRAM,
- USER_ACTION
- };
-
- ~MetricSample();
-
- // Returns true if the sample is valid (can be serialized without ambiguity).
- //
- // This function should be used to filter bad samples before serializing them.
- bool IsValid() const;
-
- // Getters for type and name. All types of metrics have these so we do not
- // need to check the type.
- SampleType type() const { return type_; }
- const std::string& name() const { return name_; }
-
- // Getters for sample, min, max, bucket_count.
- // Check the metric type to make sure the request make sense. (ex: a crash
- // sample does not have a bucket_count so we crash if we call bucket_count()
- // on it.)
- int sample() const;
- int min() const;
- int max() const;
- int bucket_count() const;
-
- // Returns a serialized version of the sample.
- //
- // The serialized message for each type is:
- // crash: crash\0|name_|\0
- // user action: useraction\0|name_|\0
- // histogram: histogram\0|name_| |sample_| |min_| |max_| |bucket_count_|\0
- // sparsehistogram: sparsehistogram\0|name_| |sample_|\0
- // linearhistogram: linearhistogram\0|name_| |sample_| |max_|\0
- std::string ToString() const;
-
- // Builds a crash sample.
- static scoped_ptr<MetricSample> CrashSample(const std::string& crash_name);
-
- // Builds a histogram sample.
- static scoped_ptr<MetricSample> HistogramSample(
- const std::string& histogram_name,
- int sample,
- int min,
- int max,
- int bucket_count);
- // Deserializes a histogram sample.
- static scoped_ptr<MetricSample> ParseHistogram(const std::string& serialized);
-
- // Builds a sparse histogram sample.
- static scoped_ptr<MetricSample> SparseHistogramSample(
- const std::string& histogram_name,
- int sample);
- // Deserializes a sparse histogram sample.
- static scoped_ptr<MetricSample> ParseSparseHistogram(
- const std::string& serialized);
-
- // Builds a linear histogram sample.
- static scoped_ptr<MetricSample> LinearHistogramSample(
- const std::string& histogram_name,
- int sample,
- int max);
- // Deserializes a linear histogram sample.
- static scoped_ptr<MetricSample> ParseLinearHistogram(
- const std::string& serialized);
-
- // Builds a user action sample.
- static scoped_ptr<MetricSample> UserActionSample(
- const std::string& action_name);
-
- // Returns true if sample and this object represent the same sample (type,
- // name, sample, min, max, bucket_count match).
- bool IsEqual(const MetricSample& sample);
-
- private:
- MetricSample(SampleType sample_type,
- const std::string& metric_name,
- const int sample,
- const int min,
- const int max,
- const int bucket_count);
-
- const SampleType type_;
- const std::string name_;
- const int sample_;
- const int min_;
- const int max_;
- const int bucket_count_;
-
- DISALLOW_COPY_AND_ASSIGN(MetricSample);
-};
-
-} // namespace metrics
-
-#endif // METRICS_SERIALIZATION_METRIC_SAMPLE_H_
diff --git a/metricsd/serialization/serialization_utils.cc b/metricsd/serialization/serialization_utils.cc
deleted file mode 100644
index 102c940..0000000
--- a/metricsd/serialization/serialization_utils.cc
+++ /dev/null
@@ -1,265 +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 "serialization/serialization_utils.h"
-
-#include <sys/file.h>
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "serialization/metric_sample.h"
-
-#define READ_WRITE_ALL_FILE_FLAGS \
- (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
-
-namespace metrics {
-namespace {
-
-// Reads the next message from |file_descriptor| into |message|.
-//
-// |message| will be set to the empty string if no message could be read (EOF)
-// or the message was badly constructed.
-//
-// Returns false if no message can be read from this file anymore (EOF or
-// unrecoverable error).
-bool ReadMessage(int fd, std::string* message) {
- CHECK(message);
-
- int result;
- int32_t message_size;
- const int32_t message_hdr_size = sizeof(message_size);
- // The file containing the metrics do not leave the device so the writer and
- // the reader will always have the same endianness.
- result = HANDLE_EINTR(read(fd, &message_size, sizeof(message_size)));
- if (result < 0) {
- DPLOG(ERROR) << "reading metrics message header";
- return false;
- }
- if (result == 0) {
- // This indicates a normal EOF.
- return false;
- }
- if (result < message_hdr_size) {
- DLOG(ERROR) << "bad read size " << result << ", expecting "
- << sizeof(message_size);
- return false;
- }
-
- // kMessageMaxLength applies to the entire message: the 4-byte
- // length field and the content.
- if (message_size > SerializationUtils::kMessageMaxLength) {
- DLOG(ERROR) << "message too long : " << message_size;
- if (HANDLE_EINTR(lseek(fd, message_size - 4, SEEK_CUR)) == -1) {
- DLOG(ERROR) << "error while skipping message. abort";
- return false;
- }
- // Badly formatted message was skipped. Treat the badly formatted sample as
- // an empty sample.
- message->clear();
- return true;
- }
-
- if (message_size < message_hdr_size) {
- DLOG(ERROR) << "message too short : " << message_size;
- return false;
- }
-
- message_size -= message_hdr_size; // The message size includes itself.
- char buffer[SerializationUtils::kMessageMaxLength];
- if (!base::ReadFromFD(fd, buffer, message_size)) {
- DPLOG(ERROR) << "reading metrics message body";
- return false;
- }
- *message = std::string(buffer, message_size);
- return true;
-}
-
-
-// Opens the metrics log file at |filename| in the given |mode|.
-//
-// Returns the file descriptor wrapped in a valid ScopedFD on success.
-base::ScopedFD OpenMetricsFile(const std::string& filename, mode_t mode) {
- struct stat stat_buf;
- int result;
-
- result = stat(filename.c_str(), &stat_buf);
- if (result < 0) {
- if (errno != ENOENT)
- DPLOG(ERROR) << filename << ": bad metrics file stat";
-
- // Nothing to collect---try later.
- return base::ScopedFD();
- }
- if (stat_buf.st_size == 0) {
- // Also nothing to collect.
- return base::ScopedFD();
- }
- base::ScopedFD fd(open(filename.c_str(), mode));
- if (fd.get() < 0) {
- DPLOG(ERROR) << filename << ": cannot open";
- return base::ScopedFD();
- }
-
- return fd.Pass();
-}
-
-
-// Parses the contents of the metrics log file descriptor |fd| into |metrics|.
-void ReadAllMetricsFromFd(int fd, ScopedVector<MetricSample>* metrics) {
- for (;;) {
- std::string message;
-
- if (!ReadMessage(fd, &message))
- break;
-
- scoped_ptr<MetricSample> sample = SerializationUtils::ParseSample(message);
- if (sample)
- metrics->push_back(sample.release());
- }
-}
-
-} // namespace
-
-scoped_ptr<MetricSample> SerializationUtils::ParseSample(
- const std::string& sample) {
- if (sample.empty())
- return scoped_ptr<MetricSample>();
-
- std::vector<std::string> parts;
- base::SplitString(sample, '\0', &parts);
- // We should have two null terminated strings so split should produce
- // three chunks.
- if (parts.size() != 3) {
- DLOG(ERROR) << "splitting message on \\0 produced " << parts.size()
- << " parts (expected 3)";
- return scoped_ptr<MetricSample>();
- }
- const std::string& name = parts[0];
- const std::string& value = parts[1];
-
- if (base::LowerCaseEqualsASCII(name, "crash")) {
- return MetricSample::CrashSample(value);
- } else if (base::LowerCaseEqualsASCII(name, "histogram")) {
- return MetricSample::ParseHistogram(value);
- } else if (base::LowerCaseEqualsASCII(name, "linearhistogram")) {
- return MetricSample::ParseLinearHistogram(value);
- } else if (base::LowerCaseEqualsASCII(name, "sparsehistogram")) {
- return MetricSample::ParseSparseHistogram(value);
- } else if (base::LowerCaseEqualsASCII(name, "useraction")) {
- return MetricSample::UserActionSample(value);
- } else {
- DLOG(ERROR) << "invalid event type: " << name << ", value: " << value;
- }
- return scoped_ptr<MetricSample>();
-}
-
-void SerializationUtils::ReadMetricsFromFile(
- const std::string& filename,
- ScopedVector<MetricSample>* metrics) {
- base::ScopedFD fd(OpenMetricsFile(filename, O_RDONLY));
- if (!fd.is_valid()) {
- return;
- }
-
- // This processes all messages in the log.
- ReadAllMetricsFromFd(fd.get(), metrics);
-}
-
-void SerializationUtils::ReadAndTruncateMetricsFromFile(
- const std::string& filename,
- ScopedVector<MetricSample>* metrics) {
- base::ScopedFD fd(OpenMetricsFile(filename, O_RDWR));
- if (!fd.is_valid()) {
- return;
- }
-
- int result = flock(fd.get(), LOCK_EX);
- if (result < 0) {
- DPLOG(ERROR) << filename << ": cannot lock";
- return;
- }
-
- // This processes all messages in the log. When all messages are
- // read and processed, or an error occurs, truncate the file to zero size.
- ReadAllMetricsFromFd(fd.get(), metrics);
-
- result = ftruncate(fd.get(), 0);
- if (result < 0)
- DPLOG(ERROR) << "truncate metrics log";
-
- result = flock(fd.get(), LOCK_UN);
- if (result < 0)
- DPLOG(ERROR) << "unlock metrics log";
-}
-
-bool SerializationUtils::WriteMetricToFile(const MetricSample& sample,
- const std::string& filename) {
- if (!sample.IsValid())
- return false;
-
- base::ScopedFD file_descriptor(open(filename.c_str(),
- O_WRONLY | O_APPEND | O_CREAT,
- READ_WRITE_ALL_FILE_FLAGS));
-
- if (file_descriptor.get() < 0) {
- DPLOG(ERROR) << filename << ": cannot open";
- return false;
- }
-
- fchmod(file_descriptor.get(), READ_WRITE_ALL_FILE_FLAGS);
- // Grab a lock to avoid chrome truncating the file
- // underneath us. Keep the file locked as briefly as possible.
- // Freeing file_descriptor will close the file and and remove the lock.
- if (HANDLE_EINTR(flock(file_descriptor.get(), LOCK_EX)) < 0) {
- DPLOG(ERROR) << filename << ": cannot lock";
- return false;
- }
-
- std::string msg = sample.ToString();
- int32 size = msg.length() + sizeof(int32);
- if (size > kMessageMaxLength) {
- DLOG(ERROR) << "cannot write message: too long";
- return false;
- }
-
- // The file containing the metrics samples will only be read by programs on
- // the same device so we do not check endianness.
- if (!base::WriteFileDescriptor(file_descriptor.get(),
- reinterpret_cast<char*>(&size),
- sizeof(size))) {
- DPLOG(ERROR) << "error writing message length";
- return false;
- }
-
- if (!base::WriteFileDescriptor(
- file_descriptor.get(), msg.c_str(), msg.size())) {
- DPLOG(ERROR) << "error writing message";
- return false;
- }
-
- return true;
-}
-
-} // namespace metrics
diff --git a/metricsd/serialization/serialization_utils.h b/metricsd/serialization/serialization_utils.h
deleted file mode 100644
index 655652d..0000000
--- a/metricsd/serialization/serialization_utils.h
+++ /dev/null
@@ -1,64 +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 METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
-#define METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-
-namespace metrics {
-
-class MetricSample;
-
-// Metrics helpers to serialize and deserialize metrics collected by
-// ChromeOS.
-namespace SerializationUtils {
-
-// Deserializes a sample passed as a string and return a sample.
-// The return value will either be a scoped_ptr to a Metric sample (if the
-// deserialization was successful) or a NULL scoped_ptr.
-scoped_ptr<MetricSample> ParseSample(const std::string& sample);
-
-// Reads all samples from a file. The file contents remain unchanged.
-void ReadMetricsFromFile(const std::string& filename,
- ScopedVector<MetricSample>* metrics);
-
-// Reads all samples from a file and truncates the file when done.
-void ReadAndTruncateMetricsFromFile(const std::string& filename,
- ScopedVector<MetricSample>* metrics);
-
-// Serializes a sample and write it to filename.
-// The format for the message is:
-// message_size, serialized_message
-// where
-// * message_size is the total length of the message (message_size +
-// serialized_message) on 4 bytes
-// * serialized_message is the serialized version of sample (using ToString)
-//
-// NB: the file will never leave the device so message_size will be written
-// with the architecture's endianness.
-bool WriteMetricToFile(const MetricSample& sample, const std::string& filename);
-
-// Maximum length of a serialized message
-static const int kMessageMaxLength = 1024;
-
-} // namespace SerializationUtils
-} // namespace metrics
-
-#endif // METRICS_SERIALIZATION_SERIALIZATION_UTILS_H_
diff --git a/metricsd/serialization/serialization_utils_unittest.cc b/metricsd/serialization/serialization_utils_unittest.cc
deleted file mode 100644
index 7a572de..0000000
--- a/metricsd/serialization/serialization_utils_unittest.cc
+++ /dev/null
@@ -1,181 +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 "serialization/serialization_utils.h"
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include "serialization/metric_sample.h"
-
-namespace metrics {
-namespace {
-
-class SerializationUtilsTest : public testing::Test {
- protected:
- SerializationUtilsTest() {
- bool success = temporary_dir.CreateUniqueTempDir();
- if (success) {
- base::FilePath dir_path = temporary_dir.path();
- filename = dir_path.value() + "chromeossampletest";
- filepath = base::FilePath(filename);
- }
- }
-
- void SetUp() override { base::DeleteFile(filepath, false); }
-
- void TestSerialization(MetricSample* sample) {
- std::string serialized(sample->ToString());
- ASSERT_EQ('\0', serialized[serialized.length() - 1]);
- scoped_ptr<MetricSample> deserialized =
- SerializationUtils::ParseSample(serialized);
- ASSERT_TRUE(deserialized);
- EXPECT_TRUE(sample->IsEqual(*deserialized.get()));
- }
-
- std::string filename;
- base::ScopedTempDir temporary_dir;
- base::FilePath filepath;
-};
-
-TEST_F(SerializationUtilsTest, CrashSerializeTest) {
- TestSerialization(MetricSample::CrashSample("test").get());
-}
-
-TEST_F(SerializationUtilsTest, HistogramSerializeTest) {
- TestSerialization(
- MetricSample::HistogramSample("myhist", 13, 1, 100, 10).get());
-}
-
-TEST_F(SerializationUtilsTest, LinearSerializeTest) {
- TestSerialization(
- MetricSample::LinearHistogramSample("linearhist", 12, 30).get());
-}
-
-TEST_F(SerializationUtilsTest, SparseSerializeTest) {
- TestSerialization(MetricSample::SparseHistogramSample("mysparse", 30).get());
-}
-
-TEST_F(SerializationUtilsTest, UserActionSerializeTest) {
- TestSerialization(MetricSample::UserActionSample("myaction").get());
-}
-
-TEST_F(SerializationUtilsTest, IllegalNameAreFilteredTest) {
- scoped_ptr<MetricSample> sample1 =
- MetricSample::SparseHistogramSample("no space", 10);
- scoped_ptr<MetricSample> sample2 = MetricSample::LinearHistogramSample(
- base::StringPrintf("here%cbhe", '\0'), 1, 3);
-
- EXPECT_FALSE(SerializationUtils::WriteMetricToFile(*sample1.get(), filename));
- EXPECT_FALSE(SerializationUtils::WriteMetricToFile(*sample2.get(), filename));
- int64 size = 0;
-
- ASSERT_TRUE(!PathExists(filepath) || base::GetFileSize(filepath, &size));
-
- EXPECT_EQ(0, size);
-}
-
-TEST_F(SerializationUtilsTest, BadInputIsCaughtTest) {
- std::string input(
- base::StringPrintf("sparsehistogram%cname foo%c", '\0', '\0'));
- EXPECT_EQ(NULL, MetricSample::ParseSparseHistogram(input).get());
-}
-
-TEST_F(SerializationUtilsTest, MessageSeparatedByZero) {
- scoped_ptr<MetricSample> crash = MetricSample::CrashSample("mycrash");
-
- SerializationUtils::WriteMetricToFile(*crash.get(), filename);
- int64 size = 0;
- ASSERT_TRUE(base::GetFileSize(filepath, &size));
- // 4 bytes for the size
- // 5 bytes for crash
- // 7 bytes for mycrash
- // 2 bytes for the \0
- // -> total of 18
- EXPECT_EQ(size, 18);
-}
-
-TEST_F(SerializationUtilsTest, MessagesTooLongAreDiscardedTest) {
- // Creates a message that is bigger than the maximum allowed size.
- // As we are adding extra character (crash, \0s, etc), if the name is
- // kMessageMaxLength long, it will be too long.
- std::string name(SerializationUtils::kMessageMaxLength, 'c');
-
- scoped_ptr<MetricSample> crash = MetricSample::CrashSample(name);
- EXPECT_FALSE(SerializationUtils::WriteMetricToFile(*crash.get(), filename));
- int64 size = 0;
- ASSERT_TRUE(base::GetFileSize(filepath, &size));
- EXPECT_EQ(0, size);
-}
-
-TEST_F(SerializationUtilsTest, ReadLongMessageTest) {
- base::File test_file(filepath,
- base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
- std::string message(SerializationUtils::kMessageMaxLength + 1, 'c');
-
- int32 message_size = message.length() + sizeof(int32);
- test_file.WriteAtCurrentPos(reinterpret_cast<const char*>(&message_size),
- sizeof(message_size));
- test_file.WriteAtCurrentPos(message.c_str(), message.length());
- test_file.Close();
-
- scoped_ptr<MetricSample> crash = MetricSample::CrashSample("test");
- SerializationUtils::WriteMetricToFile(*crash.get(), filename);
-
- ScopedVector<MetricSample> samples;
- SerializationUtils::ReadAndTruncateMetricsFromFile(filename, &samples);
- ASSERT_EQ(size_t(1), samples.size());
- ASSERT_TRUE(samples[0] != NULL);
- EXPECT_TRUE(crash->IsEqual(*samples[0]));
-}
-
-TEST_F(SerializationUtilsTest, WriteReadTest) {
- scoped_ptr<MetricSample> hist =
- MetricSample::HistogramSample("myhist", 1, 2, 3, 4);
- scoped_ptr<MetricSample> crash = MetricSample::CrashSample("mycrash");
- scoped_ptr<MetricSample> lhist =
- MetricSample::LinearHistogramSample("linear", 1, 10);
- scoped_ptr<MetricSample> shist =
- MetricSample::SparseHistogramSample("mysparse", 30);
- scoped_ptr<MetricSample> action = MetricSample::UserActionSample("myaction");
-
- SerializationUtils::WriteMetricToFile(*hist.get(), filename);
- SerializationUtils::WriteMetricToFile(*crash.get(), filename);
- SerializationUtils::WriteMetricToFile(*lhist.get(), filename);
- SerializationUtils::WriteMetricToFile(*shist.get(), filename);
- SerializationUtils::WriteMetricToFile(*action.get(), filename);
- ScopedVector<MetricSample> vect;
- SerializationUtils::ReadAndTruncateMetricsFromFile(filename, &vect);
- ASSERT_EQ(vect.size(), size_t(5));
- for (int i = 0; i < 5; i++) {
- ASSERT_TRUE(vect[0] != NULL);
- }
- EXPECT_TRUE(hist->IsEqual(*vect[0]));
- EXPECT_TRUE(crash->IsEqual(*vect[1]));
- EXPECT_TRUE(lhist->IsEqual(*vect[2]));
- EXPECT_TRUE(shist->IsEqual(*vect[3]));
- EXPECT_TRUE(action->IsEqual(*vect[4]));
-
- int64 size = 0;
- ASSERT_TRUE(base::GetFileSize(filepath, &size));
- ASSERT_EQ(0, size);
-}
-
-} // namespace
-} // namespace metrics
diff --git a/metricsd/uploader/bn_metricsd_impl.cc b/metricsd/uploader/bn_metricsd_impl.cc
new file mode 100644
index 0000000..113a705
--- /dev/null
+++ b/metricsd/uploader/bn_metricsd_impl.cc
@@ -0,0 +1,106 @@
+/*
+ * 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 "uploader/bn_metricsd_impl.h"
+
+#include <base/metrics/histogram.h>
+#include <base/metrics/sparse_histogram.h>
+#include <base/metrics/statistics_recorder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::binder::Status;
+using android::String16;
+
+static const char16_t kCrashTypeKernel[] = u"kernel";
+static const char16_t kCrashTypeUncleanShutdown[] = u"uncleanshutdown";
+static const char16_t kCrashTypeUser[] = u"user";
+
+BnMetricsdImpl::BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters)
+ : counters_(counters) {
+ CHECK(counters_);
+}
+
+void BnMetricsdImpl::Run() {
+ android::defaultServiceManager()->addService(getInterfaceDescriptor(), this);
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+ android::IPCThreadState::self()->disableBackgroundScheduling(true);
+ android::IPCThreadState::self()->joinThreadPool();
+}
+
+Status BnMetricsdImpl::recordHistogram(
+ const String16& name, int sample, int min, int max, int nbuckets) {
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ android::String8(name).string(), min, max, nbuckets,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ // |histogram| may be null if a client reports two contradicting histograms
+ // with the same name but different limits.
+ // FactoryGet will print a useful message if that is the case.
+ if (histogram) {
+ histogram->Add(sample);
+ }
+ return Status::ok();
+}
+
+Status BnMetricsdImpl::recordLinearHistogram(const String16& name,
+ int sample,
+ int max) {
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ android::String8(name).string(), 1, max, max + 1,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ // |histogram| may be null if a client reports two contradicting histograms
+ // with the same name but different limits.
+ // FactoryGet will print a useful message if that is the case.
+ if (histogram) {
+ histogram->Add(sample);
+ }
+ return Status::ok();
+}
+
+Status BnMetricsdImpl::recordSparseHistogram(const String16& name, int sample) {
+ base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+ android::String8(name).string(),
+ base::Histogram::kUmaTargetedHistogramFlag);
+ // |histogram| may be null if a client reports two contradicting histograms
+ // with the same name but different limits.
+ // FactoryGet will print a useful message if that is the case.
+ if (histogram) {
+ histogram->Add(sample);
+ }
+ return Status::ok();
+}
+
+Status BnMetricsdImpl::recordCrash(const String16& type) {
+ if (type == kCrashTypeUser) {
+ counters_->IncrementUserCrashCount();
+ } else if (type == kCrashTypeKernel) {
+ counters_->IncrementKernelCrashCount();
+ } else if (type == kCrashTypeUncleanShutdown) {
+ counters_->IncrementUncleanShutdownCount();
+ } else {
+ LOG(ERROR) << "Unknown crash type received: " << type;
+ }
+ return Status::ok();
+}
+
+Status BnMetricsdImpl::getHistogramsDump(String16* dump) {
+ std::string str_dump;
+ base::StatisticsRecorder::WriteGraph(std::string(), &str_dump);
+ *dump = String16(str_dump.c_str());
+ return Status::ok();
+}
diff --git a/metricsd/uploader/bn_metricsd_impl.h b/metricsd/uploader/bn_metricsd_impl.h
new file mode 100644
index 0000000..016ccb6
--- /dev/null
+++ b/metricsd/uploader/bn_metricsd_impl.h
@@ -0,0 +1,57 @@
+/*
+ * 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_UPLOADER_BN_METRICSD_IMPL_H_
+#define METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
+
+#include "android/brillo/metrics/BnMetricsd.h"
+#include "uploader/crash_counters.h"
+
+class BnMetricsdImpl : public android::brillo::metrics::BnMetricsd {
+ public:
+ explicit BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters);
+ virtual ~BnMetricsdImpl() = default;
+
+ // Starts the binder main loop.
+ void Run();
+
+ // Records a histogram.
+ android::binder::Status recordHistogram(const android::String16& name,
+ int sample,
+ int min,
+ int max,
+ int nbuckets) override;
+
+ // Records a linear histogram.
+ android::binder::Status recordLinearHistogram(const android::String16& name,
+ int sample,
+ int max) override;
+
+ // Records a sparse histogram.
+ android::binder::Status recordSparseHistogram(const android::String16& name,
+ int sample) override;
+
+ // Records a crash.
+ android::binder::Status recordCrash(const android::String16& type) override;
+
+ // Returns a dump of the histograms aggregated in memory.
+ android::binder::Status getHistogramsDump(android::String16* dump) override;
+
+ private:
+ std::shared_ptr<CrashCounters> counters_;
+};
+
+#endif // METRICSD_UPLOADER_BN_METRICSD_IMPL_H_
diff --git a/metricsd/uploader/crash_counters.cc b/metricsd/uploader/crash_counters.cc
new file mode 100644
index 0000000..1478b9a
--- /dev/null
+++ b/metricsd/uploader/crash_counters.cc
@@ -0,0 +1,44 @@
+/*
+ * 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 "uploader/crash_counters.h"
+
+CrashCounters::CrashCounters()
+ : kernel_crashes_(0), unclean_shutdowns_(0), user_crashes_(0) {}
+
+void CrashCounters::IncrementKernelCrashCount() {
+ kernel_crashes_++;
+}
+
+unsigned int CrashCounters::GetAndResetKernelCrashCount() {
+ return kernel_crashes_.exchange(0);
+}
+
+void CrashCounters::IncrementUncleanShutdownCount() {
+ unclean_shutdowns_++;
+}
+
+unsigned int CrashCounters::GetAndResetUncleanShutdownCount() {
+ return unclean_shutdowns_.exchange(0);
+}
+
+void CrashCounters::IncrementUserCrashCount() {
+ user_crashes_++;
+}
+
+unsigned int CrashCounters::GetAndResetUserCrashCount() {
+ return user_crashes_.exchange(0);
+}
diff --git a/metricsd/uploader/crash_counters.h b/metricsd/uploader/crash_counters.h
new file mode 100644
index 0000000..3fdbf3f
--- /dev/null
+++ b/metricsd/uploader/crash_counters.h
@@ -0,0 +1,45 @@
+/*
+ * 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_UPLOADER_CRASH_COUNTERS_H_
+#define METRICSD_UPLOADER_CRASH_COUNTERS_H_
+
+#include <atomic>
+
+// This class is used to keep track of the crash counters.
+// An instance of it will be used by both the binder thread (to increment the
+// counters) and the uploader thread (to gather and reset the counters).
+// As such, the internal counters are atomic uints to allow concurrent access.
+class CrashCounters {
+ public:
+ CrashCounters();
+
+ void IncrementKernelCrashCount();
+ unsigned int GetAndResetKernelCrashCount();
+
+ void IncrementUserCrashCount();
+ unsigned int GetAndResetUserCrashCount();
+
+ void IncrementUncleanShutdownCount();
+ unsigned int GetAndResetUncleanShutdownCount();
+
+ private:
+ std::atomic_uint kernel_crashes_;
+ std::atomic_uint unclean_shutdowns_;
+ std::atomic_uint user_crashes_;
+};
+
+#endif // METRICSD_UPLOADER_CRASH_COUNTERS_H_
diff --git a/metricsd/uploader/metrics_log.cc b/metricsd/uploader/metrics_log.cc
index 1f16ca1..a01b5da 100644
--- a/metricsd/uploader/metrics_log.cc
+++ b/metricsd/uploader/metrics_log.cc
@@ -27,25 +27,25 @@
: MetricsLogBase("", 0, metrics::MetricsLogBase::ONGOING_LOG, "") {
}
-void MetricsLog::IncrementUserCrashCount() {
+void MetricsLog::IncrementUserCrashCount(unsigned int count) {
metrics::SystemProfileProto::Stability* stability(
uma_proto()->mutable_system_profile()->mutable_stability());
int current = stability->other_user_crash_count();
- stability->set_other_user_crash_count(current + 1);
+ stability->set_other_user_crash_count(current + count);
}
-void MetricsLog::IncrementKernelCrashCount() {
+void MetricsLog::IncrementKernelCrashCount(unsigned int count) {
metrics::SystemProfileProto::Stability* stability(
uma_proto()->mutable_system_profile()->mutable_stability());
int current = stability->kernel_crash_count();
- stability->set_kernel_crash_count(current + 1);
+ stability->set_kernel_crash_count(current + count);
}
-void MetricsLog::IncrementUncleanShutdownCount() {
+void MetricsLog::IncrementUncleanShutdownCount(unsigned int count) {
metrics::SystemProfileProto::Stability* stability(
uma_proto()->mutable_system_profile()->mutable_stability());
int current = stability->unclean_system_shutdown_count();
- stability->set_unclean_system_shutdown_count(current + 1);
+ stability->set_unclean_system_shutdown_count(current + count);
}
bool MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
diff --git a/metricsd/uploader/metrics_log.h b/metricsd/uploader/metrics_log.h
index 5e09070..b76cd72 100644
--- a/metricsd/uploader/metrics_log.h
+++ b/metricsd/uploader/metrics_log.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef METRICS_UPLOADER_METRICS_LOG_H_
-#define METRICS_UPLOADER_METRICS_LOG_H_
+#ifndef METRICSD_UPLOADER_METRICS_LOG_H_
+#define METRICSD_UPLOADER_METRICS_LOG_H_
#include <string>
@@ -34,15 +34,20 @@
// SystemProfileSetter.
MetricsLog();
- void IncrementUserCrashCount();
- void IncrementKernelCrashCount();
- void IncrementUncleanShutdownCount();
+ // Increment the crash counters in the protobuf.
+ // These methods don't have to be thread safe as metrics logs are only
+ // accessed by the uploader thread.
+ void IncrementUserCrashCount(unsigned int count);
+ void IncrementKernelCrashCount(unsigned int count);
+ void IncrementUncleanShutdownCount(unsigned int count);
// Populate the system profile with system information using setter.
bool PopulateSystemProfile(SystemProfileSetter* setter);
private:
+ friend class UploadServiceTest;
FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
+ FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
FRIEND_TEST(UploadServiceTest, LogKernelCrash);
FRIEND_TEST(UploadServiceTest, LogUncleanShutdown);
FRIEND_TEST(UploadServiceTest, LogUserCrash);
@@ -51,4 +56,4 @@
DISALLOW_COPY_AND_ASSIGN(MetricsLog);
};
-#endif // METRICS_UPLOADER_METRICS_LOG_H_
+#endif // METRICSD_UPLOADER_METRICS_LOG_H_
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 8928a0d..70f6afd 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -55,11 +55,10 @@
SystemProfileCache::SystemProfileCache()
: initialized_(false),
- testing_(false),
- metrics_directory_(metrics::kMetricsDirectory),
- session_id_(new chromeos_metrics::PersistentInteger(
- kPersistentSessionIdFilename)) {
-}
+ testing_(false),
+ metrics_directory_(metrics::kMetricsdDirectory),
+ session_id_(new chromeos_metrics::PersistentInteger(
+ kPersistentSessionIdFilename, metrics_directory_)) {}
SystemProfileCache::SystemProfileCache(bool testing,
const base::FilePath& metrics_directory)
@@ -67,8 +66,7 @@
testing_(testing),
metrics_directory_(metrics_directory),
session_id_(new chromeos_metrics::PersistentInteger(
- kPersistentSessionIdFilename)) {
-}
+ kPersistentSessionIdFilename, metrics_directory)) {}
bool SystemProfileCache::Initialize() {
CHECK(!initialized_)
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
index ca5024e..ea8427a 100644
--- a/metricsd/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -33,8 +33,6 @@
#include <base/sha1.h>
#include "constants.h"
-#include "serialization/metric_sample.h"
-#include "serialization/serialization_utils.h"
#include "uploader/metrics_log.h"
#include "uploader/sender_http.h"
#include "uploader/system_profile_setter.h"
@@ -43,19 +41,20 @@
UploadService::UploadService(const std::string& server,
const base::TimeDelta& upload_interval,
- const base::FilePath& metrics_directory)
+ const base::FilePath& private_metrics_directory,
+ const base::FilePath& shared_metrics_directory,
+ const std::shared_ptr<CrashCounters> counters)
: histogram_snapshot_manager_(this),
sender_(new HttpSender(server)),
- failed_upload_count_(metrics::kFailedUploadCountName),
+ failed_upload_count_(metrics::kFailedUploadCountName,
+ private_metrics_directory),
+ counters_(counters),
upload_interval_(upload_interval) {
- metrics_file_ = metrics_directory.Append(metrics::kMetricsEventsFileName);
- staged_log_path_ = metrics_directory.Append(metrics::kStagedLogName);
- consent_file_ = metrics_directory.Append(metrics::kConsentFileName);
+ staged_log_path_ = private_metrics_directory.Append(metrics::kStagedLogName);
+ consent_file_ = shared_metrics_directory.Append(metrics::kConsentFileName);
}
int UploadService::OnInit() {
- base::StatisticsRecorder::Initialize();
-
system_profile_setter_.reset(new SystemProfileCache());
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -67,7 +66,6 @@
}
void UploadService::InitForTest(SystemProfileSetter* setter) {
- base::StatisticsRecorder::Initialize();
system_profile_setter_.reset(setter);
}
@@ -99,8 +97,7 @@
return;
}
- // Previous upload successful, reading metrics sample from the file.
- ReadMetrics();
+ // Previous upload successful, stage another log.
GatherHistograms();
StageCurrentLog();
@@ -140,76 +137,24 @@
failed_upload_count_.Set(0);
}
-void UploadService::ReadMetrics() {
- CHECK(!HasStagedLog()) << "cannot read metrics until the old logs have been "
- << "discarded";
-
- ScopedVector<metrics::MetricSample> vector;
- metrics::SerializationUtils::ReadAndTruncateMetricsFromFile(
- metrics_file_.value(), &vector);
-
- int i = 0;
- for (ScopedVector<metrics::MetricSample>::iterator it = vector.begin();
- it != vector.end(); it++) {
- metrics::MetricSample* sample = *it;
- AddSample(*sample);
- i++;
- }
- VLOG(1) << i << " samples read";
-}
-
-void UploadService::AddSample(const metrics::MetricSample& sample) {
- base::HistogramBase* counter;
- switch (sample.type()) {
- case metrics::MetricSample::CRASH:
- AddCrash(sample.name());
- break;
- case metrics::MetricSample::HISTOGRAM:
- counter = base::Histogram::FactoryGet(
- sample.name(), sample.min(), sample.max(), sample.bucket_count(),
- base::Histogram::kUmaTargetedHistogramFlag);
- counter->Add(sample.sample());
- break;
- case metrics::MetricSample::SPARSE_HISTOGRAM:
- counter = base::SparseHistogram::FactoryGet(
- sample.name(), base::HistogramBase::kUmaTargetedHistogramFlag);
- counter->Add(sample.sample());
- break;
- case metrics::MetricSample::LINEAR_HISTOGRAM:
- counter = base::LinearHistogram::FactoryGet(
- sample.name(),
- 1,
- sample.max(),
- sample.max() + 1,
- base::Histogram::kUmaTargetedHistogramFlag);
- counter->Add(sample.sample());
- break;
- case metrics::MetricSample::USER_ACTION:
- GetOrCreateCurrentLog()->RecordUserAction(sample.name());
- break;
- default:
- break;
- }
-}
-
-void UploadService::AddCrash(const std::string& crash_name) {
- if (crash_name == "user") {
- GetOrCreateCurrentLog()->IncrementUserCrashCount();
- } else if (crash_name == "kernel") {
- GetOrCreateCurrentLog()->IncrementKernelCrashCount();
- } else if (crash_name == "uncleanshutdown") {
- GetOrCreateCurrentLog()->IncrementUncleanShutdownCount();
- } else {
- DLOG(ERROR) << "crash name unknown" << crash_name;
- }
-}
-
void UploadService::GatherHistograms() {
base::StatisticsRecorder::Histograms histograms;
base::StatisticsRecorder::GetHistograms(&histograms);
histogram_snapshot_manager_.PrepareDeltas(
base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
+
+ // Gather and reset the crash counters, shared with the binder threads.
+ unsigned int kernel_crashes = counters_->GetAndResetKernelCrashCount();
+ unsigned int unclean_shutdowns = counters_->GetAndResetUncleanShutdownCount();
+ unsigned int user_crashes = counters_->GetAndResetUserCrashCount();
+
+ // Only create a log if the counters have changed.
+ if (kernel_crashes > 0 || unclean_shutdowns > 0 || user_crashes > 0) {
+ GetOrCreateCurrentLog()->IncrementKernelCrashCount(kernel_crashes);
+ GetOrCreateCurrentLog()->IncrementUncleanShutdownCount(unclean_shutdowns);
+ GetOrCreateCurrentLog()->IncrementUserCrashCount(user_crashes);
+ }
}
void UploadService::RecordDelta(const base::HistogramBase& histogram,
@@ -265,4 +210,3 @@
bool UploadService::AreMetricsEnabled() {
return base::PathExists(consent_file_);
}
-
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
index 7faf357..fe064b8 100644
--- a/metricsd/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -25,20 +25,12 @@
#include <brillo/daemons/daemon.h>
#include "persistent_integer.h"
+#include "uploader/crash_counters.h"
#include "uploader/metrics_log.h"
+#include "uploader/proto/chrome_user_metrics_extension.pb.h"
#include "uploader/sender.h"
#include "uploader/system_profile_cache.h"
-namespace metrics {
-class ChromeUserMetricsExtension;
-class CrashSample;
-class HistogramSample;
-class LinearHistogramSample;
-class MetricSample;
-class SparseHistogramSample;
-class UserActionSample;
-}
-
class SystemProfileSetter;
// Service responsible for uploading the metrics periodically to the server.
@@ -57,21 +49,21 @@
// - 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.
-// We do not try to read the metrics that are stored on
-// the disk as we want to avoid storing the metrics in memory.
//
// * if no staged logs are present:
-// Read all metrics from the disk, aggregate them and try to send them.
+// 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 keep the staged log in memory to retry
-// uploading later.
+// - if the upload fails, we continue and will retry to upload later.
//
class UploadService : public base::HistogramFlattener, public brillo::Daemon {
public:
UploadService(const std::string& server,
const base::TimeDelta& upload_interval,
- const base::FilePath& metrics_directory);
+ const base::FilePath& private_metrics_directory,
+ const base::FilePath& shared_metrics_directory,
+ const std::shared_ptr<CrashCounters> counters);
// Initializes the upload service.
int OnInit();
@@ -105,6 +97,7 @@
FRIEND_TEST(UploadServiceTest, EmptyLogsAreNotSent);
FRIEND_TEST(UploadServiceTest, FailedSendAreRetried);
FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
+ FRIEND_TEST(UploadServiceTest, LogContainsCrashCounts);
FRIEND_TEST(UploadServiceTest, LogEmptyAfterUpload);
FRIEND_TEST(UploadServiceTest, LogEmptyByDefault);
FRIEND_TEST(UploadServiceTest, LogFromTheMetricsLibrary);
@@ -124,15 +117,6 @@
// Resets the internal state.
void Reset();
- // Reads all the metrics from the disk.
- void ReadMetrics();
-
- // Adds a generic sample to the current log.
- void AddSample(const metrics::MetricSample& sample);
-
- // Adds a crash to the current log.
- void AddCrash(const std::string& crash_name);
-
// Returns true iff metrics reporting is enabled.
bool AreMetricsEnabled();
@@ -162,11 +146,11 @@
scoped_ptr<Sender> sender_;
chromeos_metrics::PersistentInteger failed_upload_count_;
scoped_ptr<MetricsLog> current_log_;
-
+ std::shared_ptr<CrashCounters> counters_;
+
base::TimeDelta upload_interval_;
base::FilePath consent_file_;
- base::FilePath metrics_file_;
base::FilePath staged_log_path_;
bool testing_;
diff --git a/metricsd/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
index 24e3127..0e2ba8f 100644
--- a/metricsd/uploader/upload_service_test.cc
+++ b/metricsd/uploader/upload_service_test.cc
@@ -20,12 +20,12 @@
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/logging.h>
+#include <base/metrics/sparse_histogram.h>
+#include <base/metrics/statistics_recorder.h>
#include <base/sys_info.h>
#include "constants.h"
-#include "metrics/metrics_library_mock.h"
#include "persistent_integer.h"
-#include "serialization/metric_sample.h"
#include "uploader/metrics_log.h"
#include "uploader/mock/mock_system_profile_setter.h"
#include "uploader/mock/sender_mock.h"
@@ -39,13 +39,23 @@
protected:
virtual void SetUp() {
CHECK(dir_.CreateUniqueTempDir());
- chromeos_metrics::PersistentInteger::SetMetricsDirectory(
- dir_.path().value());
- metrics_lib_.InitForTest(dir_.path());
- ASSERT_EQ(0, base::WriteFile(
- dir_.path().Append(metrics::kConsentFileName), "", 0));
- upload_service_.reset(new UploadService("", base::TimeDelta(),
- dir_.path()));
+ // Make sure the statistics recorder is inactive (contains no metrics) then
+ // initialize it.
+ ASSERT_FALSE(base::StatisticsRecorder::IsActive());
+ base::StatisticsRecorder::Initialize();
+
+ base::FilePath private_dir = dir_.path().Append("private");
+ base::FilePath shared_dir = dir_.path().Append("shared");
+
+ EXPECT_TRUE(base::CreateDirectory(private_dir));
+ EXPECT_TRUE(base::CreateDirectory(shared_dir));
+
+ ASSERT_EQ(0, base::WriteFile(shared_dir.Append(metrics::kConsentFileName),
+ "", 0));
+ counters_.reset(new CrashCounters);
+
+ upload_service_.reset(new UploadService("", base::TimeDelta(), private_dir,
+ shared_dir, counters_));
upload_service_->sender_.reset(new SenderMock);
upload_service_->InitForTest(new MockSystemProfileSetter);
@@ -53,8 +63,17 @@
upload_service_->Reset();
}
- scoped_ptr<metrics::MetricSample> Crash(const std::string& name) {
- return metrics::MetricSample::CrashSample(name);
+ void SendSparseHistogram(const std::string& name, int sample) {
+ base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+ name, base::Histogram::kUmaTargetedHistogramFlag);
+ histogram->Add(sample);
+ }
+
+ void SendHistogram(
+ const std::string& name, int sample, int min, int max, int nbuckets) {
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
+ histogram->Add(sample);
}
void SetTestingProperty(const std::string& name, const std::string& value) {
@@ -66,57 +85,26 @@
base::WriteFile(filepath, value.data(), value.size()));
}
+ const metrics::SystemProfileProto_Stability GetCurrentStability() {
+ EXPECT_TRUE(upload_service_->current_log_);
+
+ return upload_service_->current_log_->uma_proto()->system_profile().stability();
+ }
+
base::ScopedTempDir dir_;
scoped_ptr<UploadService> upload_service_;
- MetricsLibrary metrics_lib_;
scoped_ptr<base::AtExitManager> exit_manager_;
+ std::shared_ptr<CrashCounters> counters_;
};
-// Tests that the right crash increments a values.
-TEST_F(UploadServiceTest, LogUserCrash) {
- upload_service_->AddSample(*Crash("user").get());
-
- MetricsLog* log = upload_service_->current_log_.get();
- metrics::ChromeUserMetricsExtension* proto = log->uma_proto();
-
- EXPECT_EQ(1, proto->system_profile().stability().other_user_crash_count());
-}
-
-TEST_F(UploadServiceTest, LogUncleanShutdown) {
- upload_service_->AddSample(*Crash("uncleanshutdown"));
-
- EXPECT_EQ(1, upload_service_->current_log_
- ->uma_proto()
- ->system_profile()
- .stability()
- .unclean_system_shutdown_count());
-}
-
-TEST_F(UploadServiceTest, LogKernelCrash) {
- upload_service_->AddSample(*Crash("kernel"));
-
- EXPECT_EQ(1, upload_service_->current_log_
- ->uma_proto()
- ->system_profile()
- .stability()
- .kernel_crash_count());
-}
-
-TEST_F(UploadServiceTest, UnknownCrashIgnored) {
- upload_service_->AddSample(*Crash("foo"));
-
- // The log should be empty.
- EXPECT_FALSE(upload_service_->current_log_);
-}
-
TEST_F(UploadServiceTest, FailedSendAreRetried) {
SenderMock* sender = new SenderMock();
upload_service_->sender_.reset(sender);
sender->set_should_succeed(false);
- upload_service_->AddSample(*Crash("user"));
+ SendSparseHistogram("hello", 1);
upload_service_->UploadEvent();
EXPECT_EQ(1, sender->send_call_count());
std::string sent_string = sender->last_message();
@@ -132,7 +120,7 @@
sender->set_should_succeed(false);
- upload_service_->AddSample(*Crash("user"));
+ SendSparseHistogram("hello", 1);
for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
upload_service_->UploadEvent();
@@ -143,7 +131,7 @@
EXPECT_FALSE(upload_service_->HasStagedLog());
// Log a new sample. The failed upload counter should be reset.
- upload_service_->AddSample(*Crash("user"));
+ SendSparseHistogram("hello", 1);
for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
upload_service_->UploadEvent();
}
@@ -160,7 +148,8 @@
}
TEST_F(UploadServiceTest, LogEmptyByDefault) {
- UploadService upload_service("", base::TimeDelta(), dir_.path());
+ UploadService upload_service("", base::TimeDelta(), dir_.path(), dir_.path(),
+ std::make_shared<CrashCounters>());
// current_log_ should be initialized later as it needs AtExitManager to exit
// in order to gather system information from SysInfo.
@@ -171,35 +160,28 @@
SenderMock* sender = new SenderMock();
upload_service_->sender_.reset(sender);
- upload_service_->AddSample(*Crash("user"));
+ SendSparseHistogram("hello", 1);
+
upload_service_->UploadEvent();
std::string first_message = sender->last_message();
+ SendSparseHistogram("hello", 2);
- upload_service_->AddSample(*Crash("kernel"));
upload_service_->UploadEvent();
EXPECT_NE(first_message, sender->last_message());
}
TEST_F(UploadServiceTest, LogEmptyAfterUpload) {
- upload_service_->AddSample(*Crash("user"));
-
- EXPECT_TRUE(upload_service_->current_log_);
+ SendSparseHistogram("hello", 2);
upload_service_->UploadEvent();
EXPECT_FALSE(upload_service_->current_log_);
}
TEST_F(UploadServiceTest, LogContainsAggregatedValues) {
- scoped_ptr<metrics::MetricSample> histogram =
- metrics::MetricSample::HistogramSample("foo", 10, 0, 42, 10);
- upload_service_->AddSample(*histogram.get());
-
-
- scoped_ptr<metrics::MetricSample> histogram2 =
- metrics::MetricSample::HistogramSample("foo", 11, 0, 42, 10);
- upload_service_->AddSample(*histogram2.get());
+ SendHistogram("foo", 11, 0, 42, 10);
+ SendHistogram("foo", 12, 0, 42, 10);
upload_service_->GatherHistograms();
metrics::ChromeUserMetricsExtension* proto =
@@ -207,6 +189,37 @@
EXPECT_EQ(1, proto->histogram_event().size());
}
+TEST_F(UploadServiceTest, LogContainsCrashCounts) {
+ // By default, there is no current log.
+ upload_service_->GatherHistograms();
+ EXPECT_FALSE(upload_service_->current_log_);
+
+ // If the user crash counter is incremented, we add the count to the current
+ // log.
+ counters_->IncrementUserCrashCount();
+ upload_service_->GatherHistograms();
+ EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
+
+ // If the kernel crash counter is incremented, we add the count to the current
+ // log.
+ counters_->IncrementKernelCrashCount();
+ upload_service_->GatherHistograms();
+ EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
+
+ // If the kernel crash counter is incremented, we add the count to the current
+ // log.
+ counters_->IncrementUncleanShutdownCount();
+ counters_->IncrementUncleanShutdownCount();
+ upload_service_->GatherHistograms();
+ EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
+
+ // If no counter is incremented, the reported numbers don't change.
+ upload_service_->GatherHistograms();
+ EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
+ EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
+ EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
+}
+
TEST_F(UploadServiceTest, ExtractChannelFromString) {
EXPECT_EQ(
SystemProfileCache::ProtoChannelFromString(
@@ -230,13 +243,12 @@
SetTestingProperty(metrics::kProductId, "hello");
SetTestingProperty(metrics::kProductVersion, "1.2.3.4");
- scoped_ptr<metrics::MetricSample> histogram =
- metrics::MetricSample::SparseHistogramSample("myhistogram", 1);
+ SendSparseHistogram("hello", 1);
+
// Reset to create the new log with the profile setter.
upload_service_->system_profile_setter_.reset(
new SystemProfileCache(true, dir_.path()));
upload_service_->Reset();
- upload_service_->AddSample(*histogram.get());
upload_service_->UploadEvent();
EXPECT_EQ(1, sender->send_call_count());
@@ -277,21 +289,6 @@
EXPECT_EQ(cache.profile_.session_id, session_id + 1);
}
-// Test that we can log metrics from the metrics library and have the uploader
-// upload them.
-TEST_F(UploadServiceTest, LogFromTheMetricsLibrary) {
- SenderMock* sender = new SenderMock();
- upload_service_->sender_.reset(sender);
-
- upload_service_->UploadEvent();
- EXPECT_EQ(0, sender->send_call_count());
-
- metrics_lib_.SendEnumToUMA("testname", 2, 10);
- upload_service_->UploadEvent();
-
- EXPECT_EQ(1, sender->send_call_count());
-}
-
// The product id must be set for metrics to be uploaded.
// If it is not set, the system profile cache should fail to initialize.
TEST_F(UploadServiceTest, ProductIdMandatory) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0a857f3..b43f8f9 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -396,6 +396,7 @@
mkdir /data/system 0775 system system
mkdir /data/system/heapdump 0700 system system
mkdir /data/system_ce 0770 system system
+ mkdir /data/system_ce/0 0770 system system
mkdir /data/user 0711 system system
mkdir /data/user_de 0711 system system
@@ -593,3 +594,13 @@
service flash_recovery /system/bin/install-recovery.sh
class main
oneshot
+
+# bugreportplus is an enhanced version of bugreport that provides a better
+# user interface (like displaying progress and allowing user to enter details).
+# It's typically triggered by the power button or developer settings.
+# TODO: remove the -p option when screenshot is taken by Shell
+service bugreportplus /system/bin/dumpstate -d -p -B -P -z \
+ -o /data/data/com.android.shell/files/bugreports/bugreport
+ class main
+ disabled
+ oneshot