Home | History | Annotate | Download | only in util
      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 
     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      */
     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      */
     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      */
    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})
    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})
    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 
    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
    232     public static native void writeRaw(@NonNull byte[] buffer, int size);
    233 
    234     private static void enforceDumpCallingPermission(Context context) {
    235         context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
    236     }
    237 
    238     private static void enforcesageStatsCallingPermission(Context context) {
    239         context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
    240                 "Need PACKAGE_USAGE_STATS permission.");
    241     }
    242 }
    243