Merge changes Iac97c342,I52518d52

* changes:
  Enable sendfile() and splice() optimizations.
  Use sendfile() and splice() to speed up copying.
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index f75678b..6e0bd3a 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -34,6 +35,7 @@
 
 import libcore.io.Streams;
 
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 
@@ -583,7 +585,7 @@
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
             try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null)) {
-                Streams.copy(new FileInputStream(fd.getFileDescriptor()), System.out);
+                FileUtils.copy(fd.getFileDescriptor(), FileDescriptor.out);
             }
         }
     }
@@ -596,7 +598,7 @@
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
             try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "w", null, null)) {
-                Streams.copy(System.in, new FileOutputStream(fd.getFileDescriptor()));
+                FileUtils.copy(FileDescriptor.in, fd.getFileDescriptor());
             }
         }
     }
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 7c53ec1..21d245d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,11 @@
 
 package android.os;
 
+import static android.system.OsConstants.SPLICE_F_MORE;
+import static android.system.OsConstants.SPLICE_F_MOVE;
+import static android.system.OsConstants.S_ISFIFO;
+import static android.system.OsConstants.S_ISREG;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.provider.DocumentsContract.Document;
@@ -29,6 +34,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
 import java.io.BufferedInputStream;
@@ -41,10 +47,12 @@
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 import java.util.zip.CRC32;
 import java.util.zip.CheckedInputStream;
@@ -81,6 +89,14 @@
 
     private static final File[] EMPTY = new File[0];
 
+    private static final boolean ENABLE_COPY_OPTIMIZATIONS = true;
+
+    private static final long COPY_CHECKPOINT_BYTES = 524288;
+
+    public interface CopyListener {
+        public void onProgress(long progress);
+    }
+
     /**
      * Set owner and mode of of given {@link File}.
      *
@@ -185,6 +201,9 @@
         return false;
     }
 
+    /**
+     * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+     */
     @Deprecated
     public static boolean copyFile(File srcFile, File destFile) {
         try {
@@ -195,14 +214,19 @@
         }
     }
 
-    // copy a file from srcFile to destFile, return true if succeed, return
-    // false if fail
+    /**
+     * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+     */
+    @Deprecated
     public static void copyFileOrThrow(File srcFile, File destFile) throws IOException {
         try (InputStream in = new FileInputStream(srcFile)) {
             copyToFileOrThrow(in, destFile);
         }
     }
 
