• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 com.android.benchmark.ui.automation;
18 
19 import android.annotation.TargetApi;
20 import android.os.Handler;
21 import android.os.HandlerThread;
22 import android.os.Message;
23 import android.os.SystemClock;
24 import android.view.FrameMetrics;
25 import android.view.Window;
26 
27 import java.lang.ref.WeakReference;
28 import java.util.LinkedList;
29 import java.util.List;
30 
31 /**
32  *
33  */
34 final class CollectorThread extends HandlerThread {
35     private FrameStatsCollector mCollector;
36     private Window mAttachedWindow;
37     private List<FrameMetrics> mFrameTimingStats;
38     private long mLastFrameTime;
39     private WatchdogHandler mWatchdog;
40     private WeakReference<CollectorListener> mListener;
41 
42     private volatile boolean mCollecting;
43 
44 
45     interface CollectorListener {
onCollectorThreadReady()46         void onCollectorThreadReady();
onPostInteraction(List<FrameMetrics> stats)47         void onPostInteraction(List<FrameMetrics> stats);
48     }
49 
50     private final class WatchdogHandler extends Handler {
51         private static final long SCHEDULE_INTERVAL_MILLIS = 20 * Automator.FRAME_PERIOD_MILLIS;
52 
53         private static final int MSG_SCHEDULE = 0;
54 
55         @Override
handleMessage(Message msg)56         public void handleMessage(Message msg) {
57             if (!mCollecting) {
58                 return;
59             }
60 
61             long currentTime = SystemClock.uptimeMillis();
62             if (mLastFrameTime + SCHEDULE_INTERVAL_MILLIS <= currentTime) {
63                 // haven't seen a frame in a while, interaction is probably done
64                 mCollecting = false;
65                 CollectorListener listener = mListener.get();
66                 if (listener != null) {
67                     listener.onPostInteraction(mFrameTimingStats);
68                 }
69             } else {
70                 schedule();
71             }
72         }
73 
schedule()74         public void schedule() {
75             sendMessageDelayed(obtainMessage(MSG_SCHEDULE), SCHEDULE_INTERVAL_MILLIS);
76         }
77 
deschedule()78         public void deschedule() {
79             removeMessages(MSG_SCHEDULE);
80         }
81     }
82 
83     static boolean tripleBuffered = false;
84     static int janks = 0;
85     static int total = 0;
86     @TargetApi(24)
87     private class FrameStatsCollector implements Window.OnFrameMetricsAvailableListener {
88         @Override
onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCount)89         public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCount) {
90             if (!mCollecting) {
91                 return;
92             }
93             mFrameTimingStats.add(new FrameMetrics(frameMetrics));
94             mLastFrameTime = SystemClock.uptimeMillis();
95         }
96     }
97 
CollectorThread(CollectorListener listener)98     public CollectorThread(CollectorListener listener) {
99         super("FrameStatsCollectorThread");
100         mFrameTimingStats = new LinkedList<>();
101         mListener = new WeakReference<>(listener);
102     }
103 
104     @TargetApi(24)
attachToWindow(Window window)105     public void attachToWindow(Window window) {
106         if (mAttachedWindow != null) {
107             mAttachedWindow.removeOnFrameMetricsAvailableListener(mCollector);
108         }
109 
110         mAttachedWindow = window;
111         window.addOnFrameMetricsAvailableListener(mCollector, new Handler(getLooper()));
112     }
113 
114     @TargetApi(24)
detachFromWindow()115     public synchronized void detachFromWindow() {
116         if (mAttachedWindow != null) {
117             mAttachedWindow.removeOnFrameMetricsAvailableListener(mCollector);
118         }
119 
120         mAttachedWindow = null;
121     }
122 
123     @TargetApi(24)
124     @Override
onLooperPrepared()125     protected void onLooperPrepared() {
126         super.onLooperPrepared();
127         mCollector = new FrameStatsCollector();
128         mWatchdog = new WatchdogHandler();
129 
130         CollectorListener listener = mListener.get();
131         if (listener != null) {
132             listener.onCollectorThreadReady();
133         }
134     }
135 
quitCollector()136     public boolean quitCollector() {
137         stopCollecting();
138         detachFromWindow();
139         System.out.println("Jank Percentage: " + (100 * janks/ (double) total) + "%");
140         tripleBuffered = false;
141         total = 0;
142         janks = 0;
143         return quit();
144     }
145 
stopCollecting()146     void stopCollecting() {
147         if (!mCollecting) {
148             return;
149         }
150 
151         mCollecting = false;
152         mWatchdog.deschedule();
153 
154 
155     }
156 
markInteractionStart()157     public void markInteractionStart() {
158         mLastFrameTime = 0;
159         mFrameTimingStats.clear();
160         mCollecting = true;
161 
162         mWatchdog.schedule();
163     }
164 }
165