Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eafbbdf3 authored by Ken Mixter's avatar Ken Mixter
Browse files

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
parent fd55798d
Loading
Loading
Loading
Loading
+108 −56
Original line number Diff line number Diff line
@@ -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) {
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");
    return 1;
  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;
  }
}
+0 −1
Original line number Diff line number Diff line
@@ -210,7 +210,6 @@ void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) {

  DeleteFrequencyCounters();
  ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName);
  ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName);
  ConfigureCrashFrequencyReporter(kMetricAnyCrashesWeeklyName);
  ConfigureCrashFrequencyReporter(kMetricKernelCrashesDailyName);
  ConfigureCrashFrequencyReporter(kMetricKernelCrashesWeeklyName);
+72 −1
Original line number Diff line number Diff line
@@ -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_;
}
+12 −0
Original line number Diff line number Diff line
@@ -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);
+62 −1
Original line number Diff line number Diff line
@@ -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());