• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 android.support.test.aupt;
18 
19 import android.app.Instrumentation;
20 import android.os.SystemClock;
21 import android.util.Log;
22 
23 import java.io.File;
24 import java.io.IOException;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.concurrent.atomic.AtomicBoolean;
29 
30 public class DataCollector {
31     private static final String TAG = "AuptDataCollector";
32 
33     private final AtomicBoolean mStopped = new AtomicBoolean(true);
34     private final Map<LogGenerator, Long> generatorsWithIntervals = new HashMap<>();
35     private final Map<LogGenerator, Long> mLastUpdate = new HashMap<>();
36     private final Instrumentation instrumentation;
37     private final String resultsDirectory;
38     private final long mSleepInterval;
39 
40     private Thread mThread;
41 
42     /**
43      * Add a generator iff the interval is valid (i.e. > 0).
44      */
put(LogGenerator key, Long interval)45     private void put(LogGenerator key, Long interval) {
46         if (interval > 0) {
47             generatorsWithIntervals.put(key, interval);
48         }
49     }
50 
DataCollector(long bugreportInterval, long graphicsInterval, long meminfoInterval, long cpuinfoInterval, long fragmentationInterval, long ionHeapInterval, long pagetypeinfoInterval, long traceInterval, long bugreportzInterval, File outputLocation, Instrumentation instr)51     public DataCollector(long bugreportInterval, long graphicsInterval,      long meminfoInterval,
52                          long cpuinfoInterval,   long fragmentationInterval, long ionHeapInterval,
53                          long pagetypeinfoInterval, long traceInterval,
54                          long bugreportzInterval, File outputLocation, Instrumentation instr) {
55 
56         resultsDirectory = outputLocation.getPath();
57         instrumentation = instr;
58 
59         if (bugreportzInterval > 0) {
60             put(LogGenerator.BUGREPORTZ, bugreportzInterval);
61             if (bugreportInterval > 0) {
62                 Log.w(TAG, String.format("Both zipped and flat bugreports are enabled. Defaulting"
63                         + " to use zipped bugreports, at %s ms interval.", bugreportzInterval));
64             }
65         } else if (bugreportInterval > 0) {
66             put(LogGenerator.BUGREPORT, bugreportInterval);
67         }
68         put(LogGenerator.CPU_INFO, cpuinfoInterval);
69         put(LogGenerator.FRAGMENTATION, fragmentationInterval);
70         put(LogGenerator.GRAPHICS_STATS, graphicsInterval);
71         put(LogGenerator.ION_HEAP, ionHeapInterval);
72         put(LogGenerator.MEM_INFO, meminfoInterval);
73         put(LogGenerator.PAGETYPE_INFO, pagetypeinfoInterval);
74         put(LogGenerator.TRACE, traceInterval);
75 
76         mSleepInterval = gcd(generatorsWithIntervals.values());
77     }
78 
start()79     public synchronized void start() {
80         if (mStopped.getAndSet(false)) {
81             /* Initialize the LastUpdates to the current time */
82             for (Map.Entry<LogGenerator, Long> entry : generatorsWithIntervals.entrySet()) {
83                 if (entry.getValue() > 0) {
84                     Log.d(TAG, "Collecting " + entry.getKey() + " logs every " +
85                         entry.getValue() + " milliseconds");
86 
87                     mLastUpdate.put(entry.getKey(), SystemClock.uptimeMillis());
88                 }
89             }
90 
91             mThread = new Thread(new Runnable() {
92                 @Override
93                 public void run() {
94                     loop();
95                 }
96             });
97             mThread.start();
98         } else {
99             Log.e(TAG, "Tried to start a started DataCollector!");
100         }
101     }
102 
stop()103     public synchronized void stop() {
104         if (!mStopped.getAndSet(true)) {
105             mThread.interrupt();
106 
107             try {
108                 mThread.join();
109             } catch (InterruptedException e) {
110                 // ignore
111             }
112         } else {
113             Log.e(TAG, "Tried to stop a stoppped DataCollector!");
114         }
115     }
116 
loop()117     private void loop() {
118         if (mSleepInterval <= 0) {
119             return;
120         }
121 
122         while (!mStopped.get()) {
123             try {
124                 for (Map.Entry<LogGenerator, Long> entry : generatorsWithIntervals.entrySet()) {
125                     Long t = SystemClock.uptimeMillis() - mLastUpdate.get(entry.getKey());
126 
127                     if (entry.getValue() > 0 && t >= entry.getValue()) {
128                         try {
129                             entry.getKey().save(instrumentation, resultsDirectory);
130                         } catch (IOException ex) {
131                             Log.e(TAG, "Error writing results in " + resultsDirectory +
132                                     ": " + ex.toString());
133                         }
134 
135                         mLastUpdate.put(entry.getKey(), SystemClock.uptimeMillis());
136                     }
137                 }
138 
139                 Thread.sleep(mSleepInterval);
140             } catch (InterruptedException e) {
141                 // Ignore.
142             }
143         }
144     }
145 
gcd(Collection<Long> values)146     private long gcd(Collection<Long> values) {
147         if (values.size() < 1) {
148             return 0;
149         }
150 
151         long gcdSoFar = values.iterator().next();
152 
153         for (Long value : values) {
154             gcdSoFar = gcd(gcdSoFar, value);
155         }
156 
157         return gcdSoFar;
158     }
159 
gcd(long a, long b)160     private long gcd(long a, long b) {
161         if (a == 0) {
162             return b;
163         } else if (b == 0) {
164             return a;
165         } else if (a > b) {
166             return gcd(b, a % b);
167         } else {
168             return gcd(a, b % a);
169         }
170     }
171 }
172