Test if allocation supported; @removed clean up.

SM.allocateBytes() doesn't offer a clear way to detect if a failed
request could ever succeed.  (For example, we can never work with
pipes, or files on an unsupported storage device.)  So give
developers a first-class API to test if allocation is supported.

If the underlying filesystem doesn't support fallocate(), fall back
to ftruncate() instead of failing completely.

Clean up @removed APIs that were refactoring during API 26 review
process.

Remove support for storing downloads on the /cache partition, which
doesn't exist on many devices.

Bug: 63057877
Test: bit DownloadProviderTests:*
Test: bit DocumentsUITests:com.android.documentsui.services.CopyJobTest
Test: bit DocumentsUITests:com.android.documentsui.services.MoveJobTest
Change-Id: I85d42a1a7240034b4f2a6f359011ac182bdce36e
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 5baaeb3..b444f17 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -18,9 +18,9 @@
 
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -36,8 +36,8 @@
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.provider.Downloads;
-import android.provider.Settings;
 import android.provider.MediaStore.Images;
+import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
 import android.util.Pair;
@@ -393,7 +393,6 @@
         private int mFlags = 0;
         private boolean mIsVisibleInDownloadsUi = true;
         private boolean mScannable = false;
-        private boolean mUseSystemCache = false;
         /** if a file is designated as a MediaScanner scannable file, the following value is
          * stored in the database column {@link Downloads.Impl#COLUMN_MEDIA_SCANNED}.
          */
@@ -474,24 +473,6 @@
         }
 
         /**
-         * Set the local destination for the downloaded file to the system cache dir (/cache).
-         * This is only available to System apps with the permission
-         * {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}.
-         * <p>
-         * The downloaded file is not scanned by MediaScanner.
-         * But it can be made scannable by calling {@link #allowScanningByMediaScanner()}.
-         * <p>
-         * Files downloaded to /cache may be deleted by the system at any time to reclaim space.
-         *
-         * @return this object
-         * @hide
-         */
-        public Request setDestinationToSystemCache() {
-            mUseSystemCache = true;
-            return this;
-        }
-
-        /**
          * Set the local destination for the downloaded file to a path within
          * the application's external files directory (as returned by
          * {@link Context#getExternalFilesDir(String)}.
@@ -772,13 +753,13 @@
             values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, packageName);
 
             if (mDestinationUri != null) {
-                values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI);
-                values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, mDestinationUri.toString());
+                values.put(Downloads.Impl.COLUMN_DESTINATION,
+                        Downloads.Impl.DESTINATION_FILE_URI);
+                values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT,
+                        mDestinationUri.toString());
             } else {
                 values.put(Downloads.Impl.COLUMN_DESTINATION,
-                           (this.mUseSystemCache) ?
-                                   Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION :
-                                   Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
+                        Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
             }
             // is the file supposed to be media-scannable?
             values.put(Downloads.Impl.COLUMN_MEDIA_SCANNED, (mScannable) ? SCANNABLE_VALUE_YES :
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 71f5ff7..6372113 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -739,7 +739,7 @@
      * {@link Environment#getDataDirectory()}, the returned value will be
      * {@link #UUID_DEFAULT}.
      *
-     * @throws IOException when the storage device at the given path isn't
+     * @throws IOException when the storage device hosting the given path isn't
      *             present, or when it doesn't have a valid UUID.
      */
     public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
@@ -771,6 +771,19 @@
         throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
     }
 
