|  | /* | 
|  | * 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 <cstdio> | 
|  | #include <cstdlib> | 
|  |  | 
|  | #include "constants.h" | 
|  | #include "metrics/metrics_library.h" | 
|  |  | 
|  | enum Mode { | 
|  | kModeDumpHistograms, | 
|  | kModeSendSample, | 
|  | kModeSendEnumSample, | 
|  | kModeSendSparseSample, | 
|  | kModeSendCrosEvent, | 
|  | kModeHasConsent, | 
|  | kModeIsGuestMode, | 
|  | }; | 
|  |  | 
|  | void ShowUsage() { | 
|  | fprintf(stderr, | 
|  | "Usage:  metrics_client [-t] name sample min max nbuckets\n" | 
|  | "        metrics_client -e   name sample max\n" | 
|  | "        metrics_client -s   name sample\n" | 
|  | "        metrics_client -v   event\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 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" | 
|  | "  -v: send a Platform.CrOSEvent enum histogram sample\n"); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | static int ParseInt(const char *arg) { | 
|  | char *endptr; | 
|  | int value = strtol(arg, &endptr, 0); | 
|  | if (*endptr != '\0') { | 
|  | fprintf(stderr, "metrics client: bad integer \"%s\"\n", arg); | 
|  | ShowUsage(); | 
|  | } | 
|  | return value; | 
|  | } | 
|  |  | 
|  | static double ParseDouble(const char *arg) { | 
|  | char *endptr; | 
|  | double value = strtod(arg, &endptr); | 
|  | if (*endptr != '\0') { | 
|  | fprintf(stderr, "metrics client: bad double \"%s\"\n", arg); | 
|  | ShowUsage(); | 
|  | } | 
|  | 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, | 
|  | bool secs_to_msecs) { | 
|  | const char* name = argv[name_index]; | 
|  | int sample; | 
|  | if (secs_to_msecs) { | 
|  | sample = static_cast<int>(ParseDouble(argv[name_index + 1]) * 1000.0); | 
|  | } else { | 
|  | sample = ParseInt(argv[name_index + 1]); | 
|  | } | 
|  |  | 
|  | MetricsLibrary metrics_lib; | 
|  | metrics_lib.Init(); | 
|  | if (mode == kModeSendSparseSample) { | 
|  | metrics_lib.SendSparseToUMA(name, sample); | 
|  | } else if (mode == kModeSendEnumSample) { | 
|  | int max = ParseInt(argv[name_index + 2]); | 
|  | metrics_lib.SendEnumToUMA(name, sample, max); | 
|  | } else { | 
|  | int min = ParseInt(argv[name_index + 2]); | 
|  | int max = ParseInt(argv[name_index + 3]); | 
|  | int nbuckets = ParseInt(argv[name_index + 4]); | 
|  | metrics_lib.SendToUMA(name, sample, min, max, nbuckets); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int SendCrosEvent(char* argv[], int action_index) { | 
|  | const char* event = argv[action_index]; | 
|  | bool result; | 
|  | MetricsLibrary metrics_lib; | 
|  | metrics_lib.Init(); | 
|  | result = metrics_lib.SendCrosEventToUMA(event); | 
|  | if (!result) { | 
|  | fprintf(stderr, "metrics_client: could not send event %s\n", event); | 
|  | return 1; | 
|  | } | 
|  | 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 mode = kModeSendSample; | 
|  | bool secs_to_msecs = false; | 
|  |  | 
|  | // Parse arguments | 
|  | int flag; | 
|  | while ((flag = getopt(argc, argv, "abcdegstv")) != -1) { | 
|  | switch (flag) { | 
|  | case 'c': | 
|  | mode = kModeHasConsent; | 
|  | break; | 
|  | case 'd': | 
|  | mode = kModeDumpHistograms; | 
|  | break; | 
|  | case 'e': | 
|  | mode = kModeSendEnumSample; | 
|  | break; | 
|  | case 'g': | 
|  | mode = kModeIsGuestMode; | 
|  | break; | 
|  | case 's': | 
|  | mode = kModeSendSparseSample; | 
|  | break; | 
|  | case 't': | 
|  | secs_to_msecs = true; | 
|  | break; | 
|  | case 'v': | 
|  | mode = kModeSendCrosEvent; | 
|  | break; | 
|  | default: | 
|  | ShowUsage(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | int arg_index = optind; | 
|  |  | 
|  | int expected_args = 0; | 
|  | if (mode == kModeSendSample) | 
|  | expected_args = 5; | 
|  | else if (mode == kModeSendEnumSample) | 
|  | expected_args = 3; | 
|  | else if (mode == kModeSendSparseSample) | 
|  | expected_args = 2; | 
|  | else if (mode == kModeSendCrosEvent) | 
|  | expected_args = 1; | 
|  |  | 
|  | if ((arg_index + expected_args) != argc) { | 
|  | ShowUsage(); | 
|  | } | 
|  |  | 
|  | switch (mode) { | 
|  | case kModeDumpHistograms: | 
|  | return DumpHistograms(); | 
|  | case kModeSendSample: | 
|  | case kModeSendEnumSample: | 
|  | case kModeSendSparseSample: | 
|  | if ((mode != kModeSendSample) && secs_to_msecs) { | 
|  | ShowUsage(); | 
|  | } | 
|  | return SendStats(argv, | 
|  | arg_index, | 
|  | mode, | 
|  | secs_to_msecs); | 
|  | case kModeSendCrosEvent: | 
|  | return SendCrosEvent(argv, arg_index); | 
|  | case kModeHasConsent: | 
|  | return HasConsent(); | 
|  | case kModeIsGuestMode: | 
|  | return IsGuestMode(); | 
|  | default: | 
|  | ShowUsage(); | 
|  | return 0; | 
|  | } | 
|  | } |