1 /* 2 * Copyright (C) 2016 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.tools.build.apkzlib.zip.utils; 18 19 import com.google.common.io.ByteSource; 20 import com.google.common.io.ByteStreams; 21 import java.io.ByteArrayOutputStream; 22 import java.io.IOException; 23 import java.io.InputStream; 24 import javax.annotation.Nonnull; 25 26 /** 27 * Keeps track of used bytes allowing gauging memory usage. 28 */ 29 public class ByteTracker { 30 31 /** 32 * Number of bytes currently in use. 33 */ 34 private long bytesUsed; 35 36 /** 37 * Maximum number of bytes used. 38 */ 39 private long maxBytesUsed; 40 41 /** 42 * Creates a new byte source by fully reading an input stream. 43 * 44 * @param stream the input stream 45 * @return a byte source containing the cached data from the given stream 46 * @throws IOException failed to read the stream 47 */ fromStream(@onnull InputStream stream)48 public CloseableDelegateByteSource fromStream(@Nonnull InputStream stream) throws IOException { 49 byte[] data = ByteStreams.toByteArray(stream); 50 updateUsage(data.length); 51 return new CloseableDelegateByteSource(ByteSource.wrap(data), data.length) { 52 @Override 53 public synchronized void innerClose() throws IOException { 54 super.innerClose(); 55 updateUsage(-sizeNoException()); 56 } 57 }; 58 } 59 60 /** 61 * Creates a new byte source by snapshotting the provided stream. 62 * 63 * @param stream the stream with the data 64 * @return a byte source containing the cached data from the given stream 65 * @throws IOException failed to read the stream 66 */ 67 public CloseableDelegateByteSource fromStream(@Nonnull ByteArrayOutputStream stream) 68 throws IOException { 69 byte[] data = stream.toByteArray(); 70 updateUsage(data.length); 71 return new CloseableDelegateByteSource(ByteSource.wrap(data), data.length) { 72 @Override 73 public synchronized void innerClose() throws IOException { 74 super.innerClose(); 75 updateUsage(-sizeNoException()); 76 } 77 }; 78 } 79 80 /** 81 * Creates a new byte source from another byte source. 82 * 83 * @param source the byte source to copy data from 84 * @return the tracked byte source 85 * @throws IOException failed to read data from the byte source 86 */ 87 public CloseableDelegateByteSource fromSource(@Nonnull ByteSource source) throws IOException { 88 return fromStream(source.openStream()); 89 } 90 91 /** 92 * Updates the memory used by this tracker. 93 * 94 * @param delta the number of bytes to add or remove, if negative 95 */ 96 private synchronized void updateUsage(long delta) { 97 bytesUsed += delta; 98 if (maxBytesUsed < bytesUsed) { 99 maxBytesUsed = bytesUsed; 100 } 101 } 102 103 /** 104 * Obtains the number of bytes currently used. 105 * 106 * @return the number of bytes 107 */ 108 public synchronized long getBytesUsed() { 109 return bytesUsed; 110 } 111 112 /** 113 * Obtains the maximum number of bytes ever used by this tracker. 114 * 115 * @return the number of bytes 116 */ 117 public synchronized long getMaxBytesUsed() { 118 return maxBytesUsed; 119 } 120 } 121