/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.eclipse.gltrace; import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage; import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; import com.google.protobuf.InvalidProtocolBufferException; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; /** A class that streams data received from a socket into the trace file. */ public class TraceFileWriter { private DataInputStream mInputStream; private DataOutputStream mOutputStream; private Thread mReceiverThread; private int mFileSize = 0; private int mFrameCount = 0; /** * Construct a trace file writer. * @param fos output stream to write trace data to * @param is input stream from which trace data is read */ public TraceFileWriter(FileOutputStream fos, DataInputStream is) { mOutputStream = new DataOutputStream(fos); mInputStream = is; } public void start() { // launch thread mReceiverThread = new Thread(new GLTraceReceiverTask()); mReceiverThread.setName("GL Trace Receiver"); mReceiverThread.start(); } public void stopTracing() { // close socket to stop the receiver thread try { mInputStream.close(); } catch (IOException e) { // ignore exception while closing socket } // wait for receiver to complete try { mReceiverThread.join(); } catch (InterruptedException e1) { // ignore, this cannot be interrupted } // close stream try { mOutputStream.close(); } catch (IOException e) { // ignore error while closing stream } } /** * The GLTraceReceiverTask collects trace data from the device and writes it * into a file while collecting some stats on the way. */ private class GLTraceReceiverTask implements Runnable { @Override public void run() { while (true) { byte[] buffer = readTraceData(mInputStream); if (buffer == null) { break; } try { writeTraceData(buffer, mOutputStream); } catch (IOException e) { break; } updateTraceStats(buffer); } } } private byte[] readTraceData(DataInputStream dis) { int len; try { len = dis.readInt(); } catch (IOException e1) { return null; } len = Integer.reverseBytes(len); // readInt is big endian, we want little endian byte[] buffer = new byte[len]; int readLen = 0; while (readLen < len) { try { int read = dis.read(buffer, readLen, len - readLen); if (read < 0) { return null; } else { readLen += read; } } catch (IOException e) { return null; } } return buffer; } private void writeTraceData(byte[] buffer, DataOutputStream stream) throws IOException { stream.writeInt(buffer.length); stream.write(buffer); } private void updateTraceStats(byte[] buffer) { GLMessage msg = null; try { msg = GLMessage.parseFrom(buffer); } catch (InvalidProtocolBufferException e) { return; } mFileSize += buffer.length; if (msg.getFunction() == Function.eglSwapBuffers) { mFrameCount++; } } public int getCurrentFileSize() { return mFileSize; } public int getCurrentFrameCount() { return mFrameCount; } }