ActivityMetricsLogger.java revision 8051c5c89060906f5a3a1ca4adb3b53bb423e56b
1package com.android.server.am; 2 3import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 4import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 5import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; 6import static android.app.ActivityManager.StackId.HOME_STACK_ID; 7import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 8import static com.android.server.am.ActivityStack.STACK_INVISIBLE; 9 10import android.annotation.Nullable; 11import android.app.ActivityManager.StackId; 12import android.content.Context; 13import android.os.SystemClock; 14 15import com.android.internal.logging.MetricsLogger; 16import com.android.internal.logging.MetricsProto.MetricsEvent; 17 18/** 19 * Handles logging into Tron. 20 */ 21class ActivityMetricsLogger { 22 // Window modes we are interested in logging. If we ever introduce a new type, we need to add 23 // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array. 24 private static final int WINDOW_STATE_STANDARD = 0; 25 private static final int WINDOW_STATE_SIDE_BY_SIDE = 1; 26 private static final int WINDOW_STATE_FREEFORM = 2; 27 private static final int WINDOW_STATE_INVALID = -1; 28 29 private static final long INVALID_START_TIME = -1; 30 31 // Preallocated strings we are sending to tron, so we don't have to allocate a new one every 32 // time we log. 33 private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = { 34 "window_time_0", "window_time_1", "window_time_2"}; 35 36 private int mWindowState = WINDOW_STATE_STANDARD; 37 private long mLastLogTimeSecs; 38 private final ActivityStackSupervisor mSupervisor; 39 private final Context mContext; 40 41 private long mCurrentTransitionStartTime = INVALID_START_TIME; 42 private boolean mLoggedWindowsDrawn; 43 private boolean mLoggedStartingWindowDrawn; 44 private boolean mLoggedTransitionStarting; 45 46 ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) { 47 mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000; 48 mSupervisor = supervisor; 49 mContext = context; 50 } 51 52 void logWindowState() { 53 final long now = SystemClock.elapsedRealtime() / 1000; 54 if (mWindowState != WINDOW_STATE_INVALID) { 55 // We log even if the window state hasn't changed, because the user might remain in 56 // home/fullscreen move forever and we would like to track this kind of behavior 57 // too. 58 MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState], 59 (int) (now - mLastLogTimeSecs)); 60 } 61 mLastLogTimeSecs = now; 62 63 ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID); 64 if (stack != null && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) { 65 mWindowState = WINDOW_STATE_SIDE_BY_SIDE; 66 return; 67 } 68 mWindowState = WINDOW_STATE_INVALID; 69 stack = mSupervisor.getFocusedStack(); 70 if (stack.mStackId == PINNED_STACK_ID) { 71 stack = mSupervisor.findStackBehind(stack); 72 } 73 if (stack.mStackId == HOME_STACK_ID 74 || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { 75 mWindowState = WINDOW_STATE_STANDARD; 76 } else if (stack.mStackId == DOCKED_STACK_ID) { 77 throw new IllegalStateException("Docked stack shouldn't be the focused stack, " 78 + "because it reported not being visible."); 79 } else if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { 80 mWindowState = WINDOW_STATE_FREEFORM; 81 } else if (StackId.isStaticStack(stack.mStackId)) { 82 throw new IllegalStateException("Unknown stack=" + stack); 83 } 84 } 85 86 /** 87 * Notifies the tracker at the earliest possible point when we are starting to launch an 88 * activity. 89 */ 90 void notifyActivityLaunching() { 91 mCurrentTransitionStartTime = System.currentTimeMillis(); 92 } 93 94 /** 95 * Notifies the tracker the the activity is actually launching. 96 * 97 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the 98 * launch 99 * @param componentName the component name of the activity being launched 100 * @param processRunning whether the process that will contains the activity is already running 101 */ 102 void notifyActivityLaunched(int resultCode, @Nullable String componentName, 103 boolean processRunning) { 104 105 if (resultCode < 0 || componentName == null) { 106 107 // Failed to launch, don't track anything. 108 reset(); 109 return; 110 } 111 112 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_COMPONENT_NAME, 113 componentName); 114 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_PROCESS_RUNNING, 115 processRunning); 116 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS, 117 (int) (SystemClock.uptimeMillis() / 1000)); 118 } 119 120 /** 121 * Notifies the tracker that all windows of the app have been drawn. 122 */ 123 void notifyWindowsDrawn() { 124 if (!isTransitionActive() || mLoggedWindowsDrawn) { 125 return; 126 } 127 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, 128 calculateCurrentDelay()); 129 mLoggedWindowsDrawn = true; 130 if (mLoggedTransitionStarting) { 131 reset(); 132 } 133 } 134 135 /** 136 * Notifies the tracker that the starting window was drawn. 137 */ 138 void notifyStartingWindowDrawn() { 139 if (!isTransitionActive() || mLoggedStartingWindowDrawn) { 140 return; 141 } 142 mLoggedStartingWindowDrawn = true; 143 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS, 144 calculateCurrentDelay()); 145 } 146 147 /** 148 * Notifies the tracker that the app transition is starting. 149 * 150 * @param reason The reason why we started it. Must be on of 151 * ActivityManagerInternal.APP_TRANSITION_* reasons. 152 */ 153 void notifyTransitionStarting(int reason) { 154 if (!isTransitionActive() || mLoggedTransitionStarting) { 155 return; 156 } 157 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_REASON, reason); 158 MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DELAY_MS, 159 calculateCurrentDelay()); 160 mLoggedTransitionStarting = true; 161 if (mLoggedWindowsDrawn) { 162 reset(); 163 } 164 } 165 166 private boolean isTransitionActive() { 167 return mCurrentTransitionStartTime != INVALID_START_TIME; 168 } 169 170 private void reset() { 171 mCurrentTransitionStartTime = INVALID_START_TIME; 172 mLoggedWindowsDrawn = false; 173 mLoggedTransitionStarting = false; 174 mLoggedStartingWindowDrawn = false; 175 } 176 177 private int calculateCurrentDelay() { 178 179 // Shouldn't take more than 25 days to launch an app, so int is fine here. 180 return (int) (System.currentTimeMillis() - mCurrentTransitionStartTime); 181 } 182} 183