| /* |
| * Chrome OS Metrics - collect and record metrics data through UMA |
| * |
| * This file initially created by Google, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #if 0 |
| #define CONFIG_PSB_SUPPORT /* enable Public Safety Band support */ |
| #endif |
| |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <metrics/c_metrics_library.h> |
| |
| #define CONNMAN_API_SUBJECT_TO_CHANGE |
| #include <connman/assert.h> |
| #include <connman/plugin.h> |
| #include <connman/notifier.h> |
| #include <connman/network.h> |
| #include <connman/service.h> |
| #include <connman/log.h> |
| |
| #define _DBG_METRICS(fmt, arg...) DBG(DBG_METRICS, fmt, ## arg) |
| |
| #define METRIC_NAME_LEN 80 /* max size of a constructed name */ |
| |
| static CMetricsLibrary lib = NULL; |
| |
| const char *kMetricNetworkTimeToDropName = "Network.TimeToDrop"; |
| const int kMetricNetworkTimeToDropMin = 1; |
| const int kMetricNetworkTimeToDropMax = 8 * 60 * 60; /* 8 hours */ |
| const int kMetricNetworkTimeToDropBuckets = 50; |
| |
| const char *kMetricNetworkTimeOnlineName = "Network.%c%s.TimeOnline"; |
| const int kMetricNetworkTimeOnlineMin = 1; |
| const int kMetricNetworkTimeOnlineMax = 8 * 60 * 60; /* 8 hours */ |
| const int kMetricNetworkTimeOnlineBuckets = 50; |
| |
| const char *kMetricNetworkTimeToJoinName = "Network.%c%s.TimeToJoin"; |
| const char *kMetricNetworkTimeToConfigName = "Network.%c%s.TimeToConfig"; |
| const char *kMetricNetworkTimeToOnline = "Network.%c%s.TimeToOnline"; |
| const char *kMetricNetworkTimeToPortal = "Network.%c%s.TimeToPortal"; |
| const char *kMetricNetworkTimeResumeToReady = "Network.%c%s.TimeResumeToReady"; |
| |
| const char *kMetricNetworkServiceErrors = "Network.ServiceErrors"; |
| const int kMetricNetworkServiceErrorsMax = CONNMAN_SERVICE_ERROR_MAX; |
| |
| const char *kMetricNetworkSecurity = "Network.%c%s.Security"; |
| const int kMetricNetworkSecurityMax = CONNMAN_SERVICE_SECURITY_MAX; |
| |
| const char *kMetricNetworkAuthMode = "Network.%c%s.AuthMode"; |
| enum connman_authmode { |
| CONNMAN_AUTHMODE_UNKNOWN = 0, |
| |
| CONNMAN_AUTHMODE_EAP_AKA = 1, |
| CONNMAN_AUTHMODE_EAP_FAST = 2, |
| CONNMAN_AUTHMODE_EAP_GPSK = 3, |
| CONNMAN_AUTHMODE_EAP_GTC = 4, |
| CONNMAN_AUTHMODE_EAP_IKEV2 = 5, |
| CONNMAN_AUTHMODE_EAP_LEAP = 6, |
| CONNMAN_AUTHMODE_EAP_MD5 = 7, |
| CONNMAN_AUTHMODE_EAP_MSCHAPV2 = 8, |
| CONNMAN_AUTHMODE_EAP_OTP = 9, |
| CONNMAN_AUTHMODE_EAP_PAX = 10, |
| CONNMAN_AUTHMODE_EAP_PEAP = 11, |
| CONNMAN_AUTHMODE_EAP_PSK = 12, |
| CONNMAN_AUTHMODE_EAP_SAKE = 13, |
| CONNMAN_AUTHMODE_EAP_SIM = 14, |
| CONNMAN_AUTHMODE_EAP_TLS = 15, |
| CONNMAN_AUTHMODE_EAP_TNC = 16, |
| CONNMAN_AUTHMODE_EAP_TTLS = 17, |
| |
| CONNMAN_AUTHMODE_MAX, |
| }; |
| const int kMetricNetworkAuthModeMax = CONNMAN_AUTHMODE_MAX; |
| |
| enum connman_channel { |
| CONNMAN_CHANNEL_UNDEF = 0, |
| CONNMAN_CHANNEL_2412 = 1, |
| CONNMAN_CHANNEL_2417 = 2, |
| CONNMAN_CHANNEL_2422 = 3, |
| CONNMAN_CHANNEL_2427 = 4, |
| CONNMAN_CHANNEL_2432 = 5, |
| CONNMAN_CHANNEL_2437 = 6, |
| CONNMAN_CHANNEL_2442 = 7, |
| CONNMAN_CHANNEL_2447 = 8, |
| CONNMAN_CHANNEL_2452 = 9, |
| CONNMAN_CHANNEL_2457 = 10, |
| CONNMAN_CHANNEL_2462 = 11, |
| CONNMAN_CHANNEL_2467 = 12, |
| CONNMAN_CHANNEL_2472 = 13, |
| CONNMAN_CHANNEL_2484 = 14, |
| |
| CONNMAN_CHANNEL_5180 = 15, |
| CONNMAN_CHANNEL_5200 = 16, |
| CONNMAN_CHANNEL_5220 = 17, |
| CONNMAN_CHANNEL_5240 = 18, |
| CONNMAN_CHANNEL_5260 = 19, |
| CONNMAN_CHANNEL_5280 = 20, |
| CONNMAN_CHANNEL_5300 = 21, |
| CONNMAN_CHANNEL_5320 = 22, |
| |
| CONNMAN_CHANNEL_5500 = 23, |
| CONNMAN_CHANNEL_5520 = 24, |
| CONNMAN_CHANNEL_5540 = 25, |
| CONNMAN_CHANNEL_5560 = 26, |
| CONNMAN_CHANNEL_5580 = 27, |
| CONNMAN_CHANNEL_5600 = 28, |
| CONNMAN_CHANNEL_5620 = 29, |
| CONNMAN_CHANNEL_5640 = 30, |
| CONNMAN_CHANNEL_5660 = 31, |
| CONNMAN_CHANNEL_5680 = 32, |
| CONNMAN_CHANNEL_5700 = 33, |
| |
| CONNMAN_CHANNEL_5745 = 34, |
| CONNMAN_CHANNEL_5765 = 35, |
| CONNMAN_CHANNEL_5785 = 36, |
| CONNMAN_CHANNEL_5805 = 37, |
| CONNMAN_CHANNEL_5825 = 38, |
| |
| CONNMAN_CHANNEL_5170 = 39, |
| CONNMAN_CHANNEL_5190 = 40, |
| CONNMAN_CHANNEL_5210 = 41, |
| CONNMAN_CHANNEL_5230 = 42, |
| |
| /* NB: ignore old 11b bands 2312..2372 and 2512..2532 */ |
| /* NB: ignore regulated bands 4920..4980 and 5020..5160 */ |
| |
| #ifdef CONFIG_PSB_SUPPORT |
| CONNMAN_CHANNEL_PSB_4940 = 43, /* NB: PSB center freq's are +.5MHz */ |
| CONNMAN_CHANNEL_PSB_4941 = 44, |
| CONNMAN_CHANNEL_PSB_4942 = 45, |
| CONNMAN_CHANNEL_PSB_4943 = 46, |
| CONNMAN_CHANNEL_PSB_4944 = 47, |
| CONNMAN_CHANNEL_PSB_4947 = 48, |
| CONNMAN_CHANNEL_PSB_4952 = 49, |
| CONNMAN_CHANNEL_PSB_4957 = 50, |
| CONNMAN_CHANNEL_PSB_4962 = 51, |
| CONNMAN_CHANNEL_PSB_4967 = 52, |
| CONNMAN_CHANNEL_PSB_4972 = 53, |
| CONNMAN_CHANNEL_PSB_4977 = 54, |
| CONNMAN_CHANNEL_PSB_4982 = 55, |
| CONNMAN_CHANNEL_PSB_4985 = 56, |
| CONNMAN_CHANNEL_PSB_4986 = 57, |
| CONNMAN_CHANNEL_PSB_4987 = 58, |
| CONNMAN_CHANNEL_PSB_4988 = 59, |
| CONNMAN_CHANNEL_PSB_4989 = 60, |
| #endif |
| CONNMAN_CHANNEL_MAX |
| }; |
| const char *kMetricNetworkChannel = "Network.%c%s.Channel"; |
| const int kMetricNetworkChannelMax = CONNMAN_CHANNEL_MAX; |
| |
| const char *kMetricNetworkPhyMode = "Network.%c%s.PhyMode"; |
| const int kMetricNetworkPhyModeMax = CONNMAN_NETWORK_PHYMODE_MAX; |
| |
| static int is_suspended = FALSE; |
| |
| /* |
| * Set to the current time when resume event occurs. Cleared when the ready |
| * state is reached. |
| */ |
| static GTimeVal time_of_resume; |
| |
| static void metrics_system_suspend(void) |
| { |
| _DBG_METRICS(""); |
| is_suspended = TRUE; |
| } |
| |
| static void metrics_system_resume(void) |
| { |
| _DBG_METRICS(""); |
| is_suspended = FALSE; |
| g_get_current_time(&time_of_resume); |
| } |
| |
| static void clear_time_of_resume() |
| { |
| memset(&time_of_resume, 0, sizeof(time_of_resume)); |
| } |
| |
| static connman_bool_t is_timeset(const GTimeVal *tv) |
| { |
| return !(tv->tv_sec == 0 && tv->tv_usec == 0); |
| } |
| |
| static void __network_metric_name(char *name, size_t name_len, |
| const char *type, const char *key) |
| { |
| /* NB: we append the network type but capitalized */ |
| /* TODO(sleffler) maybe map type entirely; e.g. "wifi" -> "WiFi" */ |
| g_snprintf(name, name_len, key, toupper(type[0]), type+1); |
| } |
| |
| static void network_metric_name(char *name, size_t name_len, |
| const struct connman_service *service, const char *key) |
| { |
| const char *type = connman_service_get_type(service); |
| CONNMAN_ASSERT(type != NULL); |
| __network_metric_name(name, name_len, type, key); |
| } |
| |
| static void send_to_uma(const char *name, int value, int min, int max, |
| int nbuckets) |
| { |
| if (!CMetricsLibrarySendToUMA(lib, name, value, min, max, nbuckets)) |
| connman_error("error sending metric %s", name); |
| } |
| |
| static void send_enum_to_uma(const char *name, int value, int max) |
| { |
| if (!CMetricsLibrarySendEnumToUMA(lib, name, value, max)) |
| connman_error("error sending metric %s", name); |
| } |
| |
| static void metrics_default_changed(struct connman_service *service) |
| { |
| static int was_online = FALSE; /* NB: start offline */ |
| static time_t last_change = 0; |
| static time_t last_default_change = 0; |
| static const char *last_default_type = ""; |
| time_t now = time(NULL); |
| const char *type; |
| |
| _DBG_METRICS("service %s was_online %d is_suspended %d delta %d secs", |
| service != NULL ? connman_service_get_identifier(service) : NULL, |
| was_online, is_suspended, (int)(now - last_change)); |
| |
| /* |
| * NB: we cannot record the service ptr w/o holding a |
| * reference as the device may go away (e.g. a usb device). |
| * But we just need the type and connman_service_get_type |
| * is known to return ptr's to stable storage so just use |
| * that to detect technology switching. |
| */ |
| type = connman_service_get_type(service); |
| if (g_strcmp0(type, last_default_type) != 0) { |
| /* |
| * Type of default service changed; calculate the |
| * TimeOnline for the previous service type so we can track |
| * how much time is spent on each technology with: |
| * |
| * PerCent(sum(TimeOnline.<tech>), sum(TimeOnline.*)) |
| * |
| * Note we do not include time suspended so this time is |
| * real time on the network (unlike TimeToDrop). |
| */ |
| if (g_strcmp0(last_default_type, "") != 0) { |
| char name[METRIC_NAME_LEN]; |
| __network_metric_name(name, sizeof(name), |
| last_default_type, kMetricNetworkTimeOnlineName); |
| send_to_uma(name, now - last_default_change, |
| kMetricNetworkTimeOnlineMin, |
| kMetricNetworkTimeOnlineMax, |
| kMetricNetworkTimeOnlineBuckets); |
| |
| _DBG_METRICS("send_to_uma %s %d", |
| name, (int)(now - last_default_change)); |
| } |
| last_default_type = type; |
| last_default_change = now; |
| } |
| |
| /* |
| * Ignore changes when suspending. This assumes the suspend |
| * notification arrives before the change to the default service |
| * state which looks to be true. |
| */ |
| if (is_suspended) |
| return; |
| /* |
| * Ignore changes that are not online/offline transitions; e.g. |
| * switching between wired and wireless. TimeToDrop measures |
| * time online regardless of how we are connected. |
| */ |
| if ((service == NULL && !was_online) || (service != NULL && was_online)) |
| return; |
| |
| if (service == NULL) { |
| /* |
| * Calculate overall TimeToDrop; this is the time spent |
| * online ignoring transitions between devices. |
| */ |
| send_to_uma(kMetricNetworkTimeToDropName, now - last_change, |
| kMetricNetworkTimeToDropMin, |
| kMetricNetworkTimeToDropMax, |
| kMetricNetworkTimeToDropBuckets); |
| } |
| was_online = (service != NULL); |
| last_change = now; |
| } |
| |
| static void send_msec_to_uma(const struct connman_service *service, |
| const char *key, long secs, long usecs) |
| { |
| long msecs; |
| char name[METRIC_NAME_LEN]; |
| |
| msecs = secs * 1000 + (usecs / 1000); |
| network_metric_name(name, sizeof(name), service, key); |
| send_to_uma(name, (int) msecs, 1, 45 * 1000, 50); |
| } |
| static void send_state_delta(const struct connman_service *service, |
| const char *key, |
| enum connman_service_state from, enum connman_service_state to) |
| { |
| long secs, usecs; |
| |
| connman_service_get_time_delta(service, from, to, &secs, &usecs); |
| send_msec_to_uma(service, key, secs, usecs); |
| } |
| |
| static void send_service_error(const struct connman_service *service) |
| { |
| const enum connman_service_error error = |
| connman_service_get_error(service); |
| |
| _DBG_METRICS("error %d", error); |
| send_enum_to_uma(kMetricNetworkServiceErrors, error, |
| kMetricNetworkServiceErrorsMax); |
| } |
| |
| static void maybe_send_resume_to_ready(const struct connman_service *service) |
| { |
| long secs, usecs; |
| |
| if (!is_timeset(&time_of_resume)) |
| return; |
| |
| connman_service_get_time(service, CONNMAN_SERVICE_STATE_READY, &secs, |
| &usecs); |
| secs -= time_of_resume.tv_sec; |
| usecs -= time_of_resume.tv_usec; |
| if (usecs < 0) { |
| secs--; |
| usecs += 1000 * 1000; |
| } |
| |
| _DBG_METRICS("secs %ld usecs %ld", secs, usecs); |
| send_msec_to_uma(service, kMetricNetworkTimeResumeToReady, secs, usecs); |
| } |
| |
| static enum connman_authmode map_authmode(const char *mode) |
| { |
| /* NB: order some more common ones first */ |
| if (g_strcmp0(mode, "EAP-TLS") == 0) |
| return CONNMAN_AUTHMODE_EAP_TLS; |
| if (g_strcmp0(mode, "EAP-TTLS") == 0) |
| return CONNMAN_AUTHMODE_EAP_TTLS; |
| if (g_strcmp0(mode, "EAP-MSCHAPV2") == 0) |
| return CONNMAN_AUTHMODE_EAP_MSCHAPV2; |
| if (g_strcmp0(mode, "EAP-MD5") == 0) |
| return CONNMAN_AUTHMODE_EAP_MD5; |
| |
| if (g_strcmp0(mode, "EAP-AKA") == 0) |
| return CONNMAN_AUTHMODE_EAP_AKA; |
| if (g_strcmp0(mode, "EAP-FAST") == 0) |
| return CONNMAN_AUTHMODE_EAP_FAST; |
| if (g_strcmp0(mode, "EAP-GPSK") == 0) |
| return CONNMAN_AUTHMODE_EAP_GPSK; |
| if (g_strcmp0(mode, "EAP-GTC") == 0) |
| return CONNMAN_AUTHMODE_EAP_GTC; |
| if (g_strcmp0(mode, "EAP-IKEV2") == 0) |
| return CONNMAN_AUTHMODE_EAP_IKEV2; |
| if (g_strcmp0(mode, "EAP-LEAP") == 0) |
| return CONNMAN_AUTHMODE_EAP_LEAP; |
| if (g_strcmp0(mode, "EAP-OTP") == 0) |
| return CONNMAN_AUTHMODE_EAP_OTP; |
| if (g_strcmp0(mode, "EAP-PAX") == 0) |
| return CONNMAN_AUTHMODE_EAP_PAX; |
| if (g_strcmp0(mode, "EAP-PEAP") == 0) |
| return CONNMAN_AUTHMODE_EAP_PEAP; |
| if (g_strcmp0(mode, "EAP-PSK") == 0) |
| return CONNMAN_AUTHMODE_EAP_PSK; |
| if (g_strcmp0(mode, "EAP-SAKE") == 0) |
| return CONNMAN_AUTHMODE_EAP_SAKE; |
| if (g_strcmp0(mode, "EAP-SIM") == 0) |
| return CONNMAN_AUTHMODE_EAP_SIM; |
| if (g_strcmp0(mode, "EAP-TNC") == 0) |
| return CONNMAN_AUTHMODE_EAP_TNC; |
| |
| if (mode != NULL) |
| connman_warn("%s: unknown authmode %s", __func__, mode); |
| return CONNMAN_AUTHMODE_UNKNOWN; |
| } |
| |
| static void send_service_security(struct connman_service *service) |
| { |
| const enum connman_service_security security = |
| connman_service_get_security(service); |
| char name[METRIC_NAME_LEN]; |
| |
| _DBG_METRICS("security %d", security); |
| network_metric_name(name, sizeof(name), service, |
| kMetricNetworkSecurity); |
| send_enum_to_uma(name, security, kMetricNetworkSecurityMax); |
| |
| /* |
| * For 802.1x security send the negotiated EAP method. |
| */ |
| if (security == CONNMAN_SERVICE_SECURITY_802_1X) { |
| const enum connman_authmode authmode = map_authmode( |
| connman_service_get_authmode(service)); |
| |
| _DBG_METRICS("authmode %d", authmode); |
| network_metric_name(name, sizeof(name), service, |
| kMetricNetworkAuthMode); |
| send_enum_to_uma(name, authmode, kMetricNetworkAuthModeMax); |
| } |
| } |
| |
| /* |
| * Map WiFi frequency to UMA enum value. |
| */ |
| static enum connman_channel __map_frequency(int frequency) |
| { |
| if (2412 <= frequency && frequency <= 2472) { |
| if (((frequency - 2412) % 5) == 0) |
| return CONNMAN_CHANNEL_2412 + (frequency - 2412) / 5; |
| } else if (frequency == 2484) { |
| return CONNMAN_CHANNEL_2484; |
| } else if (5170 <= frequency && frequency <= 5230) { |
| if ((frequency % 20) == 0) |
| return CONNMAN_CHANNEL_5180 + (frequency - 5180) / 20; |
| if ((frequency % 20) == 10) |
| return CONNMAN_CHANNEL_5170 + (frequency - 5170) / 20; |
| /* NB: fall through to return undefined */ |
| } else if (5240 <= frequency && frequency <= 5320) { |
| if (((frequency - 5180) % 20) == 0) |
| return CONNMAN_CHANNEL_5180 + (frequency - 5180) / 20; |
| } else if (5500 <= frequency && frequency <= 5700) { |
| if (((frequency - 5500) % 20) == 0) |
| return CONNMAN_CHANNEL_5500 + (frequency - 5500) / 20; |
| } else if (5745 <= frequency && frequency <= 5825) { |
| if (((frequency - 5745) % 20) == 0) |
| return CONNMAN_CHANNEL_5745 + (frequency - 5745) / 20; |
| #ifdef CONFIG_PSB_SUPPORT |
| } else if (4940 <= frequency && frequency <= 4990) { |
| /* Public Safety Band */ |
| return CONNMAN_CHANNEL_PSB_4940 + (frequency * 10) + |
| ((frequency % 5) == 2 ? 5 : 0) - 49400) / 5; |
| #endif |
| } |
| connman_info("%s: no mapping for WiFi frequency %d", __func__, |
| frequency); |
| return CONNMAN_CHANNEL_UNDEF; |
| } |
| |
| static void send_service_channel(struct connman_service *service) |
| { |
| int frequency = connman_service_get_frequency(service); |
| enum connman_channel channel; |
| char name[METRIC_NAME_LEN]; |
| |
| network_metric_name(name, sizeof(name), service, kMetricNetworkChannel); |
| /* |
| * Map frequency to UMA enum value. |
| */ |
| channel = __map_frequency(frequency); |
| _DBG_METRICS("map %d to %d", frequency, channel); |
| send_enum_to_uma(name, channel, kMetricNetworkChannelMax); |
| } |
| |
| static void send_service_phymode(struct connman_service *service) |
| { |
| enum connman_network_phymode phymode = |
| connman_service_get_phymode(service); |
| char name[80]; |
| |
| network_metric_name(name, sizeof(name), service, kMetricNetworkPhyMode); |
| send_enum_to_uma(name, phymode, kMetricNetworkPhyModeMax); |
| } |
| |
| static void metrics_service_state_changed(struct connman_service *service) |
| { |
| const char *state = connman_service_get_state(service); |
| const char *type = connman_service_get_type(service); |
| |
| _DBG_METRICS("service %s state %s", service != NULL ? |
| connman_service_get_identifier(service) : NULL, state); |
| |
| if (strcmp(state, "failure") == 0) |
| send_service_error(service); |
| |
| if (strcmp(state, "online") == 0) { |
| /* |
| * Time to online is the time from when the network is |
| * marked "ready" until we can retrieve a webpage |
| * indicating connectivity. |
| */ |
| send_state_delta(service, kMetricNetworkTimeToOnline, |
| CONNMAN_SERVICE_STATE_READY, |
| CONNMAN_SERVICE_STATE_ONLINE); |
| return; |
| } |
| |
| if (strcmp(state, "portal") == 0) { |
| /* |
| * Time to portal is usually the same as the timeout |
| * used for portal detection, but it will be less when |
| * the restricted network hijacks DNS and redirects |
| * HTTP requests to a captive portal webserver. |
| */ |
| send_state_delta(service, kMetricNetworkTimeToPortal, |
| CONNMAN_SERVICE_STATE_READY, |
| CONNMAN_SERVICE_STATE_PORTAL); |
| return; |
| } |
| |
| if (strcmp(state, "ready") != 0) |
| return; |
| |
| if (strcmp(type, "wifi") == 0) { |
| /* |
| * Time to join a network covers scan+auth+assoc. This |
| * is presently provided only for wifi networks; might |
| * want to collect this for other networks. |
| */ |
| send_state_delta(service, kMetricNetworkTimeToJoinName, |
| CONNMAN_SERVICE_STATE_ASSOCIATION, |
| CONNMAN_SERVICE_STATE_CONFIGURATION); |
| |
| /* |
| * If this is the first time the WiFi network is ready after a |
| * resume, send the time from the resume event to the ready |
| * event. |
| */ |
| maybe_send_resume_to_ready(service); |
| |
| /* |
| * BSS channel (frequency); mapped to an enum. |
| */ |
| send_service_channel(service); |
| /* |
| * Description of the channel capabilities. |
| */ |
| send_service_phymode(service); |
| /* |
| * All services have a security type, but this is |
| * really only meaningful for WiFi. |
| */ |
| send_service_security(service); |
| } |
| |
| /* |
| * Subsequent connections without a resume should not report a |
| * TimeResumeToReady. |
| */ |
| clear_time_of_resume(); |
| |
| /* |
| * Time to config a network covers Layer 3 configuration |
| * work (typically acquiring a DHCP lease). |
| */ |
| send_state_delta(service, kMetricNetworkTimeToConfigName, |
| CONNMAN_SERVICE_STATE_CONFIGURATION, |
| CONNMAN_SERVICE_STATE_READY); |
| } |
| |
| static struct connman_notifier metrics_notifier = { |
| .name = "metrics", |
| .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT, |
| .default_changed = metrics_default_changed, |
| .service_state_changed = metrics_service_state_changed, |
| .system_suspend = metrics_system_suspend, |
| .system_resume = metrics_system_resume, |
| }; |
| |
| static int metrics_init(void) |
| { |
| if (connman_notifier_register(&metrics_notifier) < 0) { |
| connman_error("Failed to register metrics notifier"); |
| return -1; |
| } |
| lib = CMetricsLibraryNew(); /* NB: does not return NULL */ |
| CMetricsLibraryInit(lib); |
| clear_time_of_resume(); |
| return 0; |
| } |
| |
| static void metrics_finis(void) |
| { |
| CMetricsLibraryDelete(lib); |
| connman_notifier_unregister(&metrics_notifier); |
| } |
| |
| CONNMAN_PLUGIN_DEFINE(crosmetrics, "Chrome OS metrics plugin", VERSION, |
| CONNMAN_PLUGIN_PRIORITY_DEFAULT, metrics_init, metrics_finis) |