• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.util;
18 
19 import static android.Manifest.permission.DUMP;
20 import static android.Manifest.permission.PACKAGE_USAGE_STATS;
21 
22 import android.Manifest;
23 import android.annotation.NonNull;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.content.Context;
27 import android.os.IStatsManager;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 
31 /**
32  * StatsLog provides an API for developers to send events to statsd. The events can be used to
33  * define custom metrics inside statsd.
34  */
35 public final class StatsLog extends StatsLogInternal {
36     private static final String TAG = "StatsLog";
37     private static final boolean DEBUG = false;
38 
39     private static IStatsManager sService;
40 
41     private static Object sLogLock = new Object();
42 
StatsLog()43     private StatsLog() {
44     }
45 
46     /**
47      * Logs a start event.
48      *
49      * @param label developer-chosen label.
50      * @return True if the log request was sent to statsd.
51      */
logStart(int label)52     public static boolean logStart(int label) {
53         synchronized (sLogLock) {
54             try {
55                 IStatsManager service = getIStatsManagerLocked();
56                 if (service == null) {
57                     if (DEBUG) {
58                         Slog.d(TAG, "Failed to find statsd when logging start");
59                     }
60                     return false;
61                 }
62                 service.sendAppBreadcrumbAtom(label,
63                         StatsLog.APP_BREADCRUMB_REPORTED__STATE__START);
64                 return true;
65             } catch (RemoteException e) {
66                 sService = null;
67                 if (DEBUG) {
68                     Slog.d(TAG, "Failed to connect to statsd when logging start");
69                 }
70                 return false;
71             }
72         }
73     }
74 
75     /**
76      * Logs a stop event.
77      *
78      * @param label developer-chosen label.
79      * @return True if the log request was sent to statsd.
80      */
logStop(int label)81     public static boolean logStop(int label) {
82         synchronized (sLogLock) {
83             try {
84                 IStatsManager service = getIStatsManagerLocked();
85                 if (service == null) {
86                     if (DEBUG) {
87                         Slog.d(TAG, "Failed to find statsd when logging stop");
88                     }
89                     return false;
90                 }
91                 service.sendAppBreadcrumbAtom(label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP);
92                 return true;
93             } catch (RemoteException e) {
94                 sService = null;
95                 if (DEBUG) {
96                     Slog.d(TAG, "Failed to connect to statsd when logging stop");
97                 }
98                 return false;
99             }
100         }
101     }
102 
103     /**
104      * Logs an event that does not represent a start or stop boundary.
105      *
106      * @param label developer-chosen label.
107      * @return True if the log request was sent to statsd.
108      */
logEvent(int label)109     public static boolean logEvent(int label) {
110         synchronized (sLogLock) {
111             try {
112                 IStatsManager service = getIStatsManagerLocked();
113                 if (service == null) {
114                     if (DEBUG) {
115                         Slog.d(TAG, "Failed to find statsd when logging event");
116                     }
117                     return false;
118                 }
119                 service.sendAppBreadcrumbAtom(
120                         label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
121                 return true;
122             } catch (RemoteException e) {
123                 sService = null;
124                 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      *                         The last 3 bits indicate options:
139      *                             0x01: FLAG_REQUIRE_STAGING
140      *                             0x02: FLAG_ROLLBACK_ENABLED
141      *                             0x04: FLAG_REQUIRE_LOW_LATENCY_MONITOR
142      * @param state            current install state. Defined as State enums in
143      *                         BinaryPushStateChanged atom in
144      *                         frameworks/base/cmds/statsd/src/atoms.proto
145      * @param experimentIds    experiment ids.
146      * @return True if the log request was sent to statsd.
147      */
148     @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
logBinaryPushStateChanged(@onNull String trainName, long trainVersionCode, int options, int state, @NonNull long[] experimentIds)149     public static boolean logBinaryPushStateChanged(@NonNull String trainName,
150             long trainVersionCode, int options, int state,
151             @NonNull long[] experimentIds) {
152         synchronized (sLogLock) {
153             try {
154                 IStatsManager service = getIStatsManagerLocked();
155                 if (service == null) {
156                     if (DEBUG) {
157                         Slog.d(TAG, "Failed to find statsd when logging event");
158                     }
159                     return false;
160                 }
161                 service.sendBinaryPushStateChangedAtom(
162                         trainName, trainVersionCode, options, state, experimentIds);
163                 return true;
164             } catch (RemoteException e) {
165                 sService = null;
166                 if (DEBUG) {
167                     Slog.d(TAG,
168                             "Failed to connect to StatsCompanionService when logging "
169                                     + "BinaryPushStateChanged");
170                 }
171                 return false;
172             }
173         }
174     }
175 
176     /**
177      * Logs an event for watchdog rollbacks.
178      *
179      * @param rollbackType          state of the rollback.
180      * @param packageName           package name being rolled back.
181      * @param packageVersionCode    version of the package being rolled back.
182      *
183      * @return True if the log request was sent to statsd.
184      *
185      * @hide
186      */
187     @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
logWatchdogRollbackOccurred(int rollbackType, String packageName, long packageVersionCode)188     public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName,
189             long packageVersionCode) {
190         synchronized (sLogLock) {
191             try {
192                 IStatsManager service = getIStatsManagerLocked();
193                 if (service == null) {
194                     if (DEBUG) {
195                         Slog.d(TAG, "Failed to find statsd when logging event");
196                     }
197                     return false;
198                 }
199 
200                 service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName,
201                         packageVersionCode);
202                 return true;
203             } catch (RemoteException e) {
204                 sService = null;
205                 if (DEBUG) {
206                     Slog.d(TAG,
207                             "Failed to connect to StatsCompanionService when logging "
208                                     + "WatchdogRollbackOccurred");
209                 }
210                 return false;
211             }
212         }
213     }
214 
215 
getIStatsManagerLocked()216     private static IStatsManager getIStatsManagerLocked() throws RemoteException {
217         if (sService != null) {
218             return sService;
219         }
220         sService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
221         return sService;
222     }
223 
224     /**
225      * Write an event to stats log using the raw format.
226      *
227      * @param buffer    The encoded buffer of data to write..
228      * @param size      The number of bytes from the buffer to write.
229      * @hide
230      */
231     @SystemApi
writeRaw(@onNull byte[] buffer, int size)232     public static native void writeRaw(@NonNull byte[] buffer, int size);
233 
enforceDumpCallingPermission(Context context)234     private static void enforceDumpCallingPermission(Context context) {
235         context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
236     }
237 
enforcesageStatsCallingPermission(Context context)238     private static void enforcesageStatsCallingPermission(Context context) {
239         context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
240                 "Need PACKAGE_USAGE_STATS permission.");
241     }
242 }
243