1 // Copyright 2021 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.android.downloader; 16 17 import static com.google.common.base.Preconditions.checkState; 18 19 import java.io.IOException; 20 import java.nio.ByteBuffer; 21 import java.nio.channels.SelectableChannel; 22 import java.nio.channels.WritableByteChannel; 23 24 /** Package-local utilities for facilitating common I/O operations across engine implementations. */ 25 final class IOUtil { 26 IOUtil()27 private IOUtil() {} 28 29 /** 30 * Validates the given channel as a valid byte sink for the UrlEngine library. Specifically, it 31 * checks that the given channel is open, and if it is a {@link SelectableChannel}, then it must 32 * be in blocking mode. 33 * 34 * <p>This is to guard against having a sink that refuses write operations in a non-blocking 35 * manner by returning from {@link WritableByteChannel#write} immediately with a return value of 36 * 0, indicating no bytes were written. That would be problematic for the UrlEngine library 37 * because then threads will spin constantly trying to stream bytes from the source to the sink, 38 * saturating the CPU in the process. 39 * 40 * <p>TODO: Figure out a more robust way to handle this. Maybe writing implement proper support 41 * for selectable channels? 42 */ validateChannel(WritableByteChannel channel)43 static void validateChannel(WritableByteChannel channel) { 44 if (channel instanceof SelectableChannel) { 45 SelectableChannel selectableChannel = (SelectableChannel) channel; 46 checkState( 47 selectableChannel.isBlocking(), 48 "Target channels used by UrlEngine must be in blocking mode to ensure " 49 + "writes happen correctly; call SelectableChannel#configureBlocking(true)."); 50 } 51 52 checkState(channel.isOpen()); 53 } 54 blockingWrite(ByteBuffer source, WritableByteChannel target)55 static long blockingWrite(ByteBuffer source, WritableByteChannel target) throws IOException { 56 long written = 0; 57 while (source.hasRemaining()) { 58 written += target.write(source); 59 } 60 return written; 61 } 62 } 63