1/*
2 * Copyright (C) 2012 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
17package com.android.commands.monkey;
18
19import android.app.IActivityManager;
20import android.os.Environment;
21import android.util.Log;
22import android.view.IWindowManager;
23
24import java.lang.Process;
25import java.io.File;
26import java.io.FileWriter;
27import java.io.IOException;
28import java.io.BufferedReader;
29import java.io.InputStreamReader;
30import java.util.regex.Pattern;
31import java.util.regex.Matcher;
32
33/**
34 * Events for running a special shell command to capture the frame rate for a given app. To run
35 * this test, the system property viewancestor.profile_rendering must be set to
36 * true to force the currently focused window to render at 60 Hz.
37 */
38public class MonkeyGetAppFrameRateEvent extends MonkeyEvent {
39
40    private String GET_APP_FRAMERATE_TMPL = "dumpsys gfxinfo %s";
41    private String mStatus;
42    private static long sStartTime; // in millisecond
43    private static long sEndTime; // in millisecond
44    private static float sDuration; // in seconds
45    private static String sActivityName = null;
46    private static String sTestCaseName = null;
47    private static int sStartFrameNo;
48    private static int sEndFrameNo;
49
50    private static final String TAG = "MonkeyGetAppFrameRateEvent";
51    private static final String LOG_FILE = new File(Environment.getExternalStorageDirectory(),
52            "avgAppFrameRateOut.txt").getAbsolutePath();
53    private static final Pattern NO_OF_FRAMES_PATTERN =
54            Pattern.compile(".* ([0-9]*) frames rendered");
55
56    public MonkeyGetAppFrameRateEvent(String status, String activityName, String testCaseName) {
57        super(EVENT_TYPE_ACTIVITY);
58        mStatus = status;
59        sActivityName = activityName;
60        sTestCaseName = testCaseName;
61    }
62
63    public MonkeyGetAppFrameRateEvent(String status, String activityName) {
64        super(EVENT_TYPE_ACTIVITY);
65        mStatus = status;
66        sActivityName = activityName;
67    }
68
69    public MonkeyGetAppFrameRateEvent(String status) {
70        super(EVENT_TYPE_ACTIVITY);
71        mStatus = status;
72    }
73
74    // Calculate the average frame rate
75    private float getAverageFrameRate(int totalNumberOfFrame, float duration) {
76        float avgFrameRate = 0;
77        if (duration > 0) {
78            avgFrameRate = (totalNumberOfFrame / duration);
79        }
80        return avgFrameRate;
81    }
82
83    /**
84     * Calculate the frame rate and write the output to a file on the SD card.
85     */
86    private void writeAverageFrameRate() {
87        FileWriter writer = null;
88        float avgFrameRate;
89        int totalNumberOfFrame = 0;
90        try {
91            Log.w(TAG, "file: " +LOG_FILE);
92            writer = new FileWriter(LOG_FILE, true); // true = append
93            totalNumberOfFrame = sEndFrameNo - sStartFrameNo;
94            avgFrameRate = getAverageFrameRate(totalNumberOfFrame, sDuration);
95            writer.write(String.format("%s:%.2f\n", sTestCaseName, avgFrameRate));
96        } catch (IOException e) {
97            Log.w(TAG, "Can't write sdcard log file", e);
98        } finally {
99            try {
100                if (writer != null)
101                    writer.close();
102            } catch (IOException e) {
103                Log.e(TAG, "IOException " + e.toString());
104            }
105        }
106    }
107
108    // Parse the output of the dumpsys shell command call
109    private String getNumberOfFrames(BufferedReader reader) throws IOException {
110        String noOfFrames = null;
111        String line = null;
112        while((line = reader.readLine()) != null) {
113            Matcher m = NO_OF_FRAMES_PATTERN.matcher(line);
114            if (m.matches()) {
115                noOfFrames = m.group(1);
116                break;
117            }
118        }
119        return noOfFrames;
120    }
121
122    @Override
123    public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
124        Process p = null;
125        BufferedReader result = null;
126        String cmd = String.format(GET_APP_FRAMERATE_TMPL, sActivityName);
127        try {
128            p = Runtime.getRuntime().exec(cmd);
129            int status = p.waitFor();
130            if (status != 0) {
131                System.err.println(String.format("// Shell command %s status was %s",
132                        cmd, status));
133            }
134            result = new BufferedReader(new InputStreamReader(p.getInputStream()));
135
136            String output = getNumberOfFrames(result);
137
138            if (output != null) {
139                if ("start".equals(mStatus)) {
140                    sStartFrameNo = Integer.parseInt(output);
141                    sStartTime = System.currentTimeMillis();
142                } else if ("end".equals(mStatus)) {
143                    sEndFrameNo = Integer.parseInt(output);
144                    sEndTime = System.currentTimeMillis();
145                    long diff = sEndTime - sStartTime;
146                    sDuration = (float) (diff / 1000.0);
147                    writeAverageFrameRate();
148                }
149            }
150        } catch (Exception e) {
151            System.err.println("// Exception from " + cmd + ":");
152            System.err.println(e.toString());
153        } finally {
154            try {
155                if (result != null) {
156                    result.close();
157                }
158                if (p != null) {
159                    p.destroy();
160                }
161            } catch (IOException e) {
162                System.err.println(e.toString());
163            }
164        }
165        return MonkeyEvent.INJECT_SUCCESS;
166    }
167}
168