PerfData.java revision bc7a04b88db83b6bb91c2c50a4cd8b6bafabac06
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 */
16package com.android.statsd.loadtest;
17
18import android.annotation.Nullable;
19import android.app.Activity;
20import android.app.AlarmManager;
21import android.app.PendingIntent;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.os.Bundle;
26import android.os.Environment;
27import android.util.Log;
28import android.os.Debug;
29
30import java.io.BufferedReader;
31import java.io.Closeable;
32import java.io.File;
33import java.io.FileInputStream;
34import java.io.FileOutputStream;
35import java.io.FileWriter;
36import java.io.InputStream;
37import java.io.InputStreamReader;
38import java.io.IOException;
39import java.text.SimpleDateFormat;
40import java.util.Date;
41
42/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
43public class PerfData {
44
45    private static final String TAG = "PerfData";
46    private static final String DUMP_FILENAME = TAG + "_dump.tmp";
47
48    public void resetData(Context context) {
49        runDumpsysStats(context, "batterystats", "--reset");
50    }
51
52    public void publishData(Context context, boolean placebo, int replication, long bucketMins,
53        long periodSecs, int burst) {
54        publishBatteryData(context, placebo, replication, bucketMins, periodSecs, burst);
55    }
56
57    private void publishBatteryData(Context context, boolean placebo, int replication,
58        long bucketMins, long periodSecs, int burst) {
59        // Don't use --checkin.
60        runDumpsysStats(context, "batterystats");
61        writeBatteryData(context, placebo, replication, bucketMins, periodSecs, burst);
62    }
63
64    private void runDumpsysStats(Context context, String cmd, String... args) {
65        boolean success = false;
66        // Call dumpsys Dump statistics to a file.
67        FileOutputStream fo = null;
68        try {
69            fo = context.openFileOutput(DUMP_FILENAME, Context.MODE_PRIVATE);
70            if (!Debug.dumpService(cmd, fo.getFD(), args)) {
71                Log.w(TAG, "Dumpsys failed.");
72            }
73            success = true;
74        } catch (IOException | SecurityException | NullPointerException e) {
75            // SecurityException may occur when trying to dump multi-user info.
76            // NPE can occur during dumpService  (root cause unknown).
77            throw new RuntimeException(e);
78        } finally {
79            closeQuietly(fo);
80        }
81    }
82
83    private String readDumpFile(Context context) {
84        StringBuilder sb = new StringBuilder();
85        FileInputStream fi = null;
86        BufferedReader br = null;
87        try {
88            fi = context.openFileInput(DUMP_FILENAME);
89            br = new BufferedReader(new InputStreamReader(fi));
90            String line = br.readLine();
91            while (line != null) {
92                sb.append(line);
93                sb.append(System.lineSeparator());
94                line = br.readLine();
95            }
96        } catch (IOException e) {
97            throw new RuntimeException(e);
98        } finally {
99            closeQuietly(br);
100        }
101        return sb.toString();
102    }
103
104    private static void closeQuietly(@Nullable Closeable c) {
105        if (c != null) {
106            try {
107                c.close();
108            } catch (IOException ignore) {
109            }
110        }
111    }
112
113    public void writeBatteryData(Context context, boolean placebo, int replication, long bucketMins,
114        long periodSecs, int burst) {
115        BatteryStatsParser parser = new BatteryStatsParser();
116        FileInputStream fi = null;
117        BufferedReader br = null;
118        String suffix = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
119        File batteryDataFile = new File(getStorageDir(), "battery_" + suffix + ".csv");
120        Log.d(TAG, "Writing battery data to " + batteryDataFile.getAbsolutePath());
121
122        FileWriter writer = null;
123        try {
124            fi = context.openFileInput(DUMP_FILENAME);
125            writer = new FileWriter(batteryDataFile);
126            writer.append("time,battery_level"
127                + getColumnName(placebo, replication, bucketMins, periodSecs, burst) + "\n");
128            br = new BufferedReader(new InputStreamReader(fi));
129            String line = br.readLine();
130            while (line != null) {
131                String recordLine = parser.parseLine(line);
132                if (recordLine != null) {
133                    writer.append(recordLine);
134                }
135                line = br.readLine();
136            }
137            writer.flush();
138        } catch (IOException e) {
139            throw new RuntimeException(e);
140        } finally {
141            closeQuietly(writer);
142            closeQuietly(br);
143        }
144    }
145
146    private File getStorageDir() {
147        File file = new File(Environment.getExternalStoragePublicDirectory(
148            Environment.DIRECTORY_DOCUMENTS), "loadtest");
149        if (!file.mkdirs()) {
150            Log.e(TAG, "Directory not created");
151        }
152        return file;
153    }
154
155    private String getColumnName(boolean placebo, int replication, long bucketMins, long periodSecs,
156        int burst) {
157        if (placebo) {
158            return "_placebo_p=" + periodSecs;
159        }
160        return "_r=" + replication + "_bkt=" + bucketMins + "_p=" + periodSecs + "_bst=" + burst;
161    }
162}
163