• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
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 package com.google.android.libraries.mobiledatadownload.file.openers;
17 
18 import android.annotation.TargetApi;
19 import android.os.Build;
20 import android.os.Process;
21 import android.system.ErrnoException;
22 import android.system.Os;
23 import android.system.OsConstants;
24 import com.google.android.libraries.mobiledatadownload.file.common.UnsupportedFileStorageOperation;
25 import java.io.File;
26 import java.io.IOException;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.atomic.AtomicInteger;
30 
31 /** Static utility methods pertaining to Posix pipes and streaming data through them. */
32 final class Pipes {
33 
34   private static final int MY_PID = Process.myPid();
35 
36   /**
37    * Creates a named pipe (FIFO) in {@code directory} that's guaranteed to not collide with any
38    * other running process. {@code tag} and {@code idGenerator} should be static and specific to the
39    * caller's class in order to avoid naming collisions with other callers within the same process.
40    *
41    * @throws IOException if the FIFO cannot be created or is not supported at this SDK level (21+)
42    */
43   @TargetApi(Build.VERSION_CODES.LOLLIPOP) // for ErrnoException, Os, and OsConstants
makeFifo(File directory, String tag, AtomicInteger idGenerator)44   static File makeFifo(File directory, String tag, AtomicInteger idGenerator) throws IOException {
45     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
46       throw new UnsupportedFileStorageOperation(
47           String.format("FIFOs require SDK level 21+; current level is %d", Build.VERSION.SDK_INT));
48     }
49     int fifoId = idGenerator.getAndIncrement();
50     String fifoName = ".mobstore-" + tag + "-" + MY_PID + "-" + fifoId + ".fifo";
51     File fifoFile = new File(directory, fifoName);
52     fifoFile.delete(); // Delete stale FIFO if it exists (it shouldn't)
53     try {
54       Os.mkfifo(fifoFile.getAbsolutePath(), OsConstants.S_IRUSR | OsConstants.S_IWUSR);
55       return fifoFile;
56     } catch (ErrnoException e) {
57       fifoFile.delete();
58       throw new IOException(e);
59     }
60   }
61 
62   /**
63    * Blocks on {@code pumpFuture.get()} and propagates any exception it may have encountered as an
64    * {@code IOException}.
65    */
getAndPropagateAsIOException(Future<Throwable> pumpFuture)66   static void getAndPropagateAsIOException(Future<Throwable> pumpFuture) throws IOException {
67     try {
68       Throwable throwable = pumpFuture.get();
69       if (throwable != null) {
70         if (throwable instanceof IOException) {
71           throw (IOException) throwable;
72         }
73         throw new IOException(throwable);
74       }
75     } catch (InterruptedException e) {
76       Thread.currentThread().interrupt(); // per <internal>
77       throw new IOException(e);
78     } catch (ExecutionException e) {
79       if (e.getCause() instanceof IOException) {
80         throw (IOException) e.getCause();
81       }
82       throw new IOException(e);
83     }
84   }
85 
Pipes()86   private Pipes() {}
87 }
88