ConnectivityMetricsLogger.java revision 623ab7d7a6a7d948fa6338a3992b2680d0192427
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
26/** {@hide} */
27@SystemApi
28public class ConnectivityMetricsLogger {
29    private static String TAG = "ConnectivityMetricsLogger";
30    private static final boolean DBG = true;
31
32    public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
33
34    // Component Tags
35    public static final int COMPONENT_TAG_CONNECTIVITY = 0;
36    public static final int COMPONENT_TAG_BLUETOOTH    = 1;
37    public static final int COMPONENT_TAG_WIFI         = 2;
38    public static final int COMPONENT_TAG_TELECOM      = 3;
39    public static final int COMPONENT_TAG_TELEPHONY    = 4;
40    public static final int NUMBER_OF_COMPONENTS       = 5;
41
42    // Event Tag
43    public static final int TAG_SKIPPED_EVENTS = -1;
44
45    public static final String DATA_KEY_EVENTS_COUNT = "count";
46
47    /** {@hide} */ protected final IConnectivityMetricsLogger mService;
48    /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis;
49    private int mNumSkippedEvents;
50
51    public ConnectivityMetricsLogger() {
52        mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
53                CONNECTIVITY_METRICS_LOGGER_SERVICE));
54    }
55
56    /**
57     * Log a ConnectivityMetricsEvent.
58     *
59     * This method keeps track of skipped events when MetricsLoggerService throttles input events.
60     * It skips logging when MetricsLoggerService is active. When throttling ends, it logs a
61     * meta-event containing the number of events dropped. It is not safe to call this method
62     * concurrently from different threads.
63     *
64     * @param timestamp is the epoch timestamp of the event in ms.
65     * @param componentTag is the COMPONENT_* constant the event belongs to.
66     * @param eventTag is an event type constant whose meaning is specific to the component tag.
67     * @param data is a Parcelable instance representing the event.
68     */
69    public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
70        if (mService == null) {
71            if (DBG) {
72                Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
73            }
74            return;
75        }
76
77        if (mServiceUnblockedTimestampMillis > 0) {
78            if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
79                // Service is throttling events.
80                // Don't send new events because they will be dropped.
81                mNumSkippedEvents++;
82                return;
83            }
84        }
85
86        ConnectivityMetricsEvent skippedEventsEvent = null;
87        if (mNumSkippedEvents > 0) {
88            // Log number of skipped events
89            Bundle b = new Bundle();
90            b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
91            skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
92                    componentTag, TAG_SKIPPED_EVENTS, b);
93
94            mServiceUnblockedTimestampMillis = 0;
95        }
96
97        ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
98                eventTag, data);
99
100        try {
101            long result;
102            if (skippedEventsEvent == null) {
103                result = mService.logEvent(event);
104            } else {
105                result = mService.logEvents(new ConnectivityMetricsEvent[]
106                        {skippedEventsEvent, event});
107            }
108
109            if (result == 0) {
110                mNumSkippedEvents = 0;
111            } else {
112                mNumSkippedEvents++;
113                if (result > 0) { // events are throttled
114                    mServiceUnblockedTimestampMillis = result;
115                }
116            }
117        } catch (RemoteException e) {
118            Log.e(TAG, "Error logging event", e);
119        }
120    }
121
122    /**
123     * Retrieve events
124     *
125     * @param reference of the last event previously returned. The function will return
126     *                  events following it.
127     *                  If 0 then all events will be returned.
128     *                  After the function call it will contain reference of the
129     *                  last returned event.
130     * @return events
131     */
132    public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
133        try {
134            return mService.getEvents(reference);
135        } catch (RemoteException e) {
136            Log.e(TAG, "IConnectivityMetricsLogger.getEvents", e);
137            return null;
138        }
139    }
140
141    /**
142     * Register PendingIntent which will be sent when new events are ready to be retrieved.
143     */
144    public boolean register(PendingIntent newEventsIntent) {
145        try {
146            return mService.register(newEventsIntent);
147        } catch (RemoteException e) {
148            Log.e(TAG, "IConnectivityMetricsLogger.register", e);
149            return false;
150        }
151    }
152
153    public boolean unregister(PendingIntent newEventsIntent) {
154        try {
155            mService.unregister(newEventsIntent);
156        } catch (RemoteException e) {
157            Log.e(TAG, "IConnectivityMetricsLogger.unregister", e);
158            return false;
159        }
160
161        return true;
162    }
163}
164