blob: 2df0024bdea9268782525bff94a7dc3c681abc3f [file] [log] [blame]
Sudheer Shankad4ea5e12020-02-04 16:42:17 -08001/*
2 * Copyright 2020 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 */
16package com.android.utils.blob;
17
Sudheer Shanka96b45372020-02-29 16:49:27 -080018import static com.android.utils.blob.Utils.BUFFER_SIZE_BYTES;
19import static com.android.utils.blob.Utils.copy;
20
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080021import static com.google.common.truth.Truth.assertThat;
22
23import android.app.blob.BlobHandle;
24import android.app.blob.BlobStoreManager;
25import android.content.Context;
26import android.os.FileUtils;
27import android.os.ParcelFileDescriptor;
28
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080029import java.io.File;
30import java.io.FileDescriptor;
31import java.io.FileInputStream;
32import java.io.FileOutputStream;
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080033import java.io.RandomAccessFile;
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080034import java.security.MessageDigest;
35import java.util.Random;
36import java.util.concurrent.TimeUnit;
37
38public class DummyBlobData {
39 private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080040
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080041 private final Random mRandom;
42 private final File mFile;
43 private final long mFileSize;
Sudheer Shankac6c79942020-03-12 13:20:46 -070044 private final CharSequence mLabel;
Sudheer Shanka8992c052020-05-26 18:10:09 -070045 private final long mExpiryDurationMs;
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080046
47 byte[] mFileDigest;
48 long mExpiryTimeMs;
49
Sudheer Shankac0fd5fa2020-03-15 23:31:37 -070050 private DummyBlobData(Builder builder) {
Sudheer Shankac6c79942020-03-12 13:20:46 -070051 mRandom = new Random(builder.getRandomSeed());
52 mFile = new File(builder.getContext().getFilesDir(), builder.getFileName());
53 mFileSize = builder.getFileSize();
54 mLabel = builder.getLabel();
Sudheer Shanka8992c052020-05-26 18:10:09 -070055 mExpiryDurationMs = builder.getExpiryDurationMs();
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080056 }
57
Sudheer Shankac6c79942020-03-12 13:20:46 -070058 public static class Builder {
59 private final Context mContext;
60 private int mRandomSeed = 0;
61 private long mFileSize = DEFAULT_SIZE_BYTES;
62 private CharSequence mLabel = "Test label";
63 private String mFileName = "blob_" + System.nanoTime();
Sudheer Shanka8992c052020-05-26 18:10:09 -070064 private long mExpiryDurationMs = TimeUnit.DAYS.toMillis(1);
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080065
Sudheer Shankac6c79942020-03-12 13:20:46 -070066 public Builder(Context context) {
67 mContext = context;
68 }
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080069
Sudheer Shankac6c79942020-03-12 13:20:46 -070070 public Context getContext() {
71 return mContext;
72 }
Sudheer Shankad4ea5e12020-02-04 16:42:17 -080073
Sudheer Shankac6c79942020-03-12 13:20:46 -070074 public Builder setRandomSeed(int randomSeed) {
75 mRandomSeed = randomSeed;
76 return this;
77 }
78
79 public int getRandomSeed() {
80 return mRandomSeed;
81 }
82
Sudheer Shankaf80c8e52020-04-22 03:36:18 -070083 public Builder setFileSize(long fileSize) {
Sudheer Shankac6c79942020-03-12 13:20:46 -070084 mFileSize = fileSize;
85 return this;
86 }
87
88 public long getFileSize() {
89 return mFileSize;
90 }
91
92 public Builder setLabel(CharSequence label) {
93 mLabel = label;
94 return this;
95 }
96
97 public CharSequence getLabel() {
98 return mLabel;
99 }
100
101 public Builder setFileName(String fileName) {
102 mFileName = fileName;
103 return this;
104 }
105
106 public String getFileName() {
107 return mFileName;
108 }
109
Sudheer Shanka8992c052020-05-26 18:10:09 -0700110 public Builder setExpiryDurationMs(long durationMs) {
111 mExpiryDurationMs = durationMs;
112 return this;
113 }
114
115 public long getExpiryDurationMs() {
116 return mExpiryDurationMs;
117 }
118
Sudheer Shankac6c79942020-03-12 13:20:46 -0700119 public DummyBlobData build() {
120 return new DummyBlobData(this);
121 }
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800122 }
123
124 public void prepare() throws Exception {
125 try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) {
126 writeRandomData(file, mFileSize);
127 }
128 mFileDigest = FileUtils.digest(mFile, "SHA-256");
Sudheer Shanka8992c052020-05-26 18:10:09 -0700129 mExpiryTimeMs = System.currentTimeMillis() + mExpiryDurationMs;
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800130 }
131
132 public BlobHandle getBlobHandle() throws Exception {
Sudheer Shanka96b45372020-02-29 16:49:27 -0800133 return BlobHandle.createWithSha256(mFileDigest, mLabel,
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800134 mExpiryTimeMs, "test_tag");
135 }
136
137 public long getFileSize() throws Exception {
138 return mFileSize;
139 }
140
141 public long getExpiryTimeMillis() {
142 return mExpiryTimeMs;
143 }
144
145 public void delete() {
146 mFile.delete();
147 }
148
149 public void writeToSession(BlobStoreManager.Session session) throws Exception {
150 writeToSession(session, 0, mFileSize);
151 }
152
153 public void writeToSession(BlobStoreManager.Session session,
154 long offsetBytes, long lengthBytes) throws Exception {
155 try (FileInputStream in = new FileInputStream(mFile)) {
Sudheer Shankaa2c20872020-06-21 22:31:26 -0700156 Utils.writeToSession(session, in, offsetBytes, lengthBytes, lengthBytes);
157 }
158 }
159
160 public void writeToSession(BlobStoreManager.Session session,
161 long offsetBytes, long lengthBytes, long allocateBytes) throws Exception {
162 try (FileInputStream in = new FileInputStream(mFile)) {
163 Utils.writeToSession(session, in, offsetBytes, lengthBytes, allocateBytes);
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800164 }
165 }
166
167 public void writeToFd(FileDescriptor fd, long offsetBytes, long lengthBytes) throws Exception {
168 try (FileInputStream in = new FileInputStream(mFile)) {
169 in.getChannel().position(offsetBytes);
170 try (FileOutputStream out = new FileOutputStream(fd)) {
171 copy(in, out, lengthBytes);
172 }
173 }
174 }
175
Sudheer Shanka96b45372020-02-29 16:49:27 -0800176 public ParcelFileDescriptor openForRead() throws Exception {
177 return ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_READ_ONLY);
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800178 }
179
180 public void readFromSessionAndVerifyBytes(BlobStoreManager.Session session,
181 long offsetBytes, int lengthBytes) throws Exception {
182 final byte[] expectedBytes = new byte[lengthBytes];
183 try (FileInputStream in = new FileInputStream(mFile)) {
184 read(in, expectedBytes, offsetBytes, lengthBytes);
185 }
186
187 final byte[] actualBytes = new byte[lengthBytes];
188 try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
Sudheer Shanka2a973ab2020-03-25 12:49:30 -0700189 session.openRead())) {
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800190 read(in, actualBytes, offsetBytes, lengthBytes);
191 }
192
193 assertThat(actualBytes).isEqualTo(expectedBytes);
194
195 }
196
197 private void read(FileInputStream in, byte[] buffer,
198 long offsetBytes, int lengthBytes) throws Exception {
199 in.getChannel().position(offsetBytes);
200 in.read(buffer, 0, lengthBytes);
201 }
202
203 public void readFromSessionAndVerifyDigest(BlobStoreManager.Session session)
204 throws Exception {
205 readFromSessionAndVerifyDigest(session, 0, mFile.length());
206 }
207
208 public void readFromSessionAndVerifyDigest(BlobStoreManager.Session session,
209 long offsetBytes, long lengthBytes) throws Exception {
210 final byte[] actualDigest;
211 try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
Sudheer Shanka2a973ab2020-03-25 12:49:30 -0700212 session.openRead())) {
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800213 actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
214 }
215
216 assertThat(actualDigest).isEqualTo(mFileDigest);
217 }
218
219 public void verifyBlob(ParcelFileDescriptor pfd) throws Exception {
220 final byte[] actualDigest;
221 try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
222 actualDigest = FileUtils.digest(in, "SHA-256");
223 }
224 assertThat(actualDigest).isEqualTo(mFileDigest);
225 }
226
227 private byte[] createSha256Digest(FileInputStream in, long offsetBytes, long lengthBytes)
228 throws Exception {
229 final MessageDigest digest = MessageDigest.getInstance("SHA-256");
230 in.getChannel().position(offsetBytes);
231 final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
232 long bytesRead = 0;
233 while (bytesRead < lengthBytes) {
234 int toRead = (bytesRead + buffer.length <= lengthBytes)
235 ? buffer.length : (int) (lengthBytes - bytesRead);
236 toRead = in.read(buffer, 0, toRead);
237 digest.update(buffer, 0, toRead);
238 bytesRead += toRead;
239 }
240 return digest.digest();
241 }
242
Sudheer Shankad4ea5e12020-02-04 16:42:17 -0800243 private void writeRandomData(RandomAccessFile file, long fileSize)
244 throws Exception {
245 long bytesWritten = 0;
246 final byte[] buffer = new byte[BUFFER_SIZE_BYTES];
247 while (bytesWritten < fileSize) {
248 mRandom.nextBytes(buffer);
249 final int toWrite = (bytesWritten + buffer.length <= fileSize)
250 ? buffer.length : (int) (fileSize - bytesWritten);
251 file.seek(bytesWritten);
252 file.write(buffer, 0, toWrite);
253 bytesWritten += toWrite;
254 }
255 }
256}