ConnectivityMetricsLogger.java revision dc5a63bdd153f32d68962bc8271079295b41e1ee
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.net; 17 18import android.annotation.SystemApi; 19import android.app.PendingIntent; 20import android.os.Bundle; 21import android.os.Parcelable; 22import android.os.RemoteException; 23import android.os.ServiceManager; 24import android.util.Log; 25 26import com.android.internal.annotations.VisibleForTesting; 27 28/** {@hide} */ 29@SystemApi 30public class ConnectivityMetricsLogger { 31 private static String TAG = "ConnectivityMetricsLogger"; 32 private static final boolean DBG = true; 33 34 public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger"; 35 36 // Component Tags 37 public static final int COMPONENT_TAG_CONNECTIVITY = 0; 38 public static final int COMPONENT_TAG_BLUETOOTH = 1; 39 public static final int COMPONENT_TAG_WIFI = 2; 40 public static final int COMPONENT_TAG_TELECOM = 3; 41 public static final int COMPONENT_TAG_TELEPHONY = 4; 42 public static final int NUMBER_OF_COMPONENTS = 5; 43 44 // Event Tag 45 public static final int TAG_SKIPPED_EVENTS = -1; 46 47 public static final String DATA_KEY_EVENTS_COUNT = "count"; 48 49 /** {@hide} */ protected final IConnectivityMetricsLogger mService; 50 /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis; 51 private int mNumSkippedEvents; 52 53 public ConnectivityMetricsLogger() { 54 this(IConnectivityMetricsLogger.Stub.asInterface( 55 ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE))); 56 } 57 58 /** {@hide} */ 59 @VisibleForTesting 60 public ConnectivityMetricsLogger(IConnectivityMetricsLogger service) { 61 mService = service; 62 } 63 64 /** 65 * Log a ConnectivityMetricsEvent. 66 * 67 * This method keeps track of skipped events when MetricsLoggerService throttles input events. 68 * It skips logging when MetricsLoggerService is active. When throttling ends, it logs a 69 * meta-event containing the number of events dropped. It is not safe to call this method 70 * concurrently from different threads. 71 * 72 * @param timestamp is the epoch timestamp of the event in ms. 73 * @param componentTag is the COMPONENT_* constant the event belongs to. 74 * @param eventTag is an event type constant whose meaning is specific to the component tag. 75 * @param data is a Parcelable instance representing the event. 76 */ 77 public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) { 78 if (mService == null) { 79 if (DBG) { 80 Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready"); 81 } 82 return; 83 } 84 85 if (mServiceUnblockedTimestampMillis > 0) { 86 if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) { 87 // Service is throttling events. 88 // Don't send new events because they will be dropped. 89 mNumSkippedEvents++; 90 return; 91 } 92 } 93 94 ConnectivityMetricsEvent skippedEventsEvent = null; 95 if (mNumSkippedEvents > 0) { 96 // Log number of skipped events 97 Bundle b = new Bundle(); 98 b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents); 99 100 // Log the skipped event. 101 // TODO: Note that some of the clients push all states events into the server, 102 // If we lose some states logged here, we might mess up the statistics happened at the 103 // backend. One of the options is to introduce a non-skippable flag for important events 104 // that are logged. 105 skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis, 106 componentTag, TAG_SKIPPED_EVENTS, b); 107 108 mServiceUnblockedTimestampMillis = 0; 109 } 110 111 ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag, 112 eventTag, data); 113 114 try { 115 long result; 116 if (skippedEventsEvent == null) { 117 result = mService.logEvent(event); 118 } else { 119 result = mService.logEvents(new ConnectivityMetricsEvent[] 120 {skippedEventsEvent, event}); 121 } 122 123 if (result == 0) { 124 mNumSkippedEvents = 0; 125 } else { 126 mNumSkippedEvents++; 127 if (result > 0) { // events are throttled 128 mServiceUnblockedTimestampMillis = result; 129 } 130 } 131 } catch (RemoteException e) { 132 Log.e(TAG, "Error logging event", e); 133 } 134 } 135 136 /** 137 * Retrieve events 138 * 139 * @param reference of the last event previously returned. The function will return 140 * events following it. 141 * If 0 then all events will be returned. 142 * After the function call it will contain reference of the 143 * last returned event. 144 * @return events 145 */ 146 public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) { 147 try { 148 return mService.getEvents(reference); 149 } catch (RemoteException e) { 150 Log.e(TAG, "IConnectivityMetricsLogger.getEvents", e); 151 return null; 152 } 153 } 154 155 /** 156 * Register PendingIntent which will be sent when new events are ready to be retrieved. 157 */ 158 public boolean register(PendingIntent newEventsIntent) { 159 try { 160 return mService.register(newEventsIntent); 161 } catch (RemoteException e) { 162 Log.e(TAG, "IConnectivityMetricsLogger.register", e); 163 return false; 164 } 165 } 166 167 public boolean unregister(PendingIntent newEventsIntent) { 168 try { 169 mService.unregister(newEventsIntent); 170 return true; 171 } catch (RemoteException e) { 172 Log.e(TAG, "IConnectivityMetricsLogger.unregister", e); 173 return false; 174 } 175 } 176} 177