blob: 29ced3eda4ec254874e06fe89ef205fe4dabc25f [file] [log] [blame]
David Chen0a368b22017-12-06 16:28:16 -08001/*
2 * Copyright (C) 2017 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 */
16
17package android.util;
18
Chenjie Yu6b1667c2019-01-18 10:09:33 -080019import static android.Manifest.permission.DUMP;
20import static android.Manifest.permission.PACKAGE_USAGE_STATS;
21
22import android.Manifest;
Philip P. Moltmanne0cf4e62019-01-29 14:22:48 -080023import android.annotation.NonNull;
Chenjie Yu6b1667c2019-01-18 10:09:33 -080024import android.annotation.RequiresPermission;
25import android.app.IActivityManager;
26import android.content.Context;
yrobe6d7f92018-05-04 13:02:53 -070027import android.os.IStatsManager;
28import android.os.RemoteException;
29import android.os.ServiceManager;
Chenjie Yu33a61412018-03-14 22:28:47 -070030
David Chen0a368b22017-12-06 16:28:16 -080031/**
32 * StatsLog provides an API for developers to send events to statsd. The events can be used to
David Chenc1a3a0d2018-02-21 18:58:23 -080033 * define custom metrics inside statsd.
David Chen0a368b22017-12-06 16:28:16 -080034 */
35public final class StatsLog extends StatsLogInternal {
yrobe6d7f92018-05-04 13:02:53 -070036 private static final String TAG = "StatsLog";
37 private static final boolean DEBUG = false;
38
39 private static IStatsManager sService;
David Chen0a368b22017-12-06 16:28:16 -080040
Chenjie Yu6b1667c2019-01-18 10:09:33 -080041 private static Object sLogLock = new Object();
42
43 private StatsLog() {
44 }
David Chen0a368b22017-12-06 16:28:16 -080045
46 /**
47 * Logs a start event.
48 *
yrobe6d7f92018-05-04 13:02:53 -070049 * @param label developer-chosen label.
David Chen0a368b22017-12-06 16:28:16 -080050 * @return True if the log request was sent to statsd.
51 */
52 public static boolean logStart(int label) {
Chenjie Yu6b1667c2019-01-18 10:09:33 -080053 synchronized (sLogLock) {
yrobe6d7f92018-05-04 13:02:53 -070054 try {
55 IStatsManager service = getIStatsManagerLocked();
56 if (service == null) {
Chenjie Yu6b1667c2019-01-18 10:09:33 -080057 if (DEBUG) {
58 Slog.d(TAG, "Failed to find statsd when logging start");
59 }
yrobe6d7f92018-05-04 13:02:53 -070060 return false;
61 }
62 service.sendAppBreadcrumbAtom(label,
63 StatsLog.APP_BREADCRUMB_REPORTED__STATE__START);
64 return true;
65 } catch (RemoteException e) {
66 sService = null;
Chenjie Yu6b1667c2019-01-18 10:09:33 -080067 if (DEBUG) {
68 Slog.d(TAG, "Failed to connect to statsd when logging start");
69 }
yrobe6d7f92018-05-04 13:02:53 -070070 return false;
71 }
David Chen0a368b22017-12-06 16:28:16 -080072 }
David Chen0a368b22017-12-06 16:28:16 -080073 }
74
75 /**
76 * Logs a stop event.
77 *
yrobe6d7f92018-05-04 13:02:53 -070078 * @param label developer-chosen label.
David Chen0a368b22017-12-06 16:28:16 -080079 * @return True if the log request was sent to statsd.
80 */
81 public static boolean logStop(int label) {
Chenjie Yu6b1667c2019-01-18 10:09:33 -080082 synchronized (sLogLock) {
yrobe6d7f92018-05-04 13:02:53 -070083 try {
84 IStatsManager service = getIStatsManagerLocked();
85 if (service == null) {
Chenjie Yu6b1667c2019-01-18 10:09:33 -080086 if (DEBUG) {
87 Slog.d(TAG, "Failed to find statsd when logging stop");
88 }
yrobe6d7f92018-05-04 13:02:53 -070089 return false;
90 }
91 service.sendAppBreadcrumbAtom(label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP);
92 return true;
93 } catch (RemoteException e) {
94 sService = null;
Chenjie Yu6b1667c2019-01-18 10:09:33 -080095 if (DEBUG) {
96 Slog.d(TAG, "Failed to connect to statsd when logging stop");
97 }
yrobe6d7f92018-05-04 13:02:53 -070098 return false;
99 }
David Chen0a368b22017-12-06 16:28:16 -0800100 }
David Chen0a368b22017-12-06 16:28:16 -0800101 }
102
103 /**
104 * Logs an event that does not represent a start or stop boundary.
105 *
yrobe6d7f92018-05-04 13:02:53 -0700106 * @param label developer-chosen label.
David Chen0a368b22017-12-06 16:28:16 -0800107 * @return True if the log request was sent to statsd.
108 */
109 public static boolean logEvent(int label) {
Chenjie Yu6b1667c2019-01-18 10:09:33 -0800110 synchronized (sLogLock) {
yrobe6d7f92018-05-04 13:02:53 -0700111 try {
112 IStatsManager service = getIStatsManagerLocked();
113 if (service == null) {
Chenjie Yu6b1667c2019-01-18 10:09:33 -0800114 if (DEBUG) {
115 Slog.d(TAG, "Failed to find statsd when logging event");
116 }
yrobe6d7f92018-05-04 13:02:53 -0700117 return false;
118 }
119 service.sendAppBreadcrumbAtom(
120 label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
121 return true;
122 } catch (RemoteException e) {
123 sService = null;
Chenjie Yu6b1667c2019-01-18 10:09:33 -0800124 if (DEBUG) {
125 Slog.d(TAG, "Failed to connect to statsd when logging event");
126 }
127 return false;
128 }
129 }
130 }
131
132 /**
133 * Logs an event for binary push for module updates.
134 *
135 * @param trainName name of install train.
136 * @param trainVersionCode version code of the train.
137 * @param options optional flags about this install.
138 * @param state current install state.
139 * @param experimentIds experiment ids.
140 * @return True if the log request was sent to statsd.
141 */
142 @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
143 public static boolean logBinaryPushStateChanged(@NonNull String trainName,
144 long trainVersionCode, int options, int state,
145 @NonNull long[] experimentIds) {
146 synchronized (sLogLock) {
147 try {
148 IStatsManager service = getIStatsManagerLocked();
149 if (service == null) {
150 if (DEBUG) {
151 Slog.d(TAG, "Failed to find statsd when logging event");
152 }
153 return false;
154 }
155 int userId = IActivityManager.Stub.asInterface(
156 ServiceManager.getService("activity"))
157 .getCurrentUser()
158 .id;
159 service.sendBinaryPushStateChangedAtom(
160 trainName, trainVersionCode, options, state, experimentIds);
161 return true;
162 } catch (RemoteException e) {
163 sService = null;
164 if (DEBUG) {
165 Slog.d(TAG,
166 "Failed to connect to StatsCompanionService when logging "
167 + "BinaryPushStateChanged");
168 }
yrobe6d7f92018-05-04 13:02:53 -0700169 return false;
170 }
David Chen0a368b22017-12-06 16:28:16 -0800171 }
yrobe6d7f92018-05-04 13:02:53 -0700172 }
173
174 private static IStatsManager getIStatsManagerLocked() throws RemoteException {
175 if (sService != null) {
176 return sService;
177 }
178 sService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
179 return sService;
David Chen0a368b22017-12-06 16:28:16 -0800180 }
Philip P. Moltmanne0cf4e62019-01-29 14:22:48 -0800181
182 /**
183 * Add a log to the stats log.
184 *
Chenjie Yu6b1667c2019-01-18 10:09:33 -0800185 * @param id The id of the atom
Philip P. Moltmanne0cf4e62019-01-29 14:22:48 -0800186 * @param params The parameters of the atom's message.
187 */
188 public static void write(int id, @NonNull Object... params) {
189 switch (id) {
190 case PERMISSION_GRANT_REQUEST_RESULT_REPORTED:
191 write(id, (long) params[0], (int) params[1], (String) params[2], (String) params[3],
192 (boolean) params[4], (int) params[5]);
193 }
194 }
Chenjie Yu6b1667c2019-01-18 10:09:33 -0800195
196 private static void enforceDumpCallingPermission(Context context) {
197 context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
198 }
199
200 private static void enforcesageStatsCallingPermission(Context context) {
201 context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
202 "Need PACKAGE_USAGE_STATS permission.");
203 }
David Chen0a368b22017-12-06 16:28:16 -0800204}