Merge "adb: fix a fake data race on transport:kick reported by tsan."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29c9481..a0501a6 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -243,6 +243,11 @@
D("adb: offline\n");
//Close the associated usb
t->online = 0;
+
+ // This is necessary to avoid a race condition that occured when a transport closes
+ // while a client socket is still active.
+ close_all_sockets(t);
+
run_transport_disconnects(t);
}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index d8ea2ee..a85d5ad 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -360,9 +360,12 @@
} else {
p->len = max_payload - avail;
+ // s->peer->enqueue() may call s->close() and free s,
+ // so save variables for debug printing below.
+ unsigned saved_id = s->id;
+ int saved_fd = s->fd;
r = s->peer->enqueue(s->peer, p);
- D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd,
- r);
+ D("LS(%u): fd=%d post peer->enqueue(). r=%d\n", saved_id, saved_fd, r);
if (r < 0) {
/* error return means they closed us as a side-effect
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 03fe304..20d5d71 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -330,10 +330,6 @@
put_apacket(p);
}
- // this is necessary to avoid a race condition that occured when a transport closes
- // while a client socket is still active.
- close_all_sockets(t);
-
D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
kick_transport(t);
transport_unref(t);
diff --git a/include/log/log.h b/include/log/log.h
index 0b17574..1cdf7bc 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -563,6 +563,12 @@
#define android_btWriteLog(tag, type, payload, len) \
__android_log_btwrite(tag, type, payload, len)
+#define android_errorWriteLog(tag, subTag) \
+ __android_log_error_write(tag, subTag, -1, NULL, 0)
+
+#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
+ __android_log_error_write(tag, subTag, uid, data, dataLen)
+
/*
* IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
* android_testLog will remain constant in its purpose as a wrapper
@@ -612,6 +618,9 @@
*/
int __android_log_is_loggable(int prio, const char *tag, int def);
+int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
+ uint32_t dataLen);
+
/*
* Send a simple string to the log.
*/
diff --git a/libcutils/strdup16to8.c b/libcutils/strdup16to8.c
index 1a8ba86..4dc987e 100644
--- a/libcutils/strdup16to8.c
+++ b/libcutils/strdup16to8.c
@@ -55,7 +55,8 @@
/* Fast path for the usual case where 3*len is < SIZE_MAX-1.
*/
if (len < (SIZE_MAX-1)/3) {
- while (len--) {
+ while (len != 0) {
+ len--;
unsigned int uic = *utf16Str++;
if (uic > 0x07ff)
@@ -69,7 +70,8 @@
}
/* The slower but paranoid version */
- while (len--) {
+ while (len != 0) {
+ len--;
unsigned int uic = *utf16Str++;
size_t utf8Cur = utf8Len;
@@ -112,7 +114,8 @@
* strnlen16to8() properly or at a minimum checked the result of
* its malloc(SIZE_MAX) in case of overflow.
*/
- while (len--) {
+ while (len != 0) {
+ len--;
unsigned int uic = *utf16Str++;
if (uic > 0x07ff) {
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 930dcf7..5eed634 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,7 +24,7 @@
# so make sure we do not regret hard-coding it as follows:
liblog_cflags := -DLIBLOG_LOG_TAG=1005
-liblog_sources := logd_write.c
+liblog_sources := logd_write.c log_event_write.c
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
new file mode 100644
index 0000000..0bc42d5
--- /dev/null
+++ b/liblog/log_event_write.c
@@ -0,0 +1,88 @@
+/*
+ * 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 <errno.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#define MAX_EVENT_PAYLOAD 512
+#define MAX_SUBTAG_LEN 32
+
+static inline void copy4LE(uint8_t *buf, size_t pos, int val)
+{
+ buf[pos] = val & 0xFF;
+ buf[pos+1] = (val >> 8) & 0xFF;
+ buf[pos+2] = (val >> 16) & 0xFF;
+ buf[pos+3] = (val >> 24) & 0xFF;
+}
+
+int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
+ uint32_t dataLen)
+{
+ uint8_t buf[MAX_EVENT_PAYLOAD];
+ size_t pos = 0;
+ uint32_t subTagLen = 0;
+ uint32_t roomLeftForData = 0;
+
+ if ((subTag == NULL) || ((data == NULL) && (dataLen != 0))) return -EINVAL;
+
+ subTagLen = strlen(subTag);
+
+ // Truncate subtags that are too long.
+ subTagLen = subTagLen > MAX_SUBTAG_LEN ? MAX_SUBTAG_LEN : subTagLen;
+
+ // Truncate dataLen if it is too long.
+ roomLeftForData = MAX_EVENT_PAYLOAD -
+ (1 + // EVENT_TYPE_LIST
+ 1 + // Number of elements in list
+ 1 + // EVENT_TYPE_STRING
+ sizeof(subTagLen) +
+ subTagLen +
+ 1 + // EVENT_TYPE_INT
+ sizeof(uid) +
+ 1 + // EVENT_TYPE_STRING
+ sizeof(dataLen));
+ dataLen = dataLen > roomLeftForData ? roomLeftForData : dataLen;
+
+ buf[pos++] = EVENT_TYPE_LIST;
+ buf[pos++] = 3; // Number of elements in the list (subTag, uid, data)
+
+ // Write sub tag.
+ buf[pos++] = EVENT_TYPE_STRING;
+ copy4LE(buf, pos, subTagLen);
+ pos += 4;
+ memcpy(&buf[pos], subTag, subTagLen);
+ pos += subTagLen;
+
+ // Write UID.
+ buf[pos++] = EVENT_TYPE_INT;
+ copy4LE(buf, pos, uid);
+ pos += 4;
+
+ // Write data.
+ buf[pos++] = EVENT_TYPE_STRING;
+ copy4LE(buf, pos, dataLen);
+ pos += 4;
+ if (dataLen != 0)
+ {
+ memcpy(&buf[pos], data, dataLen);
+ pos += dataLen;
+ }
+
+ return __android_log_bwrite(tag, buf, pos);
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index abe0239..c987041 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
+#include <string.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
@@ -876,3 +877,398 @@
property_set(key, hold[2]);
property_set(key + base_offset, hold[3]);
}
+
+static inline int32_t get4LE(const char* src)
+{
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
+ const int TAG = 123456781;
+ const char SUBTAG[] = "test-subtag";
+ const int UID = -1;
+ const int DATA_LEN = 200;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ eventData += strlen(SUBTAG);
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(DATA_LEN, get4LE(eventData));
+ eventData += 4;
+
+ if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
+ continue;
+ }
+
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
+ const int TAG = 123456782;
+ const char SUBTAG[] = "test-subtag";
+ const int UID = -1;
+ const int DATA_LEN = sizeof(max_payload_buf);
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+ char *original = eventData;
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ eventData += strlen(SUBTAG);
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ size_t dataLen = get4LE(eventData);
+ eventData += 4;
+
+ if (memcmp(max_payload_buf, eventData, dataLen)) {
+ continue;
+ }
+ eventData += dataLen;
+
+ // 4 bytes for the tag, and 512 bytes for the log since the max_payload_buf should be
+ // truncated.
+ ASSERT_EQ(4 + 512, eventData - original);
+
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
+ const int TAG = 123456783;
+ const char SUBTAG[] = "test-subtag";
+ const int UID = -1;
+ const int DATA_LEN = 200;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_GT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, NULL, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag == TAG) {
+ // This tag should not have been written because the data was null
+ count++;
+ break;
+ }
+ }
+
+ EXPECT_EQ(0, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
+ const int TAG = 123456784;
+ const char SUBTAG[] = "abcdefghijklmnopqrstuvwxyz now i know my abc";
+ const int UID = -1;
+ const int DATA_LEN = 200;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ // The subtag is longer than 32 and should be truncated to that.
+ ASSERT_EQ(32, get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, 32)) {
+ continue;
+ }
+ eventData += 32;
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(DATA_LEN, get4LE(eventData));
+ eventData += 4;
+
+ if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
+ continue;
+ }
+
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
+ const int TAG = 123456785;
+ const char SUBTAG[] = "test-subtag";
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
+ const int TAG = 123456786;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag == TAG) {
+ // This tag should not have been written because the data was null
+ count++;
+ break;
+ }
+ }
+
+ EXPECT_EQ(0, count);
+
+ android_logger_list_close(logger_list);
+}
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 1e6f55f..febf775 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -48,7 +48,7 @@
char c;
while (((c = *s++)) && (++len <= max_prio_len)) {
if (!isdigit(c)) {
- return (c == '>') ? s : NULL;
+ return ((c == '>') && (*s == '[')) ? s : NULL;
}
}
return NULL;
@@ -294,6 +294,22 @@
}
}
+pid_t LogKlog::sniffPid(const char *cp) {
+ while (*cp) {
+ // Mediatek kernels with modified printk
+ if (*cp == '[') {
+ int pid = 0;
+ char dummy;
+ if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
+ return pid;
+ }
+ break; // Only the first one
+ }
+ ++cp;
+ }
+ return 0;
+}
+
// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
// compensated start time.
void LogKlog::synchronize(const char *buf) {
@@ -417,9 +433,9 @@
// sniff for start marker
const char klogd_message[] = "logd.klogd: ";
- if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
- char *endp;
- uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+ const char *start = strstr(buf, klogd_message);
+ if (start) {
+ uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10);
if (sig == signature.nsec()) {
if (initialized) {
enableLogging = true;
@@ -435,10 +451,10 @@
return 0;
}
- // Parse pid, tid and uid (not possible)
- const pid_t pid = 0;
- const pid_t tid = 0;
- const uid_t uid = 0;
+ // Parse pid, tid and uid
+ const pid_t pid = sniffPid(buf);
+ const pid_t tid = pid;
+ const uid_t uid = pid ? logbuf->pidToUid(pid) : 0;
// Parse (rules at top) to pull out a tag from the incoming kernel message.
// Some may view the following as an ugly heuristic, the desire is to
@@ -450,7 +466,7 @@
if (!*buf) {
return 0;
}
- const char *start = buf;
+ start = buf;
const char *tag = "";
const char *etag = tag;
if (!isspace(*buf)) {
@@ -461,7 +477,14 @@
// <PRI>[<TIME>] "[INFO]"<tag> ":" message
bt = buf + 6;
}
- for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+ for(et = bt; *et && (*et != ':') && !isspace(*et); ++et) {
+ // skip ':' within [ ... ]
+ if (*et == '[') {
+ while (*et && *et != ']') {
+ ++et;
+ }
+ }
+ }
for(cp = et; isspace(*cp); ++cp);
size_t size;
@@ -557,7 +580,17 @@
etag = tag = "";
}
}
- size_t l = etag - tag;
+ // Suppress additional stutter in tag:
+ // eg: [143:healthd]healthd -> [143:healthd]
+ size_t taglen = etag - tag;
+ // Mediatek-special printk induced stutter
+ char *np = strrchr(tag, ']');
+ if (np && (++np < etag)) {
+ size_t s = etag - np;
+ if (((s + s) < taglen) && !strncmp(np, np - 1 - s, s)) {
+ taglen = np - tag;
+ }
+ }
// skip leading space
while (isspace(*buf)) {
++buf;
@@ -568,11 +601,11 @@
--b;
}
// trick ... allow tag with empty content to be logged. log() drops empty
- if (!b && l) {
+ if (!b && taglen) {
buf = " ";
b = 1;
}
- size_t n = 1 + l + 1 + b + 1;
+ size_t n = 1 + taglen + 1 + b + 1;
// Allocate a buffer to hold the interpreted log message
int rc = n;
@@ -581,15 +614,15 @@
rc = -ENOMEM;
return rc;
}
- char *np = newstr;
+ np = newstr;
// Convert priority into single-byte Android logger priority
*np = convertKernelPrioToAndroidPrio(pri);
++np;
// Copy parsed tag following priority
- strncpy(np, tag, l);
- np += l;
+ strncpy(np, tag, taglen);
+ np += taglen;
*np = '\0';
++np;
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 24b2685..7e4fde0 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -47,6 +47,7 @@
protected:
void sniffTime(log_time &now, const char **buf, bool reverse);
+ pid_t sniffPid(const char *buf);
void calculateCorrection(const log_time &monotonic, const char *real_string);
virtual bool onDataAvailable(SocketClient *cli);
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 9fd8eda..89fa222 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -110,6 +110,7 @@
libprotobuf-cpp-lite \
libchromeos-http \
libchromeos-dbus \
+ libcutils \
libdbus
LOCAL_SRC_FILES := $(metrics_daemon_sources)
LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
diff --git a/metricsd/constants.h b/metricsd/constants.h
index 56dac0d..15c15d9 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -24,6 +24,11 @@
static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
static const char kConsentFilePath[] = "/data/misc/metrics/enabled";
static const char kDefaultVersion[] = "0.0.0.0";
+
+// System properties used.
+static const char kBuildTargetIdProperty[] = "ro.product.build_target_id";
+static const char kChannelProperty[] = "ro.product.channel";
+static const char kProductVersionProperty[] = "ro.product.version";
} // namespace metrics
#endif // METRICS_CONSTANTS_H_
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index 069f68e..5855cee 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -32,7 +32,7 @@
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <base/sys_info.h>
+#include <cutils/properties.h>
#include <dbus/dbus.h>
#include <dbus/message.h>
@@ -209,10 +209,13 @@
if (version_hash_is_cached)
return cached_version_hash;
version_hash_is_cached = true;
- std::string version = metrics::kDefaultVersion;
+
+ char version[PROPERTY_VALUE_MAX];
// The version might not be set for development devices. In this case, use the
// zero version.
- base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &version);
+ property_get(metrics::kProductVersionProperty, version,
+ metrics::kDefaultVersion);
+
cached_version_hash = base::Hash(version);
if (testing_) {
cached_version_hash = 42; // return any plausible value for the hash
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 7dd0323..21ec229 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -21,7 +21,7 @@
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
-#include <base/sys_info.h>
+#include <cutils/properties.h>
#include <string>
#include <vector>
@@ -73,21 +73,28 @@
CHECK(!initialized_)
<< "this should be called only once in the metrics_daemon lifetime.";
- if (!base::SysInfo::GetLsbReleaseValue("BRILLO_BUILD_TARGET_ID",
- &profile_.build_target_id)) {
- LOG(ERROR) << "BRILLO_BUILD_TARGET_ID is not set in /etc/lsb-release.";
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(metrics::kBuildTargetIdProperty, property_value, "");
+ profile_.build_target_id = std::string(property_value);
+
+ if (profile_.build_target_id.empty()) {
+ LOG(ERROR) << "System property " << metrics::kBuildTargetIdProperty
+ << " is not set.";
return false;
}
- std::string channel;
- if (!base::SysInfo::GetLsbReleaseValue("BRILLO_CHANNEL", &channel) ||
- !base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &profile_.version)) {
+ property_get(metrics::kChannelProperty, property_value, "");
+ std::string channel(property_value);
+
+ property_get(metrics::kProductVersionProperty, property_value, "");
+ profile_.version = std::string(property_value);
+
+ if (channel.empty() || profile_.version.empty()) {
// If the channel or version is missing, the image is not official.
// In this case, set the channel to unknown and the version to 0.0.0.0 to
// avoid polluting the production data.
channel = "";
profile_.version = metrics::kDefaultVersion;
-
}
profile_.client_id =
testing_ ? "client_id_test" :