+    /**
+     * Test if the given file descriptor supports allocation of disk space using
+     * {@link #allocateBytes(FileDescriptor, long)}.
+     */
+    public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
+        try {
+            getUuidForPath(ParcelFileDescriptor.getFile(fd));
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     /** {@hide} */
     public @NonNull List<VolumeInfo> getVolumes() {
         try {
@@ -1562,12 +1575,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    public long getCacheQuotaBytes(@NonNull File path) throws IOException {
-        return getCacheQuotaBytes(getUuidForPath(path));
-    }
-
     /**
      * Return total size in bytes of all cached data belonging to the calling
      * app on the given storage volume.
@@ -1603,36 +1610,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    public long getCacheSizeBytes(@NonNull File path) throws IOException {
-        return getCacheSizeBytes(getUuidForPath(path));
-    }
-
-    /** @removed */
-    @Deprecated
-    public long getCacheQuotaBytes() throws IOException {
-        return getCacheQuotaBytes(mContext.getCacheDir());
-    }
-
-    /** @removed */
-    @Deprecated
-    public long getCacheSizeBytes() throws IOException {
-        return getCacheSizeBytes(mContext.getCacheDir());
-    }
-
-    /** @removed */
-    @Deprecated
-    public long getExternalCacheQuotaBytes() throws IOException {
-        return getCacheQuotaBytes(mContext.getExternalCacheDir());
-    }
-
-    /** @removed */
-    @Deprecated
-    public long getExternalCacheSizeBytes() throws IOException {
-        return getCacheSizeBytes(mContext.getExternalCacheDir());
-    }
-
     /**
      * Flag indicating that a disk space allocation request should operate in an
      * aggressive mode. This flag should only be rarely used in situations that
@@ -1741,15 +1718,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    @WorkerThread
-    @SuppressLint("Doclava125")
-    public long getAllocatableBytes(@NonNull File path,
-            @RequiresPermission @AllocateFlags int flags) throws IOException {
-        return getAllocatableBytes(getUuidForPath(path), flags);
-    }
-
     /**
      * Allocate the requested number of bytes for your application to use on the
      * given storage volume. This will cause the system to delete any cached
@@ -1798,15 +1766,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    @WorkerThread
-    @SuppressLint("Doclava125")
-    public void allocateBytes(@NonNull File path, @BytesLong long bytes,
-            @RequiresPermission @AllocateFlags int flags) throws IOException {
-        allocateBytes(getUuidForPath(path), bytes, flags);
-    }
-
     /**
      * Allocate the requested number of bytes for your application to use in the
      * given open file. This will cause the system to delete any cached files
@@ -1834,6 +1793,7 @@
      *             doesn't support allocating space, or if the device had
      *             trouble allocating the requested space.
      * @see #getAllocatableBytes(UUID, int)
+     * @see #isAllocationSupported(FileDescriptor)
      * @see Environment#isExternalStorageEmulated(File)
      */
     @WorkerThread
@@ -1848,17 +1808,28 @@
     public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
             @RequiresPermission @AllocateFlags int flags) throws IOException {
         final File file = ParcelFileDescriptor.getFile(fd);
+        final UUID uuid = getUuidForPath(file);
         for (int i = 0; i < 3; i++) {
             try {
                 final long haveBytes = Os.fstat(fd).st_blocks * 512;
                 final long needBytes = bytes - haveBytes;
 
                 if (needBytes > 0) {
-                    allocateBytes(file, needBytes, flags);
+                    allocateBytes(uuid, needBytes, flags);
                 }
 
-                Os.posix_fallocate(fd, 0, bytes);
-                return;
+                try {
+                    Os.posix_fallocate(fd, 0, bytes);
+                    return;
+                } catch (ErrnoException e) {
+                    if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
+                        Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
+                        Os.ftruncate(fd, bytes);
+                        return;
+                    } else {
+                        throw e;
+                    }
+                }
             } catch (ErrnoException e) {
                 if (e.errno == OsConstants.ENOSPC) {
                     Log.w(TAG, "Odd, not enough space; let's try again?");
@@ -1941,18 +1912,6 @@
         return isCacheBehavior(path, XATTR_CACHE_GROUP);
     }
 
-    /** @removed */
-    @Deprecated
-    public void setCacheBehaviorAtomic(File path, boolean atomic) throws IOException {
-        setCacheBehaviorGroup(path, atomic);
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isCacheBehaviorAtomic(File path) throws IOException {
-        return isCacheBehaviorGroup(path);
-    }
-
     /**
      * Enable or disable special cache behavior that leaves deleted cache files
      * intact as tombstones.
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 9d83bd7..a2c5a92 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -485,6 +485,7 @@
          * partition. This option is only used by system apps and so it requires
          * android.permission.ACCESS_CACHE_FILESYSTEM permission.
          */
+        @Deprecated
         public static final int DESTINATION_SYSTEMCACHE_PARTITION = 5;
 
         /**
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 9c361b3..e923223 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -16,11 +16,14 @@
 
 package com.android.internal.content;
 
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
+
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageParser.PackageLite;
 import android.os.Environment;
@@ -39,21 +42,19 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collections;
 import java.util.Objects;
+import java.util.UUID;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
-import libcore.io.IoUtils;
-
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
-
 /**
  * Constants used internally between the PackageManager
  * and media container service transports.
@@ -358,7 +359,7 @@
         public boolean fitsOnInternalStorage(Context context, SessionParams params)
                 throws IOException {
             StorageManager storage = getStorageManager(context);
-            File target = getDataDirectory();
+            final UUID target = storage.getUuidForPath(getDataDirectory());
             return (params.sizeBytes <= storage.getAllocatableBytes(target,
                     translateAllocateFlags(params.installFlags)));
         }
@@ -466,7 +467,8 @@
             boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id);
             if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()
                     && (!isInternalStorage || allow3rdPartyOnInternal)) {
-                final long availBytes = storageManager.getAllocatableBytes(new File(vol.path),
+                final UUID target = storageManager.getUuidForPath(new File(vol.path));
+                final long availBytes = storageManager.getAllocatableBytes(target,
                         translateAllocateFlags(params.installFlags));
                 if (availBytes >= params.sizeBytes) {
                     allCandidates.add(vol.fsUuid);
@@ -523,7 +525,7 @@
 
     public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException {
         final StorageManager storage = context.getSystemService(StorageManager.class);
-        final File target = Environment.getDataDirectory();
+        final UUID target = storage.getUuidForPath(Environment.getDataDirectory());
         return (params.sizeBytes <= storage.getAllocatableBytes(target,
                 translateAllocateFlags(params.installFlags)));
     }
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index 42b06f5..68b9b00 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -29,13 +29,15 @@
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.os.UserHandle;
 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
+import libcore.io.Streams;
+
 import com.google.mockwebserver.MockResponse;
 import com.google.mockwebserver.MockWebServer;
 
@@ -54,8 +56,6 @@
 import java.util.Set;
 import java.util.concurrent.TimeoutException;
 
-import libcore.io.Streams;
-
 /**
  * Base class for Instrumented tests for the Download Manager.
  */
@@ -83,9 +83,6 @@
     protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000;  // 1 second
     protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 30 * 1000; // 30 seconds
 
-    protected static final int DOWNLOAD_TO_SYSTEM_CACHE = 1;
-    protected static final int DOWNLOAD_TO_DOWNLOAD_CACHE_DIR = 2;
-
     // Just a few popular file types used to return from a download
     protected enum DownloadFileType {
         PLAINTEXT,
@@ -923,13 +920,13 @@
      * @param body The body to return in the response from the server
      */
     protected long doStandardEnqueue(byte[] body) throws Exception {
-        return enqueueDownloadRequest(body, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+        return enqueueDownloadRequest(body);
     }
 
-    protected long enqueueDownloadRequest(byte[] body, int location) throws Exception {
+    protected long enqueueDownloadRequest(byte[] body) throws Exception {
         // Prepare the mock server with a standard response
         mServer.enqueue(buildResponse(HTTP_OK, body));
-        return doEnqueue(location);
+        return doEnqueue();
     }
 
     /**
@@ -938,13 +935,13 @@
      * @param body The body to return in the response from the server, contained in the file
      */
     protected long doStandardEnqueue(File body) throws Exception {
-        return enqueueDownloadRequest(body, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+        return enqueueDownloadRequest(body);
     }
 
-    protected long enqueueDownloadRequest(File body, int location) throws Exception {
+    protected long enqueueDownloadRequest(File body) throws Exception {
         // Prepare the mock server with a standard response
         mServer.enqueue(buildResponse(HTTP_OK, body));
-        return doEnqueue(location);
+        return doEnqueue();
     }
 
     /**
@@ -952,16 +949,12 @@
      * doing a standard enqueue request to the server.
      */
     protected long doCommonStandardEnqueue() throws Exception {
-        return doEnqueue(DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+        return doEnqueue();
     }
 
-    private long doEnqueue(int location) throws Exception {
+    private long doEnqueue() throws Exception {
         Uri uri = getServerUri(DEFAULT_FILENAME);
         Request request = new Request(uri).setTitle(DEFAULT_FILENAME);
-        if (location == DOWNLOAD_TO_SYSTEM_CACHE) {
-            request.setDestinationToSystemCache();
-        }
-
         return mDownloadManager.enqueue(request);
     }
 
@@ -1026,8 +1019,8 @@
     /**
      * Helper that does the actual basic download verification.
      */
-    protected long doBasicDownload(byte[] blobData, int location) throws Exception {
-        long dlRequest = enqueueDownloadRequest(blobData, location);
+    protected long doBasicDownload(byte[] blobData) throws Exception {
+        long dlRequest = enqueueDownloadRequest(blobData);
 
         // wait for the download to complete
         waitForDownloadOrTimeout(dlRequest);
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index d1a5d28..c1d4be0 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -23,12 +23,13 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.test.suitebuilder.annotation.LargeTest;
+
 import com.google.mockwebserver.MockResponse;
 
 import java.io.File;
-import java.util.concurrent.TimeoutException;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Integration tests of the DownloadManager API.
@@ -95,11 +96,11 @@
      * Test a basic download of a binary file 500k in size.
      */
     @LargeTest
-    public void testBinaryDownloadToSystemCache() throws Exception {
+    public void testBinaryDownload() throws Exception {
         int fileSize = 1024;
         byte[] blobData = generateData(fileSize, DataType.BINARY);
 
-        long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+        long dlRequest = doBasicDownload(blobData);
         verifyDownload(dlRequest, blobData);
         mDownloadManager.remove(dlRequest);
     }
@@ -108,11 +109,11 @@
      * Tests the basic downloading of a text file 300000 bytes in size.
      */
     @LargeTest
-    public void testTextDownloadToSystemCache() throws Exception {
+    public void testTextDownload() throws Exception {
         int fileSize = 1024;
         byte[] blobData = generateData(fileSize, DataType.TEXT);
 
-        long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+        long dlRequest = doBasicDownload(blobData);
         verifyDownload(dlRequest, blobData);
         mDownloadManager.remove(dlRequest);
     }
@@ -318,7 +319,7 @@
         int fileSize = 1024;
         byte[] blobData = generateData(fileSize, DataType.BINARY);
 
-        long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
+        long dlRequest = doBasicDownload(blobData);
         Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest));
         try {
             assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount());
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 9fa9131..39d9a8e 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -195,7 +195,7 @@
 
             // try to download 1MB file into /cache - and it should succeed
             byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
-            long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
+            long dlRequest = doBasicDownload(blobData);
             verifyAndCleanupSingleFileDownload(dlRequest, blobData);
         } finally {
             if (outFile != null) {
diff --git a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
index 5c497b4..55092fa 100644
--- a/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageHelperTests.java
@@ -34,6 +34,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.os.storage.VolumeInfo.STATE_MOUNTED;
@@ -90,14 +91,20 @@
         File internalFile = new File(sInternalVolPath);
         File adoptedFile = new File(sAdoptedVolPath);
         File publicFile = new File(sPublicVolPath);
+        UUID internalUuid = UUID.randomUUID();
+        UUID adoptedUuid = UUID.randomUUID();
+        UUID publicUuid = UUID.randomUUID();
         Mockito.when(storageManager.getStorageBytesUntilLow(internalFile)).thenReturn(sInternalSize);
         Mockito.when(storageManager.getStorageBytesUntilLow(adoptedFile)).thenReturn(sAdoptedSize);
         Mockito.when(storageManager.getStorageBytesUntilLow(publicFile)).thenReturn(sPublicSize);
-        Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(internalFile), Mockito.anyInt()))
+        Mockito.when(storageManager.getUuidForPath(Mockito.eq(internalFile))).thenReturn(internalUuid);
+        Mockito.when(storageManager.getUuidForPath(Mockito.eq(adoptedFile))).thenReturn(adoptedUuid);
+        Mockito.when(storageManager.getUuidForPath(Mockito.eq(publicFile))).thenReturn(publicUuid);
+        Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(internalUuid), Mockito.anyInt()))
                 .thenReturn(sInternalSize);
-        Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(adoptedFile), Mockito.anyInt()))
+        Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(adoptedUuid), Mockito.anyInt()))
                 .thenReturn(sAdoptedSize);
-        Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(publicFile), Mockito.anyInt()))
+        Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(publicUuid), Mockito.anyInt()))
                 .thenReturn(sPublicSize);
         return storageManager;
     }