+    /**
+     * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+     */
     @Deprecated
     public static boolean copyToFile(InputStream inputStream, File destFile) {
         try {
@@ -214,28 +238,153 @@
     }
 
     /**
-     * Copy data from a source stream to destFile.
-     * Return true if succeed, return false if failed.
+     * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
      */
-    public static void copyToFileOrThrow(InputStream inputStream, File destFile)
-            throws IOException {
+    @Deprecated
+    public static void copyToFileOrThrow(InputStream in, File destFile) throws IOException {
         if (destFile.exists()) {
             destFile.delete();
         }
-        FileOutputStream out = new FileOutputStream(destFile);
-        try {
-            byte[] buffer = new byte[4096];
-            int bytesRead;
-            while ((bytesRead = inputStream.read(buffer)) >= 0) {
-                out.write(buffer, 0, bytesRead);
-            }
-        } finally {
-            out.flush();
+        try (FileOutputStream out = new FileOutputStream(destFile)) {
+            copy(in, out);
             try {
-                out.getFD().sync();
-            } catch (IOException e) {
+                Os.fsync(out.getFD());
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
             }
-            out.close();
+        }
+    }
+
+    public static void copy(File from, File to) throws IOException {
+        try (FileInputStream in = new FileInputStream(from);
+                FileOutputStream out = new FileOutputStream(to)) {
+            copy(in, out);
+        }
+    }
+
+    public static void copy(InputStream in, OutputStream out) throws IOException {
+        copy(in, out, null, null);
+    }
+
+    public static void copy(InputStream in, OutputStream out, CopyListener listener,
+            CancellationSignal signal) throws IOException {
+        if (ENABLE_COPY_OPTIMIZATIONS) {
+            if (in instanceof FileInputStream && out instanceof FileOutputStream) {
+                copy(((FileInputStream) in).getFD(), ((FileOutputStream) out).getFD(),
+                        listener, signal);
+            }
+        }
+
+        // Worse case fallback to userspace
+        copyInternalUserspace(in, out, listener, signal);
+    }
+
+    public static void copy(FileDescriptor in, FileDescriptor out) throws IOException {
+        copy(in, out, null, null);
+    }
+
+    public static void copy(FileDescriptor in, FileDescriptor out, CopyListener listener,
+            CancellationSignal signal) throws IOException {
+        if (ENABLE_COPY_OPTIMIZATIONS) {
+            try {
+                final StructStat st_in = Os.fstat(in);
+                final StructStat st_out = Os.fstat(out);
+                if (S_ISREG(st_in.st_mode) && S_ISREG(st_out.st_mode)) {
+                    copyInternalSendfile(in, out, listener, signal);
+                } else if (S_ISFIFO(st_in.st_mode) || S_ISFIFO(st_out.st_mode)) {
+                    copyInternalSplice(in, out, listener, signal);
+                }
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        }
+
+        // Worse case fallback to userspace
+        copyInternalUserspace(in, out, listener, signal);
+    }
+
+    /**
+     * Requires one of input or output to be a pipe.
+     */
+    @VisibleForTesting
+    public static void copyInternalSplice(FileDescriptor in, FileDescriptor out,
+            CopyListener listener, CancellationSignal signal) throws ErrnoException {
+        long progress = 0;
+        long checkpoint = 0;
+
+        long t;
+        while ((t = Os.splice(in, null, out, null, COPY_CHECKPOINT_BYTES,
+                SPLICE_F_MOVE | SPLICE_F_MORE)) != 0) {
+            progress += t;
+            checkpoint += t;
+
+            if (checkpoint >= COPY_CHECKPOINT_BYTES) {
+                if (signal != null) {
+                    signal.throwIfCanceled();
+                }
+                if (listener != null) {
+                    listener.onProgress(progress);
+                }
+                checkpoint = 0;
+            }
+        }
+    }
+
+    /**
+     * Requires both input and output to be a regular file.
+     */
+    @VisibleForTesting
+    public static void copyInternalSendfile(FileDescriptor in, FileDescriptor out,
+            CopyListener listener, CancellationSignal signal) throws ErrnoException {
+        long progress = 0;
+        long checkpoint = 0;
+
+        long t;
+        while ((t = Os.sendfile(out, in, null, COPY_CHECKPOINT_BYTES)) != 0) {
+            progress += t;
+            checkpoint += t;
+
+            if (checkpoint >= COPY_CHECKPOINT_BYTES) {
+                if (signal != null) {
+                    signal.throwIfCanceled();
+                }
+                if (listener != null) {
+                    listener.onProgress(progress);
+                }
+                checkpoint = 0;
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public static void copyInternalUserspace(FileDescriptor in, FileDescriptor out,
+            CopyListener listener, CancellationSignal signal) throws IOException {
+        copyInternalUserspace(new FileInputStream(in), new FileOutputStream(out), listener, signal);
+    }
+
+    @VisibleForTesting
+    public static void copyInternalUserspace(InputStream in, OutputStream out,
+            CopyListener listener, CancellationSignal signal) throws IOException {
+        long progress = 0;
+        long checkpoint = 0;
+        byte[] buffer = new byte[8192];
+
+        int t;
+        while ((t = in.read(buffer)) != -1) {
+            out.write(buffer, 0, t);
+
+            progress += t;
+            checkpoint += t;
+
+            if (checkpoint >= COPY_CHECKPOINT_BYTES) {
+                if (signal != null) {
+                    signal.throwIfCanceled();
+                }
+                if (listener != null) {
+                    listener.onProgress(progress);
+                }
+                checkpoint = 0;
+            }
         }
     }
 
@@ -797,4 +946,69 @@
         }
         return val * pow;
     }
+
+    @VisibleForTesting
+    public static class MemoryPipe extends Thread implements AutoCloseable {
+        private final FileDescriptor[] pipe;
+        private final byte[] data;
+        private final boolean sink;
+
+        private MemoryPipe(byte[] data, boolean sink) throws IOException {
+            try {
+                this.pipe = Os.pipe();
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+            this.data = data;
+            this.sink = sink;
+        }
+
+        private MemoryPipe startInternal() {
+            super.start();
+            return this;
+        }
+
+        public static MemoryPipe createSource(byte[] data) throws IOException {
+            return new MemoryPipe(data, false).startInternal();
+        }
+
+        public static MemoryPipe createSink(byte[] data) throws IOException {
+            return new MemoryPipe(data, true).startInternal();
+        }
+
+        public FileDescriptor getFD() {
+            return sink ? pipe[1] : pipe[0];
+        }
+
+        public FileDescriptor getInternalFD() {
+            return sink ? pipe[0] : pipe[1];
+        }
+
+        @Override
+        public void run() {
+            final FileDescriptor fd = getInternalFD();
+            try {
+                int i = 0;
+                while (i < data.length) {
+                    if (sink) {
+                        i += Os.read(fd, data, i, data.length - i);
+                    } else {
+                        i += Os.write(fd, data, i, data.length - i);
+                    }
+                }
+            } catch (IOException | ErrnoException e) {
+                throw new RuntimeException(e);
+            } finally {
+                if (sink) {
+                    SystemClock.sleep(TimeUnit.SECONDS.toMillis(1));
+                }
+                IoUtils.closeQuietly(fd);
+            }
+        }
+
+        @Override
+        public void close() throws Exception {
+            IoUtils.closeQuietly(getFD());
+        }
+    }
 }
diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java
index 71550be..f8885a2 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -160,7 +160,7 @@
                     final File file = new File(mBasePath, name);
                     final FileInputStream is = new FileInputStream(file);
                     try {
-                        Streams.copy(is, zos);
+                        FileUtils.copy(is, zos);
                     } finally {
                         IoUtils.closeQuietly(is);
                     }
diff --git a/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java b/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
new file mode 100644
index 0000000..4f7c924
--- /dev/null
+++ b/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.os;
+
+import static android.os.FileUtils.copyInternalSendfile;
+import static android.os.FileUtils.copyInternalSplice;
+import static android.os.FileUtils.copyInternalUserspace;
+
+import android.os.FileUtils.MemoryPipe;
+
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Param;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+public class FileUtilsBenchmark {
+    @Param({"32", "32000", "32000000"})
+    private int mSize;
+
+    private File mSrc;
+    private File mDest;
+
+    private byte[] mData;
+
+    @BeforeExperiment
+    protected void setUp() throws Exception {
+        mSrc = new File("/data/local/tmp/src");
+        mDest = new File("/data/local/tmp/dest");
+
+        mData = new byte[mSize];
+
+        try (FileOutputStream os = new FileOutputStream(mSrc)) {
+            os.write(mData);
+        }
+    }
+
+    public void timeRegularUserspace(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            try (FileInputStream in = new FileInputStream(mSrc);
+                    FileOutputStream out = new FileOutputStream(mDest)) {
+                copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+            }
+        }
+    }
+
+    public void timeRegularSendfile(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            try (FileInputStream in = new FileInputStream(mSrc);
+                    FileOutputStream out = new FileOutputStream(mDest)) {
+                copyInternalSendfile(in.getFD(), out.getFD(), null, null);
+            }
+        }
+    }
+
+    public void timePipeSourceUserspace(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            try (MemoryPipe in = MemoryPipe.createSource(mData);
+                    FileOutputStream out = new FileOutputStream(mDest)) {
+                copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+            }
+        }
+    }
+
+    public void timePipeSourceSplice(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            try (MemoryPipe in = MemoryPipe.createSource(mData);
+                    FileOutputStream out = new FileOutputStream(mDest)) {
+                copyInternalSplice(in.getFD(), out.getFD(), null, null);
+            }
+        }
+    }
+
+    public void timePipeSinkUserspace(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            try (FileInputStream in = new FileInputStream(mSrc);
+                    MemoryPipe out = MemoryPipe.createSink(mData)) {
+                copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+            }
+        }
+    }
+
+    public void timePipeSinkSplice(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            try (FileInputStream in = new FileInputStream(mSrc);
+                    MemoryPipe out = MemoryPipe.createSink(mData)) {
+                copyInternalSplice(in.getFD(), out.getFD(), null, null);
+            }
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index cd20192..b7220b3 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -21,16 +21,19 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.os.FileUtils.MemoryPipe;
 import android.provider.DocumentsContract.Document;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 
 import libcore.io.IoUtils;
+import libcore.io.Streams;
 
 import com.google.android.collect.Sets;
 
@@ -40,11 +43,13 @@
 import org.junit.runner.RunWith;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Random;
 
 @RunWith(AndroidJUnit4.class)
 public class FileUtilsTest {
@@ -56,6 +61,8 @@
     private File mCopyFile;
     private File mTarget;
 
+    private final int[] DATA_SIZES = { 32, 32_000, 32_000_000 };
+
     private Context getContext() {
         return InstrumentationRegistry.getContext();
     }
@@ -80,7 +87,7 @@
 
     @Test
     public void testCopyFile() throws Exception {
-        stageFile(mTestFile, TEST_DATA);
+        writeFile(mTestFile, TEST_DATA);
         assertFalse(mCopyFile.exists());
         FileUtils.copyFile(mTestFile, mCopyFile);
         assertTrue(mCopyFile.exists());
@@ -97,6 +104,83 @@
     }
 
     @Test
+    public void testCopy_FileToFile() throws Exception {
+        for (int size : DATA_SIZES) {
+            final File src = new File(mTarget, "src");
+            final File dest = new File(mTarget, "dest");
+
+            byte[] expected = new byte[size];
+            byte[] actual = new byte[size];
+            new Random().nextBytes(expected);
+            writeFile(src, expected);
+
+            try (FileInputStream in = new FileInputStream(src);
+                    FileOutputStream out = new FileOutputStream(dest)) {
+                FileUtils.copy(in, out);
+            }
+
+            actual = readFile(dest);
+            assertArrayEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void testCopy_FileToPipe() throws Exception {
+        for (int size : DATA_SIZES) {
+            final File src = new File(mTarget, "src");
+
+            byte[] expected = new byte[size];
+            byte[] actual = new byte[size];
+            new Random().nextBytes(expected);
+            writeFile(src, expected);
+
+            try (FileInputStream in = new FileInputStream(src);
+                    MemoryPipe out = MemoryPipe.createSink(actual)) {
+                FileUtils.copy(in.getFD(), out.getFD());
+                out.join();
+            }
+
+            assertArrayEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void testCopy_PipeToFile() throws Exception {
+        for (int size : DATA_SIZES) {
+            final File dest = new File(mTarget, "dest");
+
+            byte[] expected = new byte[size];
+            byte[] actual = new byte[size];
+            new Random().nextBytes(expected);
+
+            try (MemoryPipe in = MemoryPipe.createSource(expected);
+                    FileOutputStream out = new FileOutputStream(dest)) {
+                FileUtils.copy(in.getFD(), out.getFD());
+            }
+
+            actual = readFile(dest);
+            assertArrayEquals(expected, actual);
+        }
+    }
+
+    @Test
+    public void testCopy_PipeToPipe() throws Exception {
+        for (int size : DATA_SIZES) {
+            byte[] expected = new byte[size];
+            byte[] actual = new byte[size];
+            new Random().nextBytes(expected);
+
+            try (MemoryPipe in = MemoryPipe.createSource(expected);
+                    MemoryPipe out = MemoryPipe.createSink(actual)) {
+                FileUtils.copy(in.getFD(), out.getFD());
+                out.join();
+            }
+
+            assertArrayEquals(expected, actual);
+        }
+    }
+
+    @Test
     public void testIsFilenameSafe() throws Exception {
         assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
         assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
@@ -106,7 +190,7 @@
 
     @Test
     public void testReadTextFile() throws Exception {
-        stageFile(mTestFile, TEST_DATA);
+        writeFile(mTestFile, TEST_DATA);
 
         assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null));
 
@@ -127,7 +211,7 @@
 
     @Test
     public void testReadTextFileWithZeroLengthFile() throws Exception {
-        stageFile(mTestFile, TEST_DATA);
+        writeFile(mTestFile, TEST_DATA);
         new FileOutputStream(mTestFile).close();  // Zero out the file
         assertEquals("", FileUtils.readTextFile(mTestFile, 0, null));
         assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>"));
@@ -381,12 +465,21 @@
         file.setLastModified(System.currentTimeMillis() - age);
     }
 
-    private void stageFile(File file, String data) throws Exception {
-        FileWriter writer = new FileWriter(file);
-        try {
-            writer.write(data, 0, data.length());
-        } finally {
-            writer.close();
+    private void writeFile(File file, String data) throws Exception {
+        writeFile(file, data.getBytes());
+    }
+
+    private void writeFile(File file, byte[] data) throws Exception {
+        try (FileOutputStream out = new FileOutputStream(file)) {
+            out.write(data);
+        }
+    }
+
+    private byte[] readFile(File file) throws Exception {
+        try (FileInputStream in = new FileInputStream(file);
+                ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            Streams.copy(in, out);
+            return out.toByteArray();
         }
     }
 
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 3eb9d52..fefa1ed 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -28,11 +28,13 @@
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -47,22 +49,17 @@
 
 import com.android.internal.database.SortCursor;
 
-import libcore.io.Streams;
-
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;
 
-import static android.content.ContentProvider.maybeAddUserId;
-import static android.content.pm.PackageManager.NameNotFoundException;
-
 /**
  * RingtoneManager provides access to ringtones, notification, and other types
  * of sounds. It manages querying the different media providers and combines the
@@ -855,7 +852,7 @@
             final Uri cacheUri = getCacheForType(type, context.getUserId());
             try (InputStream in = openRingtone(context, ringtoneUri);
                     OutputStream out = resolver.openOutputStream(cacheUri)) {
-                Streams.copy(in, out);
+                FileUtils.copy(in, out);
             } catch (IOException e) {
                 Log.w(TAG, "Failed to cache ringtone: " + e);
             }
@@ -960,7 +957,7 @@
         // Copy contents to external ringtone storage. Throws IOException if the copy fails.
         try (final InputStream input = mContext.getContentResolver().openInputStream(fileUri);
                 final OutputStream output = new FileOutputStream(outFile)) {
-            Streams.copy(input, output);
+            FileUtils.copy(input, output);
         }
 
         // Tell MediaScanner about the new file. Wait for it to assign a {@link Uri}.
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 8b01aef..9f165bc 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -30,6 +30,7 @@
 import android.content.res.ObbScanner;
 import android.os.Binder;
 import android.os.Environment.UserEnvironment;
+import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -43,7 +44,6 @@
 import com.android.internal.util.ArrayUtils;
 
 import libcore.io.IoUtils;
-import libcore.io.Streams;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -260,7 +260,7 @@
             in = new FileInputStream(sourcePath);
             out = new ParcelFileDescriptor.AutoCloseOutputStream(
                     target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
-            Streams.copy(in, out);
+            FileUtils.copy(in, out);
         } finally {
             IoUtils.closeQuietly(out);
             IoUtils.closeQuietly(in);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index c02331d..5060c4d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -693,7 +693,7 @@
                 InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
                 OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
         ) {
-            Streams.copy(fileIn, fileOut);
+            FileUtils.copy(fileIn, fileOut);
             Os.chmod(dstFile.getAbsolutePath(), 0644);
             return PackageManager.INSTALL_SUCCEEDED;
         } catch (IOException e) {