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