Home | History | Annotate | Download | only in automation
      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 {
     46         void onCollectorThreadReady();
     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
     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 
     74         public void schedule() {
     75             sendMessageDelayed(obtainMessage(MSG_SCHEDULE), SCHEDULE_INTERVAL_MILLIS);
     76         }
     77 
     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
     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 
     98     public CollectorThread(CollectorListener listener) {
     99         super("FrameStatsCollectorThread");
    100         mFrameTimingStats = new LinkedList<>();
    101         mListener = new WeakReference<>(listener);
    102     }
    103 
    104     @TargetApi(24)
    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)
    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
    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 
    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 
    146     void stopCollecting() {
    147         if (!mCollecting) {
    148             return;
    149         }
    150 
    151         mCollecting = false;
    152         mWatchdog.deschedule();
    153 
    154 
    155     }
    156 
    157     public void markInteractionStart() {
    158         mLastFrameTime = 0;
    159         mFrameTimingStats.clear();
    160         mCollecting = true;
    161 
    162         mWatchdog.schedule();
    163     }
    164 }
    165