1 /* 2 * Copyright (C) 2009 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 android.content.res.cts; 18 19 import static android.system.OsConstants.S_ISFIFO; 20 21 import static junit.framework.TestCase.assertEquals; 22 import static junit.framework.TestCase.assertFalse; 23 import static junit.framework.TestCase.assertTrue; 24 import static junit.framework.TestCase.fail; 25 26 import android.content.Context; 27 import android.content.res.AssetFileDescriptor; 28 import android.os.ParcelFileDescriptor; 29 import android.platform.test.annotations.AppModeSdkSandbox; 30 import android.system.Os; 31 import android.system.StructStat; 32 import android.test.MoreAsserts; 33 34 import androidx.test.ext.junit.runners.AndroidJUnit4; 35 import androidx.test.platform.app.InstrumentationRegistry; 36 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import java.io.BufferedOutputStream; 43 import java.io.File; 44 import java.io.FileDescriptor; 45 import java.io.FileInputStream; 46 import java.io.FileOutputStream; 47 import java.io.IOException; 48 import java.io.OutputStream; 49 import java.nio.ByteBuffer; 50 import java.nio.MappedByteBuffer; 51 import java.nio.channels.FileChannel; 52 import java.nio.channels.WritableByteChannel; 53 54 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 55 @RunWith(AndroidJUnit4.class) 56 public class AssetFileDescriptor_AutoCloseInputStreamTest { getContext()57 private Context getContext() { 58 return InstrumentationRegistry.getInstrumentation().getTargetContext(); 59 } 60 61 private static final int FILE_END = -1; 62 private static final String FILE_NAME = "testAssertFileDescriptorAutoCloseInputStream"; 63 private static final byte[] FILE_DATA = new byte[]{ 64 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 65 }; 66 private static final int FILE_LENGTH = FILE_DATA.length; 67 private static final String METHOD_NOT_SUPPORTED_MESSAGE = 68 "This Method is not supported in AutoCloseInputStream FileChannel."; 69 private File mFile; 70 private AssetFileDescriptor mFd; 71 private AssetFileDescriptor.AutoCloseInputStream mInput; 72 73 @Before setUp()74 public void setUp() throws Exception { 75 mFile = new File(getContext().getFilesDir(), FILE_NAME); 76 FileOutputStream outputStream = new FileOutputStream(mFile); 77 outputStream.write(FILE_DATA); 78 outputStream.close(); 79 } 80 81 @After tearDown()82 public void tearDown() throws Exception { 83 if (mFd != null) { 84 mFd.close(); 85 mFd = null; 86 } 87 mFile.delete(); 88 } 89 90 @Test testSkip()91 public void testSkip() throws IOException { 92 openInput(0, FILE_LENGTH); 93 assertEquals(FILE_DATA[0], mInput.read()); 94 assertEquals(0, mInput.skip(0)); 95 assertEquals(FILE_DATA[1], mInput.read()); 96 assertEquals(3, mInput.skip(3)); 97 assertEquals(FILE_DATA[5], mInput.read()); 98 assertEquals(3, mInput.skip(10)); 99 assertEquals(FILE_END, mInput.read()); 100 } 101 102 @Test testRead()103 public void testRead() throws IOException { 104 openInput(0, FILE_LENGTH); 105 for (int i = 0; i < FILE_LENGTH; i++) { 106 assertEquals(FILE_DATA[i], mInput.read()); 107 } 108 assertEquals(FILE_END, mInput.read()); 109 } 110 111 @Test testReadPartial()112 public void testReadPartial() throws IOException { 113 long len = 6; 114 openInput(0, len); 115 for (int i = 0; i < len; i++) { 116 assertEquals(FILE_DATA[i], mInput.read()); 117 } 118 assertEquals(FILE_END, mInput.read()); 119 } 120 121 @Test testReadBufferLen()122 public void testReadBufferLen() throws IOException { 123 openInput(0, FILE_LENGTH); 124 byte[] buf = new byte[FILE_LENGTH]; 125 assertEquals(3, mInput.read(buf, 0, 3)); 126 assertEquals(3, mInput.read(buf, 3, 3)); 127 assertEquals(3, mInput.read(buf, 6, 4)); 128 MoreAsserts.assertEquals(FILE_DATA, buf); 129 assertEquals(FILE_END, mInput.read(buf, 0, 4)); 130 } 131 132 @Test testReadBuffer()133 public void testReadBuffer() throws IOException { 134 openInput(0, FILE_LENGTH); 135 byte[] buf = new byte[6]; 136 assertEquals(6, mInput.read(buf)); 137 assertEquals(FILE_DATA[0], buf[0]); 138 assertEquals(3, mInput.read(buf)); 139 assertEquals(FILE_DATA[6], buf[0]); 140 assertEquals(FILE_END, mInput.read(buf)); 141 } 142 143 @Test testReadBufferPartial()144 public void testReadBufferPartial() throws IOException { 145 long len = 8; 146 openInput(0, len); 147 byte[] buf = new byte[6]; 148 assertEquals(6, mInput.read(buf)); 149 assertEquals(FILE_DATA[0], buf[0]); 150 assertEquals(2, mInput.read(buf)); 151 assertEquals(FILE_DATA[6], buf[0]); 152 assertEquals(FILE_END, mInput.read(buf)); 153 } 154 155 @Test testAvailableRead()156 public void testAvailableRead() throws IOException { 157 openInput(0, FILE_LENGTH); 158 assertEquals(FILE_LENGTH, mInput.available()); 159 assertEquals(FILE_DATA[0], mInput.read()); 160 assertEquals(FILE_LENGTH - 1, mInput.available()); 161 } 162 163 @Test testAvailableReadBuffer()164 public void testAvailableReadBuffer() throws IOException { 165 openInput(0, FILE_LENGTH); 166 byte[] buf = new byte[3]; 167 assertEquals(FILE_LENGTH, mInput.available()); 168 assertEquals(buf.length, mInput.read(buf)); 169 assertEquals(FILE_LENGTH - buf.length, mInput.available()); 170 } 171 172 @Test testAvailableReadBufferLen()173 public void testAvailableReadBufferLen() throws IOException { 174 openInput(0, FILE_LENGTH); 175 byte[] buf = new byte[3]; 176 assertEquals(FILE_LENGTH, mInput.available()); 177 assertEquals(2, mInput.read(buf, 0, 2)); 178 assertEquals(FILE_LENGTH - 2, mInput.available()); 179 } 180 181 /* 182 * Tests that AutoInputStream doesn't support mark(). 183 */ 184 @Test testMark()185 public void testMark() throws IOException { 186 openInput(0, FILE_LENGTH); 187 assertFalse(mInput.markSupported()); 188 assertEquals(FILE_DATA[0], mInput.read()); 189 mInput.mark(FILE_LENGTH); // should do nothing 190 assertEquals(FILE_DATA[1], mInput.read()); 191 mInput.reset(); // should do nothing 192 assertEquals(FILE_DATA[2], mInput.read()); 193 } 194 195 @Test testTwoFileDescriptorsWorkIndependently()196 public void testTwoFileDescriptorsWorkIndependently() throws IOException { 197 openInput(0, FILE_LENGTH); 198 199 AssetFileDescriptor fd2 = new AssetFileDescriptor(mFd.getParcelFileDescriptor(), 200 0, 201 FILE_LENGTH); 202 AssetFileDescriptor.AutoCloseInputStream input2 = 203 new AssetFileDescriptor.AutoCloseInputStream(fd2); 204 205 input2.skip(2); 206 input2.read(); 207 208 for (int i = 0; i < FILE_LENGTH; i++) { 209 assertEquals(FILE_DATA[i], mInput.read()); 210 } 211 assertEquals(FILE_END, mInput.read()); 212 } 213 214 @Test testReadZeroByte()215 public void testReadZeroByte() throws IOException { 216 openInput(0, FILE_LENGTH); 217 byte[] buf = new byte[1]; 218 assertEquals(FILE_LENGTH, mInput.available()); 219 assertEquals(0, mInput.read(buf, 0, 0)); 220 assertEquals(FILE_LENGTH, mInput.available()); 221 } 222 223 @Test testReadLargeBytes()224 public void testReadLargeBytes() throws IOException { 225 final int writeSize = 1_000_000; 226 mFile = new File(getContext().getFilesDir(), FILE_NAME); 227 try (OutputStream out = 228 new BufferedOutputStream(new FileOutputStream(mFile))) { 229 for (int i = 0; i < writeSize; i++) { 230 out.write(i % 256); 231 } 232 } 233 234 openInput(0, writeSize); 235 236 assertEquals(writeSize, mFd.getLength()); 237 assertEquals(writeSize, mInput.readAllBytes().length); 238 } 239 openInput(long startOffset, long length)240 private void openInput(long startOffset, long length) 241 throws IOException { 242 if (mFd != null) { 243 mFd.close(); 244 mFd = null; 245 } 246 ParcelFileDescriptor fd = 247 ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_READ_WRITE); 248 mFd = new AssetFileDescriptor(fd, startOffset, length); 249 mInput = new AssetFileDescriptor.AutoCloseInputStream(mFd); 250 } 251 252 /* 253 * Tests that AutoInputStream is returning customized File Channel of getChannel(), 254 * which could help update the channel position. 255 */ 256 @Test testGetChannel()257 public void testGetChannel() throws IOException { 258 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 259 input.skip(2); 260 FileChannel fc = input.getChannel(); 261 input.read(); 262 assertEquals(3, fc.position()); 263 } 264 265 @Test testOffsetCorrectFileChannelSize()266 public void testOffsetCorrectFileChannelSize() throws IOException { 267 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 268 FileChannel fc = input.getChannel(); 269 assertEquals(fc.size(), FILE_LENGTH); 270 } 271 272 @Test testOffsetCorrectFileChannelReadBuffer()273 public void testOffsetCorrectFileChannelReadBuffer() throws IOException { 274 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 275 FileChannel fc = input.getChannel(); 276 277 int startPosition = 0; 278 int bufferSize = 4; 279 ByteBuffer buffer = ByteBuffer.allocate(bufferSize); 280 int bytesRead = fc.read(buffer); 281 assertEquals(bufferSize, bytesRead); 282 283 buffer.flip(); 284 for (int i = startPosition; i < startPosition + bufferSize; i++) { 285 assertEquals(FILE_DATA[i], buffer.get()); 286 } 287 assertFalse(buffer.hasRemaining()); 288 assertEquals(startPosition + bufferSize, fc.position()); 289 } 290 291 @Test testOffsetCorrectFileChannelReadBuffers()292 public void testOffsetCorrectFileChannelReadBuffers() throws IOException { 293 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 294 FileChannel fc = input.getChannel(); 295 296 int startPosition = 0; 297 int bufferSize = 4; 298 ByteBuffer[] buffers = new ByteBuffer[1]; 299 buffers[0] = ByteBuffer.allocate(bufferSize); 300 fc.read(buffers, 0, buffers.length); 301 buffers[0].flip(); 302 for (int i = startPosition; i < startPosition + bufferSize; i++) { 303 assertEquals(FILE_DATA[i], buffers[0].get()); 304 } 305 assertFalse(buffers[0].hasRemaining()); 306 assertEquals(startPosition + bufferSize, fc.position()); 307 } 308 309 @Test testOffsetCorrectFileChannelReadBufferFromPosition()310 public void testOffsetCorrectFileChannelReadBufferFromPosition() throws IOException { 311 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 312 FileChannel fc = input.getChannel(); 313 314 int startPosition = 0; 315 int bufferSize = 4; 316 ByteBuffer buffer = ByteBuffer.allocate(bufferSize); 317 int readPosition = 1; 318 fc.read(buffer, readPosition); 319 buffer.flip(); 320 for (int i = readPosition; i < readPosition + bufferSize; i++) { 321 assertEquals(FILE_DATA[i], buffer.get()); 322 } 323 assertEquals(startPosition, fc.position()); 324 } 325 326 @Test testOffsetCorrectFileChannelTransferTo()327 public void testOffsetCorrectFileChannelTransferTo() throws IOException { 328 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 329 FileChannel fc = input.getChannel(); 330 331 String outputFileName = "outputFile.txt"; 332 File outputFile = new File(getContext().getFilesDir(), outputFileName); 333 FileOutputStream output = new FileOutputStream(outputFile); 334 WritableByteChannel targetChannel = output.getChannel(); 335 int startPosition = 1; 336 int transferSize = 3; 337 long bytesTransferred = fc.transferTo(startPosition, transferSize, targetChannel); 338 assertEquals(transferSize, bytesTransferred); 339 assertEquals(0, fc.position()); 340 341 ParcelFileDescriptor fd = 342 ParcelFileDescriptor.open(outputFile, ParcelFileDescriptor.MODE_READ_WRITE); 343 AssetFileDescriptor afd = new AssetFileDescriptor(fd, 0, transferSize); 344 AssetFileDescriptor.AutoCloseInputStream input2 = 345 new AssetFileDescriptor.AutoCloseInputStream(afd); 346 347 for (int i = startPosition; i < startPosition + transferSize; i++) { 348 assertEquals(FILE_DATA[i], input2.read()); 349 } 350 assertEquals(-1, input2.read()); 351 352 targetChannel.close(); 353 output.close(); 354 } 355 356 @Test testOffsetCorrectFileChannelMap()357 public void testOffsetCorrectFileChannelMap() throws IOException { 358 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 359 FileChannel fc = input.getChannel(); 360 361 int startPosition = 0; 362 int mapPosition = 1; 363 int mapSize = 4; 364 MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, mapPosition, mapSize); 365 for (int i = mapPosition; i < mapPosition + mapSize; i++) { 366 assertEquals(FILE_DATA[i], mbb.get()); 367 } 368 assertFalse(mbb.hasRemaining()); 369 assertEquals(startPosition, fc.position()); 370 } 371 372 @Test testOffsetCorrectFileChannelWriteBuffer()373 public void testOffsetCorrectFileChannelWriteBuffer() throws IOException { 374 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 375 FileChannel fc = input.getChannel(); 376 377 ByteBuffer buffer = ByteBuffer.allocate(1); 378 try { 379 fc.write(buffer); 380 fail(); 381 } catch (UnsupportedOperationException e) { 382 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 383 } 384 } 385 386 @Test testOffsetCorrectFileChannelWriteBuffers()387 public void testOffsetCorrectFileChannelWriteBuffers() throws IOException { 388 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 389 FileChannel fc = input.getChannel(); 390 391 int bufferSize = 4; 392 ByteBuffer[] buffers = new ByteBuffer[1]; 393 buffers[0] = ByteBuffer.allocate(bufferSize); 394 try { 395 fc.write(buffers, 0, 1); 396 fail(); 397 } catch (UnsupportedOperationException e) { 398 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 399 } 400 } 401 402 @Test testOffsetCorrectFileChannelWriteBufferFromPosition()403 public void testOffsetCorrectFileChannelWriteBufferFromPosition() throws IOException { 404 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 405 FileChannel fc = input.getChannel(); 406 407 int bufferSize = 4; 408 ByteBuffer buffer = ByteBuffer.allocate(bufferSize); 409 try { 410 fc.write(buffer, 0); 411 fail(); 412 } catch (UnsupportedOperationException e) { 413 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 414 } 415 } 416 417 @Test testOffsetCorrectFileChannelTransferFrom()418 public void testOffsetCorrectFileChannelTransferFrom() throws IOException { 419 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 420 FileChannel fc = input.getChannel(); 421 422 FileInputStream input2 = new FileInputStream(mFile); 423 FileChannel fc2 = input2.getChannel(); 424 try { 425 fc.transferFrom(fc2, 0, fc2.size()); 426 fail(); 427 } catch (UnsupportedOperationException e) { 428 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 429 } 430 fc2.close(); 431 input2.close(); 432 } 433 434 @Test testOffsetCorrectFileChannelTruncate()435 public void testOffsetCorrectFileChannelTruncate() throws IOException { 436 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 437 FileChannel fc = input.getChannel(); 438 439 try { 440 fc.truncate(FILE_LENGTH + 1); 441 fail(); 442 } catch (UnsupportedOperationException e) { 443 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 444 } 445 } 446 447 @Test testOffsetCorrectFileChannelForce()448 public void testOffsetCorrectFileChannelForce() throws IOException { 449 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 450 FileChannel fc = input.getChannel(); 451 452 try { 453 fc.force(true); 454 fail(); 455 } catch (UnsupportedOperationException e) { 456 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 457 } 458 } 459 460 @Test testOffsetCorrectFileChannelLock()461 public void testOffsetCorrectFileChannelLock() throws IOException { 462 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 463 FileChannel fc = input.getChannel(); 464 465 try { 466 fc.lock(0, 4, true); 467 fail(); 468 } catch (UnsupportedOperationException e) { 469 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 470 } 471 } 472 473 @Test testOffsetCorrectFileChannelTryLock()474 public void testOffsetCorrectFileChannelTryLock() throws IOException { 475 AssetFileDescriptor.AutoCloseInputStream input = getInputStream(); 476 FileChannel fc = input.getChannel(); 477 478 try { 479 fc.tryLock(0, 4, true); 480 fail(); 481 } catch (UnsupportedOperationException e) { 482 assertEquals(METHOD_NOT_SUPPORTED_MESSAGE, e.getMessage()); 483 } 484 } 485 getInputStream()486 private AssetFileDescriptor.AutoCloseInputStream getInputStream() throws IOException { 487 openInput(0, FILE_LENGTH); 488 AssetFileDescriptor fd = new AssetFileDescriptor(mFd.getParcelFileDescriptor(), 489 0, 490 FILE_LENGTH); 491 AssetFileDescriptor.AutoCloseInputStream input = 492 new AssetFileDescriptor.AutoCloseInputStream(fd); 493 return input; 494 } 495 496 @Test testNonSeekableInputStream()497 public void testNonSeekableInputStream() throws Exception { 498 final FileDescriptor[] fds = Os.pipe(); 499 AssetFileDescriptor readAFd = new AssetFileDescriptor( 500 new ParcelFileDescriptor(fds[0]), 0, FILE_LENGTH); 501 FileDescriptor writeFd = fds[1]; 502 FileOutputStream out = new FileOutputStream(writeFd); 503 out.write(FILE_DATA); 504 out.close(); 505 506 StructStat ss = Os.fstat(readAFd.getParcelFileDescriptor().getFileDescriptor()); 507 assertTrue(S_ISFIFO(ss.st_mode)); 508 509 AssetFileDescriptor.AutoCloseInputStream in = 510 new AssetFileDescriptor.AutoCloseInputStream(readAFd); 511 assertEquals(FILE_LENGTH, in.available()); 512 assertEquals(FILE_DATA[0], in.read()); 513 assertEquals(FILE_LENGTH - 1, in.available()); 514 515 byte[]buffer = new byte[2]; 516 assertEquals(buffer.length, in.read(buffer)); 517 assertEquals(FILE_DATA[3], in.read()); 518 assertEquals(FILE_LENGTH - 4, in.available()); 519 520 assertEquals(1, in.skip(1)); 521 assertEquals(FILE_DATA[5], in.read()); 522 in.close(); 523 } 524 } 525