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.IStatsd; 28 import android.os.Process; 29 import android.util.proto.ProtoOutputStream; 30 31 import com.android.internal.statsd.StatsdStatsLog; 32 33 /** 34 * StatsLog provides an API for developers to send events to statsd. The events can be used to 35 * define custom metrics inside statsd. 36 */ 37 public final class StatsLog { 38 39 // Load JNI library 40 static { 41 System.loadLibrary("stats_jni"); 42 } 43 private static final String TAG = "StatsLog"; 44 private static final boolean DEBUG = false; 45 private static final int EXPERIMENT_IDS_FIELD_ID = 1; 46 StatsLog()47 private StatsLog() { 48 } 49 50 /** 51 * Logs a start event. 52 * 53 * @param label developer-chosen label. 54 * @return True if the log request was sent to statsd. 55 */ logStart(int label)56 public static boolean logStart(int label) { 57 int callingUid = Process.myUid(); 58 StatsdStatsLog.write( 59 StatsdStatsLog.APP_BREADCRUMB_REPORTED, 60 callingUid, 61 label, 62 StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__START); 63 return true; 64 } 65 66 /** 67 * Logs a stop event. 68 * 69 * @param label developer-chosen label. 70 * @return True if the log request was sent to statsd. 71 */ logStop(int label)72 public static boolean logStop(int label) { 73 int callingUid = Process.myUid(); 74 StatsdStatsLog.write( 75 StatsdStatsLog.APP_BREADCRUMB_REPORTED, 76 callingUid, 77 label, 78 StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP); 79 return true; 80 } 81 82 /** 83 * Logs an event that does not represent a start or stop boundary. 84 * 85 * @param label developer-chosen label. 86 * @return True if the log request was sent to statsd. 87 */ logEvent(int label)88 public static boolean logEvent(int label) { 89 int callingUid = Process.myUid(); 90 StatsdStatsLog.write( 91 StatsdStatsLog.APP_BREADCRUMB_REPORTED, 92 callingUid, 93 label, 94 StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED); 95 return true; 96 } 97 98 /** 99 * Logs an event for binary push for module updates. 100 * 101 * @param trainName name of install train. 102 * @param trainVersionCode version code of the train. 103 * @param options optional flags about this install. 104 * The last 3 bits indicate options: 105 * 0x01: FLAG_REQUIRE_STAGING 106 * 0x02: FLAG_ROLLBACK_ENABLED 107 * 0x04: FLAG_REQUIRE_LOW_LATENCY_MONITOR 108 * @param state current install state. Defined as State enums in 109 * BinaryPushStateChanged atom in 110 * frameworks/base/cmds/statsd/src/atoms.proto 111 * @param experimentIds experiment ids. 112 * @return True if the log request was sent to statsd. 113 */ 114 @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS}) logBinaryPushStateChanged(@onNull String trainName, long trainVersionCode, int options, int state, @NonNull long[] experimentIds)115 public static boolean logBinaryPushStateChanged(@NonNull String trainName, 116 long trainVersionCode, int options, int state, 117 @NonNull long[] experimentIds) { 118 ProtoOutputStream proto = new ProtoOutputStream(); 119 for (long id : experimentIds) { 120 proto.write( 121 ProtoOutputStream.FIELD_TYPE_INT64 122 | ProtoOutputStream.FIELD_COUNT_REPEATED 123 | EXPERIMENT_IDS_FIELD_ID, 124 id); 125 } 126 StatsdStatsLog.write(StatsdStatsLog.BINARY_PUSH_STATE_CHANGED, 127 trainName, 128 trainVersionCode, 129 (options & IStatsd.FLAG_REQUIRE_STAGING) > 0, 130 (options & IStatsd.FLAG_ROLLBACK_ENABLED) > 0, 131 (options & IStatsd.FLAG_REQUIRE_LOW_LATENCY_MONITOR) > 0, 132 state, 133 proto.getBytes(), 134 0, 135 0, 136 false); 137 return true; 138 } 139 140 /** 141 * Write an event to stats log using the raw format. 142 * 143 * @param buffer The encoded buffer of data to write. 144 * @param size The number of bytes from the buffer to write. 145 * @hide 146 */ 147 // TODO(b/144935988): Mark deprecated. 148 @SystemApi writeRaw(@onNull byte[] buffer, int size)149 public static void writeRaw(@NonNull byte[] buffer, int size) { 150 // TODO(b/144935988): make this no-op once clients have migrated to StatsEvent. 151 writeImpl(buffer, size, 0); 152 } 153 154 /** 155 * Write an event to stats log using the raw format. 156 * 157 * @param buffer The encoded buffer of data to write. 158 * @param size The number of bytes from the buffer to write. 159 * @param atomId The id of the atom to which the event belongs. 160 */ writeImpl(@onNull byte[] buffer, int size, int atomId)161 private static native void writeImpl(@NonNull byte[] buffer, int size, int atomId); 162 163 /** 164 * Write an event to stats log using the raw format encapsulated in StatsEvent. 165 * After writing to stats log, release() is called on the StatsEvent object. 166 * No further action should be taken on the StatsEvent object following this call. 167 * 168 * @param statsEvent The StatsEvent object containing the encoded buffer of data to write. 169 * @hide 170 */ 171 @SystemApi write(@onNull final StatsEvent statsEvent)172 public static void write(@NonNull final StatsEvent statsEvent) { 173 writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId()); 174 statsEvent.release(); 175 } 176 enforceDumpCallingPermission(Context context)177 private static void enforceDumpCallingPermission(Context context) { 178 context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission."); 179 } 180 enforcesageStatsCallingPermission(Context context)181 private static void enforcesageStatsCallingPermission(Context context) { 182 context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, 183 "Need PACKAGE_USAGE_STATS permission."); 184 } 185 } 186