1 /*
2  * Copyright (C) 2011 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.ide.eclipse.gltrace;
18 
19 import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage;
20 import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function;
21 import com.google.protobuf.InvalidProtocolBufferException;
22 
23 import java.io.DataInputStream;
24 import java.io.DataOutputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 
28 /** A class that streams data received from a socket into the trace file. */
29 public class TraceFileWriter {
30     private DataInputStream mInputStream;
31     private DataOutputStream mOutputStream;
32     private Thread mReceiverThread;
33 
34     private int mFileSize = 0;
35     private int mFrameCount = 0;
36 
37     /**
38      * Construct a trace file writer.
39      * @param fos output stream to write trace data to
40      * @param is input stream from which trace data is read
41      */
TraceFileWriter(FileOutputStream fos, DataInputStream is)42     public TraceFileWriter(FileOutputStream fos, DataInputStream is) {
43         mOutputStream = new DataOutputStream(fos);
44         mInputStream = is;
45     }
46 
start()47     public void start() {
48         // launch thread
49         mReceiverThread = new Thread(new GLTraceReceiverTask());
50         mReceiverThread.setName("GL Trace Receiver");
51         mReceiverThread.start();
52     }
53 
stopTracing()54     public void stopTracing() {
55         // close socket to stop the receiver thread
56         try {
57             mInputStream.close();
58         } catch (IOException e) {
59             // ignore exception while closing socket
60         }
61 
62         // wait for receiver to complete
63         try {
64             mReceiverThread.join();
65         } catch (InterruptedException e1) {
66             // ignore, this cannot be interrupted
67         }
68 
69         // close stream
70         try {
71             mOutputStream.close();
72         } catch (IOException e) {
73             // ignore error while closing stream
74         }
75     }
76 
77     /**
78      * The GLTraceReceiverTask collects trace data from the device and writes it
79      * into a file while collecting some stats on the way.
80      */
81     private class GLTraceReceiverTask implements Runnable {
82         @Override
run()83         public void run() {
84             while (true) {
85                 byte[] buffer = readTraceData(mInputStream);
86                 if (buffer == null) {
87                     break;
88                 }
89 
90                 try {
91                     writeTraceData(buffer, mOutputStream);
92                 } catch (IOException e) {
93                     break;
94                 }
95 
96                 updateTraceStats(buffer);
97             }
98         }
99     }
100 
readTraceData(DataInputStream dis)101     private byte[] readTraceData(DataInputStream dis) {
102         int len;
103         try {
104             len = dis.readInt();
105         } catch (IOException e1) {
106             return null;
107         }
108         len = Integer.reverseBytes(len);    // readInt is big endian, we want little endian
109 
110         byte[] buffer = new byte[len];
111         int readLen = 0;
112         while (readLen < len) {
113             try {
114                 int read = dis.read(buffer, readLen, len - readLen);
115                 if (read < 0) {
116                     return null;
117                 } else {
118                     readLen += read;
119                 }
120             } catch (IOException e) {
121                 return null;
122             }
123         }
124 
125         return buffer;
126     }
127 
128 
writeTraceData(byte[] buffer, DataOutputStream stream)129     private void writeTraceData(byte[] buffer, DataOutputStream stream) throws IOException {
130         stream.writeInt(buffer.length);
131         stream.write(buffer);
132     }
133 
updateTraceStats(byte[] buffer)134     private void updateTraceStats(byte[] buffer) {
135         GLMessage msg = null;
136         try {
137             msg = GLMessage.parseFrom(buffer);
138         } catch (InvalidProtocolBufferException e) {
139             return;
140         }
141 
142         mFileSize += buffer.length;
143 
144         if (msg.getFunction() == Function.eglSwapBuffers) {
145             mFrameCount++;
146         }
147     }
148 
getCurrentFileSize()149     public int getCurrentFileSize() {
150         return mFileSize;
151     }
152 
getCurrentFrameCount()153     public int getCurrentFrameCount() {
154         return mFrameCount;
155     }
156 }
157