metrics: Add guest mode detection to metrics library and client
Change-Id: I2c27bd999330395ba3568820ea76198b202bd7f4 BUG=7203 TEST=Verify metrics_client -c and -g toggling consent and guest mode. Review URL: http://codereview.chromium.org/3571009
This commit is contained in:
parent
fd55798dc0
commit
eafbbdf3df
5 changed files with 254 additions and 59 deletions
|
@ -7,63 +7,29 @@
|
|||
|
||||
#include "metrics_library.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
bool send_to_autotest = false;
|
||||
bool send_to_chrome = true;
|
||||
bool send_enum = false;
|
||||
bool secs_to_msecs = false;
|
||||
int name_index = 1;
|
||||
bool print_usage = false;
|
||||
|
||||
if (argc >= 3) {
|
||||
// Parse arguments
|
||||
int flag;
|
||||
while ((flag = getopt(argc, argv, "abet")) != -1) {
|
||||
switch (flag) {
|
||||
case 'a':
|
||||
send_to_autotest = true;
|
||||
send_to_chrome = false;
|
||||
break;
|
||||
case 'b':
|
||||
send_to_chrome = true;
|
||||
send_to_autotest = true;
|
||||
break;
|
||||
case 'e':
|
||||
send_enum = true;
|
||||
break;
|
||||
case 't':
|
||||
secs_to_msecs = true;
|
||||
break;
|
||||
default:
|
||||
print_usage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
name_index = optind;
|
||||
} else {
|
||||
print_usage = true;
|
||||
}
|
||||
|
||||
int num_args = send_enum ? 3 : 5;
|
||||
if ((name_index + num_args) != argc ||
|
||||
(send_enum && secs_to_msecs)) {
|
||||
print_usage = true;
|
||||
}
|
||||
|
||||
if (print_usage) {
|
||||
fprintf(stderr,
|
||||
"Usage: metrics_client [-ab] [-t] name sample min max nbuckets\n"
|
||||
" metrics_client [-ab] -e name sample max\n"
|
||||
"\n"
|
||||
" default: send metric with integer values to Chrome only\n"
|
||||
" |min| > 0, |min| <= sample < |max|\n"
|
||||
" -a: send metric (name/sample) to Autotest only\n"
|
||||
" -b: send metric to both Chrome and Autotest\n"
|
||||
" -e: send linear/enumeration histogram data\n"
|
||||
" -t: convert sample from double seconds to int milliseconds\n");
|
||||
return 1;
|
||||
}
|
||||
void ShowUsage() {
|
||||
fprintf(stderr,
|
||||
"Usage: metrics_client [-ab] [-t] name sample min max nbuckets\n"
|
||||
" metrics_client [-ab] -e name sample max\n"
|
||||
" metrics_client [-cg]\n"
|
||||
"\n"
|
||||
" default: send metric with integer values to Chrome only\n"
|
||||
" |min| > 0, |min| <= sample < |max|\n"
|
||||
" -a: send metric (name/sample) to Autotest only\n"
|
||||
" -b: send metric to both Chrome and Autotest\n"
|
||||
" -c: return exit status 0 if user consents to stats, 1 otherwise\n"
|
||||
" -e: send linear/enumeration histogram data\n"
|
||||
" -g: return exit status 0 if machine in guest mode, 1 otherwise\n"
|
||||
" -t: convert sample from double seconds to int milliseconds\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int SendStats(char* argv[],
|
||||
int name_index,
|
||||
bool send_enum,
|
||||
bool secs_to_msecs,
|
||||
bool send_to_autotest,
|
||||
bool send_to_chrome) {
|
||||
const char* name = argv[name_index];
|
||||
int sample;
|
||||
if (secs_to_msecs) {
|
||||
|
@ -92,3 +58,89 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int HasConsent() {
|
||||
MetricsLibrary metrics_lib;
|
||||
metrics_lib.Init();
|
||||
return metrics_lib.AreMetricsEnabled() ? 0 : 1;
|
||||
}
|
||||
|
||||
static int IsGuestMode() {
|
||||
MetricsLibrary metrics_lib;
|
||||
metrics_lib.Init();
|
||||
return metrics_lib.IsGuestMode() ? 0 : 1;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
enum Mode {
|
||||
kModeSendStats,
|
||||
kModeHasConsent,
|
||||
kModeIsGuestMode
|
||||
} mode = kModeSendStats;
|
||||
bool send_to_autotest = false;
|
||||
bool send_to_chrome = true;
|
||||
bool send_enum = false;
|
||||
bool secs_to_msecs = false;
|
||||
bool print_usage = false;
|
||||
|
||||
// Parse arguments
|
||||
int flag;
|
||||
while ((flag = getopt(argc, argv, "abcegt")) != -1) {
|
||||
switch (flag) {
|
||||
case 'a':
|
||||
mode = kModeSendStats;
|
||||
send_to_autotest = true;
|
||||
send_to_chrome = false;
|
||||
break;
|
||||
case 'b':
|
||||
mode = kModeSendStats;
|
||||
send_to_chrome = true;
|
||||
send_to_autotest = true;
|
||||
break;
|
||||
case 'c':
|
||||
mode = kModeHasConsent;
|
||||
break;
|
||||
case 'e':
|
||||
send_enum = true;
|
||||
break;
|
||||
case 'g':
|
||||
mode = kModeIsGuestMode;
|
||||
break;
|
||||
case 't':
|
||||
secs_to_msecs = true;
|
||||
break;
|
||||
default:
|
||||
print_usage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int name_index = optind;
|
||||
|
||||
int expected_args = 0;
|
||||
if (mode == kModeSendStats)
|
||||
expected_args = send_enum ? 3 : 5;
|
||||
|
||||
if ((name_index + expected_args) != argc) {
|
||||
ShowUsage();
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case kModeSendStats:
|
||||
if (send_enum && secs_to_msecs) {
|
||||
ShowUsage();
|
||||
}
|
||||
return SendStats(argv,
|
||||
name_index,
|
||||
send_enum,
|
||||
secs_to_msecs,
|
||||
send_to_autotest,
|
||||
send_to_chrome);
|
||||
case kModeHasConsent:
|
||||
return HasConsent();
|
||||
case kModeIsGuestMode:
|
||||
return IsGuestMode();
|
||||
default:
|
||||
ShowUsage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,7 +210,6 @@ void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) {
|
|||
|
||||
DeleteFrequencyCounters();
|
||||
ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName);
|
||||
ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName);
|
||||
ConfigureCrashFrequencyReporter(kMetricAnyCrashesWeeklyName);
|
||||
ConfigureCrashFrequencyReporter(kMetricKernelCrashesDailyName);
|
||||
ConfigureCrashFrequencyReporter(kMetricKernelCrashesWeeklyName);
|
||||
|
|
|
@ -44,13 +44,84 @@ MetricsLibrary::MetricsLibrary()
|
|||
: uma_events_file_(NULL),
|
||||
consent_file_(kConsentFile) {}
|
||||
|
||||
// We take buffer and buffer_size as parameters in order to simplify testing
|
||||
// of various alignments of the |device_name| with |buffer_size|.
|
||||
bool MetricsLibrary::IsDeviceMounted(const char* device_name,
|
||||
const char* mounts_file,
|
||||
char* buffer,
|
||||
int buffer_size,
|
||||
bool* result) {
|
||||
if (buffer == NULL || buffer_size < 1)
|
||||
return false;
|
||||
int mounts_fd = open(mounts_file, O_RDONLY);
|
||||
if (mounts_fd < 0)
|
||||
return false;
|
||||
// match_offset describes:
|
||||
// -1 -- not beginning of line
|
||||
// 0..strlen(device_name)-1 -- this offset in device_name is next to match
|
||||
// strlen(device_name) -- matched full name, just need a space.
|
||||
int match_offset = 0;
|
||||
bool match = false;
|
||||
while (!match) {
|
||||
int read_size = read(mounts_fd, buffer, buffer_size);
|
||||
if (read_size <= 0) {
|
||||
if (errno == -EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < read_size; ++i) {
|
||||
if (buffer[i] == '\n') {
|
||||
match_offset = 0;
|
||||
continue;
|
||||
}
|
||||
if (match_offset < 0) {
|
||||
continue;
|
||||
}
|
||||
if (device_name[match_offset] == '\0') {
|
||||
if (buffer[i] == ' ') {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
match_offset = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buffer[i] == device_name[match_offset]) {
|
||||
++match_offset;
|
||||
} else {
|
||||
match_offset = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(mounts_fd);
|
||||
*result = match;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetricsLibrary::IsGuestMode() {
|
||||
char buffer[256];
|
||||
bool result = false;
|
||||
if (!IsDeviceMounted("guestfs",
|
||||
"/proc/mounts",
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
&result)) {
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MetricsLibrary::AreMetricsEnabled() {
|
||||
static struct stat stat_buffer;
|
||||
time_t this_check_time = time(NULL);
|
||||
|
||||
if (this_check_time != cached_enabled_time_) {
|
||||
cached_enabled_time_ = this_check_time;
|
||||
cached_enabled_ = (stat(consent_file_, &stat_buffer) >= 0);
|
||||
if (stat(consent_file_, &stat_buffer) >= 0 &&
|
||||
!IsGuestMode())
|
||||
cached_enabled_ = true;
|
||||
else
|
||||
cached_enabled_ = false;
|
||||
}
|
||||
return cached_enabled_;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,9 @@ class MetricsLibrary : public MetricsLibraryInterface {
|
|||
// Initializes the library.
|
||||
void Init();
|
||||
|
||||
// Returns whether or not the machine is running in guest mode.
|
||||
bool IsGuestMode();
|
||||
|
||||
// Returns whether or not metrics collection is enabled.
|
||||
bool AreMetricsEnabled();
|
||||
|
||||
|
@ -75,9 +78,18 @@ class MetricsLibrary : public MetricsLibraryInterface {
|
|||
FRIEND_TEST(MetricsLibraryTest, AreMetricsEnabled);
|
||||
FRIEND_TEST(MetricsLibraryTest, FormatChromeMessage);
|
||||
FRIEND_TEST(MetricsLibraryTest, FormatChromeMessageTooLong);
|
||||
FRIEND_TEST(MetricsLibraryTest, IsDeviceMounted);
|
||||
FRIEND_TEST(MetricsLibraryTest, SendMessageToChrome);
|
||||
FRIEND_TEST(MetricsLibraryTest, SendMessageToChromeUMAEventsBadFileLocation);
|
||||
|
||||
// Sets |*result| to whether or not the |mounts_file| indicates that
|
||||
// the |device_name| is currently mounted. Uses |buffer| of
|
||||
// |buffer_size| to read the file. Returns false if any error.
|
||||
bool IsDeviceMounted(const char* device_name,
|
||||
const char* mounts_file,
|
||||
char* buffer, int buffer_size,
|
||||
bool* result);
|
||||
|
||||
// Sends message of size |length| to Chrome for transport to UMA and
|
||||
// returns true on success.
|
||||
bool SendMessageToChrome(int32_t length, const char* message);
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include "metrics_library.h"
|
||||
|
||||
static const FilePath kTestUMAEventsFile("test-uma-events");
|
||||
|
||||
static const char kTestConsent[] = "test-consent";
|
||||
static const char kTestMounts[] = "test-mounts";
|
||||
|
||||
static void SetMetricsEnabled(bool enabled) {
|
||||
if (enabled)
|
||||
|
@ -35,6 +35,8 @@ class MetricsLibraryTest : public testing::Test {
|
|||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
file_util::Delete(FilePath(kTestConsent), false);
|
||||
file_util::Delete(FilePath(kTestMounts), false);
|
||||
file_util::Delete(kTestUMAEventsFile, false);
|
||||
}
|
||||
|
||||
|
@ -44,6 +46,65 @@ class MetricsLibraryTest : public testing::Test {
|
|||
MetricsLibrary lib_;
|
||||
};
|
||||
|
||||
TEST_F(MetricsLibraryTest, IsDeviceMounted) {
|
||||
static const char kTestContents[] =
|
||||
"0123456789abcde 0123456789abcde\nguestfs foo bar\n";
|
||||
char buffer[1024];
|
||||
int block_sizes[] = { 1, 2, 3, 4, 5, 6, 8, 12, 14, 16, 32, 1024 };
|
||||
bool result;
|
||||
EXPECT_FALSE(lib_.IsDeviceMounted("guestfs",
|
||||
"nonexistent",
|
||||
buffer,
|
||||
1,
|
||||
&result));
|
||||
ASSERT_TRUE(file_util::WriteFile(FilePath(kTestMounts),
|
||||
kTestContents,
|
||||
strlen(kTestContents)));
|
||||
EXPECT_FALSE(lib_.IsDeviceMounted("guestfs",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
0,
|
||||
&result));
|
||||
for (size_t i = 0; i < arraysize(block_sizes); ++i) {
|
||||
EXPECT_TRUE(lib_.IsDeviceMounted("0123456789abcde",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
block_sizes[i],
|
||||
&result));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(lib_.IsDeviceMounted("guestfs",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
block_sizes[i],
|
||||
&result));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(lib_.IsDeviceMounted("0123456",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
block_sizes[i],
|
||||
&result));
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_TRUE(lib_.IsDeviceMounted("9abcde",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
block_sizes[i],
|
||||
&result));
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_TRUE(lib_.IsDeviceMounted("foo",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
block_sizes[i],
|
||||
&result));
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_TRUE(lib_.IsDeviceMounted("bar",
|
||||
kTestMounts,
|
||||
buffer,
|
||||
block_sizes[i],
|
||||
&result));
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MetricsLibraryTest, AreMetricsEnabledFalse) {
|
||||
SetMetricsEnabled(false);
|
||||
EXPECT_FALSE(lib_.AreMetricsEnabled());
|
||||
|
|
Loading…
Reference in a new issue